Skip to content

Commit 5386907

Browse files
authored
Merge pull request #4 from zacksmash/two-factor-story
Two factor story
2 parents 013d980 + af8d60e commit 5386907

File tree

11 files changed

+332
-82
lines changed

11 files changed

+332
-82
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ If you run into errors, you'll probably need to review the [Laravel Fortify](htt
4242
- Visit `config/fortify.php` and uncomment `Features::twoFactorAuthentication()`
4343
- Visit `resources/js/pages/auth/TwoFactorChallenge.vue` and uncomment the import
4444
- Visit `resources/js/pages/settings/TwoFactorAuth.vue` and uncomment the imports
45-
- Visit `resources/js/pages/Dashboard.vue` and uncomment the `TwoFactorAuth` import and component
4645

4746
### Wayfinder Issues
4847
If you run into Node error screens, you may need to compile the Wayfinder types again.

app/Http/Middleware/HandleInertiaRequests.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\Request;
66
use Inertia\Middleware;
7+
use Laravel\Fortify\Features;
78

89
class HandleInertiaRequests extends Middleware
910
{
@@ -39,7 +40,10 @@ public function share(Request $request): array
3940
...parent::share($request),
4041
'name' => config('app.name'),
4142
'auth' => [
42-
'user' => $request->user(),
43+
'user' => auth()->check() ? array_merge($request->user()->toArray(), [
44+
'two_factor_enabled' => Features::enabled(Features::twoFactorAuthentication())
45+
&& ! is_null($request->user()->two_factor_secret),
46+
]) : null,
4347
],
4448
'status' => $request->session()->get('status'),
4549
];

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"dependencies": {
2929
"@inertiajs/vue3": "^2.1.2",
30+
"axios": "^1.11.0",
3031
"tailwindcss": "^4.0.0",
3132
"vue": "^3.5.13"
3233
}

resources/css/app.css

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
}
2323

2424
button {
25-
@apply inline-flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md font-semibold shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 transition ease-in-out duration-150 hover:bg-gray-100;
25+
@apply inline-flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md font-semibold shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 transition ease-in-out duration-150 hover:bg-gray-100 mr-2;
2626
}
2727

2828
a[href] {
@@ -80,4 +80,16 @@
8080
mark {
8181
@apply bg-green-200 text-green-900 p-1 px-2 rounded-md border border-green-300 text-sm;
8282
}
83+
84+
dialog {
85+
@apply fixed inset-0 z-50 p-4 bg-white border border-gray-300 rounded-md shadow-lg max-w-lg mx-auto my-20;
86+
87+
input {
88+
@apply w-full;
89+
}
90+
91+
button {
92+
@apply mt-2 block w-full;
93+
}
94+
}
8395
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<script setup lang="ts">
2+
import axios from 'axios'
3+
import { Ref, nextTick, reactive, ref } from 'vue'
4+
import ConfirmablePasswordController from '@/wayfinder/actions/Laravel/Fortify/Http/Controllers/ConfirmablePasswordController'
5+
import { confirmation } from '@/wayfinder/routes/password'
6+
7+
const emit = defineEmits(['confirmed'])
8+
9+
const confirmingPassword = ref(false)
10+
11+
const form = reactive({
12+
password: '',
13+
error: '',
14+
processing: false,
15+
})
16+
17+
const passwordInput: Ref<HTMLInputElement | null> = ref(null)
18+
19+
const startConfirmingPassword = () => {
20+
axios.get(confirmation.url()).then(response => {
21+
if (response.data.confirmed) {
22+
emit('confirmed')
23+
} else {
24+
confirmingPassword.value = true
25+
26+
nextTick(() => passwordInput.value?.focus())
27+
}
28+
})
29+
}
30+
31+
const confirmPassword = () => {
32+
form.processing = true
33+
34+
axios.post(ConfirmablePasswordController.store.url(), {
35+
password: form.password,
36+
}).then(() => {
37+
form.processing = false
38+
39+
closeModal()
40+
nextTick().then(() => emit('confirmed'))
41+
}).catch(error => {
42+
form.processing = false
43+
form.error = error.response.data.errors.password[0]
44+
passwordInput.value?.focus()
45+
})
46+
}
47+
48+
const closeModal = () => {
49+
confirmingPassword.value = false
50+
form.password = ''
51+
form.error = ''
52+
}
53+
</script>
54+
55+
<template>
56+
<span>
57+
<span @click="startConfirmingPassword">
58+
<slot/>
59+
</span>
60+
61+
<dialog :open="confirmingPassword">
62+
<form>
63+
<input
64+
type="text"
65+
name="email"
66+
autocomplete="username email"
67+
style="display: none;"
68+
>
69+
70+
<div>
71+
<input
72+
ref="passwordInput"
73+
v-model="form.password"
74+
type="password"
75+
placeholder="Password"
76+
autocomplete="current-password"
77+
@keyup.enter="confirmPassword"
78+
>
79+
80+
<div v-if="form.error">
81+
<mark>{{ form.error }}</mark>
82+
</div>
83+
</div>
84+
85+
<button
86+
:disabled="form.processing"
87+
@click="confirmPassword"
88+
>
89+
Confirm
90+
</button>
91+
92+
<button type="button" @click="closeModal">
93+
Cancel
94+
</button>
95+
</form>
96+
</dialog>
97+
</span>
98+
</template>

resources/js/pages/Dashboard.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import { logout } from '@/wayfinder/routes'
55
66
import Profile from '@/pages/settings/Profile.vue'
77
import Password from '@/pages/settings/Password.vue'
8-
// import TwoFactorAuth from '@/pages/settings/TwoFactorAuth.vue'
8+
import TwoFactorAuth from '@/pages/settings/TwoFactorAuth.vue'
99
1010
const user = computed(() => usePage().props.auth.user)
1111
const props = defineProps<{
1212
canUpdateProfile: boolean;
1313
canUpdatePassword?: boolean;
1414
canManageTwoFactorAuthentication?: boolean;
15+
confirmsTwoFactorAuthentication?: boolean;
1516
}>()
1617
</script>
1718
<template>
@@ -48,10 +49,10 @@ const props = defineProps<{
4849
</section>
4950
</template>
5051

51-
<!-- <template v-if="props.canManageTwoFactorAuthentication">
52+
<template v-if="props.canManageTwoFactorAuthentication">
5253
<hr>
5354

54-
<TwoFactorAuth/>
55-
</template> -->
55+
<TwoFactorAuth :requires-confirmation="props.confirmsTwoFactorAuthentication"/>
56+
</template>
5657
</div>
5758
</template>

resources/js/pages/settings/Password.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ import PasswordController from '@/wayfinder/actions/Laravel/Fortify/Http/Control
1111
reset-on-success
1212
:reset-on-error="['password', 'password_confirmation', 'current_password']"
1313
>
14+
<input
15+
type="text"
16+
name="email"
17+
autocomplete="username email"
18+
style="display: none;"
19+
>
20+
1421
<div>
1522
<label for="current_password">Password</label>
1623

0 commit comments

Comments
 (0)