This commit is contained in:
TechNoNerd87 2025-11-26 16:33:20 -08:00 committed by GitHub
commit b75c183c2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 126 additions and 8 deletions

View File

@ -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'))

View File

@ -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);

View File

@ -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',

View File

@ -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');
});
}
};