diff --git a/resources/views/components/layouts/public.blade.php b/resources/views/components/layouts/public.blade.php index 64e9c5c..274c06e 100644 --- a/resources/views/components/layouts/public.blade.php +++ b/resources/views/components/layouts/public.blade.php @@ -170,6 +170,74 @@ class="w-10 h-10 rounded-full bg-primary text-primary-content flex items-center + + + +@if ( session('password_breach_warning')) + + + + +
+ +
+ + +
+
+ + + + + + + +
+ + + Warning: {{ session('password_breach_warning') }} + +
+ + + + + +
+
+
+ + +@endif + + + + +
{{ $slot }} diff --git a/resources/views/livewire/auth/login.blade.php b/resources/views/livewire/auth/login.blade.php index 4d66965..0304cc8 100644 --- a/resources/views/livewire/auth/login.blade.php +++ b/resources/views/livewire/auth/login.blade.php @@ -2,6 +2,7 @@ use Illuminate\Auth\Events\Lockout; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Session; @@ -40,6 +41,11 @@ public function login(): void RateLimiter::clear($this->throttleKey()); Session::regenerate(); + if ($this->isPasswordPwned($this->password)) { + // Flash a warning message after successful login + session()->flash('password_breach_warning', ' Your password has appeared in a data breach. For your safety, please change it soon.'); + } + $this->redirectIntended(default: route('home', absolute: false), navigate: true); } @@ -71,6 +77,48 @@ protected function throttleKey(): string { return Str::transliterate(Str::lower($this->email).'|'.request()->ip()); } + + + + + protected function isPasswordPwned(string $password): bool +{ + $sha1 = strtoupper(sha1($password)); + $prefix = substr($sha1, 0, 5); + $suffix = substr($sha1, 5); + + try { + $response = Http::timeout(2)->get("https://api.pwnedpasswords.com/range/{$prefix}"); + } catch (\Exception $e) { + return false; // fail-safe on timeout or connection error + } + if ($response->failed()) { + return false; // fail-safe + } + + foreach (explode("\n", $response->body()) as $line) { + $line = trim($line); + if (empty($line) || strpos($line, ':') === false) { + continue; // skip empty or malformed lines + } + + [$hashSuffix, $count] = explode(':', $line, 2); // limit to 2 parts + if ($suffix === $hashSuffix) { + return true; + } + } + + return false; +} + + + + + + + + + }; ?>
@@ -79,11 +127,13 @@ protected function throttleKey(): string

{{ __('Enter your email and password below to log in') }}

- @if (session('status')) - - {{ session('status') }} - - @endif + @if (session('status')) + + {{ session('status') }} + +@endif + +