Passed
Push — b2.0.0 ( 3f7ded...cd0f2e )
by Sebastian
02:11
created

HmacTokenProvider   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 6
eloc 24
c 1
b 0
f 0
dl 0
loc 93
ccs 23
cts 23
cp 1
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A validate() 0 31 4
A getToken() 0 9 1
1
<?php
2
3
/**
4
 * Linna Cross-site Request Forgery Guard
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2020, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\CsrfGuard\Provider;
13
14
use Linna\CsrfGuard\Exception\BadExpireException;
15
use Linna\CsrfGuard\Exception\BadExpireTrait;
16
17
/**
18
 * Csrf HMAC Based Token Pattern Provider.
19
 *
20
 * It use hash_hmac with sha3-384 algorithm.
21
 */
22
class HmacTokenProvider implements TokenProviderInterface
23
{
24
    use BadExpireTrait;
25
26
    /**
27
     * @var string $key Secret key for the hmac
28
     */
29
    private string $key = '';
30
31
    /**
32
     * @var string $value Value will be hashed inside token
33
     */
34
    private string $value = '';
35
36
    /**
37
     * @var int $expire Token validity in seconds, default 600 -> 10 minutes
38
     */
39
    private int $expire = 0;
40
41
    /**
42
     * Class constructor.
43
     *
44
     * @param string $value     Value will be hashed inside token
45
     * @param string $key       Secret key for the hmac
46
     * @param int    $expire    Token validity in seconds, default 600 -> 10 minutes
47
     *
48
     * @throws BadExpireException If $expire is less than 0 and greater than 86400
49
     */
50 19
    public function __construct(string $value, string $key, int $expire = 600)
51
    {
52
        // from BadExpireTrait
53
        /** @throws BadExpireException */
54 19
        $this->checkBadExpire($expire);
55
56 17
        $this->key = $key;
57 17
        $this->value = $value;
58 17
        $this->expire = $expire;
59 17
    }
60
61
    /**
62
     * Return new Hmac Token.
63
     *
64
     * @return string
65
     */
66 3
    public function getToken(): string
67
    {
68
        //get the time for the token
69 3
        $time = \base_convert((string) \time(), 10, 16);
70
        //random bytes for avoid to wait one second to get a different token
71 3
        $random = \bin2hex(\random_bytes(2));
72
73
        //return the token
74 3
        return \hash_hmac('sha3-384', $this->value.$time.$random, $this->key).$time.$random;
75
    }
76
77
    /**
78
     * Validate Hmac Token.
79
     *
80
     * @param string $token Token must be validated.
81
     *
82
     * @return bool
83
     */
84 15
    public function validate(string $token): bool
85
    {
86
        //check for void token
87 15
        if ($token === "") {
88 1
            return false;
89
        }
90
91
        //hmac present in token
92 14
        $hmac_token = \substr($token, 0, 96);
93
        //token time
94 14
        $time = \substr($token, 96, 8);
95
        //random value
96 14
        $random = \substr($token, 104);
97
98
        //hmac generate locally with token time
99 14
        $hmac_local = \hash_hmac('sha3-384', $this->value.$time.$random, $this->key);
100
101
        //hmac check in constant time
102 14
        if (!\hash_equals($hmac_local, $hmac_token)) {
103 1
            return false;
104
        }
105
106
        //timestamp from token time
107 13
        $timestamp = (int) \base_convert($time, 16, 10);
108
109
        //token expiration check
110 13
        if ($timestamp + $this->expire < \time()) {
111 6
            return false;
112
        }
113
114 7
        return true;
115
    }
116
}
117