Completed
Push — v3.0.0-dev ( c7f980...54069c )
by Hilmi Erdem
28:15
created

TemporaryAccessService::setPasswordGenerator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * @copyright 2018 Hilmi Erdem KEREN
5
 * @license MIT
6
 */
7
8
namespace Erdemkeren\TemporaryAccess;
9
10
use Illuminate\Contracts\Auth\Authenticatable;
11
12
/**
13
 * Class TemporaryAccessService.
14
 */
15
final class TemporaryAccessService
16
{
17
    /**
18
     * The password generator manager.
19
     *
20
     * @var PasswordGeneratorManagerInterface
21
     */
22
    private $manager;
23
24
    /**
25
     * The encryptor implementation.
26
     *
27
     * @var EncryptorInterface
28
     */
29
    private $encryptor;
30
31
    /**
32
     * The password length.
33
     *
34
     * @var int
35
     */
36
    private $passwordLength;
37
38
    /**
39
     * The default temporary access password generator.
40
     *
41
     * @var string
42
     */
43
    private $defaultGenerator;
44
45
    /**
46
     * The password generator.
47
     *
48
     * @var callable
49
     */
50
    private $passwordGenerator;
51
52
    /**
53
     * The name of the token class being used
54
     * by the temporary access service.
55
     *
56
     * @var string
57
     */
58
    private $tokenClass;
59
60
    /**
61
     * TemporaryAccessService constructor.
62
     *
63
     * @param PasswordGeneratorManagerInterface $manager
64
     * @param EncryptorInterface                $encryptor
65
     * @param string                            $defaultGenerator
66
     * @param int                               $passwordLength
67
     * @param string                            $tokenClass
68
     */
69 8
    public function __construct(
70
        PasswordGeneratorManagerInterface $manager,
71
        EncryptorInterface $encryptor,
72
        string $defaultGenerator,
73
        int $passwordLength,
74
        string $tokenClass
75
    ) {
76 8
        $this->manager = $manager;
77 8
        $this->encryptor = $encryptor;
78 8
        $this->passwordLength = $passwordLength;
79 8
        $this->defaultGenerator = $defaultGenerator;
80
81 8
        if (!class_exists($tokenClass)) {
82 1
            throw new \RuntimeException(
83 1
                "The token implementation [{$tokenClass}] could not be found."
84
            );
85
        }
86
87 8
        $generatorReflection = new \ReflectionClass($tokenClass);
88 8
        if (!$generatorReflection->isInstantiable()) {
89 1
            throw new \RuntimeException(
90 1
                "The token implementation [{$tokenClass}] is not instantiable."
91
            );
92
        }
93
94 8
        if (! is_subclass_of($tokenClass, TokenInterface::class)) {
95 1
            throw new \TypeError(
96 1
                'The token class should be an instance of '.TokenInterface::class
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'The token class should ...s\TokenInterface::class.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
97
            );
98
        }
99
100 8
        $this->tokenClass = $tokenClass;
101 8
    }
102
103
    /**
104
     * Check the temporary access of the authenticable
105
     * with the given cipher text.
106
     *
107
     * @param mixed  $authenticableId
108
     * @param string $token
109
     *
110
     * @return bool
111
     */
112 1
    public function check($authenticableId, string $token): bool
113
    {
114 1
        $token = $this->retrieveByCipherText($authenticableId, $token);
115
116 1
        return (bool) $token && ! $token->expired();
117
    }
118
119
    /**
120
     * Set the active password generator of the temporary access service.
121
     *
122
     * @param string $name
123
     */
124 1
    public function setPasswordGenerator(string $name): void
125
    {
126 1
        $this->passwordGenerator = $this->manager->get($name);
127 1
    }
128
129
    /**
130
     * Create a new temporary access token.
131
     *
132
     * @param Authenticatable|mixed $authenticatableId
133
     * @param int                   $length
134
     *
135
     * @return Token
136
     */
137 2
    public function create($authenticatableId, ?int $length = null): TokenInterface
138
    {
139 2
        $plainText = $this->getPasswordGenerator()($length ?: $this->passwordLength);
140 2
        $cipherText = $this->encryptor->encrypt($plainText);
141
142 2
        if ($authenticatableId instanceof Authenticatable) {
143 2
            $authenticatableId = $authenticatableId->getAuthIdentifier();
144
        }
145
146 2
        return $this->tokenClass::create($authenticatableId, $cipherText, $plainText);
0 ignored issues
show
Bug introduced by
The method create cannot be called on $this->tokenClass (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
147
    }
148
149
    /**
150
     * Retrieve the token of the authenticable
151
     * by the given plain text.
152
     *
153
     * @param mixed  $authenticableId
154
     * @param string $plainText
155
     *
156
     * @return null|TokenInterface
157
     */
158 1
    public function retrieveByPlainText($authenticableId, string $plainText): ?TokenInterface
159
    {
160 1
        return $this->retrieveByCipherText($authenticableId, $this->encryptor->encrypt($plainText));
161
    }
162
163
    /**
164
     * Retrieve the token of the authenticable
165
     * by the given cipher text.
166
     *
167
     * @param mixed  $authenticableId
168
     * @param string $cipherText
169
     *
170
     * @return null|TokenInterface
171
     */
172 3
    public function retrieveByCipherText($authenticableId, string $cipherText): ?TokenInterface
173
    {
174 3
        if ($authenticableId instanceof Authenticatable) {
175 3
            $authenticableId = $authenticableId->getAuthIdentifier();
176
        }
177
178 3
        return $this->tokenClass::retrieveByAttributes([
0 ignored issues
show
Bug introduced by
The method retrieveByAttributes cannot be called on $this->tokenClass (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
179 3
            'authenticable_id' => $authenticableId,
180 3
            'cipher_text'      => $cipherText,
181
        ]);
182
    }
183
184
    /**
185
     * Add a new password generator implementation.
186
     *
187
     * @param string                                     $name
188
     * @param callable|PasswordGeneratorInterface|string $generator
189
     */
190 1
    public function addPasswordGenerator(string $name, $generator): void
191
    {
192 1
        $this->manager->register($name, $generator);
193 1
    }
194
195
    /**
196
     * Get the active password generator.
197
     *
198
     * @return callable
199
     */
200 2
    private function getPasswordGenerator(): callable
201
    {
202 2
        return $this->passwordGenerator ?: $this->passwordGenerator = $this->manager->get($this->defaultGenerator);
203
    }
204
}
205