diff --git a/src/Support/WebauthnAssets.php b/src/Support/WebauthnAssets.php index 5228b70..f65eb3d 100644 --- a/src/Support/WebauthnAssets.php +++ b/src/Support/WebauthnAssets.php @@ -4,6 +4,8 @@ namespace Rawilk\Webauthn\Support; +use Illuminate\Support\Facades\Vite; + class WebauthnAssets { public function javaScript(array $options = []): string @@ -17,15 +19,35 @@ public function javaScript(array $options = []): string private function javaScriptAssets(array $options = []): string { - $appUrl = config('webauthn.asset_url', rtrim($options['asset_url'] ?? '', '/')); + $assetsUrl = config('webauthn.asset_url') ?: rtrim($options['asset_url'] ?? '', '/'); + $nonce = $this->getNonce($options); $manifest = json_decode(file_get_contents(__DIR__ . '/../../dist/mix-manifest.json'), true); $versionedFileName = ltrim($manifest['/assets/webauthn.js'], '/'); - $fullAssetPath = "{$appUrl}/webauthn/{$versionedFileName}"; + $fullAssetPath = "{$assetsUrl}/webauthn/{$versionedFileName}"; return << + HTML; } + + private function getNonce(array $options): string + { + if (isset($options['nonce'])) { + return "nonce=\"{$options['nonce']}\""; + } + + // If there is a csp package installed, i.e. spatie/laravel-csp, we'll check for the existence of the helper function. + if (function_exists('csp_nonce') && $nonce = csp_nonce()) { + return "nonce=\"{$nonce}\""; + } + + // Lastly, we'll check for the existence of a csp nonce from Vite. + if (class_exists(Vite::class) && $nonce = Vite::cspNonce()) { + return "nonce=\"{$nonce}\""; + } + + return ''; + } } diff --git a/tests/Pest.php b/tests/Pest.php index c6ce5b8..c2f7491 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -11,6 +11,7 @@ uses(TestCase::class)->in( __DIR__ . '/Models', __DIR__ . '/Services', + __DIR__ . '/Unit', ); // Helpers diff --git a/tests/Unit/AssetsDirectiveTest.php b/tests/Unit/AssetsDirectiveTest.php new file mode 100644 index 0000000..8a54fec --- /dev/null +++ b/tests/Unit/AssetsDirectiveTest.php @@ -0,0 +1,59 @@ +assets = new WebauthnAssets; +}); + +it('outputs the script source', function () { + $this->assertStringContainsString( + '