diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index bd85c6807..62b754724 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -159,12 +159,12 @@ class RegisterController extends Controller $confirmPassword = $request->input('password_confirmation'); $email = $request->input('email'); - // Get the default user role. - $userDefault = Role::query()->where('isdefault', '=', 1)->first(); + // Get the default user role. + $userDefault = Role::query()->where('isdefault', '=', 1)->first(); - if (! empty($error)) { - return $this->showRegistrationForm($request, $error); - } + if (! empty($error)) { + return $this->showRegistrationForm($request, $error); + } if (Invite::isAllowed($inviteCode, $email) || Settings::settingValue('..registerstatus') !== Settings::REGISTER_STATUS_INVITE) { $user = $this->create( diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 28773a8ec..a7960b69b 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -84,18 +84,18 @@ class ResetPasswordController extends Controller $content = app('smarty.view')->fetch($theme.'/forgottenpassword.tpl'); app('smarty.view')->assign( - [ - 'content' => $content, - 'title' => $title, - 'meta_title' => $meta_title, - 'meta_keywords' => $meta_keywords, - 'meta_description' => $meta_description, - 'email' => $ret['email'] ?? '', - 'confirmed' => $confirmed, - 'error' => $error, - 'notice' => $onscreen, - ] - ); + [ + 'content' => $content, + 'title' => $title, + 'meta_title' => $meta_title, + 'meta_keywords' => $meta_keywords, + 'meta_description' => $meta_description, + 'email' => $ret['email'] ?? '', + 'confirmed' => $confirmed, + 'error' => $error, + 'notice' => $onscreen, + ] + ); app('smarty.view')->display($theme.'/basepage.tpl'); } } diff --git a/app/Http/Controllers/BasePageController.php b/app/Http/Controllers/BasePageController.php index 89c58e6e1..46f398680 100644 --- a/app/Http/Controllers/BasePageController.php +++ b/app/Http/Controllers/BasePageController.php @@ -81,7 +81,7 @@ class BasePageController extends Controller */ public function __construct() { - $this->middleware(['auth', 'web'])->except('api', 'contact', 'showContactForm', 'callback', 'getNzb', 'terms', 'capabilities', 'movie', 'apiSearch', 'tv', 'details', 'failed', 'showRssDesc', 'fullFeedRss', 'categoryFeedRss', 'cartRss', 'myMoviesRss', 'myShowsRss'); + $this->middleware(['auth', 'web', '2fa'])->except('api', 'contact', 'showContactForm', 'callback', 'getNzb', 'terms', 'capabilities', 'movie', 'apiSearch', 'tv', 'details', 'failed', 'showRssDesc', 'fullFeedRss', 'categoryFeedRss', 'cartRss', 'myMoviesRss', 'myShowsRss'); // Buffer settings/DB connection. $this->settings = new Settings(); $this->smarty = app('smarty.view'); diff --git a/app/Http/Controllers/PasswordSecurityController.php b/app/Http/Controllers/PasswordSecurityController.php new file mode 100644 index 000000000..6974c4116 --- /dev/null +++ b/app/Http/Controllers/PasswordSecurityController.php @@ -0,0 +1,101 @@ +passwordSecurity()->exists()) { + $google2fa_url = \Google2FA::getQRCodeInline( + config('app.name'), + $user->email, + $user->passwordSecurity->google2fa_secret + ); + } + $data = [ + 'user' => $user, + 'google2fa_url' => $google2fa_url, + ]; + + return view('auth.2fa')->with('data', $data); + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException + * @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException + * @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException + */ + public function generate2faSecret(Request $request) + { + $user = Auth::user(); + + // Add the secret key to the registration data + PasswordSecurity::create( + [ + 'user_id' => $user->id, + 'google2fa_enable' => 0, + 'google2fa_secret' => \Google2FA::generateSecretKey(), + ] + ); + + return redirect('2fa')->with('success', 'Secret Key is generated, Please verify Code to Enable 2FA'); + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException + * @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException + * @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException + */ + public function enable2fa(Request $request) + { + $user = Auth::user(); + $secret = $request->input('verify-code'); + $valid = \Google2FA::verifyKey($user->passwordSecurity->google2fa_secret, $secret); + if ($valid) { + $user->passwordSecurity->google2fa_enable = 1; + $user->passwordSecurity->save(); + + return redirect('2fa')->with('success', '2FA is Enabled Successfully.'); + } + + return redirect('2fa')->with('error', 'Invalid Verification Code, Please try again.'); + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function disable2fa(Request $request) + { + if (! (Hash::check($request->get('current-password'), Auth::user()->password))) { + // The passwords matches + return redirect()->back()->with('error', 'Your password does not match with your account password. Please try again.'); + } + + $validatedData = $request->validate([ + 'current-password' => 'required', + ]); + $user = Auth::user(); + $user->passwordSecurity->google2fa_enable = 0; + $user->passwordSecurity->save(); + + return redirect('2fa')->with('success', '2FA is now Disabled.'); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 3aa4275b7..fad3d28dd 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -63,5 +63,6 @@ class Kernel extends HttpKernel 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class, 'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class, 'clearance' => \App\Http\Middleware\ClearanceMiddleware::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..1bb273cd4 --- /dev/null +++ b/app/Http/Middleware/Google2FAMiddleware.php @@ -0,0 +1,27 @@ +boot($request); + + if ($authenticator->isAuthenticated()) { + return $next($request); + } + + return $authenticator->makeRequestOneTimePasswordResponse(); + } +} diff --git a/app/Models/PasswordSecurity.php b/app/Models/PasswordSecurity.php new file mode 100644 index 000000000..ea1b9c8ab --- /dev/null +++ b/app/Models/PasswordSecurity.php @@ -0,0 +1,25 @@ +belongsTo(User::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index bdcfc16a2..c1aecd116 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -946,4 +946,12 @@ class User extends Authenticatable { static::whereVerified(0)->where('created_at', '<', now()->subDays(3))->delete(); } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function passwordSecurity(): \Illuminate\Database\Eloquent\Relations\HasOne + { + return $this->hasOne(PasswordSecurity::class); + } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 03d21a5b6..68c30279c 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -16,6 +16,8 @@ class RouteServiceProvider extends ServiceProvider */ protected $namespace = 'App\Http\Controllers'; + public const HOME = '/'; + /** * Define your route model bindings, pattern filters, etc. * diff --git a/app/Support/Google2FAAuthenticator.php b/app/Support/Google2FAAuthenticator.php new file mode 100644 index 000000000..29bcb2963 --- /dev/null +++ b/app/Support/Google2FAAuthenticator.php @@ -0,0 +1,40 @@ +getUser()->passwordSecurity) { + return true; + } + + return + ! $this->getUser()->passwordSecurity->google2fa_enable || + ! $this->isEnabled() || + $this->noUserIsAuthenticated() || + $this->twoFactorAuthStillValid(); + } + + /** + * @return mixed + * @throws \PragmaRX\Google2FALaravel\Exceptions\InvalidSecretKey + */ + protected function getGoogle2FASecretKey() + { + $secret = $this->getUser()->passwordSecurity->{$this->config('otp_secret_column')}; + + if (is_null($secret) || empty($secret)) { + throw new InvalidSecretKey('Secret key cannot be empty.'); + } + + return $secret; + } +} diff --git a/composer.json b/composer.json index c4ae05915..cc07e32e6 100755 --- a/composer.json +++ b/composer.json @@ -134,6 +134,7 @@ "php-ffmpeg/php-ffmpeg": "^0.14", "php-http/guzzle6-adapter": "^1.1", "php-http/message": "^1.6", + "pragmarx/google2fa-laravel": "^1.4", "predis/predis": "^1.1", "propaganistas/laravel-disposable-email": "^2.0", "ramsey/uuid": "^4.0", diff --git a/composer.lock b/composer.lock index bd77369b0..65d35b1f2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6f13adce07c83b25e82e85fd0f403ef9", + "content-hash": "f507d2a8906f891af68933e1d18c169f", "packages": [ { "name": "aharen/omdbapi", @@ -208,6 +208,55 @@ "description": "PHP Wrapper for Accessing the Steam Storefront API", "time": "2017-08-27T15:14:06+00:00" }, + { + "name": "bacon/bacon-qr-code", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^1.4", + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "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": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "time": "2020-10-30T02:02:47+00:00" + }, { "name": "bhuvidya/laravel-countries", "version": "v1.0.7", @@ -1253,6 +1302,49 @@ ], "time": "2020-09-22T11:38:01+00:00" }, + { + "name": "dasprid/enum", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/5abf82f213618696dda8e3bf6f64dd042d8542b2", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "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/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "time": "2020-10-02T16:03:48+00:00" + }, { "name": "dborsatto/php-giantbomb", "version": "v2.1.0", @@ -4916,6 +5008,68 @@ ], "time": "2020-11-07T02:01:34+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "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": "2020-12-06T15:14:20+00:00" + }, { "name": "pear/archive_tar", "version": "1.4.11", @@ -5770,6 +5924,183 @@ ], "time": "2020-07-20T17:29:33+00:00" }, + { + "name": "pragmarx/google2fa", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "26c4c5cf30a2844ba121760fd7301f8ad240100b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/26c4c5cf30a2844ba121760fd7301f8ad240100b", + "reference": "26c4c5cf30a2844ba121760fd7301f8ad240100b", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1.0|^2.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.18", + "phpunit/phpunit": "^7.5.15|^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/" + } + }, + "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": "2020-04-05T10:47:18+00:00" + }, + { + "name": "pragmarx/google2fa-laravel", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa-laravel.git", + "reference": "f9014fd7ea36a1f7fffa233109cf59b209469647" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/f9014fd7ea36a1f7fffa233109cf59b209469647", + "reference": "f9014fd7ea36a1f7fffa233109cf59b209469647", + "shasum": "" + }, + "require": { + "laravel/framework": ">=5.4.36|^8.0", + "php": ">=7.0", + "pragmarx/google2fa-qrcode": "^1.0" + }, + "require-dev": { + "orchestra/testbench": "3.4.*|3.5.*|3.6.*|3.7.*|4.*|5.*|6.*", + "phpunit/phpunit": "~5|~6|~7|~8" + }, + "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": "2020-09-20T21:01:48+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.6", diff --git a/database/migrations/2020_12_27_214949_create_password_securities_table.php b/database/migrations/2020_12_27_214949_create_password_securities_table.php new file mode 100644 index 000000000..0208130ff --- /dev/null +++ b/database/migrations/2020_12_27_214949_create_password_securities_table.php @@ -0,0 +1,34 @@ +id(); + $table->integer('user_id'); + $table->boolean('google2fa_enable')->default(false); + $table->string('google2fa_secret')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('password_securities'); + } +} diff --git a/resources/views/auth/2fa.blade.php b/resources/views/auth/2fa.blade.php new file mode 100644 index 000000000..eb44a3bdc --- /dev/null +++ b/resources/views/auth/2fa.blade.php @@ -0,0 +1,105 @@ +@extends('layouts.app') + +@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.

+
+

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. +
+
+
+ + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + @if (session('success')) +
+ {{ session('success') }} +
+ @endif + + + @if(!($data['user']->passwordSecurity)) +
+ {{ csrf_field() }} +
+
+ +
+
+
+ @elseif(!$data['user']->passwordSecurity->google2fa_enable) + 1. Scan this barcode with your Google Authenticator App:
+ +

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

+
+ {{ csrf_field() }} + +
+ + +
+ + + @if ($errors->has('verify-code')) + + {{ $errors->first('verify-code') }} + + @endif +
+
+
+
+ +
+
+
+ @elseif($data['user']->passwordSecurity->google2fa_enable) +
+ 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.

+
+
+ + +
+ + + @if ($errors->has('current-password')) + + {{ $errors->first('current-password') }} + + @endif +
+
+
+ + {{ csrf_field() }} + +
+
+ @endif + +
+
+
+
+
+@endsection diff --git a/resources/views/auth/google2fa.blade.php b/resources/views/auth/google2fa.blade.php new file mode 100644 index 000000000..84162d896 --- /dev/null +++ b/resources/views/auth/google2fa.blade.php @@ -0,0 +1,44 @@ +@extends('layouts.app') + +@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 (session('error')) +
+ {{ session('error') }} +
+ @endif + @if (session('success')) +
+ {{ session('success') }} +
+ @endif + + Enter the pin from Google Authenticator Enable 2FA

+
+ {{ csrf_field() }} +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+@endsection diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 000000000..c12b97e57 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,73 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Login') }}
+ +
+
+ @csrf + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+
+
+ + + +
+
+
+ +
+
+ + + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/confirm.blade.php b/resources/views/auth/passwords/confirm.blade.php new file mode 100644 index 000000000..ca78fc1d3 --- /dev/null +++ b/resources/views/auth/passwords/confirm.blade.php @@ -0,0 +1,49 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Confirm Password') }}
+ +
+ {{ __('Please confirm your password before continuing.') }} + +
+ @csrf + +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+
+ + + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php new file mode 100644 index 000000000..1fea98456 --- /dev/null +++ b/resources/views/auth/passwords/email.blade.php @@ -0,0 +1,47 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Reset Password') }}
+ +
+ @if (session('status')) + + @endif + +
+ @csrf + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php new file mode 100644 index 000000000..989931d3a --- /dev/null +++ b/resources/views/auth/passwords/reset.blade.php @@ -0,0 +1,65 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Reset Password') }}
+ +
+
+ @csrf + + + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php new file mode 100644 index 000000000..d236a48ec --- /dev/null +++ b/resources/views/auth/register.blade.php @@ -0,0 +1,77 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Register') }}
+ +
+
+ @csrf + +
+ + +
+ + + @error('name') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/verify.blade.php b/resources/views/auth/verify.blade.php new file mode 100644 index 000000000..9f8c1bc0f --- /dev/null +++ b/resources/views/auth/verify.blade.php @@ -0,0 +1,28 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Verify Your Email Address') }}
+ +
+ @if (session('resent')) + + @endif + + {{ __('Before proceeding, please check your email for a verification link.') }} + {{ __('If you did not receive the email') }}, +
+ @csrf + . +
+
+
+
+
+
+@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 000000000..a255ebfa2 --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,83 @@ + + + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + + + + + + +
+ + +
+ @yield('content') +
+
+ + diff --git a/resources/views/themes/Gentele/profileedit.tpl b/resources/views/themes/Gentele/profileedit.tpl index 9b8342bc1..63c11aaec 100755 --- a/resources/views/themes/Gentele/profileedit.tpl +++ b/resources/views/themes/Gentele/profileedit.tpl @@ -204,6 +204,16 @@ + + + + + +
+ + +
Enable or disable 2FA: + Here
{if {{App\Models\Settings::settingValue('site.main.userselstyle')}} == 1} diff --git a/routes/web.php b/routes/web.php index 9d734ccc9..4724eefee 100644 --- a/routes/web.php +++ b/routes/web.php @@ -64,6 +64,7 @@ use App\Http\Controllers\MusicController; use App\Http\Controllers\MyMoviesController; use App\Http\Controllers\MyShowsController; use App\Http\Controllers\NfoController; +use App\Http\Controllers\PasswordSecurityController; use App\Http\Controllers\ProfileController; use App\Http\Controllers\QueueController; use App\Http\Controllers\RssController; @@ -270,13 +271,18 @@ Route::group(['middleware' => ['isVerified']], function () { Route::get('ajax_profile', [AjaxController::class, 'profile']); Route::post('ajax_profile', [AjaxController::class, 'profile']); + + Route::get('2fa', [PasswordSecurityController::class, 'show2faForm']); + Route::post('generate2faSecret', [PasswordSecurityController::class, 'generate2faSecret'])->name('generate2faSecret'); + Route::post('2fa', [PasswordSecurityController::class, 'enable2fa'])->name('enable2fa'); + Route::post('disable2fa', [PasswordSecurityController::class, 'disable2fa'])->name('disable2fa'); }); Route::get('forum-delete/{id}', [ForumController::class, 'destroy'])->middleware('role:Admin'); Route::post('forum-delete/{id}', [ForumController::class, 'destroy'])->middleware('role:Admin'); -Route::group(['middleware' => ['role:Admin'], 'prefix' => 'admin', 'namespace' => 'Admin'], function () { +Route::group(['middleware' => ['role:Admin', '2fa'], 'prefix' => 'admin', 'namespace' => 'Admin'], function () { Route::get('index', [AdminPageController::class, 'index']); Route::get('anidb-delete/{id}', [AdminAnidbController::class, 'destroy']); Route::post('anidb-delete/{id}', [AdminAnidbController::class, 'destroy']); @@ -401,3 +407,7 @@ Route::group(['middleware' => ['role_or_permission:Admin|Moderator|edit release' Route::get('release-edit', [AdminReleasesController::class, 'edit']); Route::post('release-edit', [AdminReleasesController::class, 'edit']); }); + +Route::post('2faVerify', function () { + return redirect(URL()->previous()); +})->name('2faVerify')->middleware('2fa');