Passed
Push — master ( ade361...b7abd4 )
by Gabor
04:17
created

ServiceAdapter::generate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 1
dl 0
loc 17
ccs 0
cts 12
cp 0
crap 6
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2018 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\CSRF\ServiceAdapter\Base;
15
16
use WebHemi\CSRF\ServiceInterface;
17
use WebHemi\Session\ServiceInterface as SessionInterface;
18
19
/**
20
 * Class ServiceAdapter.
21
 */
22
class ServiceAdapter implements ServiceInterface
23
{
24
    protected $sessionManager;
25
26
    /**
27
     * ServiceInterface constructor.
28
     *
29
     * @param SessionInterface $sessionManager
30
     */
31
    public function __construct(SessionInterface $sessionManager)
32
    {
33
        $this->sessionManager = $sessionManager;
34
    }
35
36
    /**
37
     * Generate a CSRF token.
38
     *
39
     * @param string $key
40
     * @return string
41
     */
42
    public function generate(string $key) : string
43
    {
44
        $key = preg_replace('/[^a-zA-Z0-9]/', '', $key);
45
46
        $extra = sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
47
48
        try {
49
            $randomString = bin2hex(random_bytes(16));
50
        } catch (\Throwable $error) {
51
            $randomString = $this->randomString(32);
52
        }
53
54
        $token = base64_encode(time() . $extra . $randomString);
55
56
        $this->sessionManager->set(self::SESSION_PREFIX.'_'.$key, $token);
57
58
        return $token;
59
    }
60
61
    /**
62
     * Check the CSRF token is valid.
63
     *
64
     * @param string $key
65
     * @param string $token
66
     * @param null|int $ttl
67
     * @param bool $multiple
68
     * @return bool
69
     */
70
    public function verify(string $key, string $token, ? int $ttl = null, bool $multiple = false) : bool
71
    {
72
        $key = preg_replace('/[^a-zA-Z0-9]/', '', $key);
73
74
        $extra = sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
75
        $token = base64_decode($this->sessionManager->get(self::SESSION_PREFIX.'_'.$key));
76
        $tokenTime = substr($token, 0, 10);
77
        $tokenExtra = substr($token, 10, 40);
78
        $tokenRandomString = substr($token, 40);
79
80
        if (!$multiple) {
81
            $this->sessionManager->delete(self::SESSION_PREFIX.'_'.$key);
82
        }
83
84
        return !((!empty($ttl) && $tokenTime + $ttl > time())
85
            || $extra !== $tokenExtra
86
            || strlen($tokenRandomString) !== 32
87
            || !ctype_xdigit($tokenRandomString)
88
        );
89
    }
90
91
    /**
92
     * Generate a random string
93
     *
94
     * @param int $length
95
     * @return string
96
     */
97
    protected function randomString(int $length) : string
98
    {
99
        $seed = 'abcdef0123456789';
100
        $max = strlen($seed) - 1;
101
        $string = '';
102
103
        for ($i = 0; $i < $length; ++$i) {
104
            $string .= $seed[intval(mt_rand(0.0, $max))];
105
        }
106
107
        return $string;
108
    }
109
}
110