TokenService::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
crap 1
1
<?php
2
3
namespace mindplay\kissform\Framework;
4
5
use mindplay\kissform\Facets\TokenServiceInterface;
6
use mindplay\kissform\Facets\TokenStoreInterface;
7
8
class TokenService implements TokenServiceInterface
9
{
10
    /**
11
     * @var string hash algorithm
12
     */
13
    const HASH_ALGO = 'sha512';
14
15
    /**
16
     * @var string timestamp key
17
     */
18
    const KEY_TIMESTAMP = 'T';
19
20
    /**
21
     * @var string salt key
22
     */
23
    const KEY_SALT = 'S';
24
25
    /**
26
     * @var string hash key
27
     */
28
    const KEY_HASH = 'H';
29
30
    /**
31
     * @var int token is valid n seconds from now (prevents submission quicker than a human)
32
     */
33
    public $valid_from = 5;
34
35
    /**
36
     * @var int token is valid until n seconds from now (token expires after this time)
37
     */
38
    public $valid_to = 1200;
39
40
    /**
41
     * @var string secret salt
42
     */
43
    private $secret;
44
45
    /**
46
     * @var TokenStoreInterface
47
     */
48
    private $store;
49
50
    /**
51
     * @var int timestamp
52
     */
53
    public $timestamp;
54
55
    /**
56
     * @param TokenStoreInterface $store
57
     * @param string              $secret secret salt (unique to your form or controller)
58
     */
59 3
    public function __construct(TokenStoreInterface $store, $secret)
60
    {
61 3
        $this->secret = $secret;
62 3
        $this->store = $store;
63 3
        $this->timestamp = time();
64 3
    }
65
66
    /**
67
     * @inheritdoc
68
     */
69 3
    public function createToken($name)
70
    {
71 3
        $salt = sha1(microtime(true) . rand(0, 9999999));
72
73 3
        $hash = $this->hash($name, $salt, $this->timestamp);
74
75 3
        $token = base64_encode(json_encode([
76 3
            self::KEY_TIMESTAMP => $this->timestamp,
77 3
            self::KEY_SALT      => $salt,
78 3
            self::KEY_HASH      => $hash,
79
        ]));
80
81 3
        $this->store->registerToken($token);
82
83 3
        return $token;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89 3
    public function checkToken($name, $token)
90
    {
91 3
        if (!$this->store->verifyToken($token)) {
92 2
            return false; // no such token was issued
93
        }
94
95 3
        $data = @json_decode(base64_decode($token), true);
96
97 3
        if (!isset($data[self::KEY_TIMESTAMP], $data[self::KEY_SALT], $data[self::KEY_HASH])) {
98
            return false; // invalid token
99
        }
100
101 3
        $timestamp = $data[self::KEY_TIMESTAMP];
102 3
        $salt = $data[self::KEY_SALT];
103 3
        $hash = $data[self::KEY_HASH];
104
105 3
        if ($hash !== $this->hash($name, $salt, $timestamp)) {
106 1
            return false; // wrong hash
107
        }
108
109 3
        $time = $this->timestamp - $timestamp;
110
111 3
        return ($time >= $this->valid_from)
112 3
            && ($time <= $this->valid_to);
113
    }
114
115
    /**
116
     * @param string $name
117
     * @param string $salt
118
     * @param int    $timestamp
119
     *
120
     * @return string
121
     */
122 3
    private function hash($name, $salt, $timestamp)
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
123
    {
124 3
        $data = $salt . $timestamp . $this->store->getClientSalt();
125
126 3
        return hash_hmac(self::HASH_ALGO, $data, $this->secret);
127
    }
128
}
129