Skip to content

Commit

Permalink
poc personal data
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Mar 20, 2024
1 parent 3b6277f commit 7f5192e
Show file tree
Hide file tree
Showing 42 changed files with 1,383 additions and 14 deletions.
46 changes: 44 additions & 2 deletions baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.22.2@d768d914152dbbf3486c36398802f74e80cfde48">
<files psalm-version="5.23.1@8471a896ccea3526b26d082f4461eeea467f10a4">
<file src="src/Aggregate/AggregateRootBehaviour.php">
<UnsafeInstantiation>
<code><![CDATA[new static()]]></code>
Expand All @@ -15,6 +15,28 @@
<code><![CDATA[class DoctrineHelper]]></code>
</ClassNotFinal>
</file>
<file src="src/Cryptography/Cipher/OpensslCipherKeyFactory.php">
<ArgumentTypeCoercion>
<code><![CDATA[openssl_random_pseudo_bytes($ivLength)]]></code>
<code><![CDATA[openssl_random_pseudo_bytes($this->length)]]></code>
</ArgumentTypeCoercion>
</file>
<file src="src/Cryptography/DefaultEventPayloadCryptographer.php">
<MixedArgument>
<code><![CDATA[$data[$propertyMetadata->fieldName]]]></code>
</MixedArgument>
<MixedAssignment>
<code><![CDATA[$data[$propertyMetadata->fieldName]]]></code>
<code><![CDATA[$data[$propertyMetadata->fieldName]]]></code>
<code><![CDATA[$data[$propertyMetadata->fieldName]]]></code>
</MixedAssignment>
</file>
<file src="src/Cryptography/Store/DoctrineCipherKeyStore.php">
<ArgumentTypeCoercion>
<code><![CDATA[base64_decode($result['crypto_iv'])]]></code>
<code><![CDATA[base64_decode($result['crypto_key'])]]></code>
</ArgumentTypeCoercion>
</file>
<file src="src/EventBus/AttributeListenerProvider.php">
<MixedMethodCall>
<code><![CDATA[$method->getName()]]></code>
Expand Down Expand Up @@ -88,12 +110,21 @@
<code><![CDATA[Closure(Message):void]]></code>
</MixedReturnTypeCoercion>
</file>
<file src="tests/Benchmark/BasicImplementation/Aggregate/Profile.php">
<file src="tests/Benchmark/BasicImplementation/Profile.php">
<PropertyNotSetInConstructor>
<code><![CDATA[$email]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$name]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Benchmark/PersonalDataBench.php">
<MissingConstructor>
<code><![CDATA[$bus]]></code>
<code><![CDATA[$id]]></code>
<code><![CDATA[$repository]]></code>
<code><![CDATA[$store]]></code>
</MissingConstructor>
</file>
<file src="tests/Benchmark/SimpleSetupBench.php">
<MissingConstructor>
<code><![CDATA[$bus]]></code>
Expand Down Expand Up @@ -145,6 +176,17 @@
<code><![CDATA[$name]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Integration/PersonalData/PersonalDataTest.php">
<MixedArgument>
<code><![CDATA[$row['payload']]]></code>
</MixedArgument>
</file>
<file src="tests/Integration/PersonalData/Profile.php">
<PropertyNotSetInConstructor>
<code><![CDATA[$id]]></code>
<code><![CDATA[$name]]></code>
</PropertyNotSetInConstructor>
</file>
<file src="tests/Integration/Pipeline/Aggregate/Profile.php">
<PropertyNotSetInConstructor>
<code><![CDATA[$id]]></code>
Expand Down
25 changes: 25 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ parameters:
count: 1
path: src/Console/DoctrineHelper.php

-
message: "#^Parameter \\#1 \\$key of class Patchlevel\\\\EventSourcing\\\\Cryptography\\\\Cipher\\\\CipherKey constructor expects non\\-empty\\-string, string given\\.$#"
count: 1
path: src/Cryptography/Cipher/OpensslCipherKeyFactory.php

-
message: "#^Parameter \\#3 \\$iv of class Patchlevel\\\\EventSourcing\\\\Cryptography\\\\Cipher\\\\CipherKey constructor expects non\\-empty\\-string, string given\\.$#"
count: 1
path: src/Cryptography/Cipher/OpensslCipherKeyFactory.php

-
message: "#^Parameter \\#2 \\$data of method Patchlevel\\\\EventSourcing\\\\Cryptography\\\\Cipher\\\\Cipher\\:\\:decrypt\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Cryptography/DefaultEventPayloadCryptographer.php

-
message: "#^Parameter \\#1 \\$key of class Patchlevel\\\\EventSourcing\\\\Cryptography\\\\Cipher\\\\CipherKey constructor expects non\\-empty\\-string, string given\\.$#"
count: 1
path: src/Cryptography/Store/DoctrineCipherKeyStore.php

-
message: "#^Parameter \\#3 \\$iv of class Patchlevel\\\\EventSourcing\\\\Cryptography\\\\Cipher\\\\CipherKey constructor expects non\\-empty\\-string, string given\\.$#"
count: 1
path: src/Cryptography/Store/DoctrineCipherKeyStore.php

-
message: "#^Parameter \\#2 \\$data of method Patchlevel\\\\Hydrator\\\\Hydrator\\:\\:hydrate\\(\\) expects array\\<string, mixed\\>, mixed given\\.$#"
count: 1
Expand Down
12 changes: 12 additions & 0 deletions src/Attribute/DataSubjectId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Attribute;

use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY)]
final class DataSubjectId
{
}
16 changes: 16 additions & 0 deletions src/Attribute/PersonalData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Attribute;

use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY)]
final class PersonalData
{
public function __construct(
public readonly mixed $fallback = null,
) {
}
}
14 changes: 14 additions & 0 deletions src/Cryptography/Cipher/Cipher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

interface Cipher
{
/** @throws EncryptionFailed */
public function encrypt(CipherKey $key, mixed $data): string;

/** @throws DecryptionFailed */
public function decrypt(CipherKey $key, string $data): mixed;
}
20 changes: 20 additions & 0 deletions src/Cryptography/Cipher/CipherKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

final class CipherKey
{
/**
* @param non-empty-string $key
* @param non-empty-string $method
* @param non-empty-string $iv
*/
public function __construct(
public readonly string $key,
public readonly string $method,
public readonly string $iv,
) {
}
}
11 changes: 11 additions & 0 deletions src/Cryptography/Cipher/CipherKeyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

interface CipherKeyFactory
{
/** @throws CreateCipherKeyFailed */
public function __invoke(): CipherKey;
}
15 changes: 15 additions & 0 deletions src/Cryptography/Cipher/CreateCipherKeyFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

use RuntimeException;

final class CreateCipherKeyFailed extends RuntimeException
{
public function __construct()
{
parent::__construct('create cipher key failed');
}
}
15 changes: 15 additions & 0 deletions src/Cryptography/Cipher/DecryptionFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

use RuntimeException;

final class DecryptionFailed extends RuntimeException
{
public function __construct()
{
parent::__construct('decryption failed');
}
}
15 changes: 15 additions & 0 deletions src/Cryptography/Cipher/EncryptionFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

use RuntimeException;

final class EncryptionFailed extends RuntimeException
{
public function __construct()
{
parent::__construct('encryption failed');
}
}
61 changes: 61 additions & 0 deletions src/Cryptography/Cipher/OpensslCipher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

use function base64_decode;
use function base64_encode;
use function json_decode;
use function json_encode;
use function openssl_decrypt;
use function openssl_encrypt;

use const JSON_THROW_ON_ERROR;

final class OpensslCipher implements Cipher
{
public function encrypt(CipherKey $key, mixed $data): string
{
$encryptedData = openssl_encrypt(
$this->dataEncode($data),
$key->method,
$key->key,
0,
$key->iv,
);

if ($encryptedData === false) {
throw new EncryptionFailed();
}

return base64_encode($encryptedData);
}

public function decrypt(CipherKey $key, string $data): mixed
{
$data = openssl_decrypt(
base64_decode($data),
$key->method,
$key->key,
0,
$key->iv,
);

if ($data === false) {
throw new DecryptionFailed();
}

return $this->dataDecode($data);
}

private function dataEncode(mixed $data): string
{
return json_encode($data, JSON_THROW_ON_ERROR);
}

private function dataDecode(string $data): mixed
{
return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
}
}
40 changes: 40 additions & 0 deletions src/Cryptography/Cipher/OpensslCipherKeyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Cryptography\Cipher;

use function openssl_cipher_iv_length;
use function openssl_random_pseudo_bytes;

final class OpensslCipherKeyFactory implements CipherKeyFactory
{
public const DEFAULT_LENGTH = 32;

public const DEFAULT_METHOD = 'aes128';

/**
* @param positive-int $length
* @param non-empty-string $method
*/
public function __construct(
private readonly int $length = self::DEFAULT_LENGTH,
private readonly string $method = self::DEFAULT_METHOD,
) {
}

public function __invoke(): CipherKey
{
$ivLength = openssl_cipher_iv_length($this->method);

if ($ivLength === false) {
throw new CreateCipherKeyFailed();
}

return new CipherKey(
openssl_random_pseudo_bytes($this->length),
$this->method,
openssl_random_pseudo_bytes($ivLength),
);
}
}
Loading

0 comments on commit 7f5192e

Please sign in to comment.