Passed
Push — develop ( cf941c...3cdc76 )
by nguereza
01:41
created

BaseToken::getExpiresIn()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Platine OAuth2
5
 *
6
 * Platine OAuth2 is a library that implements the OAuth2 specification
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine OAuth2
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
declare(strict_types=1);
32
33
namespace Platine\OAuth2\Entity;
34
35
use DateTime;
36
use DateTimeInterface;
37
38
/**
39
 * Provide basic functionality for both access tokens, refresh tokens and authorization codes
40
 * Please note that scopes are stored as a string instead using
41
 * associations to scope entities, mainly for performance reasons and to avoid useless database calls.
42
 *
43
 * @class BaseToken
44
 * @package Platine\OAuth2\Entity
45
 */
46
abstract class BaseToken
47
{
48
    /**
49
     * The token value
50
     * @var string
51
     */
52
    protected string $token;
53
54
    /**
55
     * The client to use
56
     * @var Client|null
57
     */
58
    protected ?Client $client = null;
59
60
    /**
61
     * The token owner
62
     * @var TokenOwnerInterface|null
63
     */
64
    protected ?TokenOwnerInterface $owner = null;
65
66
    /**
67
     * The token expires at
68
     * @var DateTimeInterface|null
69
     */
70
    protected ?DateTimeInterface $expireAt = null;
71
72
    /**
73
     * The scopes associated with the token
74
     * @var array<string>
75
     */
76
    protected array $scopes = [];
77
78
    /**
79
     * Can not create object of this class directly
80
     */
81
    private function __construct()
82
    {
83
    }
84
85
    /**
86
     * Create token using given data
87
     * @param array<string, mixed> $data
88
     * @return self
89
     */
90
    public static function hydrate(array $data): self
91
    {
92
        $token = new static();
93
        $token->token = $data['token'];
94
        $token->owner = $data['owner'];
95
        $token->client = $data['client'];
96
        $token->scopes = (array) $data['scopes'];
97
        $token->expireAt = $data['expires_at'];
98
99
        return $token;
100
    }
101
102
    /**
103
     * Return the token owner
104
     * @return TokenOwnerInterface|null
105
     */
106
    public function getOwner(): ?TokenOwnerInterface
107
    {
108
        return $this->owner;
109
    }
110
111
    /**
112
     * Return the client
113
     * @return Client|null
114
     */
115
    public function getClient(): ?Client
116
    {
117
        return $this->client;
118
    }
119
120
    /**
121
     * Return the token value
122
     * @return string
123
     */
124
    public function getToken(): string
125
    {
126
        return $this->token;
127
    }
128
129
    /**
130
     * Return the expires at
131
     * @return DateTimeInterface|null
132
     */
133
    public function getExpireAt(): ?DateTimeInterface
134
    {
135
        return $this->expireAt ? clone $this->expireAt : null;
136
    }
137
138
139
    /**
140
     * Return the token expires in (seconds)
141
     * (if expired, will return a negative value)
142
     * @return int
143
     */
144
    public function getExpiresIn(): int
145
    {
146
        if ($this->expireAt === null) {
147
            return 0;
148
        }
149
150
        return $this->expireAt->getTimestamp() - (new DateTime())->getTimestamp();
151
    }
152
153
    /**
154
     * Whether the token is expired
155
     * @return bool
156
     */
157
    public function isExpired(): bool
158
    {
159
        if ($this->expireAt === null) {
160
            return true;
161
        }
162
163
        return $this->expireAt->getTimestamp() <= (new DateTime())->getTimestamp();
164
    }
165
166
    /**
167
     * Return the scopes
168
     *
169
     * @return array<string>
170
     */
171
    public function getScopes(): array
172
    {
173
        return $this->scopes;
174
    }
175
176
    /**
177
     * Match the scopes of the token with the one provided in the parameter
178
     * @param string|array<string> $scopes
179
     * @return bool
180
     */
181
    public function matchScopes($scopes): bool
182
    {
183
        if (is_string($scopes)) {
184
            $scopes = explode(' ', $scopes);
185
        }
186
        $diff = array_diff($scopes, $this->scopes);
187
188
        return count($diff) === 0;
189
    }
190
191
    /**
192
     * Check if the token is valid, according to the
193
     * given scope(s) and expiration dates
194
     * @param string|array<string> $scopes
195
     * @return bool
196
     */
197
    public function isValid($scopes): bool
198
    {
199
        if ($this->isExpired()) {
200
            return false;
201
        }
202
203
        if (!empty($scopes) && $this->matchScopes($scopes) === false) {
204
            return false;
205
        }
206
207
        return true;
208
    }
209
210
    /**
211
     * Create new token
212
     * @param int $ttl
213
     * @param TokenOwnerInterface|null $owner
214
     * @param Client|null $client
215
     * @param array<string>|Scope[]|null $scopes
216
     * @return self
217
     */
218
    protected static function createNew(
219
        int $ttl,
220
        ?TokenOwnerInterface $owner = null,
221
        ?Client $client = null,
222
        ?array $scopes = null
223
    ): self {
224
        if (is_array($scopes)) {
225
            $scopes = array_map(fn($scope) => (string) $scope, $scopes);
226
        }
227
228
        $token = new static();
229
        $token->token = bin2hex(random_bytes(20));
230
        $token->owner = $owner;
231
        $token->client = $client;
232
        $token->scopes = $scopes ?? [];
233
        $token->expireAt = $ttl ? (new DateTime())->modify(sprintf('+%d seconds', $ttl)) : null;
234
235
        return $token;
236
    }
237
}
238