Token::getDefaultExpiryTime()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * @copyright 2018 Hilmi Erdem KEREN
5
 * @license MIT
6
 */
7
8
namespace Erdemkeren\Otp;
9
10
use Carbon\Carbon;
11
use Illuminate\Notifications\Notification;
12
use Illuminate\Support\Facades\DB;
13
14
/**
15
 * Class Token.
16
 */
17
class Token implements TokenInterface
18
{
19
    /**
20
     * The attributes of the token.
21
     *
22
     * @var array
23
     */
24
    public $attributes = [
25
        'authenticable_id' => null,
26
        'plain_text'       => null,
27
        'expiry_time'      => null,
28
        'cipher_text'      => null,
29
        'created_at'       => null,
30
        'updated_at'       => null,
31
    ];
32
33
    /**
34
     * Token constructor.
35
     *
36
     * @param int|mixed|string $authenticableId
37
     * @param string           $cipherText
38
     * @param null|string      $plainText
39
     * @param null|int         $expiryTime
40
     * @param null|Carbon      $createdAt
41
     * @param null|Carbon      $updatedAt
42
     */
43 20
    public function __construct(
44
        $authenticableId,
45
        string $cipherText,
46
        ?string $plainText = null,
47
        ?int $expiryTime = null,
48
        ?Carbon $createdAt = null,
49
        ?Carbon $updatedAt = null
50
    ) {
51 20
        $now = $this->getNow();
52
53 20
        if (null === $authenticableId) {
54 1
            throw new \LogicException(
55 1
                'The unique identifier of token owner shall not be null.'
56
            );
57
        }
58 20
        $this->attributes['authenticable_id'] = $authenticableId;
59 20
        $this->attributes['plain_text'] = $plainText;
60 20
        $this->attributes['cipher_text'] = $cipherText;
61 20
        $this->attributes['created_at'] = $createdAt ?: $now;
62 20
        $this->attributes['updated_at'] = $updatedAt ?: $now;
63 20
        $this->attributes['expiry_time'] = null === $expiryTime ? $this->getDefaultExpiryTime() : $expiryTime;
64 20
    }
65
66
    /**
67
     * Convert the token to string.
68
     *
69
     * @return string
70
     */
71 2
    public function __toString(): string
72
    {
73 2
        return $this->cipherText();
74
    }
75
76
    /**
77
     * Get the unique identifier of the authenticable
78
     * who owns the token.
79
     *
80
     * @return mixed
81
     */
82 7
    public function authenticableId()
83
    {
84 7
        return $this->attributes['authenticable_id'];
85
    }
86
87
    /**
88
     * Get the token as cipher text.
89
     *
90
     * @return string
91
     */
92 8
    public function cipherText(): string
93
    {
94 8
        return $this->attributes['cipher_text'];
95
    }
96
97
    /**
98
     * Get the token as plain text.
99
     *
100
     * @return null|string
101
     */
102 1
    public function plainText(): ?string
103
    {
104 1
        return $this->attributes['plain_text'];
105
    }
106
107
    /**
108
     * Get the date token created.
109
     *
110
     * @return Carbon
111
     */
112 4
    public function createdAt(): Carbon
113
    {
114 4
        return clone $this->attributes['created_at'];
115
    }
116
117
    /**
118
     * Get the last update date of the token.
119
     *
120
     * @return Carbon
121
     */
122 2
    public function updatedAt(): Carbon
123
    {
124 2
        return clone $this->attributes['updated_at'];
125
    }
126
127
    /**
128
     * Get the expiry time of the token in seconds.
129
     *
130
     * @return int
131
     */
132 8
    public function expiryTime(): int
133
    {
134 8
        return $this->attributes['expiry_time'];
135
    }
136
137
    /**
138
     * Get the date time the token will expire.
139
     *
140
     * @return Carbon
141
     */
142 3
    public function expiresAt(): Carbon
143
    {
144 3
        return (clone $this->createdAt())->addSeconds($this->expiryTime());
145
    }
146
147
    /**
148
     * Get the validity time left for the token.
149
     *
150
     * @return int
151
     */
152 2
    public function timeLeft(): int
153
    {
154 2
        return $this->getNow()->diffInSeconds($this->expiresAt(), false);
155
    }
156
157
    /**
158
     * Determine if the token is expired or not.
159
     *
160
     * @return bool
161
     */
162 1
    public function expired(): bool
163
    {
164 1
        return $this->timeLeft() <= 0;
165
    }
166
167
    /**
168
     * Alias for invalidate.
169
     */
170 1
    public function revoke(): void
171
    {
172 1
        $this->invalidate();
173 1
    }
174
175
    /**
176
     * Invalidate the token.
177
     */
178 2
    public function invalidate(): void
179
    {
180 2
        $this->attributes['expiry_time'] = 0;
181
182 2
        $this->persist();
183 2
    }
184
185
    /**
186
     * Extend the validity of the token.
187
     *
188
     * @param null|int $seconds
189
     *
190
     * @return bool
191
     */
192 2
    public function extend(?int $seconds = null): bool
193
    {
194 2
        $seconds = null === $seconds ? $this->getDefaultExpiryTime() : $seconds;
195
196 2
        $this->attributes['expiry_time'] += $seconds;
197
198 2
        return $this->persist();
199
    }
200
201
    /**
202
     * Refresh the token.
203
     *
204
     * @return bool
205
     */
206 1
    public function refresh(): bool
207
    {
208 1
        return $this->extend(
209 1
            $this->getNow()->diffInSeconds($this->updatedAt())
210
        );
211
    }
212
213
    /**
214
     * Create a new token.
215
     *
216
     * @param $authenticableId
217
     * @param string      $cipherText
218
     * @param null|string $plainText
219
     *
220
     * @return TokenInterface
221
     */
222 2
    public static function create(
223
        $authenticableId,
224
        string $cipherText,
225
        ?string $plainText = null
226
    ): TokenInterface {
227 2
        $token = new self($authenticableId, $cipherText, $plainText);
228
229 2
        $token->persist();
230
231 1
        return $token;
232
    }
233
234
    /**
235
     * Retrieve a token by the given attributes from the storage.
236
     *
237
     * @param array $attributes
238
     *
239
     * @return null|TokenInterface
240
     */
241 2
    public static function retrieveByAttributes(array $attributes): ?TokenInterface
242
    {
243 2
        $query = DB::table(self::getTable());
244
245 2
        foreach ($attributes as $key => $value) {
246 1
            $query->where($key, $value);
247
        }
248
249 2
        if (! $entity = $query->first()) {
250 1
            return null;
251
        }
252
253 1
        return new static(
254 1
            $entity->authenticable_id,
255 1
            $entity->cipher_text,
256 1
            null,
257 1
            $entity->expiry_time,
258 1
            new Carbon($entity->created_at),
259 1
            new Carbon($entity->updated_at)
260
        );
261
    }
262
263
    /**
264
     * Convert the token to a token notification.
265
     *
266
     * @return Notification
267
     */
268 1
    public function toNotification(): Notification
269
    {
270 1
        return new TokenNotification($this);
271
    }
272
273
    /**
274
     * Persist the token in the storage.
275
     *
276
     * @return bool
277
     */
278 6
    protected function persist(): bool
279
    {
280 6
        $this->attributes['updated_at'] = $this->getNow();
281
282 6
        $attributes = $this->attributes;
283 6
        $attributes['created_at'] = $attributes['created_at']->toDateTimeString();
284 6
        $attributes['updated_at'] = $attributes['updated_at']->toDateTimeString();
285
286 6
        if (array_key_exists('plain_text', $attributes)) {
287 6
            unset($attributes['plain_text']);
288
        }
289
290
        try {
291 6
            DB::beginTransaction();
292
293 6
            DB::table(self::getTable())->updateOrInsert([
294 6
                'authenticable_id' => $this->authenticableId(),
295 6
                'cipher_text'      => $this->cipherText(),
296 6
            ], $attributes);
297
298 5
            DB::commit();
299 1
        } catch (\Exception $e) {
300 1
            DB::rollBack();
301
302 1
            throw new \RuntimeException(
303 1
                'Something went wrong while saving the access token.',
304 1
                0,
305 1
                $e
306
            );
307
        }
308
309 5
        return true;
310
    }
311
312
    /**
313
     * Get the date time at the moment.
314
     *
315
     * @return Carbon
316
     */
317 20
    private function getNow(): Carbon
318
    {
319 20
        return Carbon::now();
320
    }
321
322
    /**
323
     * Get the name of the table token will be persisted.
324
     *
325
     * @return string
326
     */
327 8
    private static function getTable(): string
328
    {
329 8
        return config('otp.table');
330
    }
331
332
    /**
333
     * Get the default expiry time in seconds.
334
     *
335
     * @return int
336
     */
337 2
    private function getDefaultExpiryTime(): int
338
    {
339 2
        return config('otp.expires') * 60;
340
    }
341
}
342