PasswordManager   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 12
eloc 29
c 2
b 0
f 0
dl 0
loc 138
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A encrypter() 0 5 1
A decrypt() 0 3 1
A encrypt() 0 10 1
A setModel() 0 9 2
A dynamicKey() 0 3 1
A key() 0 3 1
A checkKey() 0 11 3
A __construct() 0 7 2
1
<?php
2
3
namespace Benjafield\LaravelPasswordManager;
4
5
use Benjafield\LaravelPasswordManager\Exceptions\KeyLengthException;
6
use Exception;
7
use Illuminate\Encryption\Encrypter;
8
use Illuminate\Support\Str;
9
10
class PasswordManager
11
{
12
    /**
13
     * The cipher used for encryption.
14
     */
15
    const CIPHER = 'AES-256-CBC';
16
17
    /**
18
     * Partial key used for encryption of the passwords.
19
     *
20
     * @var string|null
21
     */
22
    protected string|null $key;
23
24
    /**
25
     * The FQN of the class used as the password model.
26
     *
27
     * @var string
28
     */
29
    protected $model;
30
31
    /**
32
     * Create a new Password Manager instance.
33
     *
34
     * @param string|null $key
35
     */
36
    public function __construct(string $key = null)
37
    {
38
        $this->key = is_null($key)
39
            ? config('passwords.key')
40
            : $key;
41
42
        $this->model = Password::class;
43
    }
44
45
    /**
46
     * Set the FQN of the model to be used for passwords.
47
     *
48
     * @throws Exception
49
     */
50
    public function setModel($model): self
51
    {
52
        if (! class_exists($model)) {
53
            throw new Exception("Class [$model] does not exist.");
54
        }
55
56
        $this->model = $model;
57
58
        return $this;
59
    }
60
61
    /**
62
     * Check that the encryption key has been set.
63
     *
64
     * @throws Exception
65
     * @return bool
66
     */
67
    protected function checkKey(): bool
68
    {
69
        if (is_null($this->key)) {
70
            throw new Exception("The encryption key is not valid.");
71
        }
72
73
        if (strlen($this->key) !== 16) {
74
            throw new KeyLengthException("The specified key is not the correct size.");
75
        }
76
77
        return true;
78
    }
79
80
    /**
81
     * Create a partial dynamic key to be stored with a password.
82
     *
83
     * @param int $length
84
     * @return string
85
     */
86
    public function dynamicKey(int $length = 16): string
87
    {
88
        return Str::random($length);
89
    }
90
91
    /**
92
     * Get the full key to be used when encrypting a password.
93
     *
94
     * @param string $dynamic
95
     * @return string
96
     */
97
    protected function key(string $dynamic): string
98
    {
99
        return $this->key . $dynamic;
100
    }
101
102
    /**
103
     * Return a new Laravel Encrypter instance with the key and cipher set.
104
     *
105
     * @param string $dynamic
106
     * @return Encrypter
107
     * @throws Exception
108
     */
109
    public function encrypter(string $dynamic): Encrypter
110
    {
111
        $this->checkKey();
112
113
        return new Encrypter($this->key($dynamic), static::CIPHER);
114
    }
115
116
    /**
117
     * Encrypt a string into a storable password.
118
     *
119
     * @param string $name
120
     * @param string $value
121
     * @return mixed
122
     * @throws Exception
123
     */
124
    public function encrypt(string $name, string $value): mixed
125
    {
126
        $dynamic = $this->dynamicKey();
127
128
        return call_user_func(
129
            $this->model . '::make',
130
            $name,
131
            $dynamic,
132
            $this->encrypter($dynamic)->encrypt($value),
133
            $value
134
        );
135
    }
136
137
    /**
138
     * Decrypt a stored password back to the original string.
139
     *
140
     * @param string $dynamic
141
     * @param string $value
142
     * @return string
143
     * @throws Exception
144
     */
145
    public function decrypt(string $dynamic, string $value): string
146
    {
147
        return $this->encrypter($dynamic)->decrypt($value);
148
    }
149
}