Forráskód Böngészése

Add app register email verify resends

Daniel Supernault 4 hónapja
szülő
commit
dbd1e17b25

+ 79 - 1
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;

+ 4 - 0
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);
     }
 

+ 28 - 0
database/migrations/2025_03_02_060626_add_count_to_app_registers_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('app_registers', function (Blueprint $table) {
+            $table->unsignedInteger('uses')->default(0);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('app_registers', function (Blueprint $table) {
+            $table->dropColumn('uses');
+        });
+    }
+};

+ 145 - 0
resources/views/auth/iar-resend.blade.php

@@ -0,0 +1,145 @@
+@extends('layouts.blank')
+
+@section('content')
+    <div class="container">
+        <div class="row min-vh-100 align-items-center justify-content-center">
+            <div class="col-12 col-md-6 col-lg-5">
+                <div class="text-center mb-5">
+                    <img src="/img/pixelfed-icon-white.svg" width="90">
+                </div>
+
+                <div class="card shadow-sm">
+                    <div class="card-body p-4">
+                        <h3 class="text-center">Resend Verification</h3>
+                        <p class="lead text-center mb-4">Enter your email so we can send another verification code via email</p>
+
+                        <form method="POST" action="/i/app-email-resend">
+                            @csrf
+
+                            <div class="form-group">
+                                <label for="email">Email address</label>
+                                <input type="email"
+                                       class="form-control @error('email') is-invalid @enderror"
+                                       id="email"
+                                       name="email"
+                                       required
+                                       autocomplete="email"
+                                       @if(request()->filled('email'))
+                                       value="{{rawurldecode(request()->input('email'))}}"
+                                       @endif
+                                       >
+                                @error('email')
+                                    <div class="invalid-feedback">{{ $message }}</div>
+                                @enderror
+                            </div>
+
+                            @if((bool) config_cache('captcha.enabled') && (bool) config_cache('captcha.active.register'))
+                            <div class="form-group text-center">
+                                {!! Captcha::display() !!}
+                            </div>
+                            @endif
+
+                            <button type="submit" class="btn btn-primary btn-block">
+                                Send Verification Code
+                            </button>
+                        </form>
+
+                        @if ($errors->any())
+                        <div class="mt-4">
+                            <p class="text-center">Click <a href="/i/app-email-verify">here</a> to send a new request.</p>
+                        </div>
+                        @endif
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+@endsection
+
+@push('styles')
+    <style>
+        :root {
+            --bg-color: #111827;
+            --card-bg: #1f2937;
+            --text-color: #f3f4f6;
+            --text-muted: #9ca3af;
+            --input-bg: #374151;
+            --input-border: #4b5563;
+            --input-focus: #3b82f6;
+            --card-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.3);
+        }
+
+        body {
+            background-color: var(--bg-color);
+            color: var(--text-color);
+            transition: background-color 0.3s, color 0.3s;
+            min-height: 100vh;
+            display: flex;
+            align-items: center;
+        }
+
+        .card {
+            background-color: var(--card-bg);
+            border: none;
+            border-radius: 1rem;
+            box-shadow: var(--card-shadow);
+        }
+
+        .benefits-list {
+            color: var(--text-muted);
+        }
+
+        .benefits-list i {
+            color: #3b82f6;
+            margin-right: 0.5rem;
+        }
+
+        .form-control {
+            background-color: var(--input-bg);
+            border-color: var(--input-border);
+            color: var(--text-color);
+            border-radius: 0.5rem;
+            padding: 0.75rem 1rem;
+            transition: all 0.2s;
+        }
+
+        .form-control:focus {
+            background-color: var(--input-bg);
+            border-color: var(--input-focus);
+            color: var(--text-color);
+            box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
+        }
+
+        .btn-primary {
+            padding: 0.75rem 1.5rem;
+            border-radius: 0.5rem;
+            font-weight: 500;
+            transition: transform 0.2s;
+            background-color: #3b82f6;
+            border-color: #3b82f6;
+        }
+
+        .btn-primary:hover {
+            transform: translateY(-1px);
+            background-color: #2563eb;
+            border-color: #2563eb;
+        }
+
+        .form-group label {
+            font-weight: 500;
+            margin-bottom: 0.5rem;
+        }
+
+        @media (prefers-color-scheme: dark) {
+            a {
+                color: #60a5fa;
+            }
+            a:hover {
+                color: #93c5fd;
+            }
+            .card {
+                border: 1px solid rgba(255, 255, 255, 0.1);
+            }
+        }
+    </style>
+@endpush

+ 7 - 10
resources/views/auth/iar.blade.php

@@ -13,16 +13,6 @@
                         <h2 class="text-center">Join Pixelfed</h2>
                         <p class="lead text-center mb-4">Enter Your Email</p>
 
-                        @if ($errors->any())
-                            <div class="alert alert-danger">
-                                <ul class="mb-0">
-                                    @foreach ($errors->all() as $error)
-                                        <li>{{ $error }}</li>
-                                    @endforeach
-                                </ul>
-                            </div>
-                        @endif
-
                         <form method="POST">
                             @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
                             </button>
                         </form>
+
+                        @if ($errors->any())
+                        <div class="mt-4">
+                            <p class="text-center">If you need to resend the email verification, click <a href="/i/app-email-resend">here</a>.</p>
+                        </div>
+                        @endif
                     </div>
                 </div>
             </div>

+ 2 - 0
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('/', '/');