Passed
Push — master ( 436c58...98654e )
by Anton
06:21 queued 03:52
created

TokenStorage::load()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
eloc 12
c 1
b 1
f 1
dl 0
loc 26
rs 8.8333
cc 7
nc 5
nop 1
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Auth\Cycle;
13
14
use Cycle\ORM\ORMInterface;
15
use Cycle\ORM\Transaction;
16
use Spiral\Auth\Exception\TokenStorageException;
17
use Spiral\Auth\TokenInterface;
18
use Spiral\Auth\TokenStorageInterface;
19
20
/**
21
 * Provides the ability to fetch token information from the database via Cycle ORM.
22
 */
23
final class TokenStorage implements TokenStorageInterface
24
{
25
    /** @var ORMInterface */
26
    private $orm;
27
28
    /**
29
     * @param ORMInterface $orm
30
     */
31
    public function __construct(ORMInterface $orm)
32
    {
33
        $this->orm = $orm;
34
    }
35
36
    /**
37
     * @inheritDoc
38
     */
39
    public function load(string $id): ?TokenInterface
40
    {
41
        if (strpos($id, ':') === false) {
42
            return null;
43
        }
44
45
        list($pk, $hash) = explode(':', $id, 2);
46
47
        if (!is_numeric($pk)) {
48
            return null;
49
        }
50
51
        /** @var TokenInterface $token */
52
        $token = $this->orm->getRepository(Token::class)->findByPK((int)$pk);
53
54
        if ($token === null || $token->getID() !== $id) {
55
            // hijacked or deleted
56
            return null;
57
        }
58
59
        if ($token->getExpiresAt() !== null && $token->getExpiresAt() < new \DateTime()) {
60
            $this->delete($token);
61
            return null;
62
        }
63
64
        return $token;
65
    }
66
67
    /**
68
     * @inheritDoc
69
     */
70
    public function create(array $payload, \DateTimeInterface $expiresAt = null): TokenInterface
71
    {
72
        try {
73
            $token = new Token($this->randomHash(128), $payload, new \DateTimeImmutable(), $expiresAt);
74
75
            (new Transaction($this->orm))->persist($token)->run();
76
77
            return $token;
78
        } catch (\Throwable $e) {
79
            throw new TokenStorageException('Unable to create token', $e->getCode(), $e);
80
        }
81
    }
82
83
    /**
84
     * @inheritDoc
85
     */
86
    public function delete(TokenInterface $token): void
87
    {
88
        try {
89
            (new Transaction($this->orm))->delete($token)->run();
90
        } catch (\Throwable $e) {
91
            throw new TokenStorageException('Unable to delete token', $e->getCode(), $e);
92
        }
93
    }
94
95
    /**
96
     * @param int $length
97
     * @return string
98
     *
99
     * @throws \Exception
100
     */
101
    private function randomHash(int $length): string
102
    {
103
        return substr(bin2hex(random_bytes($length)), 0, $length);
104
    }
105
}
106