Issues (195)

includes/Security/TokenManager.php (1 issue)

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