Issues (1)

src/manager/CsrfManager.php (1 issue)

1
<?php
2
namespace Julfiker\Service;
3
4
use Symfony\Component\HttpFoundation\Request as Request;
5
use Symfony\Component\HttpFoundation\Session\Session as Session;
6
7
/**
8
 * A service to check and generate unique csrf token on each rendering page.
9
 * @author Julfiker <[email protected]>
10
 */
11
class CsrfManager
12
{
13
    /** Constant */
14
    const SLAT = "uglymindcannotbehuman";
15
    const SESSION_STORE_TOKEN_NAME = 'csrf_token';
16
    const SESSION_STORE_TOKEN_EXPIREDAT = 'EXPIRED_AT';
17
    const TOKEN_FIELD_NAME = "_token";
18
19
    /** @var  string */
20
    private $CSRFToken;
21
22
    /** @var  */
23
    private $CSRFTokenExpireTime;
24
25
    /** @var int  */
26
    private $tokenValidInMinutes = 30; //30 minutes
27
28
    /** @var \Symfony\Component\HttpFoundation\Request  */
29
    private $request;
30
31
    /** @var \Symfony\Component\HttpFoundation\Session\Session  */
32
    private $session;
33
34
    /**
35
     * Constructor
36
     */
37
    public function __construct() {
38
        $this->request = Request::createFromGlobals();
39
        $this->session = new Session();
40
    }
41
42
    /**
43
     * Check token is expired already
44
     * @return bool
45
     */
46
    private function _isTokenExpired() {
47
        return time() > $this->session->get(self::SESSION_STORE_TOKEN_EXPIREDAT);
48
    }
49
50
    /**
51
     * Check token is not expired yet
52
     * @return bool
53
     */
54
    private function _isNotExpiredAt() {
55
        return !$this->_isTokenExpired();
56
    }
57
58
    /**
59
     * Unset storage
60
     */
61
    public function unsetToken() {
62
        $this->session->remove(self::SESSION_STORE_TOKEN_EXPIREDAT);
63
        $this->session->remove(self::SESSION_STORE_TOKEN_NAME);
64
        $this->session->clear();
65
    }
66
67
    /**
68
     * Checking token based on post|pull|delete request
69
     * @return boolean
70
     * @throws \Exception
71
     */
72
    public function checkToken() {
73
        $pass = false;
74
        $method = $this->request->getRealMethod();
75
        if (in_array($method, ['PUT','POST','DELETE'])) {
76
            $csrfToken = $this->getRequest()->get($this->getTokenFieldName());
77
            if ($csrfToken && $this->getStorageToken() == $csrfToken) {
78
                $pass = true;
79
            }
80
        }
81
        $this->unsetToken();
82
        return $pass;
83
    }
84
85
    /**
86
     * Generate CSRF token to handle request
87
     *
88
     * @return string
89
     */
90
    public function generateToken() {
91
        $sesId = session_id();
92
        if (!$sesId)
93
           $sesId = session_id("UN_AUTHORIZED");
94
95
        $this->CSRFToken = md5($sesId+self::SLAT+time());
96
        $minutes = $this->tokenValidInMinutes;
97
        $this->CSRFTokenExpireTime = strtotime("+$minutes minutes");
98
99
        //Store into the session
100
        $this->session->set(self::SESSION_STORE_TOKEN_EXPIREDAT, $this->CSRFTokenExpireTime);
101
        $this->session->set(self::SESSION_STORE_TOKEN_NAME, $this->CSRFToken);
102
        $this->session->save();
103
    }
104
105
    /**
106
     * Get already storage token
107
     *
108
     * @return string
109
     */
110
    public function getStorageToken() {
111
        if ($this->session->get(self::SESSION_STORE_TOKEN_NAME) && $this->_isNotExpiredAt())
112
            return $this->session->get(self::SESSION_STORE_TOKEN_NAME);
113
114
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
115
    }
116
117
    /**
118
     * Refresh new token
119
     * @return void
120
     */
121
    public function refreshToken() {
122
        $this->generateToken();
123
    }
124
125
    /**
126
     * Get CSRF token
127
     * @return string
128
     */
129
    public function getCSRFToken() {
130
        if (!$this->session->has(self::SESSION_STORE_TOKEN_NAME) || $this->_isTokenExpired())
131
        $this->refreshToken();
132
133
       return $this->session->get(self::SESSION_STORE_TOKEN_NAME);
134
    }
135
136
    /**
137
     * Token field name
138
     */
139
    public function getTokenFieldName() {
140
        return self::TOKEN_FIELD_NAME;
141
    }
142
    /**
143
     * Get request object
144
     *
145
     * @return Request
146
     */
147
    public function getRequest() {
148
        return $this->request;
149
    }
150
151
    /**
152
     * @return Session
153
     */
154
    public function getSession() {
155
        return $this->session;
156
    }
157
158
    /**
159
     * Checking token is invalid or not
160
     * @return bool
161
     */
162
    public function isValidToken() {
163
        return $this->checkToken();
164
    }
165
166
    /**
167
     * Set time expire token
168
     * @param int $minutes
169
     * @return void
170
     */
171
    public function setExpiredAt($minutes) {
172
        $this->tokenValidInMinutes = $minutes;
173
    }
174
}
175