From e1d6fd016c7fbfdf73688e9f14bd9443ce9f4625 Mon Sep 17 00:00:00 2001 From: Harry Lewis Date: Thu, 9 Feb 2023 11:57:23 +0000 Subject: [PATCH] Add backwards-compatible encryption to provider configuration data --- CHANGELOG.md | 4 + app/Models/ProviderConfiguration.php | 15 ++- app/Models/Traits/Encryption.php | 66 +++++++++++++ ...47_encrypt_provider_configuration_data.php | 93 +++++++++++++++++++ 4 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 app/Models/Traits/Encryption.php create mode 100644 database/migrations/2023_02_09_102747_encrypt_provider_configuration_data.php diff --git a/CHANGELOG.md b/CHANGELOG.md index da772d1..2be0f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to the package will be documented in this file. +## v1.3.6 - 2023-02-09 + +- Add backwards-compatible encryption to provider configuration data + ## v1.3.5 - 2023-02-06 - Fix a crash in form-group view component when a non-array value is passed diff --git a/app/Models/ProviderConfiguration.php b/app/Models/ProviderConfiguration.php index 9ff9e7a..7ed1ddf 100644 --- a/app/Models/ProviderConfiguration.php +++ b/app/Models/ProviderConfiguration.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\Traits\Encryption; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\App; @@ -35,9 +36,7 @@ */ class ProviderConfiguration extends Model { - protected $casts = [ - 'data' => 'json', - ]; + use Encryption; /** * @param Builder $query @@ -82,4 +81,14 @@ public function getProvider(): ?ProviderRegister return $category->getProvider($this->provider_code); } + + public function getDataAttribute($value): ?array + { + return $this->decrypt($this->fromJson($value)); + } + + public function setDataAttribute($data): void + { + $this->attributes['data'] = $this->castAttributeAsJson('data', $this->encrypt($data)); + } } diff --git a/app/Models/Traits/Encryption.php b/app/Models/Traits/Encryption.php new file mode 100644 index 0000000..a810a21 --- /dev/null +++ b/app/Models/Traits/Encryption.php @@ -0,0 +1,66 @@ + $value) { + $data[$key] = $this->encrypt($value); + } + + return $data; + } + + if (!is_string($data) || is_numeric($data) || empty($data)) { + return $data; + } + + return encrypt($data); + } + + /** + * Recursively decrypts the given data. + * + * @param mixed $data + * + * @return mixed + */ + public function decrypt($data) + { + if (is_iterable($data)) { + foreach ($data as $key => $value) { + $data[$key] = $this->decrypt($value); + } + + return $data; + } + + if (!is_string($data) || is_numeric($data) || empty($data)) { + return $data; + } + + try { + return decrypt($data); + } catch (DecryptException $e) { + // If the payload cannot be decrypted, assume it was already plaintext. + return $data; + } + } +} diff --git a/database/migrations/2023_02_09_102747_encrypt_provider_configuration_data.php b/database/migrations/2023_02_09_102747_encrypt_provider_configuration_data.php new file mode 100644 index 0000000..3793fba --- /dev/null +++ b/database/migrations/2023_02_09_102747_encrypt_provider_configuration_data.php @@ -0,0 +1,93 @@ +get() as $providerConfiguration) { + DB::table('provider_configurations') + ->where('id', $providerConfiguration->id) + ->update([ + 'data' => json_encode($this->encrypt(json_decode($providerConfiguration->data, true))), + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + foreach (DB::table('provider_configurations')->get() as $providerConfiguration) { + DB::table('provider_configurations') + ->where('id', $providerConfiguration->id) + ->update([ + 'data' => json_encode($this->decrypt(json_decode($providerConfiguration->data, true))), + ]); + } + } + + /** + * Recursively encrypts the given data. + * + * @param mixed $data + * + * @return mixed + */ + public function encrypt($data) + { + if (is_iterable($data)) { + foreach ($data as $key => $value) { + $data[$key] = $this->encrypt($value); + } + + return $data; + } + + if (!is_string($data) || is_numeric($data) || empty($data)) { + return $data; + } + + return encrypt($data); + } + + /** + * Recursively decrypts the given data. + * + * @param mixed $data + * + * @return mixed + */ + public function decrypt($data) + { + if (is_iterable($data)) { + foreach ($data as $key => $value) { + $data[$key] = $this->decrypt($value); + } + + return $data; + } + + if (!is_string($data) || is_numeric($data) || empty($data)) { + return $data; + } + + try { + return decrypt($data); + } catch (DecryptException $e) { + // If the payload cannot be decrypted, assume it was already plaintext. + return $data; + } + } +}