first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
<?php
namespace Common\Auth\Fortify;
use App\Models\User;
use Closure;
use Common\Auth\Actions\CreateUser;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\CreatesNewUsers;
class FortifyRegisterUser implements CreatesNewUsers
{
use PasswordValidationRules;
public function create(array $input): User
{
if (settings('registration.disable')) {
abort(404);
}
$appRules = config('common.registration-rules') ?? [];
$commonRules = [
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique(User::class),
function (string $attribute, mixed $value, Closure $fail) {
if (!self::emailIsValid($value)) {
$fail(__('This domain is blacklisted.'));
}
},
],
'password' => $this->passwordRules(),
'token_name' => 'string|min:3|max:50',
];
foreach ($appRules as $key => $rules) {
$commonRules[$key] = array_map(function ($rule) {
if (str_contains($rule, '\\')) {
$namespace = "\\$rule";
return new $namespace();
}
return $rule;
}, $rules);
}
$data = Validator::make($input, $commonRules)->validate();
return (new CreateUser())->execute($data);
}
public static function emailIsValid(string $email): bool
{
$blacklistedDomains = explode(
',',
settings('auth.domain_blacklist', ''),
);
if ($blacklistedDomains) {
$domain = explode('@', $email)[1] ?? null;
if ($domain && in_array($domain, $blacklistedDomains)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Common\Auth\Fortify;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Laravel\Fortify\Contracts\LogoutResponse as LogoutResponseContract;
use Laravel\Fortify\Contracts\RegisterResponse as RegisterResponseContract;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
use Laravel\Fortify\Fortify;
class FortifyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->instance(LoginResponseContract::class, new LoginResponse());
$this->app->instance(
TwoFactorLoginResponseContract::class,
new TwoFactorLoginResponse(),
);
$this->app->instance(
LogoutResponseContract::class,
new LogoutResponse(),
);
$this->app->instance(
RegisterResponseContract::class,
new RegisterResponse(),
);
}
public function boot()
{
Fortify::createUsersUsing(FortifyRegisterUser::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
RateLimiter::for('login', function (Request $request) {
$email = (string) $request->email;
return Limit::perMinute(5)->by($email . $request->ip());
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by(
$request->session()->get('login.id'),
);
});
Fortify::authenticateUsing(function (Request $request) {
return (new ValidateLoginCredentials())->execute($request);
});
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Common\Auth\Fortify;
use Common\Core\Bootstrap\BootstrapData;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
public function toResponse($request): JsonResponse
{
if ($request->get('password') && settings('single_device_login')) {
Auth::logoutOtherDevices($request->get('password'));
}
$data = app(BootstrapData::class)
->init()
->getEncoded();
return response()->json([
'bootstrapData' => $data,
'two_factor' => false,
]);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Common\Auth\Fortify;
use Common\Core\Bootstrap\BootstrapData;
use Illuminate\Http\JsonResponse;
use Laravel\Fortify\Contracts\LogoutResponse as LogoutResponseContract;
class LogoutResponse implements LogoutResponseContract
{
public function toResponse($request): JsonResponse
{
$data = app(BootstrapData::class)
->init()
->getEncoded();
session()->forget('impersonator_id');
return response()->json([
'bootstrapData' => $data,
'status' => 'success',
]);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Common\Auth\Fortify;
use Laravel\Fortify\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*/
protected function passwordRules(): array
{
$password = new Password();
$password->length(5);
return ['required', 'string', $password, 'confirmed'];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Common\Auth\Fortify;
use Common\Core\Bootstrap\BootstrapData;
use Common\Core\Bootstrap\MobileBootstrapData;
use Illuminate\Http\JsonResponse;
use Laravel\Fortify\Contracts\RegisterResponse as RegisterResponseContract;
class RegisterResponse implements RegisterResponseContract
{
public function toResponse($request): JsonResponse
{
$response = [
'status' => $request->user()->hasVerifiedEmail()
? 'success'
: 'needs_email_verification',
];
// for mobile
if ($request->has('token_name')) {
$bootstrapData = app(MobileBootstrapData::class)->init();
$bootstrapData->refreshToken($request->get('token_name'));
$response['bootstrapData'] = $bootstrapData->get();
// for web
} else {
$bootstrapData = app(BootstrapData::class)->init();
$response['bootstrapData'] = $bootstrapData->getEncoded();
}
return response()->json($response);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Common\Auth\Fortify;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param mixed $user
* @param array $input
* @return void
*/
public function reset($user, array $input)
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user
->forceFill([
'password' => $input['password'],
])
->save();
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Common\Auth\Fortify;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
class TwoFactorLoginResponse extends LoginResponse implements
TwoFactorLoginResponseContract
{
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Common\Auth\Fortify;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
public function update($user, array $input)
{
Validator::make(
$input,
[
'current_password' => [
'required',
'string',
'current_password:web',
],
'password' => $this->passwordRules(),
],
[
'current_password.current_password' => __(
'The provided password does not match your current password.',
),
],
)->validateWithBag('updatePassword');
$user
->forceFill([
'password' => $input['password'],
])
->save();
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Common\Auth\Fortify;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\LoginRateLimiter;
class ValidateLoginCredentials
{
public function execute(Request $request): ?User
{
$user = User::where('email', $request->email)->first();
if (!FortifyRegisterUser::emailIsValid($request->email)) {
$this->throwFailedAuthenticationException(
$request,
__('This domain is blacklisted.'),
);
}
if ($user?->isBanned()) {
$comment = $user->bans()->first()->comment;
$this->throwFailedAuthenticationException(
$request,
$comment
? __('Banned: :reason', ['reason' => $comment])
: __('This user is banned.'),
);
}
if ($user && Hash::check($request->password, $user->password)) {
return $user;
}
return null;
}
public function throwFailedAuthenticationException(
Request $request,
string $message,
) {
app(LoginRateLimiter::class)->increment($request);
throw ValidationException::withMessages([
Fortify::username() => [$message],
]);
}
}