diff --git a/app/HMS/Auth/Google2FAAuthenticator.php b/app/HMS/Auth/Google2FAAuthenticator.php new file mode 100644 index 000000000..c81e10dab --- /dev/null +++ b/app/HMS/Auth/Google2FAAuthenticator.php @@ -0,0 +1,39 @@ +getUser()->isGoogle2faEnable() || + ! $this->isEnabled() || + $this->noUserIsAuthenticated() || + $this->twoFactorAuthStillValid(); + } + + /** + * Get the user Google2FA secret. + * + * @throws InvalidSecretKey + * + * @return mixed + */ + protected function getGoogle2FASecretKey() + { + $secret = $this->getUser()->getGoogle2faSecret(); + + if (is_null($secret) || empty($secret)) { + throw new InvalidSecretKey('Secret key cannot be empty.'); + } + + return $secret; + } +} diff --git a/app/HMS/Entities/User.php b/app/HMS/Entities/User.php index 9c3b0d4a6..c19b2c15c 100644 --- a/app/HMS/Entities/User.php +++ b/app/HMS/Entities/User.php @@ -90,6 +90,16 @@ class User implements */ protected $emails; + /** + * @var bool + */ + protected $google2faEnable; + + /** + * @var string|null + */ + protected $google2faSecret; + /** * User constructor. * @@ -340,4 +350,44 @@ public function getEmails() { return $this->emails; } + + /** + * @return bool + */ + public function isGoogle2faEnable() + { + return $this->google2faEnable; + } + + /** + * @param bool $google2faEnable + * + * @return self + */ + public function setGoogle2faEnable(bool $google2faEnable) + { + $this->google2faEnable = $google2faEnable; + + return $this; + } + + /** + * @return string|null + */ + public function getGoogle2faSecret() + { + return $this->google2faSecret; + } + + /** + * @param string|null $google2faSecret + * + * @return self + */ + public function setGoogle2faSecret($google2faSecret) + { + $this->google2faSecret = $google2faSecret; + + return $this; + } } diff --git a/app/HMS/Mappings/HMS.Entities.User.dcm.yml b/app/HMS/Mappings/HMS.Entities.User.dcm.yml index 8aa2a44d7..94aba127c 100644 --- a/app/HMS/Mappings/HMS.Entities.User.dcm.yml +++ b/app/HMS/Mappings/HMS.Entities.User.dcm.yml @@ -38,6 +38,13 @@ HMS\Entities\User: column: email_verified_at type: datetime nullable: true + google2faEnable: + type: boolean + options: + default: 0 + google2faSecret: + type: string + nullable: true deletedAt: type: datetime nullable: true diff --git a/app/Http/Controllers/Api/SearchController.php b/app/Http/Controllers/Api/SearchController.php index e0af330f2..1a7a8cb2f 100644 --- a/app/Http/Controllers/Api/SearchController.php +++ b/app/Http/Controllers/Api/SearchController.php @@ -54,6 +54,7 @@ public function users(string $searchQuery = null, Request $request) 'addressPostcode' => $user->getProfile() ? $user->getProfile()->getAddressPostcode() : null, 'accountId' => $user->getAccount() ? $user->getAccount()->getId() : null, 'paymentRef' => $user->getAccount() ? $user->getAccount()->getPaymentRef() : null, + 'google2fa' => $user->isGoogle2faEnable(), ]; })); diff --git a/app/Http/Controllers/Auth/TwoFactorAuthenticationController.php b/app/Http/Controllers/Auth/TwoFactorAuthenticationController.php new file mode 100644 index 000000000..beaaf46bb --- /dev/null +++ b/app/Http/Controllers/Auth/TwoFactorAuthenticationController.php @@ -0,0 +1,148 @@ +google2fa = $google2fa; + $this->userRepository = $userRepository; + + $this->middleware('auth'); + } + + /** + * Show the 2fa enable/disable form. + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\Response + */ + public function show2faForm(Request $request) + { + $user = Auth::user(); + + $google2faUrl = ''; + if (! empty($user->getGoogle2faSecret())) { + $google2faUrl = $this->google2fa->getQRCodeInline( + 'Nottingham Hackspace HMS', + $user->getEmail(), + $user->getGoogle2faSecret() + ); + } + + return view('auth.2fa') + ->with('user', $user) + ->with('google2faUrl', $google2faUrl); + } + + /** + * Generate new 2fa secret for user. + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\Response + */ + public function generate2faSecret(Request $request) + { + $user = Auth::user(); + + // Add the secret key to the registration data + $user->setGoogle2faEnable(false); + $user->setGoogle2faSecret($this->google2fa->generateSecretKey(32)); + $this->userRepository->save($user); + + return redirect('2fa')->with('success', 'Secret Key is generated, Please verify Code to Enable 2FA'); + } + + /** + * Enable 2fa for USer. + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\Response + */ + public function enable2fa(Request $request) + { + $user = Auth::user(); + // $google2fa = app('pragmarx.google2fa'); + $secret = $request->input('verify-code'); + + $valid = $this->google2fa->verifyKey($user->getGoogle2faSecret(), $secret); + + if ($valid) { + $user->setGoogle2faEnable(true); + $this->userRepository->save($user); + + return redirect('2fa')->with('success', '2FA is Enabled Successfully.'); + } else { + return redirect('2fa')->with('error', 'Invalid Verification Code, Please try again.'); + } + } + + /** + * Disable 2fa for User. + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\Response + */ + public function disable2fa(Request $request) + { + $validatedData = $request->validate([ + 'current-password' => 'required', + ]); + + $user = Auth::user(); + $credentials = [ + $user->getAuthIdentifierName() => $user->getAuthIdentifier(), + 'password' => $validatedData['current-password'], + ]; + if (! Auth::attempt($credentials)) { + return redirect() + ->back() + ->with('error', 'Your password does not matches with your account password. Please try again.'); + } + + $user = Auth::user(); + $user->setGoogle2faEnable(false); + $user->setGoogle2faSecret(null); + $this->userRepository->save($user); + + return redirect('2fa')->with('success', '2FA is now Disabled.'); + } + + /** + * Google2FAMiddleware verify redirect. + * + * @return \Illuminate\Http\Response + */ + public function verify() + { + return redirect(request()->session()->get('_previous')['url']); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index b848cb257..1e33a1fce 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -67,6 +67,7 @@ class Kernel extends HttpKernel 'entity.bindings' => \LaravelDoctrine\ORM\Middleware\SubstituteBindings::class, 'json.request' => \App\Http\Middleware\JsonRequestMiddleware::class, 'client' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class, + '2fa' => \App\Http\Middleware\Google2FAMiddleware::class, ]; /** diff --git a/app/Http/Middleware/Google2FAMiddleware.php b/app/Http/Middleware/Google2FAMiddleware.php new file mode 100644 index 000000000..b123e2626 --- /dev/null +++ b/app/Http/Middleware/Google2FAMiddleware.php @@ -0,0 +1,43 @@ +authenticator = $authenticator; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle($request, Closure $next) + { + $this->authenticator->boot($request); + + if ($this->authenticator->isAuthenticated()) { + return $next($request); + } + + return $this->authenticator->makeRequestOneTimePasswordResponse(); + } +} diff --git a/composer.json b/composer.json index ab3caead5..7166f063d 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "type": "project", "require": { "php": "^7.1.3", + "bacon/bacon-qr-code": "^2.0", "brainrepo/carbon-normalizer": "dev-master", "fideloper/proxy": "^4.0", "garygreen/pretty-routes": "^1.0", @@ -26,6 +27,7 @@ "maxbrokman/safe-queue": "^0.3.0", "orphans/git-deploy-laravel": "dev-master", "pda/pheanstalk": "~4.0", + "pragmarx/google2fa-laravel": "^1.0", "predis/predis": "^1.1", "spatie/laravel-cookie-consent": "^2.0", "tremby/laravel-git-version": "^1.1" diff --git a/composer.lock b/composer.lock index 155a2b795..ce4d1ee71 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,57 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4d798e5c1138ce51881007203ec3f081", + "content-hash": "1bedfd1eda50d618b4caaff9205ebfbc", "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/eaac909da3ccc32b748a65b127acd8918f58d9b0", + "reference": "eaac909da3ccc32b748a65b127acd8918f58d9b0", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0", + "ext-iconv": "*", + "php": "^7.1" + }, + "require-dev": { + "phly/keep-a-changelog": "^1.4", + "phpunit/phpunit": "^6.4", + "squizlabs/php_codesniffer": "^3.1" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "http://www.dasprids.de", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "time": "2018-04-25T17:53:56+00:00" + }, { "name": "behat/transliterator", "version": "v1.2.0", @@ -148,6 +197,48 @@ ], "time": "2019-04-23T19:00:57+00:00" }, + { + "name": "dasprid/enum", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "631ef6e638e9494b0310837fa531bedd908fc22b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/631ef6e638e9494b0310837fa531bedd908fc22b", + "reference": "631ef6e638e9494b0310837fa531bedd908fc22b", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^6.4", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "time": "2017-10-25T22:45:27+00:00" + }, { "name": "defuse/php-encryption", "version": "v2.2.1", @@ -3375,6 +3466,68 @@ "description": "Helps automate the deployment of projects onto servers by utilising Git web hooks.", "time": "2019-02-05T21:51:54+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.2.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/55af0dc01992b4d0da7f6372e2eac097bbbaffdb", + "reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb", + "shasum": "" + }, + "require": { + "php": "^7" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7", + "vimeo/psalm": "^1|^2" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "time": "2019-01-03T20:26:31+00:00" + }, { "name": "paragonie/random_compat", "version": "v9.99.99", @@ -3615,6 +3768,191 @@ ], "time": "2019-03-10T16:53:45+00:00" }, + { + "name": "pragmarx/google2fa", + "version": "v5.0.0", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/17c969c82f427dd916afe4be50bafc6299aef1b4", + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "~1.0|~2.0", + "paragonie/random_compat": ">=1", + "php": ">=5.4", + "symfony/polyfill-php56": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5|~6" + }, + "type": "library", + "extra": { + "component": "package", + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/", + "PragmaRX\\Google2FA\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa" + ], + "time": "2019-03-19T22:44:16+00:00" + }, + { + "name": "pragmarx/google2fa-laravel", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa-laravel.git", + "reference": "b5f5bc71dcc52c48720441bc01c701023bd82882" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/b5f5bc71dcc52c48720441bc01c701023bd82882", + "reference": "b5f5bc71dcc52c48720441bc01c701023bd82882", + "shasum": "" + }, + "require": { + "laravel/framework": ">=5.4.36", + "php": ">=7.0", + "pragmarx/google2fa-qrcode": "^1.0" + }, + "require-dev": { + "orchestra/testbench": "3.4.*|3.5.*|3.6.*|3.7.*", + "phpunit/phpunit": "~5|~6|~7" + }, + "suggest": { + "bacon/bacon-qr-code": "Required to generate inline QR Codes.", + "pragmarx/recovery": "Generate recovery codes." + }, + "type": "library", + "extra": { + "component": "package", + "frameworks": [ + "Laravel" + ], + "branch-alias": { + "dev-master": "0.2-dev" + }, + "laravel": { + "providers": [ + "PragmaRX\\Google2FALaravel\\ServiceProvider" + ], + "aliases": { + "Google2FA": "PragmaRX\\Google2FALaravel\\Facade" + } + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FALaravel\\": "src/", + "PragmaRX\\Google2FALaravel\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "Authentication", + "Two Factor Authentication", + "google2fa", + "laravel" + ], + "time": "2019-03-22T19:54:51+00:00" + }, + { + "name": "pragmarx/google2fa-qrcode", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa-qrcode.git", + "reference": "fd5ff0531a48b193a659309cc5fb882c14dbd03f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/fd5ff0531a48b193a659309cc5fb882c14dbd03f", + "reference": "fd5ff0531a48b193a659309cc5fb882c14dbd03f", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "~1.0|~2.0", + "php": ">=5.4", + "pragmarx/google2fa": ">=4.0" + }, + "require-dev": { + "khanamiryan/qrcode-detector-decoder": "^1.0", + "phpunit/phpunit": "~4|~5|~6|~7" + }, + "type": "library", + "extra": { + "component": "package", + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FAQRCode\\": "src/", + "PragmaRX\\Google2FAQRCode\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "QR Code package for Google2FA", + "keywords": [ + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa", + "qr code", + "qrcode" + ], + "time": "2019-03-20T16:42:58+00:00" + }, { "name": "predis/predis", "version": "v1.1.1", @@ -5090,6 +5428,62 @@ ], "time": "2019-02-06T07:57:58+00:00" }, + { + "name": "symfony/polyfill-php56", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "f4dddbc5c3471e1b700a147a20ae17cdb72dbe42" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/f4dddbc5c3471e1b700a147a20ae17cdb72dbe42", + "reference": "f4dddbc5c3471e1b700a147a20ae17cdb72dbe42", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php56\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-02-06T07:57:58+00:00" + }, { "name": "symfony/polyfill-php70", "version": "v1.11.0", @@ -5204,6 +5598,58 @@ ], "time": "2019-02-06T07:57:58+00:00" }, + { + "name": "symfony/polyfill-util", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-util.git", + "reference": "b46c6cae28a3106735323f00a0c38eccf2328897" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/b46c6cae28a3106735323f00a0c38eccf2328897", + "reference": "b46c6cae28a3106735323f00a0c38eccf2328897", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Util\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony utilities for portability of PHP codes", + "homepage": "https://symfony.com", + "keywords": [ + "compat", + "compatibility", + "polyfill", + "shim" + ], + "time": "2019-02-08T14:16:39+00:00" + }, { "name": "symfony/process", "version": "v4.2.8", diff --git a/config/google2fa.php b/config/google2fa.php new file mode 100644 index 000000000..809de2dc2 --- /dev/null +++ b/config/google2fa.php @@ -0,0 +1,73 @@ + true, + + /* + * Lifetime in minutes. + * In case you need your users to be asked for a new one time passwords from time to time. + */ + + 'lifetime' => 0, // 0 = eternal + + /* + * Renew lifetime at every new request. + */ + + 'keep_alive' => true, + + /* + * Auth container binding + */ + + 'auth' => 'auth', + + /* + * 2FA verified session var + */ + + 'session_var' => 'google2fa', + + /* + * One Time Password request input name + */ + 'otp_input' => 'one_time_password', + + /* + * One Time Password Window + */ + 'window' => 1, + + /* + * Forbid user to reuse One Time Passwords. + */ + 'forbid_old_passwords' => false, + + /* + * User's table column for google2fa secret + */ + 'otp_secret_column' => 'google2fa_secret', + + /* + * One Time Password View + */ + 'view' => 'auth.google2fa', + + /* + * One Time Password error message + */ + 'error_messages' => [ + 'wrong_otp' => "The 'One Time Password' typed was wrong.", + ], + + /* + * Throw exceptions or just fire events? + */ + 'throw_exceptions' => true, + +]; diff --git a/database/migrations_doctrine/Version20190520022326_alter_user_add_2fa.php b/database/migrations_doctrine/Version20190520022326_alter_user_add_2fa.php new file mode 100644 index 000000000..bec71b4e4 --- /dev/null +++ b/database/migrations_doctrine/Version20190520022326_alter_user_add_2fa.php @@ -0,0 +1,29 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE user ADD google2fa_enable TINYINT(1) DEFAULT \'0\' NOT NULL, ADD google2fa_secret VARCHAR(255) DEFAULT NULL'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE user DROP google2fa_enable, DROP google2fa_secret'); + } +} diff --git a/resources/js/select2.js b/resources/js/select2.js index 49bc6cc4f..3a094ae12 100644 --- a/resources/js/select2.js +++ b/resources/js/select2.js @@ -84,7 +84,7 @@ $(".js-data-existing-account-ajax").select2({ obj.text = obj.fullname; return obj; }); - + // indicate that infinite scrolling can be used params.page = params.page || 1; @@ -106,8 +106,9 @@ $(".js-data-existing-account-ajax").select2({ // helpers for the above select2 searches function formatUser (user) { if (user.loading) return user.text; + var lock = user.google2fa ? ' ' : ''; var markup = '
' + - '
' + user.fullname + ' ' + user.username + '
' + + '
' + user.fullname + ' (' + user.username + ')' + lock + '
' + '
' + user.email + '
' + '
' + user.address1 + ', ' + user.addressPostcode + '
' + '
' + user.paymentRef + '
' + diff --git a/resources/sass/layout/_member-search.scss b/resources/sass/layout/_member-search.scss index 618e1b484..82b70c6f1 100644 --- a/resources/sass/layout/_member-search.scss +++ b/resources/sass/layout/_member-search.scss @@ -9,14 +9,6 @@ .username { font-style: italic; - - &::before { - content: '('; - } - - &::after { - content: ')'; - } } } diff --git a/resources/views/auth/2fa.blade.php b/resources/views/auth/2fa.blade.php new file mode 100644 index 000000000..9177436d3 --- /dev/null +++ b/resources/views/auth/2fa.blade.php @@ -0,0 +1,106 @@ +@extends('layouts.app') + +@section('title', 'Two Factor Authentication') + +@section('content') +
+
+
+
+
Two Factor Authentication
+
+

Two factor authentication (2FA) strengthens access security by requiring two methods (also referred to as factors) to verify your identity. Two factor authentication protects against phishing, social engineering and password brute force attacks and secures your logins from attackers exploiting weak or stolen credentials.

+
+ @if (! $user->isGoogle2faEnable()) +

To Enable Two Factor Authentication on your Account, you need to do following steps

+ +
    +
  1. Click on Generate Secret Button , To Generate a Unique secret QR code for your profile
  2. +
  3. Verify the OTP from Google Authenticator Mobile App
  4. +
+
+
+ @endif + + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + @if (session('success')) +
+ {{ session('success') }} +
+ @endif + + @if(empty($user->getGoogle2faSecret())) +
+ @csrf +
+
+ +
+
+
+ @elseif (! $user->isGoogle2faEnable()) + 1. Scan this barcode with your Google Authenticator App:
+ +

+ 2.Enter the pin the code to Enable 2FA

+
+ @csrf + +
+ + +
+ + + @if ($errors->has('verify-code')) + + {{ $errors->first('verify-code') }} + + @endif +
+
+
+
+ +
+
+
+ @elseif($user->isGoogle2faEnable()) +
+ 2FA is Currently Enabled for your account. +
+

If you are looking to disable Two Factor Authentication. Please confirm your password and Click Disable 2FA Button.

+
+ @csrf +
+ + +
+ + + @if ($errors->has('current-password')) + + {{ $errors->first('current-password') }} + + @endif +
+
+
+ +
+
+ @endif +
+
+
+
+
+@endsection diff --git a/resources/views/auth/google2fa.blade.php b/resources/views/auth/google2fa.blade.php new file mode 100644 index 000000000..947fc6205 --- /dev/null +++ b/resources/views/auth/google2fa.blade.php @@ -0,0 +1,45 @@ +@extends('layouts.app') + +@section('pageTitle', 'Log In, 2FA') + +@section('content') +
+
+
+
+
Two Factor Authentication
+
+

Two factor authentication (2FA) strengthens access security by requiring two methods (also referred to as factors) to verify your identity. Two factor authentication protects against phishing, social engineering and password brute force attacks and secures your logins from attackers exploiting weak or stolen credentials.

+ + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + + Enter the pin from Google Authenticator Enable 2FA

+
+ @csrf +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+@endsection diff --git a/resources/views/layouts/navbar.blade.php b/resources/views/layouts/navbar.blade.php index 8e7ce92d5..96497d164 100644 --- a/resources/views/layouts/navbar.blade.php +++ b/resources/views/layouts/navbar.blade.php @@ -68,6 +68,7 @@ Update Details Change Password Standing Order details + Two Factor Auth
+