Merge 193cc5358f into 9e17c85f1b
This commit is contained in:
commit
b75c183c2c
|
|
@ -131,9 +131,28 @@ class LoginController extends BaseController
|
|||
|
||||
//2FA
|
||||
if ($user->google_2fa_secret && $request->has('one_time_password')) {
|
||||
$google2fa = new Google2FA();
|
||||
$otp = $request->input('one_time_password');
|
||||
$secret = decrypt($user->google_2fa_secret);
|
||||
$timestamp = false;
|
||||
|
||||
if (strlen($request->input('one_time_password')) == 0 || !$google2fa->verifyKey(decrypt($user->google_2fa_secret), $request->input('one_time_password'))) {
|
||||
if (strlen($otp) > 0) {
|
||||
// Try SHA512 first (new algorithm) with timestamp to prevent OTP reuse
|
||||
$google2fa = new Google2FA();
|
||||
$google2fa->setAlgorithm(\PragmaRX\Google2FA\Support\Constants::SHA512);
|
||||
$timestamp = $google2fa->verifyKeyNewer($secret, $otp, $user->google_2fa_ts ?? 0);
|
||||
|
||||
// Fall back to SHA1 for existing users (backward compatibility)
|
||||
if ($timestamp === false) {
|
||||
$google2fa = new Google2FA();
|
||||
$timestamp = $google2fa->verifyKeyNewer($secret, $otp, $user->google_2fa_ts ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ($timestamp !== false) {
|
||||
// Update timestamp to prevent OTP reuse
|
||||
$user->google_2fa_ts = $timestamp;
|
||||
$user->save();
|
||||
} else {
|
||||
return response()
|
||||
->json(['message' => ctrans('texts.invalid_one_time_password')], 422)
|
||||
->header('X-App-Version', config('ninja.app_version'))
|
||||
|
|
|
|||
|
|
@ -40,13 +40,17 @@ class TwoFactorController extends BaseController
|
|||
}
|
||||
|
||||
$google2fa = new Google2FA();
|
||||
$secret = $google2fa->generateSecretKey();
|
||||
$google2fa->setAlgorithm(\PragmaRX\Google2FA\Support\Constants::SHA512);
|
||||
$secret = $google2fa->generateSecretKey(32);
|
||||
|
||||
$qr_code = $google2fa->getQRCodeUrl(
|
||||
config('ninja.app_name'),
|
||||
$user->email,
|
||||
$secret
|
||||
);
|
||||
|
||||
// Append algorithm parameter for SHA512
|
||||
$qr_code .= '&algorithm=SHA512';
|
||||
|
||||
$data = [
|
||||
'secret' => $secret,
|
||||
|
|
@ -57,21 +61,31 @@ class TwoFactorController extends BaseController
|
|||
}
|
||||
|
||||
public function enableTwoFactor(EnableTwoFactorRequest $request)
|
||||
{
|
||||
$google2fa = new Google2FA();
|
||||
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$secret = $request->input('secret');
|
||||
$oneTimePassword = $request->input('one_time_password');
|
||||
|
||||
if ($google2fa->verifyKey($secret, $oneTimePassword) && $user->phone && $user->email_verified_at) {
|
||||
// Try SHA512 first (new algorithm)
|
||||
$google2fa = new Google2FA();
|
||||
$google2fa->setAlgorithm(\PragmaRX\Google2FA\Support\Constants::SHA512);
|
||||
$timestamp = $google2fa->verifyKeyNewer($secret, $oneTimePassword, 0);
|
||||
|
||||
// Fall back to SHA1 for manual entry (authenticator apps default to SHA1)
|
||||
if ($timestamp === false) {
|
||||
$google2fa = new Google2FA();
|
||||
$timestamp = $google2fa->verifyKeyNewer($secret, $oneTimePassword, 0);
|
||||
}
|
||||
|
||||
if ($timestamp !== false && $user->phone && $user->email_verified_at) {
|
||||
$user->google_2fa_secret = encrypt($secret);
|
||||
$user->google_2fa_ts = $timestamp;
|
||||
$user->save();
|
||||
|
||||
return response()->json(['message' => ctrans('texts.enabled_two_factor')], 200);
|
||||
} elseif (! $secret || ! $google2fa->verifyKey($secret, $oneTimePassword)) {
|
||||
} elseif (! $secret || $timestamp === false) {
|
||||
return response()->json(['message' => ctrans('texts.invalid_one_time_password')], 400);
|
||||
} elseif (! $user->phone) {
|
||||
return response()->json(['message' => ctrans('texts.set_phone_for_two_factor')], 400);
|
||||
|
|
@ -94,6 +108,7 @@ class TwoFactorController extends BaseController
|
|||
$user = auth()->user();
|
||||
|
||||
$user->google_2fa_secret = null;
|
||||
$user->google_2fa_ts = null;
|
||||
$user->save();
|
||||
|
||||
return $this->itemResponse($user);
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
'remember_token',
|
||||
'google_2fa_secret',
|
||||
'google_2fa_phone',
|
||||
'google_2fa_ts',
|
||||
'remember_2fa_token',
|
||||
'slack_webhook_url',
|
||||
'referral_earnings',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return new class extends Migration
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
* Run the migrations.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public function up(): void
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
|
||||
$table->integer('google_2fa_ts')->nullable()->after('google_2fa_secret');
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
* Reverse the migrations.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public function down(): void
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
|
||||
|
||||
$table->dropColumn('google_2fa_ts');
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
Loading…
Reference in New Issue