Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ parameters:
count: 1
path: src/Cryptography/Cipher/OpensslCipherKeyFactory.php

-
message: '#^Parameter \#2 \$data of method Patchlevel\\Hydrator\\Cryptography\\Cipher\\Cipher\:\:decrypt\(\) expects string, mixed given\.$#'
identifier: argument.type
count: 1
path: src/Cryptography/PersonalDataPayloadCryptographer.php

-
message: '#^Offset ''k'' on array\{v\: 1, a\: non\-empty\-string, k\: non\-empty\-string, n\?\: non\-empty\-string, d\: non\-empty\-string, t\?\: non\-empty\-string\} on left side of \?\? always exists and is not nullable\.$#'
identifier: nullCoalesce.offset
Expand Down
13 changes: 12 additions & 1 deletion src/Cryptography/PersonalDataPayloadCryptographer.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
private readonly Cipher $cipher,
private readonly bool $useEncryptedFieldName = false,
private readonly bool $fallbackToFieldName = false,
private readonly bool $encryptNull = true,
) {
}

Expand Down Expand Up @@ -55,17 +56,23 @@
continue;
}

$value = $data[$propertyMetadata->fieldName()] ?? null;

if (!$this->encryptNull && $value === null) {
continue;

Check warning on line 62 in src/Cryptography/PersonalDataPayloadCryptographer.php

View workflow job for this annotation

GitHub Actions / Mutation tests (locked, 8.5, ubuntu-latest)

Escaped Mutant for Mutator "Continue_": @@ @@ $value = $data[$propertyMetadata->fieldName()] ?? null; if (!$this->encryptNull && $value === null) { - continue; + break; } $targetFieldName = $this->useEncryptedFieldName

Check warning on line 62 in src/Cryptography/PersonalDataPayloadCryptographer.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.5, ubuntu-latest)

Escaped Mutant for Mutator "Continue_": @@ @@ $value = $data[$propertyMetadata->fieldName()] ?? null; if (!$this->encryptNull && $value === null) { - continue; + break; } $targetFieldName = $this->useEncryptedFieldName
}

$targetFieldName = $this->useEncryptedFieldName
? $propertyMetadata->encryptedFieldName()
: $propertyMetadata->fieldName();

$data[$targetFieldName] = $this->cipher->encrypt(
$cipherKey,
$data[$propertyMetadata->fieldName()],
$value,
);

if (!$this->useEncryptedFieldName) {
continue;

Check warning on line 75 in src/Cryptography/PersonalDataPayloadCryptographer.php

View workflow job for this annotation

GitHub Actions / Mutation tests (locked, 8.5, ubuntu-latest)

Escaped Mutant for Mutator "Continue_": @@ @@ ); if (!$this->useEncryptedFieldName) { - continue; + break; } unset($data[$propertyMetadata->fieldName()]);
}

unset($data[$propertyMetadata->fieldName()]);
Expand Down Expand Up @@ -107,6 +114,10 @@
continue;
}

if (!is_string($rawData)) {
continue;

Check warning on line 118 in src/Cryptography/PersonalDataPayloadCryptographer.php

View workflow job for this annotation

GitHub Actions / Mutation tests on diff (locked, 8.5, ubuntu-latest)

Escaped Mutant for Mutator "Continue_": @@ @@ } if (!is_string($rawData)) { - continue; + break; } if (!$cipherKey) {
}

if (!$cipherKey) {
$data[$propertyMetadata->fieldName()] = $this->fallback($propertyMetadata, $subjectId, $rawData);
continue;
Expand Down
92 changes: 92 additions & 0 deletions tests/Unit/Cryptography/PersonalDataPayloadCryptographerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,74 @@ public function testEncryptWithExistingKeyEncryptedFieldName(): void
self::assertEquals(['id' => 'foo', '!email' => 'encrypted'], $result);
}

public function testEncryptSkipNullValueIfEncryptNullDisabled(): void
{
$cipherKey = new CipherKey(
'foo',
'bar',
'baz',
);

$cipherKeyStore = $this->createMock(CipherKeyStore::class);
$cipherKeyStore->method('get')->with('foo')->willReturn($cipherKey);
$cipherKeyStore->expects($this->never())->method('store');

$cipherKeyFactory = $this->createMock(CipherKeyFactory::class);
$cipherKeyFactory->expects($this->never())->method('__invoke');

$cipher = $this->createMock(Cipher::class);
$cipher->expects($this->never())->method('encrypt');

$cryptographer = new PersonalDataPayloadCryptographer(
$cipherKeyStore,
$cipherKeyFactory,
$cipher,
false,
false,
false,
);

$result = $cryptographer->encrypt(
$this->metadata(PersonalDataProfileCreated::class),
['id' => 'foo', 'email' => null],
);

self::assertSame(['id' => 'foo', 'email' => null], $result);
}

public function testEncryptNullValueIfEncryptNullEnabled(): void
{
$cipherKey = new CipherKey(
'foo',
'bar',
'baz',
);

$cipherKeyStore = $this->createMock(CipherKeyStore::class);
$cipherKeyStore->method('get')->with('foo')->willReturn($cipherKey);
$cipherKeyStore->expects($this->never())->method('store');

$cipherKeyFactory = $this->createMock(CipherKeyFactory::class);
$cipherKeyFactory->expects($this->never())->method('__invoke');

$cipher = $this->createMock(Cipher::class);
$cipher->expects($this->once())->method('encrypt')->with($cipherKey, null)
->willReturn('encrypted-null');

$cryptographer = new PersonalDataPayloadCryptographer(
$cipherKeyStore,
$cipherKeyFactory,
$cipher,
);

$result = $cryptographer->encrypt(
$this->metadata(PersonalDataProfileCreated::class),
['id' => 'foo', 'email' => null],
);

self::assertSame(['id' => 'foo', 'email' => 'encrypted-null'], $result);
}

public function testSkipDecrypt(): void
{
$cipherKeyStore = $this->createMock(CipherKeyStore::class);
Expand Down Expand Up @@ -373,6 +441,30 @@ public function testDecryptWithValidKeyAndEncryptedFieldNameAndFallbackFieldName
self::assertEquals(['id' => 'foo', 'email' => '[email protected]'], $result);
}

public function testDecryptSkipNonStringValue(): void
{
$cipherKeyStore = $this->createMock(CipherKeyStore::class);
$cipherKeyStore->method('get')->with('foo')->willThrowException(new CipherKeyNotExists('foo'));

$cipherKeyFactory = $this->createMock(CipherKeyFactory::class);
$cipher = $this->createMock(Cipher::class);
$cipher->expects($this->never())->method('decrypt');

$cryptographer = new PersonalDataPayloadCryptographer(
$cipherKeyStore,
$cipherKeyFactory,
$cipher,
);

$email = new Email('[email protected]');
$result = $cryptographer->decrypt(
$this->metadata(PersonalDataProfileCreated::class),
['id' => 'foo', 'email' => $email],
);

self::assertSame(['id' => 'foo', 'email' => $email], $result);
}

public function testUnsupportedSubjectId(): void
{
$this->expectException(UnsupportedSubjectId::class);
Expand Down
Loading