feat: add rate limiting, case-insensitive usernames and session security
This commit is contained in:
@@ -43,7 +43,15 @@ class CompleteProfileController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'username' => ['required', 'string', 'max:255', 'alpha_dash', 'unique:'.User::class],
|
'username' => [
|
||||||
|
'required', 'string', 'max:255', 'alpha_dash',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$exists = User::whereRaw('LOWER(username) = ?', [strtolower($value)])->exists();
|
||||||
|
if ($exists) {
|
||||||
|
$fail('The username has already been taken.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
'first_name' => ['required', 'string', 'max:255'],
|
'first_name' => ['required', 'string', 'max:255'],
|
||||||
'last_name' => ['required', 'string', 'max:255'],
|
'last_name' => ['required', 'string', 'max:255'],
|
||||||
]);
|
]);
|
||||||
@@ -62,6 +70,7 @@ class CompleteProfileController extends Controller
|
|||||||
event(new Registered($user));
|
event(new Registered($user));
|
||||||
|
|
||||||
Auth::login($user, remember: true);
|
Auth::login($user, remember: true);
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
return redirect()->intended(config('auth-ui.redirects.login', '/'));
|
return redirect()->intended(config('auth-ui.redirects.login', '/'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,15 @@ class RegisterController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'username' => ['required', 'string', 'max:255', 'alpha_dash', 'unique:'.User::class],
|
'username' => [
|
||||||
|
'required', 'string', 'max:255', 'alpha_dash',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$exists = User::whereRaw('LOWER(username) = ?', [strtolower($value)])->exists();
|
||||||
|
if ($exists) {
|
||||||
|
$fail('The username has already been taken.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
'first_name' => ['required', 'string', 'max:255'],
|
'first_name' => ['required', 'string', 'max:255'],
|
||||||
'last_name' => ['required', 'string', 'max:255'],
|
'last_name' => ['required', 'string', 'max:255'],
|
||||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class SocialiteController extends Controller
|
|||||||
$suggestedUsername = $this->suggestUsername($socialUser);
|
$suggestedUsername = $this->suggestUsername($socialUser);
|
||||||
|
|
||||||
// Check if username is already taken
|
// Check if username is already taken
|
||||||
if (User::where('username', $suggestedUsername)->exists()) {
|
if (User::whereRaw('LOWER(username) = ?', [strtolower($suggestedUsername)])->exists()) {
|
||||||
// Store social data in session and redirect to complete profile
|
// Store social data in session and redirect to complete profile
|
||||||
session()->put('socialite_user', [
|
session()->put('socialite_user', [
|
||||||
'email' => $socialUser->getEmail(),
|
'email' => $socialUser->getEmail(),
|
||||||
@@ -103,6 +103,7 @@ class SocialiteController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
Auth::login($user, remember: true);
|
Auth::login($user, remember: true);
|
||||||
|
request()->session()->regenerate();
|
||||||
|
|
||||||
return redirect()->intended(config('auth-ui.redirects.login', '/'));
|
return redirect()->intended(config('auth-ui.redirects.login', '/'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class HandleInertiaRequests extends Middleware
|
|||||||
'message' => fn () => $request->session()->get('message'),
|
'message' => fn () => $request->session()->get('message'),
|
||||||
'status' => fn () => $request->session()->get('status'),
|
'status' => fn () => $request->session()->get('status'),
|
||||||
],
|
],
|
||||||
'authConfig' => $this->getAuthConfig(),
|
'authConfig' => fn () => $this->getAuthConfig(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ use Illuminate\Support\Facades\Route;
|
|||||||
|
|
||||||
Route::middleware('guest')->group(function () {
|
Route::middleware('guest')->group(function () {
|
||||||
Route::get('login', [LoginController::class, 'create'])->name('login');
|
Route::get('login', [LoginController::class, 'create'])->name('login');
|
||||||
Route::post('login', [LoginController::class, 'store']);
|
Route::post('login', [LoginController::class, 'store'])->middleware('throttle:5,1');
|
||||||
|
|
||||||
Route::get('register', [RegisterController::class, 'create'])->name('register');
|
Route::get('register', [RegisterController::class, 'create'])->name('register');
|
||||||
Route::post('register', [RegisterController::class, 'store']);
|
Route::post('register', [RegisterController::class, 'store'])->middleware('throttle:3,60');
|
||||||
|
|
||||||
Route::get('forgot-password', [ForgotPasswordController::class, 'create'])->name('password.request');
|
Route::get('forgot-password', [ForgotPasswordController::class, 'create'])->name('password.request');
|
||||||
Route::post('forgot-password', [ForgotPasswordController::class, 'store'])->name('password.email');
|
Route::post('forgot-password', [ForgotPasswordController::class, 'store'])->name('password.email')->middleware('throttle:3,15');
|
||||||
|
|
||||||
Route::get('reset-password/{token}', [ResetPasswordController::class, 'create'])->name('password.reset');
|
Route::get('reset-password/{token}', [ResetPasswordController::class, 'create'])->name('password.reset');
|
||||||
Route::post('reset-password', [ResetPasswordController::class, 'store'])->name('password.store');
|
Route::post('reset-password', [ResetPasswordController::class, 'store'])->name('password.store')->middleware('throttle:5,15');
|
||||||
|
|
||||||
// Socialite routes
|
// Socialite routes
|
||||||
Route::get('auth/{provider}', [SocialiteController::class, 'redirect'])->name('socialite.redirect');
|
Route::get('auth/{provider}', [SocialiteController::class, 'redirect'])->name('socialite.redirect');
|
||||||
|
|||||||
Reference in New Issue
Block a user