LocalFileAccount::getKeyName()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Rogierw\RwAcme\Support;
4
5
use Rogierw\RwAcme\Exceptions\LetsEncryptClientException;
6
use Rogierw\RwAcme\Interfaces\AcmeAccountInterface;
7
8
class LocalFileAccount implements AcmeAccountInterface
9
{
10
    private string $accountName;
11
12
    public function __construct(private string $accountKeysPath)
13
    {
14
        // Make sure the path ends with a slash.
15
        $this->accountKeysPath = rtrim($this->accountKeysPath, '/').'/';
16
        $this->accountName = 'account_'.substr(hash('sha256', $this->accountKeysPath), 0, 16);
17
    }
18
19
    public function getPrivateKey(): string
20
    {
21
        return $this->getKey('private');
22
    }
23
24
    public function getPublicKey(): string
25
    {
26
        return $this->getKey('public');
27
    }
28
29
    public function exists(): bool
30
    {
31
        if (is_dir($this->accountKeysPath)) {
32
            return is_file($this->accountKeysPath.$this->getKeyName('private'))
33
                && is_file($this->accountKeysPath.$this->getKeyName('public'));
34
        }
35
36
        return false;
37
    }
38
39
    public function generateNewKeys(string $keyType = 'RSA'): bool
40
    {
41
        if ($keyType !== 'RSA') {
42
            throw new LetsEncryptClientException('Key type is not supported.');
43
        }
44
45
        $concurrentDirectory = rtrim($this->accountKeysPath, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
46
47
        if (!is_dir($concurrentDirectory) && !mkdir($concurrentDirectory) && !is_dir($concurrentDirectory)) {
48
            throw new LetsEncryptClientException(sprintf('Directory "%s" was not created', $concurrentDirectory));
49
        }
50
51
        $keys = CryptRSA::generate();
52
53
        if (!isset($keys['privateKey'], $keys['publicKey'])) {
54
            throw new LetsEncryptClientException('Key generation failed.');
55
        }
56
57
        $privateKeyPath = $concurrentDirectory.$this->getKeyName('private');
58
        $publicKeyPath = $concurrentDirectory.$this->getKeyName('public');
59
60
        if (file_put_contents($privateKeyPath, $keys['privateKey']) === false ||
61
            file_put_contents($publicKeyPath, $keys['publicKey']) === false) {
62
            throw new LetsEncryptClientException('Failed to write keys to files.');
63
        }
64
65
        return true;
66
    }
67
68
    protected function getKey(string $type): string
69
    {
70
        $filePath = $this->accountKeysPath.$this->getKeyName($type);
71
72
        if (!file_exists($filePath)) {
73
            throw new LetsEncryptClientException(sprintf('[%s] File does not exist', $filePath));
74
        }
75
76
        $content = file_get_contents($filePath);
77
78
        if ($content === false) {
79
            throw new LetsEncryptClientException(sprintf('[%s] Failed to get contents of the file', $filePath));
80
        }
81
82
        return $content;
83
    }
84
85
    private function getKeyName(string $type): string
86
    {
87
        if (empty($this->accountName)) {
88
            throw new LetsEncryptClientException('Account name is not set.');
89
        }
90
91
        return sprintf('%s-%s.pem', $this->accountName, $type);
92
    }
93
}
94