diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 296e65c0acb2..1252a0e46287 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -11,6 +11,8 @@ use Illuminate\Contracts\Auth\Authenticatable; use Event; use Cache; use Lang; +use Str; +use Cookie; use App\Events\UserLoggedIn; use App\Http\Requests\ValidateTwoFactorRequest; @@ -139,9 +141,18 @@ class LoginController extends Controller private function authenticated(Request $request, Authenticatable $user) { if ($user->google_2fa_secret) { - auth()->logout(); - session()->put('2fa:user:id', $user->id); - return redirect('/validate_two_factor/' . $user->account->account_key); + $cookie = false; + if ($user->remember_2fa_token) { + $cookie = Cookie::get('remember_2fa_' . sha1($user->id)); + } + + if ($cookie && hash_equals($user->remember_2fa_token, $cookie)) { + // do nothing + } else { + auth()->logout(); + session()->put('2fa:user:id', $user->id); + return redirect('/validate_two_factor/' . $user->account->account_key); + } } Event::fire(new UserLoggedIn()); @@ -180,6 +191,16 @@ class LoginController extends Controller auth()->loginUsingId($userId); Event::fire(new UserLoggedIn()); + if ($trust = request()->trust) { + $user = auth()->user(); + if (! $user->remember_2fa_token) { + $user->remember_2fa_token = Str::random(60); + $user->save(); + } + $minutes = $trust == 30 ? 60 * 27 * 30 : 2628000; + cookie()->queue('remember_2fa_' . sha1($user->id), $user->remember_2fa_token, $minutes); + } + return redirect()->intended($this->redirectTo); } diff --git a/app/Models/User.php b/app/Models/User.php index 4b0c8bdbc05f..6c18b1748674 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -69,6 +69,7 @@ class User extends Authenticatable 'oauth_provider_id', 'google_2fa_secret', 'google_2fa_phone', + 'remember_2fa_token', ]; /** diff --git a/database/migrations/2017_12_13_074024_add_remember_2fa_token.php b/database/migrations/2017_12_13_074024_add_remember_2fa_token.php new file mode 100644 index 000000000000..b7c5477a5d02 --- /dev/null +++ b/database/migrations/2017_12_13_074024_add_remember_2fa_token.php @@ -0,0 +1,32 @@ +string('remember_2fa_token', 100)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function ($table) { + $table->dropColumn('remember_2fa_token'); + }); + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 9b0cff0859a7..4c9dc9236085 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -2610,6 +2610,9 @@ $LANG = array( 'copy_billing' => 'Copy Billing', 'quote_has_expired' => 'The quote has expired, please contact the merchant.', 'empty_table_footer' => 'Showing 0 to 0 of 0 entries', + 'do_not_trust' => 'Do not remember this device', + 'trust_for_30_days' => 'Trust for 30 days', + 'trust_forever' => 'Trust forever', ); diff --git a/resources/views/auth/two_factor.blade.php b/resources/views/auth/two_factor.blade.php index 19f00b24e587..13b0a849fa6f 100644 --- a/resources/views/auth/two_factor.blade.php +++ b/resources/views/auth/two_factor.blade.php @@ -18,9 +18,17 @@ {!! Former::text('totp') ->placeholder(trans('texts.one_time_password')) ->autofocus() + ->style('text-indent:4px') ->forceValue('') ->raw() !!} + {!! Former::select('trust') + ->style('background-color:white !important') + ->addOption(trans('texts.do_not_trust'), '') + ->addOption(trans('texts.trust_for_30_days'), '30') + ->addOption(trans('texts.trust_forever'), 'forever') + ->raw() !!} + {!! Button::success(trans('texts.submit')) ->withAttributes(['id' => 'loginButton', 'class' => 'green']) ->large()->submit()->block() !!}