diff --git a/app/Http/Controllers/AppRegisterController.php b/app/Http/Controllers/AppRegisterController.php index 77d7b952d..824cec540 100644 --- a/app/Http/Controllers/AppRegisterController.php +++ b/app/Http/Controllers/AppRegisterController.php @@ -59,12 +59,14 @@ class AppRegisterController extends Controller 'message' => 'Too many attempts, please try again later.', ]); DB::rollBack(); + return redirect()->away("pixelfed://verifyEmail?{$errorParams}"); } $registration = AppRegister::create([ 'email' => $email, 'verify_code' => $code, + 'uses' => 1, 'email_delivered_at' => now(), ]); @@ -117,6 +119,82 @@ class AppRegisterController extends Controller ]); } + public function resendVerification(Request $request) + { + abort_unless(config('auth.in_app_registration'), 404); + $open = (bool) config_cache('pixelfed.open_registration'); + if (! $open || $request->user()) { + return redirect('/'); + } + + return view('auth.iar-resend'); + } + + public function resendVerificationStore(Request $request) + { + abort_unless(config('auth.in_app_registration'), 404); + $open = (bool) config_cache('pixelfed.open_registration'); + if (! $open || $request->user()) { + return redirect('/'); + } + + $rules = [ + 'email' => 'required|email:rfc,dns,spoof,strict|unique:users,email|exists:app_registers,email', + ]; + + if ((bool) config_cache('captcha.enabled') && (bool) config_cache('captcha.active.register')) { + $rules['h-captcha-response'] = 'required|captcha'; + } + + $this->validate($request, $rules); + + $email = strtolower($request->input('email')); + $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); + + DB::beginTransaction(); + + $exists = AppRegister::whereEmail($email)->first(); + + if (! $exists || $exists->uses > 5) { + $errorMessage = $exists->uses > 5 ? 'Too many attempts have been made, please contact the admins.' : 'Email not found'; + $errorParams = http_build_query([ + 'status' => 'error', + 'message' => $errorMessage, + ]); + DB::rollBack(); + + return redirect()->away("pixelfed://verifyEmail?{$errorParams}"); + } + + $registration = $exists->update([ + 'verify_code' => $code, + 'uses' => ($exists->uses + 1), + 'email_delivered_at' => now(), + ]); + + try { + Mail::to($email)->send(new InAppRegisterEmailVerify($code)); + } catch (\Exception $e) { + DB::rollBack(); + $errorParams = http_build_query([ + 'status' => 'error', + 'message' => 'Failed to send verification code', + ]); + + return redirect()->away("pixelfed://verifyEmail?{$errorParams}"); + } + + DB::commit(); + + $queryParams = http_build_query([ + 'email' => $request->email, + 'expires_in' => 3600, + 'status' => 'success', + ]); + + return redirect()->away("pixelfed://verifyEmail?{$queryParams}"); + } + public function onboarding(Request $request) { abort_unless(config('auth.in_app_registration'), 404); @@ -161,7 +239,7 @@ class AppRegisterController extends Controller 'email_verified_at' => now(), ]); - sleep(random_int(5,10)); + sleep(random_int(8, 10)); $user = User::findOrFail($user->id); $token = $user->createToken('Pixelfed App', ['read', 'write', 'follow', 'push']); $tokenModel = $token->token; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 129ff0f8b..c46509811 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -98,6 +98,10 @@ class AppServiceProvider extends ServiceProvider return Limit::perHour(10)->by($request->ip()); }); + RateLimiter::for('app-code-resend', function (Request $request) { + return Limit::perHour(5)->by($request->ip()); + }); + // Model::preventLazyLoading(true); } diff --git a/database/migrations/2025_03_02_060626_add_count_to_app_registers_table.php b/database/migrations/2025_03_02_060626_add_count_to_app_registers_table.php new file mode 100644 index 000000000..3f52d6257 --- /dev/null +++ b/database/migrations/2025_03_02_060626_add_count_to_app_registers_table.php @@ -0,0 +1,28 @@ +unsignedInteger('uses')->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('app_registers', function (Blueprint $table) { + $table->dropColumn('uses'); + }); + } +}; diff --git a/resources/views/auth/iar-resend.blade.php b/resources/views/auth/iar-resend.blade.php new file mode 100644 index 000000000..ea1ead33a --- /dev/null +++ b/resources/views/auth/iar-resend.blade.php @@ -0,0 +1,145 @@ +@extends('layouts.blank') + +@section('content') +
+
+
+
+ +
+ +
+
+

Resend Verification

+

Enter your email so we can send another verification code via email

+ +
+ @csrf + +
+ + filled('email')) + value="{{rawurldecode(request()->input('email'))}}" + @endif + > + @error('email') +
{{ $message }}
+ @enderror +
+ + @if((bool) config_cache('captcha.enabled') && (bool) config_cache('captcha.active.register')) +
+ {!! Captcha::display() !!} +
+ @endif + + +
+ + @if ($errors->any()) +
+

Click here to send a new request.

+
+ @endif +
+
+
+
+
+@endsection + +@push('styles') + +@endpush diff --git a/resources/views/auth/iar.blade.php b/resources/views/auth/iar.blade.php index 5714e3bc5..7382b390e 100644 --- a/resources/views/auth/iar.blade.php +++ b/resources/views/auth/iar.blade.php @@ -13,16 +13,6 @@

Join Pixelfed

Enter Your Email

- @if ($errors->any()) -
- -
- @endif -
@csrf @@ -32,6 +22,7 @@ class="form-control @error('email') is-invalid @enderror" id="email" name="email" + placeholder="Enter your email address here" required autocomplete="email"> @error('email') @@ -49,6 +40,12 @@ Send Verification Code
+ + @if ($errors->any()) +
+

If you need to resend the email verification, click here.

+
+ @endif diff --git a/routes/web.php b/routes/web.php index a32dd587c..bb1903f3c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -141,6 +141,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('/i/app-email-verify', 'AppRegisterController@index'); Route::post('/i/app-email-verify', 'AppRegisterController@store')->middleware('throttle:app-signup'); + Route::get('/i/app-email-resend', 'AppRegisterController@resendVerification'); + Route::post('/i/app-email-resend', 'AppRegisterController@resendVerificationStore')->middleware('throttle:app-code-resend'); Route::group(['prefix' => 'i'], function () { Route::redirect('/', '/');