Skip to content

Commit

Permalink
Adding all functionality from original attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
tnylea committed May 8, 2024
1 parent 60af34c commit a328656
Show file tree
Hide file tree
Showing 13 changed files with 438 additions and 106 deletions.
15 changes: 15 additions & 0 deletions resources/views/components/layouts/empty.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">

<title>Authentication Setup</title>


</head>
<body>
{{ $slot }}
</body>
</html>
2 changes: 0 additions & 2 deletions resources/views/pages/auth/login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ public function authenticate()
return;
}
dd('waht');
event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true));
return redirect()->intended('/');
Expand Down
145 changes: 94 additions & 51 deletions resources/views/pages/auth/two-factor-challenge.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,133 @@
use App\Models\User;
use function Laravel\Folio\{middleware, name};
use Illuminate\Support\Facades\Route;
use Livewire\Volt\Component;
use PragmaRX\Google2FA\Google2FA;
use Devdojo\Auth\Traits\HasConfigs;
use Illuminate\Support\Facades\Cache;
middleware(['guest']);
//middleware(['guest']);
name('auth.two-factor-challenge');
new class extends Component
{
use HasConfigs;
public $recovery = false;
public $google2fa;
public $auth_code;
public $recovery_code;
public function mount()
{
$this->loadConfigs();
$this->recovery = false;
}
public function switchToRecovery()
{
$this->recovery = !$this->recovery;
if($this->recovery){
$this->js("setTimeout(function(){ console.log('made'); window.dispatchEvent(new CustomEvent('focus-auth-2fa-recovery-code', {})); }, 10);");
} else {
$this->js("setTimeout(function(){ window.dispatchEvent(new CustomEvent('focus-auth-2fa-auth-code', {})); }, 10);");
}
return;
}
public function authenticate()
public function submit_auth_code()
{
// Authentication logic here
$google2fa = new Google2FA();
//$this->verify(auth()->user()->two_factor_secret, $this->auth_code, $google2fa);
$valid = $google2fa->verifyKey(decrypt(auth()->user()->two_factor_secret), $this->auth_code);
if ($valid) {
dd('Valid!');
} else {
dd('Failed');
}
}
public function submit_recovery_code(){
$valid = in_array($this->recovery_code, auth()->user()->two_factor_recovery_codes);
if ($valid) {
dd('valid yo!');
} else {
dd('not valid');
}
}
/*private function verify($secret, $code, $google2fa)
{
$cachedTimestampKey = 'auth.2fa_codes.'.md5($code);
if (is_int($customWindow = config('fortify-options.two-factor-authentication.window'))) {
$google2fa->setWindow($customWindow);
}
$timestamp = $google2fa->verifyKeyNewer(
$secret, $code, Cache::get($cachedTimestampKey)
);
if ($timestamp !== false) {
if ($timestamp === true) {
$timestamp = $google2fa->getTimestamp();
}
optional($cache)->put($cachedTimestampKey, $timestamp, ($google2fa->getWindow() ?: 1) * 60);
return true;
}
return false;
}*/
}
?>

<x-auth::layouts.app title="{{ config('devdojo.auth.language.register.page_title') }}">
@volt('auth.two-factor-challenge')
<x-auth::layouts.app title="{{ config('devdojo.auth.language.twoFactorChallenge.page_title') }}">
@volt('auth.twofactorchallenge')
<x-auth::elements.container>

<x-auth::elements.heading
:text="($language->twoFactorChallenge->headline ?? 'No Heading')"
:description="($language->twoFactorChallenge->subheadline ?? 'No Description')"
:show_subheadline="($language->twoFactorChallenge->show_subheadline ?? false)" />

<form method="POST" action="{{ route('two-factor.login') }}">
@csrf
@if(!$recovery)
<x-auth::elements.heading
:text="($language->twoFactorChallenge->headline_auth ?? 'No Heading')"
:description="($language->twoFactorChallenge->subheadline_auth ?? 'No Description')"
:show_subheadline="($language->twoFactorChallenge->show_subheadline_auth ?? false)" />
@else
<x-auth::elements.heading
:text="($language->twoFactorChallenge->headline_recovery ?? 'No Heading')"
:description="($language->twoFactorChallenge->subheadline_recovery ?? 'No Description')"
:show_subheadline="($language->twoFactorChallenge->show_subheadline_recovery ?? false)" />
@endif

<form wire:submit="submit_auth_code" class="mt-5 space-y-5">

@if(!$recovery)
<div class="form-group row">
<label for="code" class="col-md-4 col-form-label text-md-right">{{ __('Code') }}</label>

<div class="col-md-6">
<input id="code" type="text" class="form-control @error('code') is-invalid @enderror" name="code" required autofocus>

@error('code')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<div class="relative">
<x-auth::elements.input label="Code" type="text" wire:model="auth_code" autofocus="true" id="auth-2fa-auth-code" required />
</div>
@else
<div class="form-group row">
<label for="recovery_code" class="col-md-4 col-form-label text-md-right">{{ __('Recovery Code') }}</label>

<div class="col-md-6">
<input id="recovery_code" type="text" class="form-control @error('recovery_code') is-invalid @enderror" name="recovery_code" required autofocus>

@error('recovery_code')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<div class="relative">
<x-auth::elements.input label="Recovery Code" type="text" wire:model="recovery_code" id="auth-2fa-recovery-code" required />
</div>
@endif

<div class="mb-0 form-group row">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>

<a href="#" wire:click="switchToRecovery" class="btn btn-link">
@if(!$recovery)
{{ __('Use a recovery code') }}
@else
{{ __('Use an authentication code') }}
@endif
</a>
</div>
</div>
<x-auth::elements.button rounded="md" submit="true">Continue</x-auth::elements.button>
</form>

<div class="mt-5 space-x-0.5 text-sm leading-5 text-left" style="color:{{ config('devdojo.auth.appearance.color.text') }}">
<span class="opacity-[47%]">or you can </span>
<span class="font-medium underline opacity-60 cursor-pointer" wire:click="switchToRecovery" href="#_">
@if(!$recovery)
<span>login using a recovery code</span>
@else
<span>login using an authentication code</span>
@endif
</span>
</div>
</x-auth::elements.container>
@endvolt
</x-auth::layouts.app>
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
use function Laravel\Folio\{middleware, name};
use Livewire\Volt\Component;
name('user.two-factor-authentication');
//middleware(['auth', 'verified', 'password.confirm']);
middleware(['auth', 'verified']);
// middleware(['auth'])
new class extends Component
{
public $showingConfirmation = false;
public function mount(){
}
}
?>

<x-auth::layouts.empty title="Two Factor Authentication">
@volt('user.two-factor-authentication')
<div class="flex mx-auto w-full max-w-xl">
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
{{ __('Finish enabling two factor authentication.') }}
</h3>

<div class="mt-3 max-w-xl text-sm text-gray-600 dark:text-gray-400">
<p>
{{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }}
</p>
</div>

<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
<p class="font-semibold">
@if ($showingConfirmation)
{{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }}
@else
{{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }}
@endif
</p>
</div>

<div class="inline-block p-2 mt-4 bg-white">
{!! auth()->user()->twoFactorQrCodeSvg() !!}
</div>

<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
<p class="font-semibold">
{{ __('Setup Key') }}: {{ decrypt(auth()->user()->two_factor_secret) }}
</p>
</div>

@if ($showingConfirmation)
<div class="mt-4">
<label>code</label>

<x-auth::elements.input id="code" type="text" name="code" class="block mt-1 w-1/2" inputmode="numeric" autofocus autocomplete="one-time-code"
wire:model="code"
wire:keydown.enter="confirmTwoFactorAuthentication" />
</div>
@endif

@if ($showingRecoveryCodes ?? false)
<div class="mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400">
<p class="font-semibold">
{{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }}
</p>
</div>

<div class="grid gap-1 px-4 py-4 mt-4 max-w-xl font-mono text-sm bg-gray-100 rounded-lg dark:bg-gray-900 dark:text-gray-100">
@foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code)
<div>{{ $code }}</div>
@endforeach
</div>
@endif

</div>
@endvolt

</x-auth::layouts.empty>
3 changes: 0 additions & 3 deletions resources/views/tester.blade.php

This file was deleted.

26 changes: 24 additions & 2 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,40 @@
use Illuminate\Support\Facades\Route;


use Devdojo\Auth\Actions\TwoFactorAuth\GenerateNewRecoveryCodes;
use Devdojo\Auth\Actions\TwoFactorAuth\GenerateQrCodeAndSecretKey;

// Create redirect routes for common authentication routes

Route::redirect('login', 'auth/login')->name('login');
Route::redirect('register', 'auth/register')->name('register');

// define the logout route
Route::middleware(['auth', 'web'])->group(function () {
Route::post('logout', LogoutController::class)

Route::post('/auth/logout', LogoutController::class)
->name('logout');
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)

Route::get('/auth/verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');

Route::get('/auth/logout', [LogoutController::class, 'getLogout'])->name('logout.get');


Route::get('g2fa', function(){
$QrCodeAndSecret = new GenerateQrCodeAndSecretKey();
[$qr, $secret] = $QrCodeAndSecret(auth()->user());
echo '<img src="data:image/png;base64, ' . $qr . ' " style="width:400px; height:auto" />';
// $secret should be saved to user database as two_factor_secret, but it should be encrypted like `encrypt($secret)`

});

Route::get('getr', function(){
$generateCodesFor = new GenerateNewRecoveryCodes();
$generateCodesFor(auth()->user());
});

});


Expand Down
28 changes: 28 additions & 0 deletions src/Actions/TwoFactorAuth/GenerateNewRecoveryCodes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Devdojo\Auth\Actions\TwoFactorAuth;

use Illuminate\Support\Str;
use Illuminate\Support\Collection;

class GenerateNewRecoveryCodes
{
/**
* Generate new recovery codes for the user.
*
* @param mixed $user
* @return void
*/
public function __invoke($user)
{
$user->forceFill([
'two_factor_recovery_codes' => encrypt(json_encode(Collection::times(8, function () {
return $this->generate();
})->all())),
])->save();
}

public function generate(){
return Str::random(10).'-'.Str::random(10);
}
}
Loading

0 comments on commit a328656

Please sign in to comment.