Passed
Push — master ( b5ac42...6dbb24 )
by Marco
36s
created

Builder::convertDate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 6
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
4
 *
5
 * @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
6
 */
7
8
declare(strict_types=1);
9
10
namespace Lcobucci\JWT\Token;
11
12
use DateTimeImmutable;
13
use Lcobucci\Jose\Parsing;
14
use Lcobucci\JWT\Builder as BuilderInterface;
15
use Lcobucci\JWT\Signer;
16
use Lcobucci\JWT\Signer\Key;
17
18
/**
19
 * This class makes easier the token creation process
20
 *
21
 * @author Luís Otávio Cobucci Oblonczyk <[email protected]>
22
 * @since 0.1.0
23
 */
24
final class Builder implements BuilderInterface
25
{
26
    /**
27
     * The token header
28
     *
29
     * @var array
30
     */
31
    private $headers = ['typ'=> 'JWT', 'alg' => 'none'];
32
33
    /**
34
     * The token claim set
35
     *
36
     * @var array
37
     */
38
    private $claims = [];
39
40
    /**
41
     * The data encoder
42
     *
43
     * @var Parsing\Encoder
44
     */
45
    private $encoder;
46
47
    /**
48
     * Initializes a new builder
49
     */
50 1
    public function __construct(Parsing\Encoder $encoder)
51
    {
52 1
        $this->encoder = $encoder;
53 1
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 3
    public function permittedFor(string $audience): BuilderInterface
59
    {
60 3
        $audiences = $this->claims[RegisteredClaims::AUDIENCE] ?? [];
61
62 3
        if (!in_array($audience, $audiences)) {
63 3
            $audiences[] = $audience;
64
        }
65
66 3
        return $this->setClaim(RegisteredClaims::AUDIENCE, $audiences);
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 2
    public function expiresAt(DateTimeImmutable $expiration): BuilderInterface
73
    {
74 2
        return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration);
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80 2
    public function identifiedBy(string $id): BuilderInterface
81
    {
82 2
        return $this->setClaim(RegisteredClaims::ID, $id);
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 2
    public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface
89
    {
90 2
        return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt);
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96 2
    public function issuedBy(string $issuer): BuilderInterface
97
    {
98 2
        return $this->setClaim(RegisteredClaims::ISSUER, $issuer);
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 2
    public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface
105
    {
106 2
        return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 2
    public function relatedTo(string $subject): BuilderInterface
113
    {
114 2
        return $this->setClaim(RegisteredClaims::SUBJECT, $subject);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 2
    public function withHeader(string $name, $value): BuilderInterface
121
    {
122 2
        $this->headers[$name] = $value;
123
124 2
        return $this;
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130 3
    public function withClaim(string $name, $value): BuilderInterface
131
    {
132 3
        if (in_array($name, RegisteredClaims::ALL, true)) {
133 1
            throw new \InvalidArgumentException('You should use the correct methods to set registered claims');
134
        }
135
136 2
        return $this->setClaim($name, $value);
137
    }
138
139 17
    private function setClaim(string $name, $value): BuilderInterface
140
    {
141 17
        $this->claims[$name] = $value;
142
143 17
        return $this;
144
    }
145
146
    private function encode(array $items): string
147
    {
148
        return $this->encoder->base64UrlEncode(
149
            $this->encoder->jsonEncode($items)
150
        );
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156
    public function getToken(Signer $signer, Key $key): Plain
157
    {
158
        $headers = $this->headers;
159
        $headers['alg'] = $signer->getAlgorithmId();
160
161
        $encodedHeaders = $this->encode($headers);
162
        $encodedClaims = $this->encode($this->formatClaims($this->claims));
163
164
        $signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key);
165
        $encodedSignature = $this->encoder->base64UrlEncode($signature);
166
167
        return new Plain(
168
            new DataSet($headers, $encodedHeaders),
169
            new DataSet($this->claims, $encodedClaims),
170
            new Signature($signature, $encodedSignature)
171
        );
172
    }
173
174
    private function formatClaims(array $claims): array
175
    {
176
        if (isset($claims[RegisteredClaims::AUDIENCE][0]) && !isset($claims[RegisteredClaims::AUDIENCE][1])) {
177
            $claims[RegisteredClaims::AUDIENCE] = $claims[RegisteredClaims::AUDIENCE][0];
178
        }
179
180
        foreach (array_intersect(RegisteredClaims::DATE_CLAIMS, array_keys($claims)) as $claim) {
181
            $claims[$claim] = $this->convertDate($claims[$claim]);
182
        }
183
184
        return $claims;
185
    }
186
187
    /**
188
     * @return int|string
189
     */
190
    private function convertDate(DateTimeImmutable $date)
191
    {
192
        $seconds = $date->format('U');
193
        $microseconds = $date->format('u');
194
195
        if ((int) $microseconds === 0) {
196
            return (int) $seconds;
197
        }
198
199
        return $seconds . '.' . $microseconds;
200
    }
201
}
202