Skip to content

Commit cd10d3a

Browse files
committed
Add abstract Key class
1 parent 9b9209e commit cd10d3a

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

src/Nexus/Encryption/Key.php

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the Nexus framework.
7+
*
8+
* (c) John Paul E. Balandan, CPA <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace Nexus\Encryption;
15+
16+
abstract class Key
17+
{
18+
private ?string $keyString;
19+
20+
public function __construct(Secret $key)
21+
{
22+
$this->keyString = $key->reveal();
23+
}
24+
25+
public function __destruct()
26+
{
27+
sodium_memzero($this->keyString);
28+
}
29+
30+
public function __clone(): void
31+
{
32+
throw new \BadMethodCallException(\sprintf('Cannot clone a %s object.', basename(static::class)));
33+
}
34+
35+
/**
36+
* @return array<string, string>
37+
*/
38+
public function __debugInfo(): array
39+
{
40+
return ['keyString' => '[redacted]'];
41+
}
42+
43+
public function __serialize(): never
44+
{
45+
throw new \BadMethodCallException(\sprintf('Cannot serialise a %s object.', static::class));
46+
}
47+
48+
/**
49+
* @param array<string, mixed> $data
50+
*/
51+
public function __unserialize(array $data): never
52+
{
53+
throw new \BadMethodCallException(\sprintf('Cannot unserialise a %s object.', static::class)); // @codeCoverageIgnore
54+
}
55+
56+
public function getKeyString(): string
57+
{
58+
return $this->keyString ?? '';
59+
}
60+
}

tests/Encryption/KeyTest.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the Nexus framework.
7+
*
8+
* (c) John Paul E. Balandan, CPA <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace Nexus\Tests\Encryption;
15+
16+
use Nexus\Encryption\Key;
17+
use Nexus\Encryption\Secret;
18+
use PHPUnit\Framework\Attributes\CoversClass;
19+
use PHPUnit\Framework\Attributes\Group;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
use PHPUnit\Framework\TestCase;
22+
23+
/**
24+
* @internal
25+
*/
26+
#[CoversClass(Key::class)]
27+
#[Group('unit-test')]
28+
final class KeyTest extends TestCase
29+
{
30+
private Key&MockObject $key;
31+
32+
protected function setUp(): void
33+
{
34+
parent::setUp();
35+
36+
$this->key = $this->getMockBuilder(Key::class)
37+
->setConstructorArgs([new Secret(random_bytes(32))])
38+
->onlyMethods([])
39+
->getMock()
40+
;
41+
}
42+
43+
public function testCannotCloneKey(): void
44+
{
45+
$this->expectException(\BadMethodCallException::class);
46+
$this->expectExceptionMessage(\sprintf('Cannot clone a %s object.', \get_class($this->key)));
47+
48+
clone $this->key; // @phpstan-ignore expr.resultUnused
49+
}
50+
51+
public function testCannotSerialiseKey(): void
52+
{
53+
$this->expectException(\BadMethodCallException::class);
54+
$this->expectExceptionMessage(\sprintf('Cannot serialise a %s object.', \get_class($this->key)));
55+
56+
serialize($this->key);
57+
}
58+
59+
public function testHidesKeyStringFromDump(): void
60+
{
61+
$secret = new Secret(random_bytes(32));
62+
$this->key = $this->getMockBuilder(Key::class)
63+
->setConstructorArgs([$secret])
64+
->onlyMethods([])
65+
->getMock()
66+
;
67+
68+
ob_start();
69+
var_dump($this->key);
70+
$dump = (string) ob_get_clean();
71+
$print = print_r($this->key, true);
72+
73+
self::assertStringNotContainsString($secret->reveal(), $dump);
74+
self::assertStringContainsString('[redacted]', $dump);
75+
self::assertStringNotContainsString($secret->reveal(), $print);
76+
self::assertStringContainsString('[redacted]', $print);
77+
}
78+
79+
public function testGetKeyString(): void
80+
{
81+
$secret = new Secret(random_bytes(32));
82+
$this->key = $this->getMockBuilder(Key::class)
83+
->setConstructorArgs([$secret])
84+
->onlyMethods([])
85+
->getMock()
86+
;
87+
88+
self::assertSame($secret->reveal(), $this->key->getKeyString());
89+
}
90+
}

0 commit comments

Comments
 (0)