Add all files

This commit is contained in:
root
2025-11-30 11:57:22 +01:00
parent 2ee51cac4f
commit 044271db3d
1476 changed files with 142544 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
<?php
namespace App\Livewire\Auth;
use App\Livewire\Component;
use App\Models\User;
use App\Traits\Captchable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Session;
use Livewire\Attributes\Validate;
class Login extends Component
{
use Captchable;
#[Validate('required|email')]
public string $email = '';
#[Validate('required')]
public string $password = '';
public $remember = false;
public function submit()
{
$this->captcha();
$this->validate();
if (RateLimiter::tooManyAttempts('login:' . $this->email, 5)) {
$this->addError('email', 'Too many login attempts. Please try again in 60 seconds.');
return;
}
RateLimiter::increment('login:' . $this->email);
if (!Auth::attempt($this->only('email', 'password'), $this->remember)) {
$this->addError('email', 'These credentials do not match our records.');
return;
}
// Check 2FA
if (Auth::user()->tfa_secret) {
Session::put('2fa', [
'user_id' => Auth::id(),
'remember' => $this->remember,
'expires' => now()->addMinutes(5),
]);
Auth::logout();
return $this->redirect(route('2fa'), true);
}
RateLimiter::clear('login:' . $this->email);
event(new \App\Events\Auth\Login(User::find(Auth::id())));
$intendedUrl = session()->pull('url.intended', default: route('dashboard'));
$isAdminRoute = str_starts_with($intendedUrl, url('/admin'));
// Redirect normally if it is an admin route, otherwise navigate using livewire
return $this->redirect($intendedUrl, navigate: !$isAdminRoute);
}
public function render()
{
return view('auth.login');
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Livewire\Auth;
use App\Livewire\Component;
use Illuminate\Support\Facades\Auth;
class Logout extends Component
{
public function logout()
{
Auth::logout();
return redirect('/');
}
public function render()
{
return view('auth.logout');
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Livewire\Auth\Password;
use App\Helpers\NotificationHelper;
use App\Livewire\Component;
use App\Models\User;
use App\Traits\Captchable;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\RateLimiter;
class Request extends Component
{
use Captchable;
public string $email = '';
public function submit()
{
$this->captcha();
$this->validate([
'email' => 'required|email',
]);
$rateLimitKey = 'password-reset:' . request()->ip();
if (RateLimiter::tooManyAttempts($rateLimitKey, 3)) {
$this->addError('email', 'Too many password reset attempts. Please try again later.');
return;
}
RateLimiter::hit($rateLimitKey, 60);
// Find the user
$user = User::where('email', $this->email)->first();
if ($user && !$user?->role) {
NotificationHelper::passwordResetNotification($user, ['url' => url(route('password.reset', [
'token' => Password::createToken($user),
'email' => $user->email,
], false))]);
}
$this->notify('If the email address is associated with an account, you will receive an email with instructions on how to reset your password.', 'success');
}
public function render()
{
return view('auth.password.request');
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Livewire\Auth\Password;
use App\Livewire\Component;
use App\Models\User;
use App\Traits\Captchable;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Url;
use Livewire\Attributes\Validate;
class Reset extends Component
{
use Captchable;
public string $token;
#[Url, Locked]
public string $email = '';
#[Validate('required|string|min:8|confirmed')]
public string $password = '';
#[Validate('required')]
public string $password_confirmation = '';
public function mount()
{
if (!$this->token || !Request::has('email')) {
return abort(404);
}
// Validate token
if (!Password::tokenExists(User::where('email', $this->email)->firstOrFail(), $this->token)) {
return abort(404);
}
}
public function submit()
{
$this->validate();
$this->captcha();
$status = Password::reset(
['email' => $this->email, 'password' => $this->password, 'password_confirmation' => $this->password_confirmation, 'token' => $this->token],
function ($user) {
$user->forceFill([
'password' => Hash::make($this->password),
])->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $status === Password::PASSWORD_RESET ? $this->redirect(route('login')) : $this->notify($status, 'error');
}
public function render()
{
return view('auth.password.reset');
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Livewire\Auth;
use App\Attributes\DisabledIf;
use App\Livewire\ComponentWithProperties;
use App\Models\User;
use App\Traits\Captchable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
#[DisabledIf('registration_disabled')]
class Register extends ComponentWithProperties
{
use Captchable;
public string $first_name = '';
public string $last_name = '';
public string $email = '';
public string $password = '';
public string $password_confirmation = '';
public function mount()
{
$this->initializeProperties(null, User::class);
}
public function rules()
{
return array_merge([
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
], $this->getRulesForProperties());
}
public function submit()
{
$validatedData = $this->validate();
$user = User::create([
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'password' => Hash::make($this->password),
]);
if (array_key_exists('properties', $validatedData)) {
$this->updateProperties($user, $validatedData['properties']);
}
Auth::login($user);
return $this->redirectIntended(route('dashboard'), true);
}
public function render()
{
return view('auth.register');
}
}

74
app/Livewire/Auth/Tfa.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
namespace App\Livewire\Auth;
use App\Livewire\Component;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Session;
use RobThree\Auth\Providers\Qr\EndroidQrCodeProvider;
use RobThree\Auth\TwoFactorAuth;
class Tfa extends Component
{
public $code;
public function mount()
{
$session = Session::get('2fa');
if (!$session || $session['expires'] < now()) {
return $this->redirect(route('login'), true);
}
}
public function verify()
{
$this->validate([
'code' => 'required|numeric',
]);
if (RateLimiter::tooManyAttempts('2fa', 5)) {
$this->addError('code', 'Too many attempts.');
return;
}
RateLimiter::increment('2fa');
$session = Session::get('2fa');
$user = User::findOrfail($session['user_id']);
if (!$user->tfa_secret) {
return $this->redirect(route('login'), true);
}
$tfa = new TwoFactorAuth(new EndroidQrCodeProvider, config('app.name'));
if (!$tfa->verifyCode($user->tfa_secret, $this->code)) {
return $this->addError('code', 'Invalid code.');
}
// Check if code has been used before, preventing replay attacks
if (Cache::has('tfa_used_code_' . $user->id . '_' . $this->code)) {
return $this->addError('code', 'Invalid code.');
}
// Mark code as used for 60 seconds just in case
Cache::put('tfa_used_code_' . $user->id . '_' . $this->code, true, 60);
Auth::loginUsingId($user->id, $session['remember']);
event(new \App\Events\Auth\Login(User::find(Auth::id())));
Session::forget('2fa');
RateLimiter::clear('2fa');
return $this->redirect(route('dashboard'), true);
}
public function render()
{
return view('auth.2fa');
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Livewire\Auth;
use App\Helpers\NotificationHelper;
use App\Livewire\Component;
use App\Traits\Captchable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
class VerifyEmail extends Component
{
use Captchable;
public function mount()
{
if (Auth::user()->hasVerifiedEmail()) {
return redirect()->route('dashboard');
}
}
public function submit()
{
$this->captcha();
if (RateLimiter::tooManyAttempts('email-verification', 1)) {
$this->addError('code', 'Too many attempts. Try again later.');
return;
}
NotificationHelper::emailVerificationNotification(Auth::user());
RateLimiter::hit('email-verification', 120);
$this->notify('Verification email sent.');
}
public function render()
{
return view('auth.verify-email');
}
}