Passed
Push — b2.0.0 ( 59ba4e...bb1327 )
by Sebastian
02:46
created

HmacTokenProvider   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 28.57%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 5
eloc 22
c 1
b 0
f 0
dl 0
loc 88
ccs 6
cts 21
cp 0.2857
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A validate() 0 26 3
A __construct() 0 9 1
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 $secret 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 3
    public function __construct(string $value, string $key, int $expire = 600)
51
    {
52
        // from BadExpireTrait
53
        /** @throws BadExpireException */
54 3
        $this->checkBadExpire($expire);
55
56 1
        $this->key = $key;
57 1
        $this->value = $value;
58 1
        $this->expire = $expire;
59 1
    }
60
61
    /**
62
     * Return new Hmac Token.
63
     *
64
     * @return string
65
     */
66
    public function getToken(): string
67
    {
68
        //get the time for the token
69
        $time = \base_convert((string) \time(), 10, 16);
70
        //random bytes for avoid to wait one second to get a different token
71
        $random = \bin2hex(\random_bytes(2));
72
73
        //return the token
74
        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
    public function validate(string $token): bool
85
    {
86
        //hmac present in token
87
        $hmac_token = \substr($token, 0, 96);
88
        //token time
89
        $time = \substr($token, 96, 8);
90
        //random value
91
        $random = \substr($token, 104);
92
93
        //hmac generate locally with token time
94
        $hmac_local = \hash_hmac('sha3-384', $this->value.$time.$random, $this->key);
95
96
        //hmac check in constant time
97
        if (!\hash_equals($hmac_local, $hmac_token)) {
98
            return false;
99
        }
100
101
        //timestamp from token time
102
        $timestamp = (int) \base_convert($time, 16, 10);
103
104
        //token expiration check
105
        if ($timestamp + $this->expire < \time()) {
106
            return false;
107
        }
108
109
        return true;
110
    }
111
}
112