]>
Commit | Line | Data |
---|---|---|
ebd650c0 | 1 | <?php |
fab87c26 | 2 | namespace Shaarli\Security; |
ebd650c0 | 3 | |
c7721487 V |
4 | use Shaarli\Config\ConfigManager; |
5 | ||
ebd650c0 V |
6 | /** |
7 | * Manages the server-side session | |
8 | */ | |
9 | class SessionManager | |
10 | { | |
af290059 A |
11 | public const KEY_LINKS_PER_PAGE = 'LINKS_PER_PAGE'; |
12 | public const KEY_VISIBILITY = 'visibility'; | |
13 | public const KEY_UNTAGGED_ONLY = 'untaggedonly'; | |
14 | ||
ef00f9d2 A |
15 | public const KEY_SUCCESS_MESSAGES = 'successes'; |
16 | public const KEY_WARNING_MESSAGES = 'warnings'; | |
17 | public const KEY_ERROR_MESSAGES = 'errors'; | |
18 | ||
c7721487 | 19 | /** @var int Session expiration timeout, in seconds */ |
51f0128c V |
20 | public static $SHORT_TIMEOUT = 3600; // 1 hour |
21 | ||
22 | /** @var int Session expiration timeout, in seconds */ | |
23 | public static $LONG_TIMEOUT = 31536000; // 1 year | |
db45a36a | 24 | |
c7721487 | 25 | /** @var array Local reference to the global $_SESSION array */ |
ebd650c0 V |
26 | protected $session = []; |
27 | ||
c7721487 | 28 | /** @var ConfigManager Configuration Manager instance **/ |
49f18323 V |
29 | protected $conf = null; |
30 | ||
51f0128c V |
31 | /** @var bool Whether the user should stay signed in (LONG_TIMEOUT) */ |
32 | protected $staySignedIn = false; | |
33 | ||
ebd650c0 V |
34 | /** |
35 | * Constructor | |
36 | * | |
37 | * @param array $session The $_SESSION array (reference) | |
dd883aaf | 38 | * @param ConfigManager $conf ConfigManager instance |
ebd650c0 | 39 | */ |
dd883aaf | 40 | public function __construct(& $session, $conf) |
ebd650c0 V |
41 | { |
42 | $this->session = &$session; | |
dd883aaf | 43 | $this->conf = $conf; |
ebd650c0 V |
44 | } |
45 | ||
51f0128c V |
46 | /** |
47 | * Define whether the user should stay signed in across browser sessions | |
48 | * | |
49 | * @param bool $staySignedIn Keep the user signed in | |
50 | */ | |
51 | public function setStaySignedIn($staySignedIn) | |
52 | { | |
53 | $this->staySignedIn = $staySignedIn; | |
54 | } | |
55 | ||
ebd650c0 V |
56 | /** |
57 | * Generates a session token | |
58 | * | |
59 | * @return string token | |
60 | */ | |
61 | public function generateToken() | |
62 | { | |
63 | $token = sha1(uniqid('', true) .'_'. mt_rand() . $this->conf->get('credentials.salt')); | |
64 | $this->session['tokens'][$token] = 1; | |
65 | return $token; | |
66 | } | |
67 | ||
68 | /** | |
69 | * Checks the validity of a session token, and destroys it afterwards | |
70 | * | |
71 | * @param string $token The token to check | |
72 | * | |
73 | * @return bool true if the token is valid, else false | |
74 | */ | |
75 | public function checkToken($token) | |
76 | { | |
77 | if (! isset($this->session['tokens'][$token])) { | |
78 | // the token is wrong, or has already been used | |
79 | return false; | |
80 | } | |
81 | ||
82 | // destroy the token to prevent future use | |
83 | unset($this->session['tokens'][$token]); | |
84 | return true; | |
85 | } | |
fd7d8461 V |
86 | |
87 | /** | |
88 | * Validate session ID to prevent Full Path Disclosure. | |
89 | * | |
90 | * See #298. | |
91 | * The session ID's format depends on the hash algorithm set in PHP settings | |
92 | * | |
93 | * @param string $sessionId Session ID | |
94 | * | |
95 | * @return true if valid, false otherwise. | |
96 | * | |
97 | * @see http://php.net/manual/en/function.hash-algos.php | |
98 | * @see http://php.net/manual/en/session.configuration.php | |
99 | */ | |
100 | public static function checkId($sessionId) | |
101 | { | |
102 | if (empty($sessionId)) { | |
103 | return false; | |
104 | } | |
105 | ||
106 | if (!$sessionId) { | |
107 | return false; | |
108 | } | |
109 | ||
110 | if (!preg_match('/^[a-zA-Z0-9,-]{2,128}$/', $sessionId)) { | |
111 | return false; | |
112 | } | |
113 | ||
114 | return true; | |
115 | } | |
49f18323 V |
116 | |
117 | /** | |
118 | * Store user login information after a successful login | |
119 | * | |
c7721487 | 120 | * @param string $clientIpId Client IP address identifier |
49f18323 | 121 | */ |
c7721487 | 122 | public function storeLoginInfo($clientIpId) |
49f18323 | 123 | { |
c7721487 | 124 | $this->session['ip'] = $clientIpId; |
49f18323 | 125 | $this->session['username'] = $this->conf->get('credentials.login'); |
51f0128c | 126 | $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); |
49f18323 V |
127 | } |
128 | ||
c7721487 V |
129 | /** |
130 | * Extend session validity | |
131 | */ | |
132 | public function extendSession() | |
133 | { | |
51f0128c V |
134 | if ($this->staySignedIn) { |
135 | return $this->extendTimeValidityBy(self::$LONG_TIMEOUT); | |
c7721487 | 136 | } |
51f0128c V |
137 | return $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); |
138 | } | |
139 | ||
140 | /** | |
141 | * Extend expiration time | |
142 | * | |
143 | * @param int $duration Expiration time extension (seconds) | |
144 | * | |
145 | * @return int New session expiration time | |
146 | */ | |
147 | protected function extendTimeValidityBy($duration) | |
148 | { | |
149 | $expirationTime = time() + $duration; | |
150 | $this->session['expires_on'] = $expirationTime; | |
151 | return $expirationTime; | |
c7721487 V |
152 | } |
153 | ||
49f18323 V |
154 | /** |
155 | * Logout a user by unsetting all login information | |
156 | * | |
157 | * See: | |
158 | * - https://secure.php.net/manual/en/function.setcookie.php | |
49f18323 | 159 | */ |
51f0128c | 160 | public function logout() |
49f18323 V |
161 | { |
162 | if (isset($this->session)) { | |
49f18323 | 163 | unset($this->session['ip']); |
51f0128c | 164 | unset($this->session['expires_on']); |
49f18323 V |
165 | unset($this->session['username']); |
166 | unset($this->session['visibility']); | |
167 | unset($this->session['untaggedonly']); | |
168 | } | |
49f18323 | 169 | } |
c7721487 V |
170 | |
171 | /** | |
172 | * Check whether the session has expired | |
173 | * | |
174 | * @param string $clientIpId Client IP address identifier | |
175 | * | |
176 | * @return bool true if the session has expired, false otherwise | |
177 | */ | |
178 | public function hasSessionExpired() | |
179 | { | |
8edd7f15 V |
180 | if (empty($this->session['expires_on'])) { |
181 | return true; | |
182 | } | |
c7721487 V |
183 | if (time() >= $this->session['expires_on']) { |
184 | return true; | |
185 | } | |
186 | return false; | |
187 | } | |
188 | ||
189 | /** | |
190 | * Check whether the client IP address has changed | |
191 | * | |
192 | * @param string $clientIpId Client IP address identifier | |
193 | * | |
194 | * @return bool true if the IP has changed, false if it has not, or | |
195 | * if session protection has been disabled | |
196 | */ | |
197 | public function hasClientIpChanged($clientIpId) | |
198 | { | |
199 | if ($this->conf->get('security.session_protection_disabled') === true) { | |
200 | return false; | |
201 | } | |
8edd7f15 | 202 | if (isset($this->session['ip']) && $this->session['ip'] === $clientIpId) { |
c7721487 V |
203 | return false; |
204 | } | |
205 | return true; | |
206 | } | |
6c50a6cc A |
207 | |
208 | /** @return array Local reference to the global $_SESSION array */ | |
209 | public function getSession(): array | |
210 | { | |
211 | return $this->session; | |
212 | } | |
c266a89d A |
213 | |
214 | /** | |
215 | * @param mixed $default value which will be returned if the $key is undefined | |
216 | * | |
217 | * @return mixed Content stored in session | |
218 | */ | |
219 | public function getSessionParameter(string $key, $default = null) | |
220 | { | |
221 | return $this->session[$key] ?? $default; | |
222 | } | |
af290059 A |
223 | |
224 | /** | |
225 | * Store a variable in user session. | |
226 | * | |
227 | * @param string $key Session key | |
228 | * @param mixed $value Session value to store | |
229 | * | |
230 | * @return $this | |
231 | */ | |
232 | public function setSessionParameter(string $key, $value): self | |
233 | { | |
234 | $this->session[$key] = $value; | |
235 | ||
236 | return $this; | |
237 | } | |
238 | ||
239 | /** | |
240 | * Store a variable in user session. | |
241 | * | |
242 | * @param string $key Session key | |
243 | * | |
244 | * @return $this | |
245 | */ | |
246 | public function deleteSessionParameter(string $key): self | |
247 | { | |
248 | unset($this->session[$key]); | |
249 | ||
250 | return $this; | |
251 | } | |
ebd650c0 | 252 | } |