shopit-back/app/Domains/Integration/Casts/EncryptedIntegrationData.php

67 lines
1.9 KiB
PHP

<?php
namespace App\Domains\Integration\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Encryption\Encrypter;
use Exception;
class EncryptedIntegrationData implements CastsAttributes
{
protected function getEncrypter(): Encrypter
{
$secret = config('services.integrations.secret');
if (empty($secret)) {
throw new Exception('The integrations secret is not configured.');
}
// Laravel encrypter requires a key of exact length. Typically 32 bytes for AES-256-CBC.
// If the secret is base64 encoded like the APP_KEY:
if (str_starts_with($secret, 'base64:')) {
$key = base64_decode(substr($secret, 7));
} else {
// Otherwise, we hash it to ensure 32 bytes for AES-256-CBC.
$key = hash('sha256', $secret, true);
}
return new Encrypter($key, config('app.cipher', 'AES-256-CBC'));
}
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
*/
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
{
if ($value === null) {
return null;
}
try {
$decrypted = $this->getEncrypter()->decryptString($value);
return json_decode($decrypted, true);
} catch (Exception $e) {
// Return null or throw depending on how strict we want to be.
return null;
}
}
/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
if ($value === null) {
return null;
}
$json = json_encode($value);
return $this->getEncrypter()->encryptString($json);
}
}