Skip to content

Commit

Permalink
Merge branch 'main' into Add-Auth-Providers-Config-Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tnylea authored May 12, 2024
2 parents e3e59cd + 8d3bb90 commit deccd0b
Show file tree
Hide file tree
Showing 24 changed files with 555 additions and 354 deletions.
3 changes: 2 additions & 1 deletion config/devdojo/auth/descriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
'registration_include_name_field' => 'During registration, include the Name field.',
'registration_require_email_verification' => 'During registration, require users to verify their email.',
'enable_branding' => 'This will toggle on/off the Auth branding at the bottom of each auth screen. Consider leaving on to support and help grow this project.',
'dev_mode' => 'This is for development mode, when set in Dev Mode Assets will be loaded from Vite'
'dev_mode' => 'This is for development mode, when set in Dev Mode Assets will be loaded from Vite',
'enable_2fa' => 'Enable the ability for users to turn on Two Factor Authentication'
]
];
9 changes: 9 additions & 0 deletions config/devdojo/auth/language.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,14 @@
'headline' => 'Verify your email address',
'subheadline' => 'Before you can proceed you must verify your email.',
'show_subheadline' => false
],
'twoFactorChallenge' => [
'page_title' => 'Two Factor Challenge',
'headline_auth' => 'Authentication Code',
'subheadline_auth' => 'Enter the authentication code provided by your authenticator application.',
'show_subheadline_auth' => false,
'headline_recovery' => 'Recovery Code',
'subheadline_recovery' => 'Please confirm access to your account by entering one of your emergency recovery codes.',
'show_subheadline_recovery' => false
]
];
8 changes: 4 additions & 4 deletions config/devdojo/auth/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
'registration_show_password_same_screen' => true,
'registration_include_name_field' => false,
'registration_require_email_verification' => false,
'enable_branding' => env('DEVDOJO_AUTH_BRANDING', true),
'dev_mode' => env('DEVDOJO_AUTH_DEV', false),
'enable_2fa' => env('DEVDOJO_AUTH_ENABLE_2FA', false), // Enable or disable 2FA functionality globally
];
'enable_branding' => true,
'dev_mode' => false,
'enable_2fa' => false, // Enable or disable 2FA functionality globally
];
180 changes: 28 additions & 152 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"dependencies": {
"@invoate/alpine-query-string": "^1.0.0",
"highlightjs": "^9.16.2",
"phaser": "^3.80.1",
"split.js": "^1.6.5"
"@tailwindcss/container-queries": "^0.1.1"
}
}
2 changes: 1 addition & 1 deletion public/build/assets/styles.css

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions resources/css/auth.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,13 @@
.CodeMirror{
border-radius: 6px;
border: 1px solid #e1e1e5;
}

input[type='number'].auth-component-code-input {
-moz-appearance:textfield;
}

input.auth-component-code-input::-webkit-outer-spin-button,
input.auth-component-code-input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
17 changes: 15 additions & 2 deletions resources/views/components/elements/button.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@
};
@endphp

@php
$typeClasses = match ($type) {
'primary' => '',
'secondary' => 'bg-zinc-100 border text-gray-500 hover:text-gray-700 border-zinc-100 dark:focus:ring-offset-gray-900 dark:border-gray-400/10 active:bg-white dark:focus:ring-gray-700 focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-200/60 dark:bg-gray-800/50 dark:hover:bg-gray-800/70 dark:text-gray-400 focus:shadow-outline',
'success' => 'bg-green-600 text-white hover:bg-green-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-green-700/90 focus:ring-green-700',
'info' => 'bg-blue-600 text-white hover:bg-blue-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-blue-700/90 focus:ring-blue-700',
'warning' => 'bg-amber-500 text-white hover:bg-amber-500/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-amber-600/90 focus:ring-amber-600',
'danger' => 'bg-red-600 text-white hover:bg-red-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-red-700/90 focus:ring-red-700',
};
$loadingTarget = $attributes['wire:target'];
@endphp

@php
switch ($tag ?? 'button') {
case 'button':
Expand All @@ -35,7 +48,7 @@
}
@endphp

<{!! $tagAttr !!} {!! $attributes->except(['class']) !!} class="{{ $sizeClasses }} auth-component-button opacity-[95%] hover:opacity-100 focus:ring-2 focus:ring-offset-2 cursor-pointer inline-flex items-center w-full justify-center disabled:opacity-50 font-semibold focus:outline-none" style="color:{{ config('devdojo.auth.appearance.color.button_text') }}; background-color:{{ config('devdojo.auth.appearance.color.button') }};">
<svg xmlns="http://www.w3.org/2000/svg" wire:loading viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1.5 w-4 h-4 animate-spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg>
<{!! $tagAttr !!} {!! $attributes->except(['class']) !!} class="@if($type == 'primary'){{ 'auth-component-button' }}@endif {{ $sizeClasses }} {{ $typeClasses }} opacity-[95%] hover:opacity-100 focus:ring-2 focus:ring-offset-2 cursor-pointer inline-flex items-center w-full justify-center disabled:opacity-50 font-semibold focus:outline-none" style="@if($type == 'primary') color:{{ config('devdojo.auth.appearance.color.button_text') }}; background-color:{{ config('devdojo.auth.appearance.color.button') }}; @endif">
<svg xmlns="http://www.w3.org/2000/svg" wire:loading @if(isset($loadingTarget)) wire:target="{{ $loadingTarget }}" @endif viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1.5 w-4 h-4 animate-spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg>
{{ $slot }}
</{{ $tagClose }}>
111 changes: 111 additions & 0 deletions resources/views/components/elements/input-code.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
@props([
// total number of boxes to display
'digits' => 4,
'eventCallback' => null
])

<div x-data="
{
total_digits: @js($digits),
eventCallback: @js($eventCallback),
moveCursorNext (index, digits, evt) {
if (!isNaN(parseInt(evt.key)) && parseInt(evt.key) >= 0 && parseInt(evt.key) <= 9 && index != digits) {
evt.preventDefault();
evt.stopPropagation();
this.$refs['input' + index].value = evt.key;
this.$refs['input' + (index+1)].focus();
} else {
if (evt.key === 'Backspace') {
evt.preventDefault();
evt.stopPropagation();
if (index > 1) {
if (this.$refs['input' + index].value !== '') {
this.$refs['input' + index].value = '';
} else {
if (index > 1) {
this.$refs['input' + (index-1)].value='';
this.$refs['input' + (index-1)].focus();
}
}
} else {
this.$refs['input' + index].value = '';
}
} else {
}
}
let that = this;
setTimeout(function(){
that.$refs.pin.value = that.generateCode();
if (index === digits && [...Array(digits).keys()].every(i => that.$refs['input' + (i + 1)].value !== '')) {
that.submitCallback();
}
}, 100);
{{-- console.log(this.generateCode()); --}}
},
submitCallback(){
if(this.eventCallback){
window.dispatchEvent(new CustomEvent(this.eventCallback, { detail: { code: this.generateCode() }}));
}
},
pasteValue(event){
event.preventDefault();
{{-- let paste = (event.clipboardData || window.clipboardData).getData('text'); --}}
let paste = (event.clipboardData || window.clipboardData).getData('text');
for (let i = 0; i < paste.length; i++) {
if (i < this.total_digits) {
this.$refs['input' + (i + 1)].value = paste[i];
}
let focusLastInput = (paste.length <= this.total_digits) ? paste.length : this.total_digits;
this.$refs['input' + focusLastInput].focus();
if(paste.length >= this.total_digits){
let that = this;
setTimeout(function(){
that.$refs.pin.value = that.generateCode();
that.submitCallback();
}, 100);
}
}
},
generateCode() {
let code = '';
for (let i = 1; i <= this.total_digits; i++) {
code += this.$refs['input' + i].value;
}
return code;
},
}"
x-init="
$refs.input1.focus();
"
class="relative"
>
<div class="flex">
<div class="flex mx-auto space-x-2">
@for ($x = 1; $x <= $digits; $x++)
<input
x-ref="input{{ $x }}"
numeric="true"
type="number"
x-on:paste="pasteValue"
x-on:keydown="moveCursorNext({{ $x }}, {{ $digits }}, event)"
x-on:focus="$el.select()"
class="w-12 h-12 font-light text-center text-black rounded-md border shadow-sm appearance-none auth-component-code-input dark:text-dark-400 border-zinc-200 focus:border-2"
maxlength="1"
/>
@endfor
</div>
</div>
<input {{ $attributes->whereStartsWith('id') }} type="hidden" x-ref="pin" name="pin" />
</div>
44 changes: 3 additions & 41 deletions resources/views/components/layouts/app.blade.php
Original file line number Diff line number Diff line change
@@ -1,46 +1,8 @@
<!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>{{ $title ?? 'Auth' }}</title>
@if(config('devdojo.auth.settings.dev_mode'))
@vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js'])
@else
<script src="/auth/build/assets/scripts.js"></script>
<link rel="stylesheet" href="/auth/build/assets/styles.css" />
@endif

@php
$buttonRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.button'));
$inputBorderRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.input_border'));
@endphp
<style>
.auth-component-button:focus{
--tw-ring-opacity: 1; --tw-ring-color: rgb({{ $buttonRGBColor }} / var(--tw-ring-opacity));
}
.auth-component-input{
color: {{ config('devdojo.auth.appearance.color.input_text') }}
}
.auth-component-input:focus{
--tw-ring-color: rgb({{ $inputBorderRGBColor }} / var(--tw-ring-opacity));
border-color: rgb({{ $inputBorderRGBColor }} / var(--tw-border-opacity));
}
.auth-component-input-label-focused{
color: {{ config('devdojo.auth.appearance.color.input_border') }}
}
</style>

@if(file_exists(public_path('auth/app.css')))
<link rel="stylesheet" href="/auth/app.css" />
@endif

<link href="{{ url(config('devdojo.auth.appearance.favicon.light')) }}" rel="icon" media="(prefers-color-scheme: light)" />
<link href="{{ url(config('devdojo.auth.appearance.favicon.dark')) }}" rel="icon" media="(prefers-color-scheme: dark)" />

</head>
<head>
@include('auth::includes.head')
</head>
<body id="auth-body" class="overflow-hidden relative w-screen h-screen" style="background-color:{{ config('devdojo.auth.appearance.background.color') }}">
@if(config('devdojo.auth.appearance.background.image'))
<img src="{{ config('devdojo.auth.appearance.background.image') }}" id="auth-background-image" class="object-cover absolute z-10 w-screen h-screen" />
Expand Down
12 changes: 3 additions & 9 deletions resources/views/components/layouts/empty.blade.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
<!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>
<head>
@include('auth::includes.head')
</head>
<body>
{{ $slot }}
</body>
Expand Down
38 changes: 38 additions & 0 deletions resources/views/includes/head.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">

<title>{{ $title ?? 'Auth' }}</title>
@if(config('devdojo.auth.settings.dev_mode'))
@vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js'])
@else
<script src="/auth/build/assets/scripts.js"></script>
<link rel="stylesheet" href="/auth/build/assets/styles.css" />
@endif

@php
$buttonRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.button'));
$inputBorderRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.input_border'));
@endphp
<style>
.auth-component-button:focus{
--tw-ring-opacity: 1; --tw-ring-color: rgb({{ $buttonRGBColor }} / var(--tw-ring-opacity));
}
.auth-component-input{
color: {{ config('devdojo.auth.appearance.color.input_text') }}
}
.auth-component-input:focus, .auth-component-code-input:focus{
--tw-ring-color: rgb({{ $inputBorderRGBColor }} / var(--tw-ring-opacity));
border-color: rgb({{ $inputBorderRGBColor }} / var(--tw-border-opacity));
}
.auth-component-input-label-focused{
color: {{ config('devdojo.auth.appearance.color.input_border') }}
}
</style>

@if(file_exists(public_path('auth/app.css')))
<link rel="stylesheet" href="/auth/app.css" />
@endif

<link href="{{ url(config('devdojo.auth.appearance.favicon.light')) }}" rel="icon" media="(prefers-color-scheme: light)" />
<link href="{{ url(config('devdojo.auth.appearance.favicon.dark')) }}" rel="icon" media="(prefers-color-scheme: dark)" />
43 changes: 40 additions & 3 deletions resources/views/pages/auth/login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@
public $language = [];
public $twoFactorEnabled = true;
public function mount(){
$this->loadConfigs();
$this->twoFactorEnabled = $this->settings->enable_2fa;
}
public function editIdentity(){
Expand All @@ -47,6 +50,7 @@ public function editIdentity(){
public function authenticate()
{
if(!$this->showPasswordField){
$this->validateOnly('email');
$this->showPasswordField = true;
Expand All @@ -57,14 +61,47 @@ public function authenticate()
$this->validate();
if (!Auth::attempt(['email' => $this->email, 'password' => $this->password])) {
$credentials = ['email' => $this->email, 'password' => $this->password];
if(!\Auth::validate($credentials)){
$this->addError('password', trans('auth.failed'));
return;
}
$userAttemptingLogin = User::where('email', $this->email)->first();
if(!isset($userAttemptingLogin->id)){
$this->addError('password', trans('auth.failed'));
return;
}
event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true));
if($this->twoFactorEnabled && !is_null($userAttemptingLogin->two_factor_confirmed_at)){
// We want this user to login via 2fa
session()->put([
'login.id' => $userAttemptingLogin->getKey()
]);
return redirect()->intended('/');
return redirect()->route('auth.two-factor-challenge');
} else {
if (!Auth::attempt($credentials)) {
$this->addError('password', trans('auth.failed'));
return;
}
event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true));
return redirect()->intended('/');
}
/*$request->session()->put([
'login.id' => $user->getKey(),
'login.remember' => $request->boolean('remember'),
]);*/
}
};
Expand Down
Loading

0 comments on commit deccd0b

Please sign in to comment.