Skip to content

Commit b19881c

Browse files
Feat | Migrate from Google reCAPTCHA to Cloudflare Turnstile (#121)
* feat: Migrate from Google reCAPTCHA to Cloudflare Turnstile * chore: Change to vendor recommended implementation * feat: Update login attempts retrieval to use user data if available * chore: Add PR's requested changes and Unit tests - Validation failure when cf-turnstile-response is missing - Login flow behaviour before/after CAPTCHA threshold - Rendering of Turnstile on the thresholded login screen - Auth form submission when Turnstile is expired or not solved * chore: upgrade to Node 22.22.2 and fix yarn build (#131) - Bump NODE_VERSION 20.20.2 → 22.22.2 in Dockerfile and .nvmrc - Replace node-sass@8 (EOL, no Node 22 binary) with sass@^1.77 (dart-sass) - Bump webpack@^5.94, webpack-cli@^5.1.4 (resolves OpenSSL-3 legacy hash issue) - Bump copy-webpack-plugin@^11 for webpack 5.94+ compatibility - Add util:false to webpack.common.js resolve.fallback (webpack 5.106 is stricter than 5.70 about unresolved Node built-ins; jsdom/tough-cookie transitively require util which should not be browser-polyfilled) - Drop unused devDeps: clean-webpack-plugin, html-webpack-plugin, optimize-css-assets-webpack-plugin, path polyfill, webpack-node-externals - Regenerate yarn.lock * chore: Add PR's requested changes * chore: Add PR's requested changes * chore: Fix composer.lock update issue * feat: Add remote IP address to Turnstile verification request * fix: add timeout and scope retry to connection errors in TurnstileClient - Add ->timeout(5) to bound max wall time to ~15s during Cloudflare outages - Restrict retry to ConnectionException only so success:false responses (valid HTTP 200) do not trigger wasteful retries --------- Co-authored-by: sebastian marcet <smarcet@gmail.com>
1 parent a59a4bb commit b19881c

48 files changed

Lines changed: 3260 additions & 5127 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ LOG_LEVEL=info
5858

5959
EVENTBRITE_OAUTH2_PERSONAL_TOKEN=
6060

61-
RECAPTCHA_PUBLIC_KEY=
62-
RECAPTCHA_PRIVATE_KEY=
61+
TURNSTILE_SECRET_KEY=
62+
TURNSTILE_SITE_KEY=
6363

6464
BANNING_ENABLE=
6565
SUPPORT_EMAIL=

.github/workflows/pull_request_unit_tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ jobs:
6565
env:
6666
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.PAT }}"} }'
6767
- name: 'Run Tests'
68+
env:
69+
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
70+
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
6871
run: |
6972
./update_doctrine.sh
7073
php artisan doctrine:migrations:migrate --no-interaction

.github/workflows/push.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ jobs:
6161
env:
6262
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.PAT }}"} }'
6363
- name: 'Run Tests'
64+
env:
65+
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
66+
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
6467
run: |
6568
./update_doctrine.sh
6669
php artisan doctrine:migrations:migrate --no-interaction

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
18.20.2
1+
22.22.2

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM php:8.3-fpm
22

33
ARG DEBIAN_FRONTEND=noninteractive
44
ARG NVM_VERSION="v0.40.3"
5-
ENV NODE_VERSION="18.20.4"
5+
ENV NODE_VERSION="22.22.2"
66
ARG YARN_VERSION="1.22.22"
77
ARG GITHUB_OAUTH_TOKEN
88
ARG XDEBUG_VERSION="xdebug-3.3.2"

app/Http/Controllers/Auth/EmailVerificationController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
**/
1414
use App\Http\Controllers\Controller;
1515
use App\libs\Utils\EmailUtils;
16+
use RyanChandler\LaravelCloudflareTurnstile\Rules\Turnstile;
1617
use App\Services\Auth\IUserService;
1718
use Illuminate\Support\Facades\Log;
1819
use Illuminate\Support\Facades\Redirect;
@@ -87,7 +88,7 @@ protected function validator(array $data)
8788
{
8889
return Validator::make($data, [
8990
'email' => 'required|string|email|max:255',
90-
'g-recaptcha-response' => 'required|recaptcha',
91+
'cf-turnstile-response' => ['required', new Turnstile()],
9192
]);
9293
}
9394

@@ -100,7 +101,6 @@ public function resend(LaravelRequest $request)
100101
if (!$validator->passes()) {
101102
return Redirect::action('Auth\EmailVerificationController@showVerificationForm')->withErrors($validator);
102103
}
103-
104104
$user = $this->user_service->resendVerificationEmail($payload);
105105

106106
return view("auth.email_verification_resend_success", ['user' => $user]);

app/Http/Controllers/Auth/ForgotPasswordController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
**/
1414

1515
use App\Http\Controllers\Controller;
16+
use RyanChandler\LaravelCloudflareTurnstile\Rules\Turnstile;
1617
use App\libs\Utils\EmailUtils;
1718
use App\Services\Auth\IUserService;
1819
use Illuminate\Support\Facades\Log;
@@ -162,6 +163,7 @@ protected function validator(array $data)
162163
{
163164
return Validator::make($data, [
164165
'email' => 'required|string|email|max:255',
166+
'cf-turnstile-response' => ['required', new Turnstile()],
165167
]);
166168
}
167169

app/Http/Controllers/Auth/PasswordSetController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
**/
1414

1515
use App\Http\Controllers\Controller;
16+
use RyanChandler\LaravelCloudflareTurnstile\Rules\Turnstile;
1617
use App\Http\Utils\CountryList;
1718
use App\libs\Auth\Repositories\IUserRegistrationRequestRepository;
1819
use App\Services\Auth\IUserService;
@@ -155,7 +156,7 @@ protected function validator(array $data)
155156
'company' => 'sometimes|string|max:100',
156157
'country_iso_code' => 'required|string|country_iso_alpha2_code',
157158
'password' => 'required|string|confirmed|password_policy',
158-
'g-recaptcha-response' => 'required|recaptcha',
159+
'cf-turnstile-response' => ['required', new Turnstile()],
159160
]);
160161
}
161162

app/Http/Controllers/Auth/RegisterController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
**/
1414
use App\Http\Controllers\Controller;
1515
use App\Http\Utils\CountryList;
16+
use RyanChandler\LaravelCloudflareTurnstile\Rules\Turnstile;
1617
use App\Services\Auth\IUserService;
1718
use Illuminate\Support\Facades\Auth;
1819
use Illuminate\Support\Facades\Config;
@@ -177,7 +178,7 @@ protected function validator(array $data)
177178
'country_iso_code' => 'required|string|country_iso_alpha2_code',
178179
'email' => 'required|string|email|max:255',
179180
'password' => 'required|string|confirmed|password_policy',
180-
'g-recaptcha-response' => 'required|recaptcha',
181+
'cf-turnstile-response' => ['required', new Turnstile()],
181182
];
182183

183184
if(!empty(Config::get("app.code_of_conduct_link", null))){

app/Http/Controllers/Auth/ResetPasswordController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
**/
1414
use App\Http\Controllers\Controller;
1515
use App\libs\Auth\Repositories\IUserPasswordResetRequestRepository;
16+
use RyanChandler\LaravelCloudflareTurnstile\Rules\Turnstile;
1617
use App\Services\Auth\IUserService;
1718
use Auth\Exceptions\UserPasswordResetRequestVoidException;
1819
use Illuminate\Support\Facades\Log;
@@ -113,7 +114,7 @@ protected function validator(array $data)
113114
return Validator::make($data, [
114115
'token' => 'required',
115116
'password' => 'required|string|confirmed|password_policy',
116-
'g-recaptcha-response' => 'required|recaptcha',
117+
'cf-turnstile-response' => ['required', new Turnstile()],
117118
]);
118119
}
119120

0 commit comments

Comments
 (0)