Completed
Push — master ( 96bb9e...dc511e )
by Hilmi Erdem
02:05
created

TemporaryAccessService::checkAndProlong()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 3
crap 2
1
<?php
2
3
namespace Erdemkeren\TemporaryAccess;
4
5
use Carbon\Carbon;
6
use Erdemkeren\TemporaryAccess\Contracts\TokenInterface;
7
use Erdemkeren\TemporaryAccess\Contracts\AccessTokenInterface;
8
use Erdemkeren\TemporaryAccess\Contracts\TokenGeneratorInterface;
9
use Erdemkeren\TemporaryAccess\Contracts\AccessTokenRepositoryInterface;
10
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
11
12
final class TemporaryAccessService
13
{
14
    /**
15
     * The access token repository implementation.
16
     *
17
     * @var AccessTokenRepositoryInterface
18
     */
19
    private $repository;
20
21
    /**
22
     * The token generator implementation.
23
     *
24
     * @var TokenGeneratorInterface
25
     */
26
    private $tokenGenerator;
27
28
    /**
29
     * TemporaryAccessService constructor.
30
     *
31
     * @param AccessTokenRepositoryInterface $repository     The access token repository implementation.
32
     * @param TokenGeneratorInterface        $tokenGenerator The token generator implementation.
33
     */
34 24
    public function __construct(AccessTokenRepositoryInterface $repository, TokenGeneratorInterface $tokenGenerator)
35
    {
36 24
        $this->repository = $repository;
37 24
        $this->tokenGenerator = $tokenGenerator;
38 24
    }
39
40
    /**
41
     * Retrieve an access token from the storage by the actual token.
42
     *
43
     * @param AuthenticatableContract $authenticatable The authenticatable who owns the token.
44
     * @param string|TokenInterface   $encryptedText   The token of the authenticatable.
45
     *
46
     * @return null|AccessTokenInterface
47
     */
48 16
    public function retrieve(AuthenticatableContract $authenticatable, $encryptedText)
49
    {
50 16
        $authenticatableIdentifier = $authenticatable->getAuthIdentifier();
51
52 16
        return $this->retrieveFromRepository($authenticatableIdentifier, (string) $encryptedText);
53
    }
54
55
    /**
56
     * Retrieve an access token from the storage by the plain token.
57
     *
58
     * @param AuthenticatableContract $authenticatable The authenticatable who owns the token.
59
     * @param string|TokenInterface   $plainText       The token of the authenticatable.
60
     *
61
     * @return null|AccessTokenInterface
62
     */
63 1
    public function retrieveUsingPlainText(AuthenticatableContract $authenticatable, $plainText)
64
    {
65 1
        if (! $plainText instanceof TokenInterface) {
66 1
            $plainText = $this->makeTokenFromPlainText($plainText);
67 1
        }
68
69 1
        return $this->retrieve($authenticatable, $plainText);
70
    }
71
72
    /**
73
     * Determine if an access token exists and is valid.
74
     *
75
     * @param  AuthenticatableContract $authenticatable The authenticatable who owns the token.
76
     * @param  string|TokenInterface   $encryptedText   The encrypted token of the authenticatable.
77
     *
78
     * @return bool
79
     */
80 6
    public function check(AuthenticatableContract $authenticatable, $encryptedText)
81
    {
82 6
        return (bool) $this->retrieve($authenticatable, $encryptedText);
83
    }
84
85
    /**
86
     * Determine if an access token exists and is valid.
87
     *
88
     * @param  AuthenticatableContract $authenticatable The authenticatable who owns the token.
89
     * @param  string|TokenInterface   $plainText       The plain token of the authenticatable.
90
     *
91
     * @return bool
92
     */
93 2
    public function checkUsingPlainText(AuthenticatableContract $authenticatable, $plainText)
94
    {
95 2
        $token = $this->makeTokenFromPlainText($plainText);
0 ignored issues
show
Bug introduced by
It seems like $plainText defined by parameter $plainText on line 93 can also be of type object<Erdemkeren\Tempor...ntracts\TokenInterface>; however, Erdemkeren\TemporaryAcce...akeTokenFromPlainText() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
96
97 2
        return $this->check($authenticatable, $token);
98
    }
99
100
    /**
101
     * Determine if an access token record exists and prolong the expire date if so.
102
     * If no prolong time given, we will reset the original expire time.
103
     *
104
     * @param  AuthenticatableContract $authenticatable The authenticatable who owns the token.
105
     * @param  string|TokenInterface   $encryptedText   The token of the authenticatable.
106
     * @param  int|null                $prolong         The prolong time in minutes.
107
     *
108
     * @return bool|AccessTokenInterface
109
     */
110 6
    public function checkAndProlong(AuthenticatableContract $authenticatable, $encryptedText, $prolong = null)
111
    {
112 6
        if (! $accessToken = $this->retrieve($authenticatable, $encryptedText)) {
113 1
            return false;
114
        }
115
116 5
        return $this->prolongAndUpdateAccessToken($accessToken, $prolong);
117
    }
118
119
    /**
120
     * Determine if an access token record exists and prolong the expire date if so.
121
     * If no prolong time given, we will reset the original expire time.
122
     *
123
     * @param  AuthenticatableContract $authenticatable The authenticatable who owns the token.
124
     * @param  string|TokenInterface   $plainText       The token of the authenticatable.
125
     * @param  int|null                $prolong         The prolong time in minutes.
126
     *
127
     * @return bool|AccessTokenInterface
128
     */
129 1
    public function checkUsingPlainTextAndProlong(AuthenticatableContract $authenticatable, $plainText, $prolong = null)
130
    {
131 1
        $token = $this->makeTokenFromPlainText($plainText);
0 ignored issues
show
Bug introduced by
It seems like $plainText defined by parameter $plainText on line 129 can also be of type object<Erdemkeren\Tempor...ntracts\TokenInterface>; however, Erdemkeren\TemporaryAcce...akeTokenFromPlainText() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
132
133 1
        return $this->checkAndProlong($authenticatable, $token, $prolong);
134
    }
135
136
    /**
137
     * Generate a new access token in the storage and get the token.
138
     *
139
     * @param  AuthenticatableContract $authenticatable The authenticatable who owns the token.
140
     * @param  Carbon|null             $expiresAt       The optional expire date of the access token.
141
     *
142
     * @return AccessTokenInterface
143
     */
144 2
    public function generate(AuthenticatableContract $authenticatable, Carbon $expiresAt = null)
145
    {
146 2
        $token = $this->tokenGenerator->generate();
147 2
        $authenticatableId = $authenticatable->getAuthIdentifier();
148 2
        $expiresAt = $expiresAt ? (string) $expiresAt : null;
149
150 2
        $payload = (array) $this->repository->store($authenticatableId, (string) $token, $expiresAt);
151
152 2
        return $this->makeAccessToken($token, $payload);
153
    }
154
155
    /**
156
     * Update an access token in the storage.
157
     *
158
     * @param  AccessTokenInterface $accessToken The access token to be updated.
159
     *
160
     * @return bool
161
     */
162 6
    public function update(AccessTokenInterface $accessToken)
163
    {
164 6
        $token = (string) $accessToken;
165 6
        $expiresAt = (string) $accessToken->expiresAt();
166 6
        $authenticatableId = $accessToken->authenticatableId();
167
168 6
        return $this->repository->update($authenticatableId, $token, $expiresAt);
169
    }
170
171
    /**
172
     * Revive an token from the given plain text.
173
     *
174
     * @param  string $plainText The plain text to be converted back to token instance.
175
     *
176
     * @return TokenInterface
177
     */
178 5
    public function makeTokenFromPlainText($plainText)
179
    {
180 5
        return $this->tokenGenerator->fromPlain($plainText);
181
    }
182
183
    /**
184
     * Revive an token from the given plain text.
185
     *
186
     * @param  string $encryptedText The encrypted token to be converted back to token instance.
187
     *
188
     * @return TokenInterface
189
     */
190 12
    public function makeTokenFromEncryptedText($encryptedText)
191
    {
192 12
        return $this->tokenGenerator->fromEncrypted($encryptedText);
193
    }
194
195
    /**
196
     * Retrieve the first resource by the given attributes.
197
     *
198
     * @param  array $queryParams The key - value pairs to match.
199
     * @param  array $attributes  The attributes to be returned from the storage.
200
     *
201
     * @return AccessTokenInterface|null
202
     */
203 2
    public function retrieveByAttributes(array $queryParams, array $attributes = ['*'])
204
    {
205 2
        if (! $attributes = $this->repository->retrieveByAttributes($queryParams, $attributes)) {
206 1
            return;
207
        }
208
209 1
        return $attributes ? $this->makeAccessToken((array) $attributes) : null;
210
    }
211
212
    /**
213
     * Delete the given access token from the storage.
214
     *
215
     * @param  AccessTokenInterface|string $accessToken The access token or the encrypted text to be deleted.
216
     *
217
     * @return bool
218
     */
219 1
    public function delete($accessToken)
220
    {
221 1
        return (bool) $this->repository->delete($accessToken->authenticatableId(), (string) $accessToken);
1 ignored issue
show
Bug introduced by
It seems like $accessToken is not always an object, but can also be of type string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
222
    }
223
224
    /**
225
     * Delete the expired access tokens from the storage.
226
     *
227
     * @return void
228
     */
229 1
    public function deleteExpired()
230
    {
231 1
        $this->repository->deleteExpired();
232 1
    }
233
234
    /**
235
     * Retrieve an access token from the storage.
236
     *
237
     * @param  int    $authenticatableId
238
     * @param  string $encryptedText
239
     *
240
     * @return GenericAccessToken|null
241
     */
242 16
    private function retrieveFromRepository($authenticatableId, $encryptedText)
243 1
    {
244 16
        if (! $attributes = $this->repository->retrieve($authenticatableId, $encryptedText)) {
245 5
            return;
246
        }
247
248 11
        return $this->makeAccessToken((array) $attributes);
249
    }
250
251
    /**
252
     * Prolong the access token then update it in the storage.
253
     *
254
     * @param  AccessTokenInterface $accessToken
255
     * @param  int|null             $prolong
256
     *
257
     * @return bool|AccessTokenInterface
258
     */
259 5
    private function prolongAndUpdateAccessToken(AccessTokenInterface $accessToken, $prolong = null)
260
    {
261 5
        $accessToken = $this->prolongAccessToken($accessToken, $prolong);
262
263 5
        if ($this->update($accessToken)) {
264 4
            return $accessToken;
265
        }
266
267 1
        return false;
268
    }
269
270
    /**
271
     * Prolong an access token.
272
     *
273
     * @param AccessTokenInterface $accessToken
274
     * @param int|null             $prolong
275
     *
276
     * @return AccessTokenInterface
277
     */
278 5
    private function prolongAccessToken(AccessTokenInterface $accessToken, $prolong = null)
279
    {
280 5
        $prolong = $prolong ? $prolong * 60 : $this->getNow()->diffInSeconds($accessToken->createdAt());
281
282 5
        return $accessToken->prolong($prolong);
283
    }
284
285
    /**
286
     * Get a new access token instance with the given attributes.
287
     *
288
     * @param array|TokenInterface $token
289
     * @param array                $attributes
290
     *
291
     * @return GenericAccessToken
292
     */
293 14
    private function makeAccessToken($token, array $attributes = [])
294
    {
295 14
        if (! $token instanceof TokenInterface) {
296 12
            $attributes = $token;
297
298 12
            $token = $this->makeTokenFromEncryptedText(array_pull($attributes, 'token'));
299 12
        }
300
301 14
        return new GenericAccessToken($token, $attributes);
302
    }
303
304
    /**
305
     * Get the current UNIX timestamp.
306
     *
307
     * @return Carbon
308
     */
309 2
    private function getNow()
310
    {
311 2
        return Carbon::now();
312
    }
313
}
314