Issues (186)

includes/Security/TokenManager.php (1 issue)

Severity
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\Security;
11
12
use Exception;
13
use Waca\WebRequest;
14
15
class TokenManager
16
{
17
    /**
18
     * Validates a CSRF token
19
     *
20
     * @param string      $data    The token data string itself
21
     * @param string|null $context Token context for extra validation
22
     *
23
     * @return bool
24
     */
25
    public function validateToken($data, $context = null)
26
    {
27
        if (!is_string($data) || strlen($data) === 0) {
0 ignored issues
show
The condition is_string($data) is always true.
Loading history...
28
            // Nothing to validate
29
            return false;
30
        }
31
32
        $tokens = WebRequest::getSessionTokenData();
33
34
        // if the token doesn't exist, then it's not valid
35
        if (!array_key_exists($data, $tokens)) {
36
            return false;
37
        }
38
39
        /** @var Token $token */
40
        $token = unserialize($tokens[$data]);
41
42
        if ($token->getTokenData() !== $data) {
43
            return false;
44
        }
45
46
        if ($token->getContext() !== $context) {
47
            return false;
48
        }
49
50
        if ($token->isUsed()) {
51
            return false;
52
        }
53
54
        // mark the token as used, and save it back to the session
55
        $token->markAsUsed();
56
        $this->storeToken($token);
57
58
        return true;
59
    }
60
61
    /**
62
     * @param string|null $context An optional context for extra validation
63
     *
64
     * @return Token
65
     */
66
    public function getNewToken($context = null)
67
    {
68
        $token = new Token($this->generateTokenData(), $context);
69
        $this->storeToken($token);
70
71
        return $token;
72
    }
73
74
    /**
75
     * Stores a token in the session data
76
     *
77
     * @param Token $token
78
     */
79
    private function storeToken(Token $token)
80
    {
81
        $tokens = WebRequest::getSessionTokenData();
82
        $tokens[$token->getTokenData()] = serialize($token);
83
        WebRequest::setSessionTokenData($tokens);
84
    }
85
86
    /**
87
     * Generates a security token
88
     *
89
     * @return string
90
     * @throws Exception
91
     *
92
     * @category Security-Critical
93
     */
94
    private function generateTokenData()
95
    {
96
        $genBytes = openssl_random_pseudo_bytes(33);
97
98
        if ($genBytes !== false) {
99
            return base64_encode($genBytes);
100
        }
101
102
        throw new Exception('Unable to generate secure token.');
103
    }
104
}