encrypter()->encryptString($plain); } public function decrypt(string $cipher): string { return $this->encrypter()->decryptString($cipher); } /** * Is storing credentials possible at all on this installation? * * Delegates to the exact same resolveKey() that encrypter() below checks * its input against, rather than a second, shorter rule that only looks * at emptiness. A malformed-but-nonempty key (wrong length, garbage * base64) used to pass a bare "!== ''" check while encrypter() rejected * it — which let EditMailbox::save() and MailboxTester::run() sail past * the very guard they call this method for, straight into the uncaught * RuntimeException it exists to prevent. */ public function isUsable(): bool { return $this->resolveKey() !== null; } /** * The raw, exactly-32-byte key — or null if SECRETS_KEY is empty or * malformed. The one place that decides "is this key any good", so * isUsable() and encrypter() read it from the same rule and cannot * disagree about a value either one is given. */ private function resolveKey(): ?string { $key = (string) config('admin_access.secrets_key'); if ($key === '') { return null; } if (str_starts_with($key, 'base64:')) { $key = substr($key, 7); } if (strlen($key) !== 32) { $decoded = base64_decode($key, true); if ($decoded !== false && strlen($decoded) === 32) { $key = $decoded; } } return strlen($key) === 32 ? $key : null; } private function encrypter(): Encrypter { $key = $this->resolveKey(); if ($key === null) { throw new RuntimeException( (string) config('admin_access.secrets_key') === '' ? 'SECRETS_KEY is not set — refusing to store or read credentials.' : 'SECRETS_KEY must be 32 bytes (or base64 of 32 bytes).' ); } return new Encrypter($key, 'aes-256-cbc'); } }