update: require 24 (configurable) hours after enabling 2fa before inviting

Previous (less secure) behavior can be restored by setting the config value to 0.
This commit is contained in:
Roardom
2025-06-22 20:38:54 +00:00
parent cf95a900e5
commit da7a606d3a
4 changed files with 28 additions and 19 deletions

View File

@@ -67,9 +67,11 @@ class InviteController extends Controller
->withErrors(trans('user.invites-disabled-group'));
}
if ($user->two_factor_confirmed_at === null) {
$minHours = config('other.hours-until-invite-after-2fa');
if ($user->two_factor_confirmed_at === null || $user->two_factor_confirmed_at->addHours($minHours)->isFuture()) {
return to_route('home.index')
->withErrors('Two-factor authentication must be enabled to send invites');
->withErrors("Two-factor authentication must be enabled for {$minHours} hours to send invites");
}
return view('user.invite.create', ['user' => $user]);
@@ -94,9 +96,11 @@ class InviteController extends Controller
->withErrors(trans('user.not-enough-invites'));
}
if ($user->two_factor_confirmed_at === null) {
$minHours = config('other.hours-until-invite-after-2fa');
if ($user->two_factor_confirmed_at === null || $user->two_factor_confirmed_at->addHours($minHours)->isFuture()) {
return to_route('home.index')
->withErrors('Two-factor authentication must be enabled to send invites');
->withErrors("Two-factor authentication must be enabled for {$minHours} hours to send invites");
}
$request->validate([

View File

@@ -36,7 +36,7 @@ use Laravel\Fortify\TwoFactorAuthenticatable;
* @property string $password
* @property string|null $two_factor_secret
* @property string|null $two_factor_recovery_codes
* @property string|null $two_factor_confirmed_at
* @property \Illuminate\Support\Carbon|null $two_factor_confirmed_at
* @property string $passkey
* @property int $group_id
* @property int $uploaded
@@ -129,18 +129,19 @@ class User extends Authenticatable implements MustVerifyEmail
protected function casts(): array
{
return [
'seedbonus' => 'decimal:2',
'last_login' => 'datetime',
'last_action' => 'datetime',
'disabled_at' => 'datetime',
'can_comment' => 'bool',
'can_download' => 'bool',
'can_request' => 'bool',
'can_invite' => 'bool',
'can_upload' => 'bool',
'can_chat' => 'bool',
'is_donor' => 'bool',
'is_lifetime' => 'bool',
'seedbonus' => 'decimal:2',
'last_login' => 'datetime',
'last_action' => 'datetime',
'disabled_at' => 'datetime',
'two_factor_confirmed_at' => 'datetime',
'can_comment' => 'bool',
'can_download' => 'bool',
'can_request' => 'bool',
'can_invite' => 'bool',
'can_upload' => 'bool',
'can_chat' => 'bool',
'is_donor' => 'bool',
'is_lifetime' => 'bool',
];
}

View File

@@ -132,6 +132,8 @@ return [
],
'max_unused_user_invites' => 1,
'hours-until-invite-after-2fa' => 24,
/*
|--------------------------------------------------------------------------
| Default Users Stats

View File

@@ -161,6 +161,7 @@ test('store returns an ok response', function (): void {
config(['other.invites_restriced' => true]);
config(['other.invite_groups' => [$group->name]]);
config(['other.invite_groups' => [$group->name]]);
config(['other.hours-until-invite-after-2fa' => 0]);
config(['email-blacklist.enabled' => false]);
Mail::fake();
@@ -193,8 +194,9 @@ test('store with internal note as staff user', function (): void {
$inviteEmail = 'test@unit3d.dev';
config(['other' => [
'invites_restriced' => true,
'invite_groups' => [$group->name],
'invites_restriced' => true,
'invite_groups' => [$group->name],
'hours-until-invite-after-2fa' => 0,
],
'email-blacklist.enabled' => false,
]);