fixes for client portal double set password session

This commit is contained in:
David Bomba
2026-03-24 08:45:52 +11:00
parent 8cdce46bb6
commit c440f02fcd
3 changed files with 65 additions and 33 deletions

View File

@@ -44,35 +44,35 @@ class InvitationController extends Controller
public function router(string $entity, string $invitation_key)
{
Auth::logout();
auth()->guard('contact')->logout();
return $this->genericRouter($entity, $invitation_key);
}
public function recurringRouter(string $invitation_key)
{
Auth::logout();
auth()->guard('contact')->logout();
return $this->genericRouter('recurring_invoice', $invitation_key);
}
public function invoiceRouter(string $invitation_key)
{
Auth::logout();
auth()->guard('contact')->logout();
return $this->genericRouter('invoice', $invitation_key);
}
public function quoteRouter(string $invitation_key)
{
Auth::logout();
auth()->guard('contact')->logout();
return $this->genericRouter('quote', $invitation_key);
}
public function creditRouter(string $invitation_key)
{
Auth::logout();
auth()->guard('contact')->logout();
return $this->genericRouter('credit', $invitation_key);
}
@@ -121,10 +121,10 @@ class InvitationController extends Controller
} elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
//if no contact password has been set - allow user to set password - then continue to view entity
if (empty($invitation->contact->password)) {
return $this->render('view_entity.set_password', [
'root' => 'themes',
return redirect()->route('client.set_password_form', [
'entity_type' => $entity,
'invitation_key' => $invitation_key,
'hash' => hash_hmac('sha256', $invitation_key, config('app.key')),
]);
}
@@ -230,6 +230,36 @@ class InvitationController extends Controller
public function routerForIframe(string $entity, string $client_hash, string $invitation_key) {}
public function setPasswordForm(Request $request)
{
if (!in_array($request->entity_type, ['invoice', 'quote', 'credit', 'recurring_invoice'])) {
abort(404);
}
if (!hash_equals(hash_hmac('sha256', $request->invitation_key, config('app.key')), $request->hash ?? '')) {
abort(403);
}
$entity_obj = 'App\Models\\' . ucfirst(Str::camel($request->entity_type)) . 'Invitation';
$invitation = $entity_obj::where('key', $request->invitation_key)
->whereHas($request->entity_type, function ($query) {
$query->where('is_deleted', 0);
})
->with('contact')
->firstOrFail();
if (!empty($invitation->contact->password)) {
abort(404);
}
return $this->render('view_entity.set_password', [
'root' => 'themes',
'entity_type' => $request->entity_type,
'invitation_key' => $request->invitation_key,
]);
}
public function handlePasswordSet(Request $request)
{
$entity_obj = 'App\Models\\' . ucfirst(Str::camel($request->entity_type)) . 'Invitation';

53
composer.lock generated
View File

@@ -384,16 +384,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.373.7",
"version": "3.373.8",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "4402bd10f913e66b7271f44466be8d5ba6c9146e"
"reference": "18035d80bab38c962af8580307a787bf4e15cc47"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4402bd10f913e66b7271f44466be8d5ba6c9146e",
"reference": "4402bd10f913e66b7271f44466be8d5ba6c9146e",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/18035d80bab38c962af8580307a787bf4e15cc47",
"reference": "18035d80bab38c962af8580307a787bf4e15cc47",
"shasum": ""
},
"require": {
@@ -475,9 +475,9 @@
"support": {
"forum": "https://github.com/aws/aws-sdk-php/discussions",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.373.7"
"source": "https://github.com/aws/aws-sdk-php/tree/3.373.8"
},
"time": "2026-03-20T18:14:19+00:00"
"time": "2026-03-23T18:08:22+00:00"
},
{
"name": "babenkoivan/elastic-adapter",
@@ -10398,16 +10398,16 @@
},
{
"name": "psy/psysh",
"version": "v0.12.21",
"version": "v0.12.22",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
"reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97"
"reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/4821fab5b7cd8c49a673a9fd5754dc9162bb9e97",
"reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/3be75d5b9244936dd4ac62ade2bfb004d13acf0f",
"reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f",
"shasum": ""
},
"require": {
@@ -10471,9 +10471,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.12.21"
"source": "https://github.com/bobthecow/psysh/tree/v0.12.22"
},
"time": "2026-03-06T21:21:28+00:00"
"time": "2026-03-22T23:03:24+00:00"
},
{
"name": "pusher/pusher-php-server",
@@ -11198,16 +11198,16 @@
},
{
"name": "sentry/sentry",
"version": "4.22.0",
"version": "4.23.0",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "ce6ab95a7021f976a27b4628a4072e481c8acf60"
"reference": "121a674d5fffcdb8e414b75c1b76edba8e592b66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/ce6ab95a7021f976a27b4628a4072e481c8acf60",
"reference": "ce6ab95a7021f976a27b4628a4072e481c8acf60",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/121a674d5fffcdb8e414b75c1b76edba8e592b66",
"reference": "121a674d5fffcdb8e414b75c1b76edba8e592b66",
"shasum": ""
},
"require": {
@@ -11229,12 +11229,14 @@
"guzzlehttp/psr7": "^1.8.4|^2.1.1",
"monolog/monolog": "^1.6|^2.0|^3.0",
"nyholm/psr7": "^1.8",
"open-telemetry/api": "^1.0",
"open-telemetry/exporter-otlp": "^1.0",
"open-telemetry/sdk": "^1.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5.52|^9.6.34",
"spiral/roadrunner-http": "^3.6",
"spiral/roadrunner-worker": "^3.6",
"vimeo/psalm": "^4.17"
"spiral/roadrunner-worker": "^3.6"
},
"suggest": {
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler."
@@ -11273,7 +11275,7 @@
],
"support": {
"issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.22.0"
"source": "https://github.com/getsentry/sentry-php/tree/4.23.0"
},
"funding": [
{
@@ -11285,7 +11287,7 @@
"type": "custom"
}
],
"time": "2026-03-16T13:03:46+00:00"
"time": "2026-03-23T13:15:52+00:00"
},
{
"name": "sentry/sentry-laravel",
@@ -11695,20 +11697,19 @@
},
{
"name": "socialiteproviders/microsoft",
"version": "4.8.0",
"version": "4.9.0",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Microsoft.git",
"reference": "33ac5df3e13e0430bcff04031d606bda88f2b27f"
"reference": "1d6af46e96e8dd83a4de0b994cf93dcceeb87ecd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Microsoft/zipball/33ac5df3e13e0430bcff04031d606bda88f2b27f",
"reference": "33ac5df3e13e0430bcff04031d606bda88f2b27f",
"url": "https://api.github.com/repos/SocialiteProviders/Microsoft/zipball/1d6af46e96e8dd83a4de0b994cf93dcceeb87ecd",
"reference": "1d6af46e96e8dd83a4de0b994cf93dcceeb87ecd",
"shasum": ""
},
"require": {
"ext-json": "*",
"firebase/php-jwt": "^7.0",
"php": "^8.0",
"socialiteproviders/manager": "^4.4"
@@ -11742,7 +11743,7 @@
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers"
},
"time": "2026-02-18T14:40:47+00:00"
"time": "2026-03-23T02:21:23+00:00"
},
{
"name": "sprain/swiss-qr-bill",

View File

@@ -30,6 +30,7 @@ Route::post('client/password/email', [ContactForgotPasswordController::class, 's
Route::get('client/password/reset/{token}', [ContactResetPasswordController::class, 'showResetForm'])->name('client.password.reset')->middleware(['domain_db', 'contact_account','locale', 'throttle:portal']);
Route::post('client/password/reset', [ContactResetPasswordController::class, 'reset'])->name('client.password.update')->middleware(['domain_db', 'contact_account','locale', 'throttle:portal']);
Route::get('set_password', [App\Http\Controllers\ClientPortal\InvitationController::class, 'setPasswordForm'])->name('client.set_password_form')->middleware('domain_db');
Route::post('set_password', [App\Http\Controllers\ClientPortal\InvitationController::class, 'handlePasswordSet'])->name('client.set_password')->middleware('domain_db');
Route::get('tmp_pdf/{hash}', [App\Http\Controllers\ClientPortal\TempRouteController::class, 'index'])->name('tmp_pdf');