chore: commit current workspace changes
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginRequest;
|
||||
use App\Services\Auth\AuthAuditLogger;
|
||||
use App\Services\Security\CaptchaVerifier;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -17,6 +18,7 @@ class AuthenticatedSessionController extends Controller
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly CaptchaVerifier $captchaVerifier,
|
||||
private readonly AuthAuditLogger $authAuditLogger,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -35,9 +37,22 @@ class AuthenticatedSessionController extends Controller
|
||||
{
|
||||
$request->authenticate();
|
||||
|
||||
$user = $request->authenticatedUser();
|
||||
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'login',
|
||||
request: $request,
|
||||
status: 'success',
|
||||
identifier: (string) $request->input('email'),
|
||||
user: $user,
|
||||
metadata: [
|
||||
'via' => $request->authenticatedViaUsername() ? 'username' : 'email',
|
||||
'remember' => $request->boolean('remember'),
|
||||
],
|
||||
);
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
$user = $request->authenticatedUser();
|
||||
if ($user && $request->authenticatedViaUsername() && ! $user->hasCompletedOnboarding()) {
|
||||
$request->session()->put('username_login_upgrade', true);
|
||||
|
||||
|
||||
@@ -4,17 +4,24 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\AuthAuditLogger;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class NewPasswordController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AuthAuditLogger $authAuditLogger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the password reset view.
|
||||
*/
|
||||
@@ -30,17 +37,36 @@ class NewPasswordController extends Controller
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
$validator = Validator::make($request->all(), [
|
||||
'token' => ['required'],
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
// Here we will attempt to reset the user's password. If it is successful we
|
||||
// will update the password on an actual user model and persist it to the
|
||||
// database. Otherwise we will parse the error and return the response.
|
||||
if ($validator->fails()) {
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'reset_password',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'validation_failed',
|
||||
identifier: (string) $request->input('email'),
|
||||
metadata: ['fields' => array_keys($validator->errors()->toArray())],
|
||||
);
|
||||
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
$validated = $validator->validated();
|
||||
$email = strtolower(trim((string) $validated['email']));
|
||||
$user = User::query()->whereRaw('LOWER(email) = ?', [$email])->first();
|
||||
|
||||
$status = Password::reset(
|
||||
$request->only('email', 'password', 'password_confirmation', 'token'),
|
||||
[
|
||||
'email' => $email,
|
||||
'password' => (string) $validated['password'],
|
||||
'password_confirmation' => (string) $request->input('password_confirmation'),
|
||||
'token' => (string) $validated['token'],
|
||||
],
|
||||
function (User $user) use ($request) {
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($request->password),
|
||||
@@ -51,12 +77,20 @@ class NewPasswordController extends Controller
|
||||
}
|
||||
);
|
||||
|
||||
// If the password was successfully reset, we will redirect the user back to
|
||||
// the application's home authenticated view. If there is an error we can
|
||||
// redirect them back to where they came from with their error message.
|
||||
return $status == Password::PASSWORD_RESET
|
||||
$success = $status === Password::PASSWORD_RESET;
|
||||
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'reset_password',
|
||||
request: $request,
|
||||
status: $success ? 'success' : 'failed',
|
||||
reason: strtolower((string) $status),
|
||||
identifier: $email,
|
||||
user: $user,
|
||||
);
|
||||
|
||||
return $success
|
||||
? redirect()->route('login')->with('status', __($status))
|
||||
: back()->withInput($request->only('email'))
|
||||
: back()->withInput(['email' => $email])
|
||||
->withErrors(['email' => __($status)]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,21 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\AuthAuditLogger;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class PasswordResetLinkController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AuthAuditLogger $authAuditLogger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the password reset link request view.
|
||||
*/
|
||||
@@ -25,20 +33,45 @@ class PasswordResetLinkController extends Controller
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
$validator = Validator::make($request->all(), [
|
||||
'email' => ['required', 'email'],
|
||||
]);
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
// to send the link, we will examine the response then see the message we
|
||||
// need to show to the user. Finally, we'll send out a proper response.
|
||||
if ($validator->fails()) {
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'forgot_password',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'validation_failed',
|
||||
identifier: (string) $request->input('email'),
|
||||
metadata: ['fields' => array_keys($validator->errors()->toArray())],
|
||||
);
|
||||
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
$validated = $validator->validated();
|
||||
$email = strtolower(trim((string) $validated['email']));
|
||||
$user = User::query()->whereRaw('LOWER(email) = ?', [$email])->first();
|
||||
|
||||
$status = Password::sendResetLink(
|
||||
$request->only('email')
|
||||
['email' => $email]
|
||||
);
|
||||
|
||||
return $status == Password::RESET_LINK_SENT
|
||||
$success = $status === Password::RESET_LINK_SENT;
|
||||
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'forgot_password',
|
||||
request: $request,
|
||||
status: $success ? 'success' : 'failed',
|
||||
reason: strtolower((string) $status),
|
||||
identifier: $email,
|
||||
user: $user,
|
||||
);
|
||||
|
||||
return $success
|
||||
? back()->with('status', __($status))
|
||||
: back()->withInput($request->only('email'))
|
||||
: back()->withInput(['email' => $email])
|
||||
->withErrors(['email' => __($status)]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Jobs\SendVerificationEmailJob;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\EmailSendEvent;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\AuthAuditLogger;
|
||||
use App\Services\Auth\DisposableEmailService;
|
||||
use App\Services\Auth\RegistrationVerificationTokenService;
|
||||
use App\Services\Security\CaptchaVerifier;
|
||||
@@ -15,6 +16,7 @@ use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
@@ -25,6 +27,7 @@ class RegisteredUserController extends Controller
|
||||
private readonly TurnstileVerifier $turnstileVerifier,
|
||||
private readonly DisposableEmailService $disposableEmailService,
|
||||
private readonly RegistrationVerificationTokenService $verificationTokenService,
|
||||
private readonly AuthAuditLogger $authAuditLogger,
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -65,7 +68,22 @@ class RegisteredUserController extends Controller
|
||||
];
|
||||
$rules[$this->captchaVerifier->inputName()] = ['nullable', 'string'];
|
||||
|
||||
$validated = $request->validate($rules);
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'register',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'validation_failed',
|
||||
identifier: (string) $request->input('email'),
|
||||
metadata: ['fields' => array_keys($validator->errors()->toArray())],
|
||||
);
|
||||
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
$validated = $validator->validated();
|
||||
|
||||
$email = strtolower(trim((string) $validated['email']));
|
||||
$ip = $request->ip();
|
||||
@@ -86,6 +104,14 @@ class RegisteredUserController extends Controller
|
||||
}
|
||||
|
||||
if (! $verified) {
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'register',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'captcha_failed',
|
||||
identifier: $email,
|
||||
);
|
||||
|
||||
return back()
|
||||
->withInput($request->except('website'))
|
||||
->withErrors(['captcha' => 'Captcha verification failed. Please try again.']);
|
||||
@@ -94,6 +120,13 @@ class RegisteredUserController extends Controller
|
||||
|
||||
if ($this->disposableEmailService->isDisposableEmail($email)) {
|
||||
$this->logEmailEvent($email, $ip, null, 'blocked', 'disposable');
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'register',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'disposable_email',
|
||||
identifier: $email,
|
||||
);
|
||||
|
||||
return back()
|
||||
->withInput($request->except('website'))
|
||||
@@ -103,6 +136,15 @@ class RegisteredUserController extends Controller
|
||||
$user = User::query()->where('email', $email)->first();
|
||||
|
||||
if ($user && $user->hasCompletedOnboarding()) {
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'register',
|
||||
request: $request,
|
||||
status: 'failed',
|
||||
reason: 'email_exists',
|
||||
identifier: $email,
|
||||
user: $user,
|
||||
);
|
||||
|
||||
return back()
|
||||
->withInput($request->except('website'))
|
||||
->withErrors(['email' => 'An account with this email already exists.']);
|
||||
@@ -136,6 +178,15 @@ class RegisteredUserController extends Controller
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
$this->authAuditLogger->log(
|
||||
eventType: 'register',
|
||||
request: $request,
|
||||
status: 'success',
|
||||
reason: $user->wasRecentlyCreated ? 'user_created' : 'resume_onboarding',
|
||||
identifier: $email,
|
||||
user: $user,
|
||||
);
|
||||
|
||||
$needsPasswordSetup = strtolower((string) ($user->onboarding_step ?? '')) !== 'password'
|
||||
|| (bool) $user->needs_password_reset;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user