Tiqr_UserSecretStorage_Abstract::getSecret()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 25
ccs 13
cts 13
cp 1
rs 9.8666
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
use Psr\Log\LoggerInterface;
4
5
abstract class Tiqr_UserSecretStorage_Abstract implements Tiqr_UserSecretStorage_Interface, Tiqr_HealthCheck_Interface
6
{
7
    protected LoggerInterface $logger;
8
    private Tiqr_UserSecretStorage_Encryption_Interface $encryption;
9
10
    /**
11
     * @var array() of type_id (prefix) => Tiqr_UserSecretStorage_Encryption_Interface
12
     */
13
    private array $decryption;
14
15 21
    public function __construct(LoggerInterface $logger, Tiqr_UserSecretStorage_Encryption_Interface $encryption, array $decryption = array())
16
    {
17 21
        $this->logger = $logger;
18 21
        $this->encryption = $encryption;
19 21
        $this->decryption = $decryption;
20
    }
21
22
    /**
23
     * Get the user's secret
24
     * @param String $userId
25
     * @return String The user's secret
26
     * @throws Exception
27
     */
28
    abstract protected function getUserSecret(string $userId): string;
29
30
    /**
31
     * Set the user's secret
32
     *
33
     * @param String $userId
34
     * @param String $secret The user's secret
35
     * @throws Exception
36
     */
37
    abstract protected function setUserSecret(string $userId, string $secret): void;
38
39
40
    /**
41
     * Get the user's secret
42
     * @param String $userId
43
     * @return String The user's secret
44
     * @throws Exception
45
     */
46 6
    public function getSecret(string $userId): string
47
    {
48 6
        $encryptedSecret = $this->getUserSecret($userId);
49 6
        $pos = strpos($encryptedSecret, ':');
50 6
        if ($pos === false) {
51
            // If the secret is not prefixed with the encryption type_id, it is assumed to be unencrypted.
52 2
            $this->logger->info("Secret for user '$userId' is not prefixed with the encryption type, assuming that it is not encrypted");
53 2
            return $encryptedSecret;
54
        }
55
56 6
        $prefix = substr($encryptedSecret, 0, $pos);
57 6
        if ($prefix === $this->encryption->get_type()) {
58
            // Decrypt the secret if it is prefixed with the current encryption type
59
            // Remove the encryption type prefix before decrypting
60 6
            return $this->encryption->decrypt( substr($encryptedSecret, $pos+1) );
61
        }
62
63
        // Check the decryption array for the encryption type to see if there is an encryption
64
        // instance defined for it. If so, use that to decrypt the secret.
65 2
        if (isset($this->decryption[$prefix])) {
66 2
            return $this->decryption[$prefix]->decrypt( substr($encryptedSecret, $pos+1) );
67
        }
68
69 2
        $this->logger->error("Secret for user '$userId' is encrypted with unsupported encryption type '$prefix'");
70 2
        throw new RuntimeException("Secret for user '$userId' is encrypted with an unsupported encryption type");
71
    }
72
73
    /**
74
     * Store a secret for a user.
75
     * @param String $userId
76
     * @param String $secret
77
     * @throws Exception
78
     */
79 8
    public function setSecret(string $userId, string $secret): void
80
    {
81 8
        $encryptedSecret = $this->encryption->encrypt($secret);
82
        // Prefix the user secret with the encryption type
83 8
        $this->setUserSecret($userId, $this->encryption->get_type() . ':' . $encryptedSecret);
84
    }
85
86
    /**
87
     * @see Tiqr_HealthCheck_Interface::healthCheck()
88
     */
89
    public function healthCheck(string &$statusMessage = ''): bool
90
    {
91
        return true;    // Health check is always successful when not implemented
92
    }
93
}
94