55 lines
2.1 KiB
PHP
55 lines
2.1 KiB
PHP
<?php
|
|
|
|
use App\Services\Secrets\SecretCipher;
|
|
|
|
it('round-trips a value with a raw base64 key', function () {
|
|
config()->set('admin_access.secrets_key', base64_encode(random_bytes(32)));
|
|
|
|
$cipher = app(SecretCipher::class);
|
|
|
|
expect($cipher->decrypt($cipher->encrypt('hunter2')))->toBe('hunter2');
|
|
});
|
|
|
|
it('accepts the base64: prefix as well, because the documented generator omits it', function () {
|
|
config()->set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32)));
|
|
|
|
$cipher = app(SecretCipher::class);
|
|
|
|
expect($cipher->decrypt($cipher->encrypt('hunter2')))->toBe('hunter2');
|
|
});
|
|
|
|
it('refuses rather than silently falling back to APP_KEY', function () {
|
|
config()->set('admin_access.secrets_key', '');
|
|
|
|
expect(fn () => app(SecretCipher::class)->encrypt('x'))
|
|
->toThrow(RuntimeException::class, 'SECRETS_KEY');
|
|
|
|
expect(app(SecretCipher::class)->isUsable())->toBeFalse();
|
|
});
|
|
|
|
it('refuses a key that is not 32 bytes', function () {
|
|
config()->set('admin_access.secrets_key', 'zu-kurz');
|
|
|
|
expect(fn () => app(SecretCipher::class)->encrypt('x'))
|
|
->toThrow(RuntimeException::class, '32 bytes');
|
|
});
|
|
|
|
it('reports unusable for a malformed key, not just an empty one', function () {
|
|
// Codex R15#3, P2: isUsable() used to check only "is the string
|
|
// nonempty", so a SET-but-malformed SECRETS_KEY (wrong length, garbage
|
|
// base64) read back as usable even though encrypter() — called from the
|
|
// very same encrypt()/decrypt() this object exposes — rejects exactly
|
|
// this value two lines below. EditMailbox::save() and
|
|
// MailboxTester::run() both gate on isUsable() specifically to avoid an
|
|
// uncaught RuntimeException reaching the operator; a lying isUsable()
|
|
// means that guard does not fire in exactly the configuration it exists
|
|
// for.
|
|
config()->set('admin_access.secrets_key', 'zu-kurz');
|
|
|
|
expect(app(SecretCipher::class)->isUsable())->toBeFalse();
|
|
|
|
// Same key, same verdict from the method it must never disagree with.
|
|
expect(fn () => app(SecretCipher::class)->encrypt('x'))
|
|
->toThrow(RuntimeException::class, '32 bytes');
|
|
});
|