70
common/Auth/Fortify/FortifyRegisterUser.php
Executable file
70
common/Auth/Fortify/FortifyRegisterUser.php
Executable 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;
|
||||
}
|
||||
}
|
||||
55
common/Auth/Fortify/FortifyServiceProvider.php
Executable file
55
common/Auth/Fortify/FortifyServiceProvider.php
Executable 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
27
common/Auth/Fortify/LoginResponse.php
Executable file
27
common/Auth/Fortify/LoginResponse.php
Executable 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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
24
common/Auth/Fortify/LogoutResponse.php
Executable file
24
common/Auth/Fortify/LogoutResponse.php
Executable 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',
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
common/Auth/Fortify/PasswordValidationRules.php
Executable file
18
common/Auth/Fortify/PasswordValidationRules.php
Executable 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'];
|
||||
}
|
||||
}
|
||||
34
common/Auth/Fortify/RegisterResponse.php
Executable file
34
common/Auth/Fortify/RegisterResponse.php
Executable 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);
|
||||
}
|
||||
}
|
||||
31
common/Auth/Fortify/ResetUserPassword.php
Executable file
31
common/Auth/Fortify/ResetUserPassword.php
Executable 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();
|
||||
}
|
||||
}
|
||||
10
common/Auth/Fortify/TwoFactorLoginResponse.php
Executable file
10
common/Auth/Fortify/TwoFactorLoginResponse.php
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Auth\Fortify;
|
||||
|
||||
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
|
||||
|
||||
class TwoFactorLoginResponse extends LoginResponse implements
|
||||
TwoFactorLoginResponseContract
|
||||
{
|
||||
}
|
||||
37
common/Auth/Fortify/UpdateUserPassword.php
Executable file
37
common/Auth/Fortify/UpdateUserPassword.php
Executable 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();
|
||||
}
|
||||
}
|
||||
52
common/Auth/Fortify/ValidateLoginCredentials.php
Executable file
52
common/Auth/Fortify/ValidateLoginCredentials.php
Executable 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],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user