Teren-app/app/Services/MailSecretEncrypter.php
2025-10-07 21:57:10 +02:00

74 lines
2.0 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;
class MailSecretEncrypter
{
public function __construct(
protected ?string $key = null,
) {
$this->key = $this->key ?? config('mail_profiles.key');
if (empty($this->key)) {
// Fall back to app key for now
$this->key = config('app.key');
}
}
public function encrypt(string $plain): string
{
// For simplicity use Crypt facade (already uses APP_KEY) unless a dedicated key is set.
if ($this->usingAppKey()) {
return Crypt::encryptString($plain);
}
return $this->encryptWithCustomKey($plain);
}
public function decrypt(string $cipher): string
{
if ($this->usingAppKey()) {
return Crypt::decryptString($cipher);
}
return $this->decryptWithCustomKey($cipher);
}
protected function usingAppKey(): bool
{
return $this->key === config('app.key');
}
protected function encryptWithCustomKey(string $plain): string
{
$iv = random_bytes(openssl_cipher_iv_length('AES-256-CBC'));
$cipher = openssl_encrypt($plain, 'AES-256-CBC', $this->normalizedKey(), 0, $iv);
return base64_encode($iv.'::'.$cipher);
}
protected function decryptWithCustomKey(string $payload): string
{
$decoded = base64_decode($payload, true);
if ($decoded === false || ! str_contains($decoded, '::')) {
throw new DecryptException('Invalid encrypted payload');
}
[$iv, $cipher] = explode('::', $decoded, 2);
$plain = openssl_decrypt($cipher, 'AES-256-CBC', $this->normalizedKey(), 0, $iv);
if ($plain === false) {
throw new DecryptException('Cannot decrypt payload');
}
return $plain;
}
protected function normalizedKey(): string
{
$raw = base64_decode($this->key, true);
return $raw !== false ? $raw : $this->key; // support base64 or plain
}
}