From 0c009445d4a52450c88fc0e47116782511acad12 Mon Sep 17 00:00:00 2001 From: zjean Date: Thu, 3 Mar 2016 20:45:27 +0100 Subject: [PATCH 1/5] Added 2fa code validation --- .../Controllers/PreferencesController.php | 55 ++++++++++++++++++- app/Http/Requests/TokenFormRequest.php | 39 +++++++++++++ app/Http/routes.php | 2 + app/Validation/FireflyValidator.php | 26 +++++++++ composer.json | 1 + config/app.php | 3 +- resources/views/preferences/code.twig | 52 ++++++++++++++++++ resources/views/preferences/index.twig | 33 ++++++++--- 8 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 app/Http/Requests/TokenFormRequest.php create mode 100644 resources/views/preferences/code.twig diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index f27a73797c..9e3ad3ab18 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -1,11 +1,15 @@ data; $fiscalYearStart = date('Y') . '-' . $fiscalYearStartStr; $twoFactorAuthEnabled = Preferences::get('twoFactorAuthEnabled', 0)->data; + + $hasTwoFactorAuthSecret = Preferences::get('twoFactorAuthSecret') != null && !empty(Preferences::get('twoFactorAuthSecret')->data); + $showIncomplete = env('SHOW_INCOMPLETE_TRANSLATIONS', false) === true; return view( 'preferences.index', compact( - 'budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange', 'customFiscalYear', 'fiscalYearStart', 'twoFactorAuthEnabled', + 'budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange', 'customFiscalYear', 'fiscalYearStart', 'twoFactorAuthEnabled', 'hasTwoFactorAuthSecret', 'showIncomplete' ) ); @@ -87,7 +94,14 @@ class PreferencesController extends Controller // two factor auth $twoFactorAuthEnabled = (int)Input::get('twoFactorAuthEnabled'); - Preferences::set('twoFactorAuthEnabled', $twoFactorAuthEnabled); + + $hasTwoFactorAuthSecret = Preferences::get('twoFactorAuthSecret') != null && !empty(Preferences::get('twoFactorAuthSecret')->data); + + // If we already have a secret, just set the two factor auth enabled to 1, and let the user continue with the existing secret. + if($hasTwoFactorAuthSecret) + { + Preferences::set('twoFactorAuthEnabled', $twoFactorAuthEnabled); + } // language: $lang = Input::get('language'); @@ -99,7 +113,44 @@ class PreferencesController extends Controller Session::flash('success', 'Preferences saved!'); Preferences::mark(); + // if we don't have a valid secret yet, redirect to the code page. + if(!$hasTwoFactorAuthSecret) + { + return redirect(route('preferences.code')); + } + return redirect(route('preferences')); } + /* + * @param TokenFormRequest $request + * + * @return $this|\Illuminate\View\View + */ + public function postCode(TokenFormRequest $request) + { + Preferences::set('twoFactorAuthEnabled', 1); + Preferences::set('twoFactorAuthSecret', $request->input('secret')); + + Session::flash('success', 'Preferences saved!'); + Preferences::mark(); + + return redirect(route('preferences')); + } + + /* + * @param Google2FA $google2fa + * + * @return $this|\Illuminate\View\View + */ + public function code(Google2FA $google2fa) + { + $secret = $google2fa->generateSecretKey(16, Auth::user()->id); + + $image = $google2fa->getQRCodeInline("FireflyIII", null, $secret, 150); + + + return view('preferences.code', compact('secret', 'image')); + } + } diff --git a/app/Http/Requests/TokenFormRequest.php b/app/Http/Requests/TokenFormRequest.php new file mode 100644 index 0000000000..19456f635b --- /dev/null +++ b/app/Http/Requests/TokenFormRequest.php @@ -0,0 +1,39 @@ + 'required', + 'code' => 'required|2faCode:secret', + ]; + + return $rules; + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index 62e4eaf029..574c333d5b 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -246,6 +246,8 @@ Route::group( */ Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']); Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']); + Route::get('/preferences/code', ['uses' => 'PreferencesController@code', 'as' => 'preferences.code']); + Route::post('/preferences/code', ['uses' => 'PreferencesController@postCode']); /** * Profile Controller diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index ed447e81c1..8535ed7fc4 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -16,10 +16,13 @@ use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Rules\Triggers\TriggerInterface; use FireflyIII\User; +use Input; use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Validation\Validator; use Log; +use PragmaRX\Google2FA\Contracts\Google2FA; use Symfony\Component\Translation\TranslatorInterface; +use Session; /** * Class FireflyValidator @@ -43,6 +46,29 @@ class FireflyValidator extends Validator parent::__construct($translator, $data, $rules, $messages, $customAttributes); } + /** + * @param $attribute + * @param $value + * @param $parameters + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * + * @return bool + */ + public function validate2faCode($attribute, $value, $parameters): bool + { + if (!is_string($value) || is_null($value) || strlen($value) <> 6) { + return false; + } + + // Retrieve the secret from our hidden form field. + $secret = Input::get($parameters[0]); + + $google2fa = app('PragmaRX\Google2FA\Google2FA'); + + return $google2fa->verifyKey($secret, $value); + } + /** * @param $attribute * @param $value diff --git a/composer.json b/composer.json index 5e40fb7ba0..8664702215 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "league/csv": "^7.1", "laravelcollective/html": "^5.2", "rmccue/requests": "^1.6" + "pragmarx/google2fa": "^0.7.1" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/config/app.php b/config/app.php index c7255ff5c0..7efa1d2687 100644 --- a/config/app.php +++ b/config/app.php @@ -181,6 +181,7 @@ return [ // Barryvdh\Debugbar\ServiceProvider::class, 'DaveJamesMiller\Breadcrumbs\ServiceProvider', 'TwigBridge\ServiceProvider', + 'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider', ], @@ -238,7 +239,7 @@ return [ 'ExpandedForm' => 'FireflyIII\Support\Facades\ExpandedForm', 'Entrust' => 'Zizaco\Entrust\EntrustFacade', 'Input' => 'Illuminate\Support\Facades\Input', - + 'Google2FA' => 'PragmaRX\Google2FA\Vendor\Laravel\Facade', ], diff --git a/resources/views/preferences/code.twig b/resources/views/preferences/code.twig new file mode 100644 index 0000000000..fec7b89ebe --- /dev/null +++ b/resources/views/preferences/code.twig @@ -0,0 +1,52 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }} +{% endblock %} + +{% block content %} + {{ Form.open({'class' : 'form-horizontal','id' : 'preferences.code'}) }} + + +
+
+
+
+

{{ 'pref_code'|_ }}

+
+
+

+ {{ 'pref_code_help'|_ }} +

+
+ +
+ +
+ +
+
+
+

{{ secret }}

+
+
+ + {{ ExpandedForm.text('code', code, {'label' : 'Code'}) }} +
+
+
+ +
+
+
+
+
+ +
+
+
+
+ + + {{ Form.close|raw }} +{% endblock %} \ No newline at end of file diff --git a/resources/views/preferences/index.twig b/resources/views/preferences/index.twig index 78e48f64c0..9e9eae2766 100644 --- a/resources/views/preferences/index.twig +++ b/resources/views/preferences/index.twig @@ -145,19 +145,34 @@

{{ 'pref_two_factor_auth_help'|_ }}

-
-
-
- -
+
+
+
+
+ + {% if twoFactorAuthEnabled == '1' and hasTwoFactorAuthSecret == true %} + + + {% endif %} + +
+ + +
@@ -171,4 +186,4 @@ {{ Form.close|raw }} -{% endblock %} +{% endblock %} \ No newline at end of file From 69b338ca85bb31add5f078c67f500bd5608f0bc6 Mon Sep 17 00:00:00 2001 From: zjean Date: Thu, 3 Mar 2016 22:00:56 +0100 Subject: [PATCH 2/5] Added translations for 2fa. --- resources/lang/en_US/firefly.php | 2 ++ resources/lang/en_US/validation.php | 1 + resources/lang/nl_NL/firefly.php | 2 ++ resources/lang/nl_NL/validation.php | 2 ++ 4 files changed, 7 insertions(+) diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 81dc74a139..c85839a5e7 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -230,6 +230,8 @@ return [ 'pref_two_factor_auth' => '2-step verification', 'pref_two_factor_auth_help' => 'When you enable 2-step verification (also known as two-factor authentication), you add an extra layer of security to your account. You sign in with something you know (your password) and something you have (a verification code). Verification codes are generated by an application on your phone, such as Authy or Google Authenticator.', 'pref_enable_two_factor_auth' => 'Enable 2-step verification', + 'pref_code' => 'Verify code', + 'pref_code_help' => 'Scan the QR code with an application on your phone such as Authy or Google Authenticator and enter the generated code.', 'pref_save_settings' => 'Save settings', // profile: diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index 5be1b8d145..86b7ece35c 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -68,4 +68,5 @@ return [ 'string' => 'The :attribute must be a string.', 'url' => 'The :attribute format is invalid.', 'timezone' => 'The :attribute must be a valid zone.', + '2fa_code' => 'The :attribute field is invalid.', ]; diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php index 253317581d..31cd6de233 100644 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -227,6 +227,8 @@ return [ 'pref_fiscal_year_start_label' => 'Start van boekjaar', 'pref_two_factor_auth' => 'Authenticatie in twee stappen', 'pref_two_factor_auth_help' => 'Als je authenticatie in twee stappen (ook wel twee-factor authenticatie genoemd) inschakelt voeg je een extra beveiligingslaag toe aan je account. Je logt in met iets dat je weet (je wachtwoord) en iets dat je hebt (een verificatiecode). Verificatiecodes worden gegeneerd door apps op je telefoon, zoals Authy en Google Authenticator.', + 'pref_code' => 'Verifieer code', + 'pref_code_help' => 'Scan onderstaande QR code met een app op je telefoon zoals Authy of Google Authenticator en vul de code die gegenereerd wordt in.', 'pref_enable_two_factor_auth' => 'Authenticatie in twee stappen inschakelen', 'pref_save_settings' => 'Instellingen opslaan', diff --git a/resources/lang/nl_NL/validation.php b/resources/lang/nl_NL/validation.php index f2f03ebd0b..dede00973c 100644 --- a/resources/lang/nl_NL/validation.php +++ b/resources/lang/nl_NL/validation.php @@ -68,4 +68,6 @@ return [ 'string' => 'Het :attribute moet een tekenreeks zijn.', 'url' => ':attribute is geen geldige URL.', 'timezone' => 'Het :attribute moet een geldige zone zijn.', + '2fa_code' => ':attribute is ongeldig.', ]; + From 888e9beb4cfb690c04f51317d94832827ab68557 Mon Sep 17 00:00:00 2001 From: zjean Date: Thu, 3 Mar 2016 22:02:08 +0100 Subject: [PATCH 3/5] Add breadcrumbs --- app/Http/breadcrumbs.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/Http/breadcrumbs.php b/app/Http/breadcrumbs.php index f4ff12c12d..6d1ae21e9c 100644 --- a/app/Http/breadcrumbs.php +++ b/app/Http/breadcrumbs.php @@ -378,6 +378,14 @@ Breadcrumbs::register( } ); +Breadcrumbs::register( + 'preferences.code', function (BreadCrumbGenerator $breadcrumbs) { + $breadcrumbs->parent('home'); + $breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences')); + +} +); + /** * PROFILE */ From 90ad06c65cf1509199ef805687e1f5f213564402 Mon Sep 17 00:00:00 2001 From: zjean Date: Fri, 4 Mar 2016 19:35:11 +0100 Subject: [PATCH 4/5] Fixed composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8664702215..98a2dd3ee7 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "rcrowe/twigbridge": "~0.9", "league/csv": "^7.1", "laravelcollective/html": "^5.2", - "rmccue/requests": "^1.6" + "rmccue/requests": "^1.6", "pragmarx/google2fa": "^0.7.1" }, "require-dev": { From fcf7d98834d8dd7694377e8f998610941a2f350d Mon Sep 17 00:00:00 2001 From: zjean Date: Fri, 4 Mar 2016 19:36:42 +0100 Subject: [PATCH 5/5] Update translations. --- resources/lang/en_US/firefly.php | 5 +++-- resources/lang/nl_NL/firefly.php | 5 +++-- resources/views/preferences/code.twig | 4 ++-- resources/views/preferences/index.twig | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index c85839a5e7..e13a9edb6d 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -230,8 +230,9 @@ return [ 'pref_two_factor_auth' => '2-step verification', 'pref_two_factor_auth_help' => 'When you enable 2-step verification (also known as two-factor authentication), you add an extra layer of security to your account. You sign in with something you know (your password) and something you have (a verification code). Verification codes are generated by an application on your phone, such as Authy or Google Authenticator.', 'pref_enable_two_factor_auth' => 'Enable 2-step verification', - 'pref_code' => 'Verify code', - 'pref_code_help' => 'Scan the QR code with an application on your phone such as Authy or Google Authenticator and enter the generated code.', + 'pref_two_factor_auth_code' => 'Verify code', + 'pref_two_factor_auth_code_help' => 'Scan the QR code with an application on your phone such as Authy or Google Authenticator and enter the generated code.', + 'pref_two_factor_auth_reset_code' => 'Reset verification code', 'pref_save_settings' => 'Save settings', // profile: diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php index 31cd6de233..5d27a49585 100644 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -227,9 +227,10 @@ return [ 'pref_fiscal_year_start_label' => 'Start van boekjaar', 'pref_two_factor_auth' => 'Authenticatie in twee stappen', 'pref_two_factor_auth_help' => 'Als je authenticatie in twee stappen (ook wel twee-factor authenticatie genoemd) inschakelt voeg je een extra beveiligingslaag toe aan je account. Je logt in met iets dat je weet (je wachtwoord) en iets dat je hebt (een verificatiecode). Verificatiecodes worden gegeneerd door apps op je telefoon, zoals Authy en Google Authenticator.', - 'pref_code' => 'Verifieer code', - 'pref_code_help' => 'Scan onderstaande QR code met een app op je telefoon zoals Authy of Google Authenticator en vul de code die gegenereerd wordt in.', 'pref_enable_two_factor_auth' => 'Authenticatie in twee stappen inschakelen', + 'pref_two_factor_auth_code' => 'Verifieer code', + 'pref_two_factor_auth_code_help' => 'Scan onderstaande QR code met een app op je telefoon zoals Authy of Google Authenticator en vul de code die gegenereerd wordt in.', + 'pref_two_factor_auth_reset_code' => 'Reset verificatiecode', 'pref_save_settings' => 'Instellingen opslaan', // profile: diff --git a/resources/views/preferences/code.twig b/resources/views/preferences/code.twig index fec7b89ebe..778af11096 100644 --- a/resources/views/preferences/code.twig +++ b/resources/views/preferences/code.twig @@ -12,11 +12,11 @@
-

{{ 'pref_code'|_ }}

+

{{ 'pref_two_factor_auth_code'|_ }}

- {{ 'pref_code_help'|_ }} + {{ 'pref_two_factor_auth_code_help'|_ }}

diff --git a/resources/views/preferences/index.twig b/resources/views/preferences/index.twig index 9e9eae2766..b029a896c9 100644 --- a/resources/views/preferences/index.twig +++ b/resources/views/preferences/index.twig @@ -160,7 +160,7 @@