diff --git a/app/Extensions/Captcha/Providers/CaptchaProvider.php b/app/Extensions/Captcha/Providers/CaptchaProvider.php new file mode 100644 index 000000000..7c5db3009 --- /dev/null +++ b/app/Extensions/Captcha/Providers/CaptchaProvider.php @@ -0,0 +1,118 @@ + + */ + protected static array $providers = []; + + /** + * @return self|static[] + */ + public static function get(?string $id = null): array|self + { + return $id ? static::$providers[$id] : static::$providers; + } + + protected function __construct(protected Application $app) + { + if (array_key_exists($this->getId(), static::$providers)) { + if (!$this->app->runningUnitTests()) { + logger()->warning("Tried to create duplicate Captcha provider with id '{$this->getId()}'"); + } + + return; + } + + config()->set('captcha.' . Str::lower($this->getId()), $this->getConfig()); + + static::$providers[$this->getId()] = $this; + } + + abstract public function getId(): string; + + abstract public function getComponent(): Component; + + /** + * @return array + */ + public function getConfig(): array + { + $id = Str::upper($this->getId()); + + return [ + 'site_key' => env("CAPTCHA_{$id}_SITE_KEY"), + 'secret_key' => env("CAPTCHA_{$id}_SECRET_KEY"), + ]; + } + + /** + * @return Component[] + */ + public function getSettingsForm(): array + { + $id = Str::upper($this->getId()); + + return [ + TextInput::make("CAPTCHA_{$id}_SITE_KEY") + ->label('Site Key') + ->placeholder('Site Key') + ->columnSpan(2) + ->required() + ->password() + ->revealable() + ->autocomplete(false) + ->default(env("CAPTCHA_{$id}_SITE_KEY")), + TextInput::make("CAPTCHA_{$id}_SECRET_KEY") + ->label('Secret Key') + ->placeholder('Secret Key') + ->columnSpan(2) + ->required() + ->password() + ->revealable() + ->autocomplete(false) + ->default(env("CAPTCHA_{$id}_SECRET_KEY")), + ]; + } + + public function getName(): string + { + return Str::title($this->getId()); + } + + public function getIcon(): ?string + { + return null; + } + + public function isEnabled(): bool + { + $id = Str::upper($this->getId()); + + return env("CAPTCHA_{$id}_ENABLED", false); + } + + /** + * @return array + */ + public function validateResponse(?string $captchaResponse = null): array + { + return [ + 'success' => false, + 'message' => 'validateResponse not defined', + ]; + } + + public function verifyDomain(string $hostname, ?string $requestUrl = null): bool + { + return true; + } +} diff --git a/app/Extensions/Captcha/Providers/TurnstileProvider.php b/app/Extensions/Captcha/Providers/TurnstileProvider.php new file mode 100644 index 000000000..70980a249 --- /dev/null +++ b/app/Extensions/Captcha/Providers/TurnstileProvider.php @@ -0,0 +1,106 @@ + + */ + public function getConfig(): array + { + return array_merge(parent::getConfig(), [ + 'verify_domain' => env('CAPTCHA_TURNSTILE_VERIFY_DOMAIN'), + ]); + } + + /** + * @return Component[] + */ + public function getSettingsForm(): array + { + return array_merge(parent::getSettingsForm(), [ + Toggle::make('CAPTCHA_TURNSTILE_VERIFY_DOMAIN') + ->label(trans('admin/setting.captcha.verify')) + ->columnSpan(2) + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->default(env('CAPTCHA_TURNSTILE_VERIFY_DOMAIN', true)), + Placeholder::make('info') + ->label(trans('admin/setting.captcha.info_label')) + ->columnSpan(2) + ->content(new HtmlString(trans('admin/setting.captcha.info'))), + + ]); + } + + public function getIcon(): string + { + return 'tabler-brand-cloudflare'; + } + + public static function register(Application $app): self + { + return new self($app); + } + + /** + * @return array + */ + public function validateResponse(?string $captchaResponse = null): array + { + $captchaResponse ??= request()->get('cf-turnstile-response'); + + if (!$secret = env('CAPTCHA_TURNSTILE_SECRET_KEY')) { + throw new Exception('Turnstile secret key is not defined.'); + } + + $response = Http::asJson() + ->timeout(15) + ->connectTimeout(5) + ->throw() + ->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [ + 'secret' => $secret, + 'response' => $captchaResponse, + ]); + + return count($response->json()) ? $response->json() : [ + 'success' => false, + 'message' => 'Unknown error occurred, please try again', + ]; + } + + public function verifyDomain(string $hostname, ?string $requestUrl = null): bool + { + if (!env('CAPTCHA_TURNSTILE_VERIFY_DOMAIN', true)) { + return true; + } + + $requestUrl ??= request()->url; + $requestUrl = parse_url($requestUrl); + + return $hostname === array_get($requestUrl, 'host'); + } +} diff --git a/app/Filament/Admin/Pages/Settings.php b/app/Filament/Admin/Pages/Settings.php index 735797138..6ae8c98cf 100644 --- a/app/Filament/Admin/Pages/Settings.php +++ b/app/Filament/Admin/Pages/Settings.php @@ -2,6 +2,7 @@ namespace App\Filament\Admin\Pages; +use App\Extensions\Captcha\Providers\CaptchaProvider; use App\Extensions\OAuth\Providers\OAuthProvider; use App\Models\Backup; use App\Notifications\MailTested; @@ -13,7 +14,6 @@ use Filament\Forms\Components\Actions\Action as FormAction; use Filament\Forms\Components\Component; use Filament\Forms\Components\Group; use Filament\Forms\Components\Hidden; -use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Section; use Filament\Forms\Components\Select; use Filament\Forms\Components\Tabs; @@ -34,7 +34,6 @@ use Filament\Support\Enums\MaxWidth; use Illuminate\Http\Client\Factory; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Notification as MailNotification; -use Illuminate\Support\HtmlString; use Illuminate\Support\Str; /** @@ -219,47 +218,49 @@ class Settings extends Page implements HasForms */ private function captchaSettings(): array { - return [ - Toggle::make('TURNSTILE_ENABLED') - ->label(trans('admin/setting.captcha.enable')) - ->inline(false) - ->columnSpan(1) - ->onIcon('tabler-check') - ->offIcon('tabler-x') - ->onColor('success') - ->offColor('danger') - ->live() - ->formatStateUsing(fn ($state): bool => (bool) $state) - ->afterStateUpdated(fn ($state, Set $set) => $set('TURNSTILE_ENABLED', (bool) $state)) - ->default(env('TURNSTILE_ENABLED', config('turnstile.turnstile_enabled'))), - Placeholder::make('info') - ->label(trans('admin/setting.captcha.info_label')) - ->columnSpan(2) - ->content(new HtmlString('Link to Cloudflare Dashboard
' . trans('admin/setting.captcha.info'))), - TextInput::make('TURNSTILE_SITE_KEY') - ->label(trans('admin/setting.captcha.site_key')) - ->required() - ->visible(fn (Get $get) => $get('TURNSTILE_ENABLED')) - ->default(env('TURNSTILE_SITE_KEY', config('turnstile.turnstile_site_key'))) - ->placeholder('1x00000000000000000000AA'), - TextInput::make('TURNSTILE_SECRET_KEY') - ->label(trans('admin/setting.captcha.secret_key')) - ->required() - ->visible(fn (Get $get) => $get('TURNSTILE_ENABLED')) - ->default(env('TURNSTILE_SECRET_KEY', config('turnstile.secret_key'))) - ->placeholder('1x0000000000000000000000000000000AA'), - Toggle::make('TURNSTILE_VERIFY_DOMAIN') - ->label(trans('admin/setting.captcha.verify')) - ->inline(false) - ->onIcon('tabler-check') - ->offIcon('tabler-x') - ->onColor('success') - ->offColor('danger') - ->visible(fn (Get $get) => $get('TURNSTILE_ENABLED')) - ->formatStateUsing(fn ($state): bool => (bool) $state) - ->afterStateUpdated(fn ($state, Set $set) => $set('TURNSTILE_VERIFY_DOMAIN', (bool) $state)) - ->default(env('TURNSTILE_VERIFY_DOMAIN', config('turnstile.turnstile_verify_domain'))), - ]; + $formFields = []; + + $captchaProviders = CaptchaProvider::get(); + foreach ($captchaProviders as $captchaProvider) { + $id = Str::upper($captchaProvider->getId()); + $name = Str::title($captchaProvider->getId()); + + $formFields[] = Section::make($name) + ->columns(5) + ->icon($captchaProvider->getIcon() ?? 'tabler-shield') + ->collapsed(fn () => !env("CAPTCHA_{$id}_ENABLED", false)) + ->collapsible() + ->schema([ + Hidden::make("CAPTCHA_{$id}_ENABLED") + ->live() + ->default(env("CAPTCHA_{$id}_ENABLED")), + Actions::make([ + FormAction::make("disable_captcha_$id") + ->visible(fn (Get $get) => $get("CAPTCHA_{$id}_ENABLED")) + ->label(trans('admin/setting.captcha.disable')) + ->color('danger') + ->action(function (Set $set) use ($id) { + $set("CAPTCHA_{$id}_ENABLED", false); + }), + FormAction::make("enable_captcha_$id") + ->visible(fn (Get $get) => !$get("CAPTCHA_{$id}_ENABLED")) + ->label(trans('admin/setting.captcha.enable')) + ->color('success') + ->action(function (Set $set) use ($id, $captchaProviders) { + foreach ($captchaProviders as $captchaProvider) { + $loopId = Str::upper($captchaProvider->getId()); + $set("CAPTCHA_{$loopId}_ENABLED", $loopId === $id); + } + }), + ])->columnSpan(1), + Group::make($captchaProvider->getSettingsForm()) + ->visible(fn (Get $get) => $get("CAPTCHA_{$id}_ENABLED")) + ->columns(4) + ->columnSpan(4), + ]); + } + + return $formFields; } /** diff --git a/app/Filament/Components/Forms/Fields/TurnstileCaptcha.php b/app/Filament/Components/Forms/Fields/TurnstileCaptcha.php new file mode 100644 index 000000000..694b34f00 --- /dev/null +++ b/app/Filament/Components/Forms/Fields/TurnstileCaptcha.php @@ -0,0 +1,26 @@ +hiddenLabel(); + + $this->required(); + + $this->after(function (TurnstileCaptcha $component) { + $component->rule(new ValidTurnstileCaptcha()); + }); + } +} diff --git a/app/Filament/Pages/Auth/Login.php b/app/Filament/Pages/Auth/Login.php index 173ae17db..60179fff1 100644 --- a/app/Filament/Pages/Auth/Login.php +++ b/app/Filament/Pages/Auth/Login.php @@ -2,9 +2,9 @@ namespace App\Filament\Pages\Auth; +use App\Extensions\Captcha\Providers\CaptchaProvider; use App\Extensions\OAuth\Providers\OAuthProvider; use App\Models\User; -use Coderflex\FilamentTurnstile\Forms\Components\Turnstile; use Filament\Facades\Filament; use Filament\Forms\Components\Actions; use Filament\Forms\Components\Actions\Action; @@ -83,22 +83,22 @@ class Login extends BaseLogin protected function getForms(): array { + $schema = [ + $this->getLoginFormComponent(), + $this->getPasswordFormComponent(), + $this->getRememberFormComponent(), + $this->getOAuthFormComponent(), + $this->getTwoFactorAuthenticationComponent(), + ]; + + if ($captchaProvider = $this->getCaptchaComponent()) { + $schema = array_merge($schema, [$captchaProvider]); + } + return [ 'form' => $this->form( $this->makeForm() - ->schema([ - $this->getLoginFormComponent(), - $this->getPasswordFormComponent(), - $this->getRememberFormComponent(), - $this->getOAuthFormComponent(), - $this->getTwoFactorAuthenticationComponent(), - Turnstile::make('captcha') - ->hidden(!config('turnstile.turnstile_enabled')) - ->validationMessages([ - 'required' => config('turnstile.error_messages.turnstile_check_message'), - ]) - ->view('filament.plugins.turnstile'), - ]) + ->schema($schema) ->statePath('data'), ), ]; @@ -113,6 +113,17 @@ class Login extends BaseLogin ->live(); } + private function getCaptchaComponent(): ?Component + { + $captchaProvider = collect(CaptchaProvider::get())->filter(fn (CaptchaProvider $provider) => $provider->isEnabled())->first(); + + if (!$captchaProvider) { + return null; + } + + return $captchaProvider->getComponent(); + } + protected function throwFailureValidationException(): never { $this->dispatch('reset-captcha'); diff --git a/app/Http/Middleware/VerifyCaptcha.php b/app/Http/Middleware/VerifyCaptcha.php new file mode 100644 index 000000000..5836682b7 --- /dev/null +++ b/app/Http/Middleware/VerifyCaptcha.php @@ -0,0 +1,39 @@ +app->isLocal()) { + return $next($request); + } + + $captchaProviders = collect(CaptchaProvider::get())->filter(fn (CaptchaProvider $provider) => $provider->isEnabled())->all(); + foreach ($captchaProviders as $captchaProvider) { + $response = $captchaProvider->validateResponse(); + + if ($response['success'] && $captchaProvider->verifyDomain($response['hostname'] ?? '', $request->url())) { + return $next($request); + } + + event(new FailedCaptcha($request->ip(), $response['message'] ?? null)); + + throw new HttpException(Response::HTTP_BAD_REQUEST, "Failed to validate {$captchaProvider->getId()} captcha data."); + } + + // No captcha enabled + return $next($request); + } +} diff --git a/app/Http/Middleware/VerifyReCaptcha.php b/app/Http/Middleware/VerifyReCaptcha.php deleted file mode 100644 index 138c6fd4f..000000000 --- a/app/Http/Middleware/VerifyReCaptcha.php +++ /dev/null @@ -1,52 +0,0 @@ -app->isLocal()) { - return $next($request); - } - - if ($request->filled('cf-turnstile-response')) { - $response = LaravelTurnstile::validate($request->get('cf-turnstile-response')); - - if ($response['success'] && $this->isResponseVerified($response['hostname'] ?? '', $request)) { - return $next($request); - } - } - - event(new FailedCaptcha($request->ip(), $response['message'] ?? null)); - - throw new HttpException(Response::HTTP_BAD_REQUEST, 'Failed to validate turnstile captcha data.'); - } - - /** - * Determine if the response from the recaptcha servers was valid. - */ - private function isResponseVerified(string $hostname, Request $request): bool - { - if (!config('turnstile.turnstile_verify_domain')) { - return true; - } - - $url = parse_url($request->url()); - - return $hostname === array_get($url, 'host'); - } -} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 6257a2876..199a42fe9 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -38,6 +38,7 @@ use App\Checks\DatabaseCheck; use App\Checks\DebugModeCheck; use App\Checks\EnvironmentCheck; use App\Checks\ScheduleCheck; +use App\Extensions\Captcha\Providers\TurnstileProvider; use Spatie\Health\Facades\Health; class AppServiceProvider extends ServiceProvider @@ -108,6 +109,9 @@ class AppServiceProvider extends ServiceProvider DiscordProvider::register($app); SteamProvider::register($app); + // Default Captcha provider + TurnstileProvider::register($app); + FilamentColor::register([ 'danger' => Color::Red, 'gray' => Color::Zinc, diff --git a/app/Rules/ValidTurnstileCaptcha.php b/app/Rules/ValidTurnstileCaptcha.php new file mode 100644 index 000000000..83783e063 --- /dev/null +++ b/app/Rules/ValidTurnstileCaptcha.php @@ -0,0 +1,19 @@ +validateResponse($value); + + if (!$response['success']) { + $fail($response['message'] ?? 'Unknown error occurred, please try again'); + } + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index f779d8949..8d8ed0f97 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -44,7 +44,7 @@ return Application::configure(basePath: dirname(__DIR__)) 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'node.maintenance' => \App\Http\Middleware\MaintenanceMiddleware::class, - 'recaptcha' => \App\Http\Middleware\VerifyReCaptcha::class, + 'captcha' => \App\Http\Middleware\VerifyCaptcha::class, ]); }) ->withSingletons([ diff --git a/composer.json b/composer.json index ead99640f..5ec7852a8 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,6 @@ "aws/aws-sdk-php": "^3.341", "calebporzio/sushi": "^2.5", "chillerlan/php-qrcode": "^5.0.2", - "coderflex/filament-turnstile": "^2.2", "dedoc/scramble": "^0.12.10", "doctrine/dbal": "~3.6.0", "filament/filament": "3.3.3", diff --git a/composer.lock b/composer.lock index d35b54a8e..2575f3c34 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b630e514f50a47d69caf251330dcbc01", + "content-hash": "7bdf17dde3abc6f87fd48674c3034f49", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -1607,159 +1607,6 @@ ], "time": "2024-07-16T11:13:48+00:00" }, - { - "name": "coderflex/filament-turnstile", - "version": "v2.3.1", - "source": { - "type": "git", - "url": "https://github.com/coderflexx/filament-turnstile.git", - "reference": "a49cf626c7ba88457761b7594daf16c532f6adb1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/coderflexx/filament-turnstile/zipball/a49cf626c7ba88457761b7594daf16c532f6adb1", - "reference": "a49cf626c7ba88457761b7594daf16c532f6adb1", - "shasum": "" - }, - "require": { - "coderflex/laravel-turnstile": "^1.0|^2.0", - "illuminate/contracts": "^10.0|^11.0|^12.0", - "php": "^8.2|^8.3", - "spatie/laravel-package-tools": "^1.14.0" - }, - "require-dev": { - "filament/filament": "^3.0", - "larastan/larastan": "^2.8|^3.0", - "laravel/pint": "^1.0", - "nunomaduro/collision": "^7.0|^8.0", - "nunomaduro/larastan": "^2.8.0|^3.1.0", - "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^2.0|^3.7", - "pestphp/pest-plugin-arch": "^2.0|^3.0", - "pestphp/pest-plugin-livewire": "^2.0|^3.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", - "phpstan/phpstan-phpunit": "^1.0|^2.0" - }, - "type": "library", - "extra": { - "laravel": { - "aliases": { - "FilamentTurnstile": "Coderflex\\FilamentTurnstile\\Facades\\FilamentTurnstile" - }, - "providers": [ - "Coderflex\\FilamentTurnstile\\FilamentTurnstileServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Coderflex\\FilamentTurnstile\\": "src/", - "Coderflex\\FilamentTurnstile\\Database\\Factories\\": "database/factories/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Oussama", - "email": "oussama@coderflex.com", - "role": "Developer" - } - ], - "description": "Filament Plugin to help you implement Cloudflare Turnstile", - "homepage": "https://github.com/coderflex/filament-turnstile", - "keywords": [ - "cloudflare", - "coderflex", - "filament", - "filament-turnstile", - "laravel", - "laravel-turnstile", - "turnstile" - ], - "support": { - "issues": "https://github.com/coderflexx/filament-turnstile/issues", - "source": "https://github.com/coderflexx/filament-turnstile/tree/v2.3.1" - }, - "time": "2025-03-01T16:11:30+00:00" - }, - { - "name": "coderflex/laravel-turnstile", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/coderflexx/laravel-turnstile.git", - "reference": "1c1d0c5829851efaa1febcde34733537780eb0a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/coderflexx/laravel-turnstile/zipball/1c1d0c5829851efaa1febcde34733537780eb0a9", - "reference": "1c1d0c5829851efaa1febcde34733537780eb0a9", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^7.7", - "illuminate/contracts": "^10.0|^11.0|^12.0", - "php": "^8.2|^8.3", - "spatie/laravel-package-tools": "^1.14.0" - }, - "require-dev": { - "laravel/pint": "^1.0", - "nunomaduro/collision": "^7.0|^8.0", - "nunomaduro/larastan": "^2.8.0|^3.1.0", - "orchestra/testbench": "^8.0|^9.0|^10.0", - "pestphp/pest": "^2.0|^3.7", - "pestphp/pest-plugin-arch": "^2.0|^3.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", - "phpstan/phpstan-phpunit": "^1.0|^2.0" - }, - "type": "library", - "extra": { - "laravel": { - "aliases": { - "LaravelTurnstile": "Coderflex\\LaravelTurnstile\\Facades\\LaravelTurnstile" - }, - "providers": [ - "Coderflex\\LaravelTurnstile\\LaravelTurnstileServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Coderflex\\LaravelTurnstile\\": "src/", - "Coderflex\\LaravelTurnstile\\Database\\Factories\\": "database/factories/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "ousid", - "email": "oussama@coderflex.com", - "role": "Developer" - } - ], - "description": "A package to help you implement the Cloudflare turnstile \"CAPTCHA Alternative\"", - "homepage": "https://github.com/coderflexx/laravel-turnstile", - "keywords": [ - "cloudflare", - "coderflex", - "laravel", - "laravel-turnstile", - "turnstile" - ], - "support": { - "issues": "https://github.com/coderflexx/laravel-turnstile/issues", - "source": "https://github.com/coderflexx/laravel-turnstile/tree/2.1.1" - }, - "time": "2025-03-01T13:04:55+00:00" - }, { "name": "danharrin/date-format-converter", "version": "v0.3.1", diff --git a/config/turnstile.php b/config/turnstile.php deleted file mode 100644 index 2a2e6c8cb..000000000 --- a/config/turnstile.php +++ /dev/null @@ -1,15 +0,0 @@ - env('TURNSTILE_ENABLED', false), - - 'turnstile_site_key' => env('TURNSTILE_SITE_KEY', null), - 'turnstile_secret_key' => env('TURNSTILE_SECRET_KEY', null), - - 'turnstile_verify_domain' => env('TURNSTILE_VERIFY_DOMAIN', true), - - 'error_messages' => [ - 'turnstile_check_message' => 'Captcha failed! Please refresh and try again.', - ], -]; diff --git a/lang/en/admin/setting.php b/lang/en/admin/setting.php index f412791a9..a56a26d92 100644 --- a/lang/en/admin/setting.php +++ b/lang/en/admin/setting.php @@ -34,9 +34,10 @@ return [ 'display_width' => 'Display Width', ], 'captcha' => [ - 'enable' => 'Enable Turnstile Captcha?', + 'enable' => 'Enable', + 'disable' => 'Disable', 'info_label' => 'Info', - 'info' => 'You can generate the keys on your Cloudflare Dashboard. A Cloudflare account is required.', + 'info' => 'You can generate the keys on your Cloudflare Dashboard. A Cloudflare account is required.', 'site_key' => 'Site Key', 'secret_key' => 'Secret Key', 'verify' => 'Verify Domain?', diff --git a/phpstan.neon b/phpstan.neon index 778952147..3320b0842 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -20,5 +20,6 @@ parameters: identifier: larastan.noEnvCallsOutsideOfConfig paths: - app/Console/Commands/Environment/*.php + - app/Extensions/Captcha/Providers/*.php - app/Extensions/OAuth/Providers/*.php - app/Filament/Admin/Pages/Settings.php diff --git a/resources/views/filament/plugins/turnstile.blade.php b/resources/views/filament/components/turnstile-captcha.blade.php similarity index 67% rename from resources/views/filament/plugins/turnstile.blade.php rename to resources/views/filament/components/turnstile-captcha.blade.php index bc7d75aa1..bb62c3454 100644 --- a/resources/views/filament/plugins/turnstile.blade.php +++ b/resources/views/filament/components/turnstile-captcha.blade.php @@ -1,19 +1,14 @@ @php $statePath = $getStatePath(); $fieldWrapperView = $getFieldWrapperView(); - - $theme = $getTheme(); - $size = $getSize(); - $language = $getLanguage(); @endphp -
{ let options= { callback: function (token) { $wire.set('{{ $statePath }}', token) @@ -33,13 +28,7 @@ } })()" > -
-
+
@@ -48,9 +37,9 @@ @endpush -
\ No newline at end of file +