Updated to Laravel 12

This commit is contained in:
Will Browning 2025-07-29 14:59:24 +01:00
parent 322f19c300
commit 31b8798656
9 changed files with 64 additions and 71 deletions

View File

@ -1,41 +0,0 @@
<?php
namespace App\Actions;
use App\Facades\Webauthn;
use App\Models\WebauthnKey;
use Exception;
use Illuminate\Contracts\Auth\Authenticatable;
use LaravelWebauthn\Actions\RegisterKeyStore as ActionsRegisterKeyStore;
use LaravelWebauthn\Events\WebauthnRegister;
use LaravelWebauthn\Services\Webauthn\CredentialAttestationValidator;
use Webauthn\PublicKeyCredentialCreationOptions;
class RegisterKeyStore extends ActionsRegisterKeyStore
{
/**
* Register a new key.
*/
public function __invoke(Authenticatable $user, PublicKeyCredentialCreationOptions $publicKey, string $data, string $keyName): ?WebauthnKey
{
if (! Webauthn::canRegister($user)) {
$this->throwFailedRegisterException($user);
}
try {
$publicKeyCredentialSource = $this->app[CredentialAttestationValidator::class]($publicKey, $data);
$webauthnKey = Webauthn::create($user, $keyName, $publicKeyCredentialSource);
WebauthnRegister::dispatch($webauthnKey);
Webauthn::login();
return $webauthnKey;
} catch (Exception $e) {
$this->throwFailedRegisterException($user, $e);
}
return null;
}
}

View File

@ -3,8 +3,8 @@
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialRequestOptions;
use LaravelWebauthn\Services\Webauthn\PublicKeyCredentialCreationOptions;
use LaravelWebauthn\Services\Webauthn\PublicKeyCredentialRequestOptions;
/**
* @method static PublicKeyCredentialCreationOptions getRegisterData(\Illuminate\Contracts\Auth\Authenticatable $user)

View File

@ -8,17 +8,17 @@
"license": "AGPL-3.0-or-later",
"require": {
"php": "^8.2",
"asbiin/laravel-webauthn": "^4.0.0",
"asbiin/laravel-webauthn": "5.0.1",
"bacon/bacon-qr-code": "^3.0",
"chillerlan/php-qrcode": "^5.0",
"guzzlehttp/guzzle": "^7.2",
"inertiajs/inertia-laravel": "^2.0",
"laravel/framework": "^11.0",
"laravel/framework": "^12.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.7",
"laravel/ui": "^4.0",
"maatwebsite/excel": "^3.1",
"mews/captcha": "3.3.3",
"mews/captcha": "^3.3.3",
"php-mime-mail-parser/php-mime-mail-parser": "^9.0",
"pragmarx/google2fa-laravel": "^2.0.0",
"ramsey/uuid": "^4.0",

View File

@ -131,6 +131,20 @@ return [
'register' => 'vendor.webauthn.register',
],
/*
|--------------------------------------------------------------------------
| Webauthn logging
|--------------------------------------------------------------------------
|
| Here you may specify the channel to which Webauthn will log messages.
| This value should correspond with one of your loggers that is already
| present in your "logging" configuration file. If left as null, it will
| use the default logger for the application.
|
*/
'log' => 'null',
/*
|--------------------------------------------------------------------------
| Session name
@ -268,6 +282,23 @@ return [
/*
|--------------------------------------------------------------------------
| The resident key
|--------------------------------------------------------------------------
|
| When userless is set to 'preferred' or 'required', the resident key will be
| forced to be 'required' automatically.
|
| See https://www.w3.org/TR/webauthn/#enum-residentKeyRequirement
|
| Supported: "null", "required", "preferred", "discouraged".
| Forced to "required" when userless is true.
|
*/
'resident_key' => null,
/*
|--------------------------------------------------------------------------
| Userless (One touch, Typeless) login
|--------------------------------------------------------------------------
|

View File

@ -217,13 +217,13 @@
<div
v-if="search"
@click="
;(searchForm.search = ''),
;((searchForm.search = ''),
$inertia.visit(
route(route().current(), omit(route().params, ['search', 'page'])),
{
only: ['initialRows', 'search'],
},
)
))
"
class="absolute inset-y-0 right-0 cursor-pointer flex items-center pr-3 rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>

View File

@ -385,8 +385,8 @@
</span>
<button
@click="
;(aliasIdToEdit = props.row.id),
(aliasDescriptionToEdit = props.row.description)
;((aliasIdToEdit = props.row.id),
(aliasDescriptionToEdit = props.row.description))
"
>
<icon name="edit" class="inline-block w-6 h-6 text-grey-300 fill-current" />
@ -395,7 +395,7 @@
<div v-else>
<button
class="inline-block text-grey-300 text-sm py-1 border border-transparent"
@click=";(aliasIdToEdit = props.row.id), (aliasDescriptionToEdit = '')"
@click=";((aliasIdToEdit = props.row.id), (aliasDescriptionToEdit = ''))"
>
Add description
</button>
@ -695,10 +695,10 @@
It doesn't look like you have any aliases yet!
</h3>
<div v-if="subdomain">
<p class="mb-4 text-md text-grey-700">There {{ domain ? 'are two ways' : 'is one way'}} to create new aliases.</p>
<h3 class="mb-2 text-lg text-indigo-800 font-semibold">
Create aliases on the fly
</h3>
<p class="mb-4 text-md text-grey-700">
There {{ domain ? 'are two ways' : 'is one way' }} to create new aliases.
</p>
<h3 class="mb-2 text-lg text-indigo-800 font-semibold">Create aliases on the fly</h3>
<p class="mb-2 text-grey-700">
To create aliases on the fly all you have to do is make up any new alias and give that out
instead of your real email address.
@ -720,19 +720,20 @@
</p>
</div>
<div v-if="domain">
<p v-if="!subdomain" class="mb-4 text-md text-grey-700">There is one way to create new aliases.</p>
<h3 class="mb-2 text-lg text-indigo-800 font-semibold">
Create a unique random alias
</h3>
<p v-if="!subdomain" class="mb-4 text-md text-grey-700">
There is one way to create new aliases.
</p>
<h3 class="mb-2 text-lg text-indigo-800 font-semibold">Create a unique random alias</h3>
<p class="mb-2 text-grey-700">
You can click the button above to create a random alias that will look something like this:
You can click the button above to create a random alias that will look something like
this:
</p>
<p class="mb-2 text-grey-700">
<b>x481n904@{{ domain }}</b>
</p>
<p clas="text-grey-700">
This is useful if you do not wish to include your username in the email as a potential link
between aliases.
This is useful if you do not wish to include your username in the email as a potential
link between aliases.
</p>
</div>
<div class="mt-4">
@ -1312,8 +1313,8 @@
</p>
<p class="mt-4 text-grey-700">
<b>Shared Domain Aliases</b> - A shared domain alias is any alias that has a domain name
that is also shared with other users. Aliases with shared domain names must be pre-generated and cannot be
created on-the-fly like standard aliases.
that is also shared with other users. Aliases with shared domain names must be
pre-generated and cannot be created on-the-fly like standard aliases.
</p>
<div class="mt-6 flex flex-col sm:flex-row">

View File

@ -105,14 +105,15 @@
}}</span>
<button
@click="
;(domainIdToEdit = props.row.id), (domainDescriptionToEdit = props.row.description)
;((domainIdToEdit = props.row.id),
(domainDescriptionToEdit = props.row.description))
"
>
<icon name="edit" class="inline-block w-6 h-6 text-grey-300 fill-current" />
</button>
</div>
<div v-else class="flex justify-center">
<button @click=";(domainIdToEdit = props.row.id), (domainDescriptionToEdit = '')">
<button @click=";((domainIdToEdit = props.row.id), (domainDescriptionToEdit = ''))">
<icon name="plus" class="block w-6 h-6 text-grey-300 fill-current" />
</button>
</div>

View File

@ -190,8 +190,9 @@
</div>
<div v-show="accessToken">
<p class="my-4 text-grey-700">
This is your new personal access key. <b>This is the only time the key will ever be
displayed</b>, so please make a note of it in a safe place (e.g. password manager)!
This is your new personal access key.
<b>This is the only time the key will ever be displayed</b>, so please make a note of it
in a safe place (e.g. password manager)!
</p>
<textarea
v-model="accessToken"

View File

@ -113,15 +113,15 @@
}}</span>
<button
@click="
;(usernameIdToEdit = props.row.id),
(usernameDescriptionToEdit = props.row.description)
;((usernameIdToEdit = props.row.id),
(usernameDescriptionToEdit = props.row.description))
"
>
<Icon name="edit" class="inline-block w-6 h-6 text-grey-300 fill-current" />
</button>
</div>
<div v-else class="flex justify-center">
<button @click=";(usernameIdToEdit = props.row.id), (usernameDescriptionToEdit = '')">
<button @click=";((usernameIdToEdit = props.row.id), (usernameDescriptionToEdit = ''))">
<Icon name="plus" class="block w-6 h-6 text-grey-300 fill-current" />
</button>
</div>