Stop the mailbox password save from crashing without SECRETS_KEY
EditMailbox::save() now checks SecretCipher::isUsable() before touching a typed password and reports it as a form error, instead of letting SecretCipher::encrypt() throw all the way to Laravel's debug page. Also switches the mail.manage migration to Role::findOrCreate, matching every sibling capability migration, so a squashed replay can't hit RoleDoesNotExist.feat/mailboxes
parent
4211f3dfab
commit
67a3e78cb4
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Mailbox;
|
||||
use App\Services\Secrets\SecretCipher;
|
||||
use LivewireUI\Modal\ModalComponent;
|
||||
|
||||
/**
|
||||
|
|
@ -57,6 +58,18 @@ class EditMailbox extends ModalComponent
|
|||
'password' => ['nullable', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
// A password can only be STORED where SECRETS_KEY exists to encrypt it
|
||||
// under — the same condition the page's own banner already names.
|
||||
// Checked here rather than left for Mailbox::setPasswordAttribute() to
|
||||
// throw through: an uncaught RuntimeException would render Laravel's
|
||||
// debug page, whose request-payload inspector can show the very
|
||||
// password just typed. The page must say so, not crash on it.
|
||||
if ($this->password !== '' && ! app(SecretCipher::class)->isUsable()) {
|
||||
$this->addError('password', __('mail_settings.no_key'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$box = Mailbox::query()->where('uuid', $this->uuid)->firstOrFail();
|
||||
|
||||
$box->address = $this->address;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ return new class extends Migration
|
|||
$permission = Permission::findOrCreate('mail.manage', 'web');
|
||||
|
||||
foreach (['Owner', 'Admin', 'Support'] as $role) {
|
||||
Role::findByName($role, 'web')->givePermissionTo($permission);
|
||||
Role::findOrCreate($role, 'web')->givePermissionTo($permission);
|
||||
}
|
||||
|
||||
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||
|
|
|
|||
|
|
@ -97,6 +97,25 @@ it('says so when SECRETS_KEY is missing, instead of crashing on the first passwo
|
|||
->assertSee(__('mail_settings.no_key'));
|
||||
});
|
||||
|
||||
it('fails the password save with a form error, not an exception, when SECRETS_KEY is missing', function () {
|
||||
// The test above only proves the PAGE says so. Nothing proved that typing
|
||||
// a password into the MODAL and saving it fails gracefully — the gap a
|
||||
// reviewer found: left unfixed, SecretCipher::encrypt() throws all the way
|
||||
// up, and with APP_DEBUG on, Laravel's debug page can put the just-typed
|
||||
// plaintext password in its request-payload inspector. All three
|
||||
// password-writing tests above run under this file's valid-key beforeEach,
|
||||
// so none of them would have caught it.
|
||||
$box = Mailbox::factory()->create(['key' => 'support']);
|
||||
|
||||
config()->set('admin_access.secrets_key', '');
|
||||
|
||||
Livewire::actingAs(User::factory()->operator('Owner')->create())
|
||||
->test(EditMailbox::class, ['uuid' => $box->uuid])
|
||||
->set('password', 'neu-und-sicher')
|
||||
->call('save')
|
||||
->assertHasErrors('password');
|
||||
});
|
||||
|
||||
it('refuses to leave the system purpose empty, because it is the fallback', function () {
|
||||
Mailbox::factory()->create(['key' => 'no-reply']);
|
||||
Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');
|
||||
|
|
|
|||
Loading…
Reference in New Issue