Fixes for urlencoding of password reset form

This commit is contained in:
David Bomba
2026-05-18 14:42:15 +10:00
parent fb90156478
commit 2aad093620
4 changed files with 36 additions and 26 deletions

View File

@@ -72,7 +72,30 @@ class ResetPasswordController extends Controller
}
return $this->render('auth.passwords.reset', ['root' => 'themes', 'token' => $token, 'account' => $account, 'email' => $request->email]);
return $this->render('auth.passwords.reset', [
'root' => 'themes',
'token' => $this->normalize((string) $token),
'account' => $account,
'email' => $this->normalize((string) $request->query('email', '')),
]);
}
/**
* Idempotently URL-decode an inbound link value (handles single and
* double encoding from SPA / email link rewriters). rawurldecode is
* used so '+' is preserved (plus-addressed emails).
*/
private function normalize(string $value): string
{
for ($i = 0; $i < 3 && str_contains($value, '%'); $i++) {
$decoded = rawurldecode($value);
if ($decoded === $value) {
break;
}
$value = $decoded;
}
return trim($value);
}
/**
@@ -84,24 +107,6 @@ class ResetPasswordController extends Controller
*/
public function reset(Request $request)
{
// Safely decode URL-encoded token and email before validation
if ($request->has('token')) {
$token = $request->input('token');
// Only decode if it contains URL encoding characters
if (strpos($token, '%') !== false) {
$request->merge(['token' => urldecode($token)]);
}
}
if ($request->has('email')) {
$email = $request->input('email');
// Only decode if it contains URL encoding characters
if (strpos($email, '%') !== false) {
$request->merge(['email' => urldecode($email)]);
}
}
$request->validate($this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we

View File

@@ -12,15 +12,17 @@
namespace App\Jobs\Cron;
use App\Jobs\Entity\EmailEntity;
use App\Libraries\MultiDB;
use App\Models\Invoice;
use App\Models\Webhook;
use App\Libraries\MultiDB;
use App\Utils\Ninja;
use Illuminate\Bus\Queueable;
use App\Jobs\Entity\EmailEntity;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
class AutoBill implements ShouldQueue
{
@@ -60,6 +62,9 @@ class AutoBill implements ShouldQueue
$invoice = Invoice::withTrashed()->find($this->invoice_id);
if ($invoice) {
App::setLocale($invoice->client->locale());
$t = app('translator');
$t->replace(Ninja::transformTranslations($invoice->client->getMergedSettings()));
$invoice->service()->autoBill();
}

View File

@@ -27,9 +27,9 @@
<div class="flex flex-col">
<label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label>
<input type="email" name="email" id="email"
class="input"
class="input @if(!empty($email)) bg-gray-100 cursor-not-allowed @endif"
value="{{ $email ?? old('email') }}"
autofocus>
@if(!empty($email)) readonly @else autofocus @endif>
@error('email')
<div class="validation validation-fail">
{{ $message }}

View File

@@ -143,7 +143,7 @@ Route::group(['middleware' => ['throttle:api', 'api_secret_check']], function ()
Route::group(['middleware' => ['throttle:login', 'api_secret_check', 'email_db']], function () {
Route::post('api/v1/login', [LoginController::class, 'apiLogin'])->name('login.submit');
Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail'])->middleware('throttle:2,1');
Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail'])->middleware('throttle:10,1');
Route::post('api/v1/passkeys/login/options', [PasskeyController::class, 'loginOptions'])->name('passkeys.login.options');
});