Failed Conditions
Pull Request — oauthcreation (#531)
by Simon
18:38 queued 08:37
created
includes/DataObjects/Credential.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
     }
113 113
 
114 114
     /**
115
-     * @return mixed
115
+     * @return null|DateTimeImmutable
116 116
      */
117 117
     public function getTimeout()
118 118
     {
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
     }
125 125
 
126 126
     /**
127
-     * @param mixed $timeout
127
+     * @param null|DateTimeImmutable $timeout
128 128
      */
129 129
     public function setTimeout(DateTimeImmutable $timeout = null)
130 130
     {
Please login to merge, or discard this patch.
Indentation   +196 added lines, -196 removed lines patch added patch discarded remove patch
@@ -15,187 +15,187 @@  discard block
 block discarded – undo
15 15
 
16 16
 class Credential extends DataObject
17 17
 {
18
-    /** @var int */
19
-    private $user;
20
-    /** @var int */
21
-    private $factor;
22
-    /** @var string */
23
-    private $type;
24
-    /** @var string */
25
-    private $data;
26
-    /** @var int */
27
-    private $version;
28
-    private $timeout;
29
-    /** @var int */
30
-    private $disabled = 0;
31
-    /** @var int */
32
-    private $priority;
33
-
34
-    /**
35
-     * @return int
36
-     */
37
-    public function getUserId()
38
-    {
39
-        return $this->user;
40
-    }
41
-
42
-    /**
43
-     * @param int $user
44
-     */
45
-    public function setUserId($user)
46
-    {
47
-        $this->user = $user;
48
-    }
49
-
50
-    /**
51
-     * @return int
52
-     */
53
-    public function getFactor()
54
-    {
55
-        return $this->factor;
56
-    }
57
-
58
-    /**
59
-     * @param int $factor
60
-     */
61
-    public function setFactor($factor)
62
-    {
63
-        $this->factor = $factor;
64
-    }
65
-
66
-    /**
67
-     * @return string
68
-     */
69
-    public function getType()
70
-    {
71
-        return $this->type;
72
-    }
73
-
74
-    /**
75
-     * @param string $type
76
-     */
77
-    public function setType($type)
78
-    {
79
-        $this->type = $type;
80
-    }
81
-
82
-    /**
83
-     * @return string
84
-     */
85
-    public function getData()
86
-    {
87
-        return $this->data;
88
-    }
89
-
90
-    /**
91
-     * @param string $data
92
-     */
93
-    public function setData($data)
94
-    {
95
-        $this->data = $data;
96
-    }
97
-
98
-    /**
99
-     * @return int
100
-     */
101
-    public function getVersion()
102
-    {
103
-        return $this->version;
104
-    }
105
-
106
-    /**
107
-     * @param int $version
108
-     */
109
-    public function setVersion($version)
110
-    {
111
-        $this->version = $version;
112
-    }
113
-
114
-    /**
115
-     * @return mixed
116
-     */
117
-    public function getTimeout()
118
-    {
119
-        if ($this->timeout === null) {
120
-            return null;
121
-        }
122
-
123
-        return new DateTimeImmutable($this->timeout);
124
-    }
125
-
126
-    /**
127
-     * @param mixed $timeout
128
-     */
129
-    public function setTimeout(DateTimeImmutable $timeout = null)
130
-    {
131
-        if ($timeout === null) {
132
-            $this->timeout = null;
133
-        }
134
-        else {
135
-            $this->timeout = $timeout->format('Y-m-d H:i:s');
136
-        }
137
-    }
138
-
139
-    /**
140
-     * @return int
141
-     */
142
-    public function getDisabled()
143
-    {
144
-        return $this->disabled;
145
-    }
146
-
147
-    /**
148
-     * @param int $disabled
149
-     */
150
-    public function setDisabled($disabled)
151
-    {
152
-        $this->disabled = $disabled;
153
-    }
154
-
155
-    /**
156
-     * @return int
157
-     */
158
-    public function getPriority()
159
-    {
160
-        return $this->priority;
161
-    }
162
-
163
-    /**
164
-     * @param int $priority
165
-     */
166
-    public function setPriority($priority)
167
-    {
168
-        $this->priority = $priority;
169
-    }
170
-
171
-    public function save()
172
-    {
173
-        if ($this->isNew()) {
174
-            // insert
175
-            $statement = $this->dbObject->prepare(<<<SQL
18
+	/** @var int */
19
+	private $user;
20
+	/** @var int */
21
+	private $factor;
22
+	/** @var string */
23
+	private $type;
24
+	/** @var string */
25
+	private $data;
26
+	/** @var int */
27
+	private $version;
28
+	private $timeout;
29
+	/** @var int */
30
+	private $disabled = 0;
31
+	/** @var int */
32
+	private $priority;
33
+
34
+	/**
35
+	 * @return int
36
+	 */
37
+	public function getUserId()
38
+	{
39
+		return $this->user;
40
+	}
41
+
42
+	/**
43
+	 * @param int $user
44
+	 */
45
+	public function setUserId($user)
46
+	{
47
+		$this->user = $user;
48
+	}
49
+
50
+	/**
51
+	 * @return int
52
+	 */
53
+	public function getFactor()
54
+	{
55
+		return $this->factor;
56
+	}
57
+
58
+	/**
59
+	 * @param int $factor
60
+	 */
61
+	public function setFactor($factor)
62
+	{
63
+		$this->factor = $factor;
64
+	}
65
+
66
+	/**
67
+	 * @return string
68
+	 */
69
+	public function getType()
70
+	{
71
+		return $this->type;
72
+	}
73
+
74
+	/**
75
+	 * @param string $type
76
+	 */
77
+	public function setType($type)
78
+	{
79
+		$this->type = $type;
80
+	}
81
+
82
+	/**
83
+	 * @return string
84
+	 */
85
+	public function getData()
86
+	{
87
+		return $this->data;
88
+	}
89
+
90
+	/**
91
+	 * @param string $data
92
+	 */
93
+	public function setData($data)
94
+	{
95
+		$this->data = $data;
96
+	}
97
+
98
+	/**
99
+	 * @return int
100
+	 */
101
+	public function getVersion()
102
+	{
103
+		return $this->version;
104
+	}
105
+
106
+	/**
107
+	 * @param int $version
108
+	 */
109
+	public function setVersion($version)
110
+	{
111
+		$this->version = $version;
112
+	}
113
+
114
+	/**
115
+	 * @return mixed
116
+	 */
117
+	public function getTimeout()
118
+	{
119
+		if ($this->timeout === null) {
120
+			return null;
121
+		}
122
+
123
+		return new DateTimeImmutable($this->timeout);
124
+	}
125
+
126
+	/**
127
+	 * @param mixed $timeout
128
+	 */
129
+	public function setTimeout(DateTimeImmutable $timeout = null)
130
+	{
131
+		if ($timeout === null) {
132
+			$this->timeout = null;
133
+		}
134
+		else {
135
+			$this->timeout = $timeout->format('Y-m-d H:i:s');
136
+		}
137
+	}
138
+
139
+	/**
140
+	 * @return int
141
+	 */
142
+	public function getDisabled()
143
+	{
144
+		return $this->disabled;
145
+	}
146
+
147
+	/**
148
+	 * @param int $disabled
149
+	 */
150
+	public function setDisabled($disabled)
151
+	{
152
+		$this->disabled = $disabled;
153
+	}
154
+
155
+	/**
156
+	 * @return int
157
+	 */
158
+	public function getPriority()
159
+	{
160
+		return $this->priority;
161
+	}
162
+
163
+	/**
164
+	 * @param int $priority
165
+	 */
166
+	public function setPriority($priority)
167
+	{
168
+		$this->priority = $priority;
169
+	}
170
+
171
+	public function save()
172
+	{
173
+		if ($this->isNew()) {
174
+			// insert
175
+			$statement = $this->dbObject->prepare(<<<SQL
176 176
 INSERT INTO credential ( updateversion, user, factor, type, data, version, timeout, disabled, priority )
177 177
 VALUES ( 0, :user, :factor, :type, :data, :version, :timeout, :disabled, :priority );
178 178
 SQL
179
-            );
180
-            $statement->bindValue(":user", $this->user);
181
-            $statement->bindValue(":factor", $this->factor);
182
-            $statement->bindValue(":type", $this->type);
183
-            $statement->bindValue(":data", $this->data);
184
-            $statement->bindValue(":version", $this->version);
185
-            $statement->bindValue(":timeout", $this->timeout);
186
-            $statement->bindValue(":disabled", $this->disabled);
187
-            $statement->bindValue(":priority", $this->priority);
188
-
189
-            if ($statement->execute()) {
190
-                $this->id = (int)$this->dbObject->lastInsertId();
191
-            }
192
-            else {
193
-                throw new Exception($statement->errorInfo());
194
-            }
195
-        }
196
-        else {
197
-            // update
198
-            $statement = $this->dbObject->prepare(<<<SQL
179
+			);
180
+			$statement->bindValue(":user", $this->user);
181
+			$statement->bindValue(":factor", $this->factor);
182
+			$statement->bindValue(":type", $this->type);
183
+			$statement->bindValue(":data", $this->data);
184
+			$statement->bindValue(":version", $this->version);
185
+			$statement->bindValue(":timeout", $this->timeout);
186
+			$statement->bindValue(":disabled", $this->disabled);
187
+			$statement->bindValue(":priority", $this->priority);
188
+
189
+			if ($statement->execute()) {
190
+				$this->id = (int)$this->dbObject->lastInsertId();
191
+			}
192
+			else {
193
+				throw new Exception($statement->errorInfo());
194
+			}
195
+		}
196
+		else {
197
+			// update
198
+			$statement = $this->dbObject->prepare(<<<SQL
199 199
                 UPDATE credential
200 200
                 SET   factor = :factor
201 201
                     , data = :data
@@ -206,27 +206,27 @@  discard block
 block discarded – undo
206 206
                     , updateversion = updateversion + 1
207 207
                 WHERE id = :id AND updateversion = :updateversion;
208 208
 SQL
209
-            );
209
+			);
210 210
 
211
-            $statement->bindValue(':id', $this->id);
212
-            $statement->bindValue(':updateversion', $this->updateversion);
211
+			$statement->bindValue(':id', $this->id);
212
+			$statement->bindValue(':updateversion', $this->updateversion);
213 213
 
214
-            $statement->bindValue(":factor", $this->factor);
215
-            $statement->bindValue(":data", $this->data);
216
-            $statement->bindValue(":version", $this->version);
217
-            $statement->bindValue(":timeout", $this->timeout);
218
-            $statement->bindValue(":disabled", $this->disabled);
219
-            $statement->bindValue(":priority", $this->priority);
214
+			$statement->bindValue(":factor", $this->factor);
215
+			$statement->bindValue(":data", $this->data);
216
+			$statement->bindValue(":version", $this->version);
217
+			$statement->bindValue(":timeout", $this->timeout);
218
+			$statement->bindValue(":disabled", $this->disabled);
219
+			$statement->bindValue(":priority", $this->priority);
220 220
 
221
-            if (!$statement->execute()) {
222
-                throw new Exception($statement->errorInfo());
223
-            }
221
+			if (!$statement->execute()) {
222
+				throw new Exception($statement->errorInfo());
223
+			}
224 224
 
225
-            if ($statement->rowCount() !== 1) {
226
-                throw new OptimisticLockFailedException();
227
-            }
225
+			if ($statement->rowCount() !== 1) {
226
+				throw new OptimisticLockFailedException();
227
+			}
228 228
 
229
-            $this->updateversion++;
230
-        }
231
-    }
229
+			$this->updateversion++;
230
+		}
231
+	}
232 232
 }
233 233
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/LoginCredentialPageBase.php 3 patches
Doc Comments   +4 added lines, -1 removed lines patch added patch discarded remove patch
@@ -281,6 +281,9 @@  discard block
 block discarded – undo
281 281
         $this->redirect("login/" . $this->nextPageMap[$nextStage]);
282 282
     }
283 283
 
284
+    /**
285
+     * @param integer|null $partialStage
286
+     */
284 287
     private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
285 288
     {
286 289
         // get the providers available
@@ -313,7 +316,7 @@  discard block
 block discarded – undo
313 316
 
314 317
     /**
315 318
      * @param $types
316
-     * @param $type
319
+     * @param string $type
317 320
      * @param $userOptions
318 321
      *
319 322
      * @return mixed
Please login to merge, or discard this patch.
Indentation   +311 added lines, -311 removed lines patch added patch discarded remove patch
@@ -21,315 +21,315 @@
 block discarded – undo
21 21
 
22 22
 abstract class LoginCredentialPageBase extends InternalPageBase
23 23
 {
24
-    /** @var User */
25
-    protected $partialUser = null;
26
-    protected $nextPageMap = array(
27
-        'yubikeyotp' => 'otp',
28
-        'totp'       => 'otp',
29
-        'scratch'    => 'otp',
30
-        'u2f'        => 'u2f',
31
-    );
32
-    protected $names = array(
33
-        'yubikeyotp' => 'Yubikey OTP',
34
-        'totp'       => 'TOTP (phone code generator)',
35
-        'scratch'    => 'scratch token',
36
-        'u2f'        => 'U2F security token',
37
-    );
38
-
39
-    /**
40
-     * Main function for this page, when no specific actions are called.
41
-     * @return void
42
-     */
43
-    protected function main()
44
-    {
45
-        if (!$this->enforceHttps()) {
46
-            return;
47
-        }
48
-
49
-        if (WebRequest::wasPosted()) {
50
-            $this->validateCSRFToken();
51
-
52
-            $database = $this->getDatabase();
53
-            try {
54
-                list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
55
-
56
-                if ($partialStage === null) {
57
-                    $partialStage = 1;
58
-                }
59
-
60
-                if ($partialId === null) {
61
-                    $username = WebRequest::postString('username');
62
-
63
-                    if ($username === null || trim($username) === '') {
64
-                        throw new ApplicationLogicException('No username specified.');
65
-                    }
66
-
67
-                    $user = User::getByUsername($username, $database);
68
-                }
69
-                else {
70
-                    $user = User::getById($partialId, $database);
71
-                }
72
-
73
-                if ($user === false) {
74
-                    throw new ApplicationLogicException("Authentication failed");
75
-                }
76
-
77
-                $authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
78
-                    $this->getHttpHelper());
79
-
80
-                $credential = $this->getProviderCredentials();
81
-
82
-                $authResult = $authMan->authenticate($user, $credential, $partialStage);
83
-
84
-                if ($authResult === AuthenticationManager::AUTH_FAIL) {
85
-                    throw new ApplicationLogicException("Authentication failed");
86
-                }
87
-
88
-                if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
89
-                    $this->processJumpNextStage($user, $partialStage, $database);
90
-
91
-                    return;
92
-                }
93
-
94
-                if ($authResult === AuthenticationManager::AUTH_OK) {
95
-                    $this->processLoginSuccess($user);
96
-
97
-                    return;
98
-                }
99
-            }
100
-            catch (ApplicationLogicException $ex) {
101
-                WebRequest::clearAuthPartialLogin();
102
-
103
-                SessionAlert::error($ex->getMessage());
104
-                $this->redirect('login');
105
-
106
-                return;
107
-            }
108
-        }
109
-        else {
110
-            $this->assign('showSignIn', true);
111
-
112
-            $this->setupPartial();
113
-            $this->assignCSRFToken();
114
-            $this->providerSpecificSetup();
115
-        }
116
-    }
117
-
118
-    protected function isProtectedPage()
119
-    {
120
-        return false;
121
-    }
122
-
123
-    /**
124
-     * Enforces HTTPS on the login form
125
-     *
126
-     * @return bool
127
-     */
128
-    private function enforceHttps()
129
-    {
130
-        if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
131
-            if (WebRequest::isHttps()) {
132
-                // Client can clearly use HTTPS, so let's enforce it for all connections.
133
-                $this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
134
-            }
135
-            else {
136
-                // This is the login form, not the request form. We need protection here.
137
-                $this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
138
-
139
-                return false;
140
-            }
141
-        }
142
-
143
-        return true;
144
-    }
145
-
146
-    protected abstract function providerSpecificSetup();
147
-
148
-    protected function setupPartial()
149
-    {
150
-        $database = $this->getDatabase();
151
-
152
-        // default stuff
153
-        $this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
154
-
155
-        // is this stage one?
156
-        list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
157
-        if ($partialStage === null || $partialId === null) {
158
-            WebRequest::clearAuthPartialLogin();
159
-        }
160
-
161
-        // Check to see if we have a partial login in progress
162
-        $username = null;
163
-        if ($partialId !== null) {
164
-            // Yes, enforce this username
165
-            $this->partialUser = User::getById($partialId, $database);
166
-            $username = $this->partialUser->getUsername();
167
-
168
-            $this->setupAlternates($this->partialUser, $partialStage, $database);
169
-        }
170
-        else {
171
-            // No, see if we've preloaded a username
172
-            $preloadUsername = WebRequest::getString('tplUsername');
173
-            if ($preloadUsername !== null) {
174
-                $username = $preloadUsername;
175
-            }
176
-        }
177
-
178
-        if ($partialStage === null) {
179
-            $partialStage = 1;
180
-        }
181
-
182
-        $this->assign('partialStage', $partialStage);
183
-        $this->assign('username', $username);
184
-    }
185
-
186
-    /**
187
-     * Redirect the user back to wherever they came from after a successful login
188
-     *
189
-     * @param User $user
190
-     */
191
-    protected function goBackWhenceYouCame(User $user)
192
-    {
193
-        // Redirect to wherever the user came from
194
-        $redirectDestination = WebRequest::clearPostLoginRedirect();
195
-        if ($redirectDestination !== null) {
196
-            $this->redirectUrl($redirectDestination);
197
-        }
198
-        else {
199
-            if ($user->isNewUser()) {
200
-                // home page isn't allowed, go to preferences instead
201
-                $this->redirect('preferences');
202
-            }
203
-            else {
204
-                // go to the home page
205
-                $this->redirect('');
206
-            }
207
-        }
208
-    }
209
-
210
-    private function processLoginSuccess(User $user)
211
-    {
212
-        // Touch force logout
213
-        $user->setForceLogout(false);
214
-        $user->save();
215
-
216
-        $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
217
-            $this->getSiteConfiguration());
218
-
219
-        if ($oauth->isFullyLinked()) {
220
-            try {
221
-                // Reload the user's identity ticket.
222
-                $oauth->refreshIdentity();
223
-
224
-                // Check for blocks
225
-                if ($oauth->getIdentity()->getBlocked()) {
226
-                    // blocked!
227
-                    SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
228
-                    $this->redirect('login');
229
-
230
-                    return;
231
-                }
232
-            }
233
-            catch (OAuthException $ex) {
234
-                // Oops. Refreshing ticket failed. Force a re-auth.
235
-                $authoriseUrl = $oauth->getRequestToken();
236
-                WebRequest::setOAuthPartialLogin($user);
237
-                $this->redirectUrl($authoriseUrl);
238
-
239
-                return;
240
-            }
241
-        }
242
-
243
-        if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
244
-            || $oauth->isPartiallyLinked()
245
-        ) {
246
-            $authoriseUrl = $oauth->getRequestToken();
247
-            WebRequest::setOAuthPartialLogin($user);
248
-            $this->redirectUrl($authoriseUrl);
249
-
250
-            return;
251
-        }
252
-
253
-        WebRequest::setLoggedInUser($user);
254
-
255
-        $this->goBackWhenceYouCame($user);
256
-    }
257
-
258
-    protected abstract function getProviderCredentials();
259
-
260
-    /**
261
-     * @param User        $user
262
-     * @param int         $partialStage
263
-     * @param PdoDatabase $database
264
-     *
265
-     * @throws ApplicationLogicException
266
-     */
267
-    private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
268
-    {
269
-        WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
270
-
271
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
272
-        $statement = $database->prepare($sql);
273
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
274
-        $nextStage = $statement->fetchColumn();
275
-        $statement->closeCursor();
276
-
277
-        if (!isset($this->nextPageMap[$nextStage])) {
278
-            throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
279
-        }
280
-
281
-        $this->redirect("login/" . $this->nextPageMap[$nextStage]);
282
-    }
283
-
284
-    private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
285
-    {
286
-        // get the providers available
287
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
288
-        $statement = $database->prepare($sql);
289
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
290
-        $alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
291
-
292
-        $types = array();
293
-        foreach ($alternates as $item) {
294
-            $type = $this->nextPageMap[$item];
295
-            if (!isset($types[$type])) {
296
-                $types[$type] = array();
297
-            }
298
-
299
-            $types[$type][] = $item;
300
-        }
301
-
302
-        $userOptions = array();
303
-        if (get_called_class() === PageOtpLogin::class) {
304
-            $userOptions = $this->setupUserOptionsForType($types, 'u2f', $userOptions);
305
-        }
306
-
307
-        if (get_called_class() === PageU2FLogin::class) {
308
-            $userOptions = $this->setupUserOptionsForType($types, 'otp', $userOptions);
309
-        }
310
-
311
-        $this->assign('alternatives', $userOptions);
312
-    }
313
-
314
-    /**
315
-     * @param $types
316
-     * @param $type
317
-     * @param $userOptions
318
-     *
319
-     * @return mixed
320
-     */
321
-    private function setupUserOptionsForType($types, $type, $userOptions)
322
-    {
323
-        if (isset($types[$type])) {
324
-            $options = $types[$type];
325
-
326
-            array_walk($options, function(&$val) {
327
-                $val = $this->names[$val];
328
-            });
329
-
330
-            $userOptions[$type] = $options;
331
-        }
332
-
333
-        return $userOptions;
334
-    }
24
+	/** @var User */
25
+	protected $partialUser = null;
26
+	protected $nextPageMap = array(
27
+		'yubikeyotp' => 'otp',
28
+		'totp'       => 'otp',
29
+		'scratch'    => 'otp',
30
+		'u2f'        => 'u2f',
31
+	);
32
+	protected $names = array(
33
+		'yubikeyotp' => 'Yubikey OTP',
34
+		'totp'       => 'TOTP (phone code generator)',
35
+		'scratch'    => 'scratch token',
36
+		'u2f'        => 'U2F security token',
37
+	);
38
+
39
+	/**
40
+	 * Main function for this page, when no specific actions are called.
41
+	 * @return void
42
+	 */
43
+	protected function main()
44
+	{
45
+		if (!$this->enforceHttps()) {
46
+			return;
47
+		}
48
+
49
+		if (WebRequest::wasPosted()) {
50
+			$this->validateCSRFToken();
51
+
52
+			$database = $this->getDatabase();
53
+			try {
54
+				list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
55
+
56
+				if ($partialStage === null) {
57
+					$partialStage = 1;
58
+				}
59
+
60
+				if ($partialId === null) {
61
+					$username = WebRequest::postString('username');
62
+
63
+					if ($username === null || trim($username) === '') {
64
+						throw new ApplicationLogicException('No username specified.');
65
+					}
66
+
67
+					$user = User::getByUsername($username, $database);
68
+				}
69
+				else {
70
+					$user = User::getById($partialId, $database);
71
+				}
72
+
73
+				if ($user === false) {
74
+					throw new ApplicationLogicException("Authentication failed");
75
+				}
76
+
77
+				$authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
78
+					$this->getHttpHelper());
79
+
80
+				$credential = $this->getProviderCredentials();
81
+
82
+				$authResult = $authMan->authenticate($user, $credential, $partialStage);
83
+
84
+				if ($authResult === AuthenticationManager::AUTH_FAIL) {
85
+					throw new ApplicationLogicException("Authentication failed");
86
+				}
87
+
88
+				if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
89
+					$this->processJumpNextStage($user, $partialStage, $database);
90
+
91
+					return;
92
+				}
93
+
94
+				if ($authResult === AuthenticationManager::AUTH_OK) {
95
+					$this->processLoginSuccess($user);
96
+
97
+					return;
98
+				}
99
+			}
100
+			catch (ApplicationLogicException $ex) {
101
+				WebRequest::clearAuthPartialLogin();
102
+
103
+				SessionAlert::error($ex->getMessage());
104
+				$this->redirect('login');
105
+
106
+				return;
107
+			}
108
+		}
109
+		else {
110
+			$this->assign('showSignIn', true);
111
+
112
+			$this->setupPartial();
113
+			$this->assignCSRFToken();
114
+			$this->providerSpecificSetup();
115
+		}
116
+	}
117
+
118
+	protected function isProtectedPage()
119
+	{
120
+		return false;
121
+	}
122
+
123
+	/**
124
+	 * Enforces HTTPS on the login form
125
+	 *
126
+	 * @return bool
127
+	 */
128
+	private function enforceHttps()
129
+	{
130
+		if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
131
+			if (WebRequest::isHttps()) {
132
+				// Client can clearly use HTTPS, so let's enforce it for all connections.
133
+				$this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
134
+			}
135
+			else {
136
+				// This is the login form, not the request form. We need protection here.
137
+				$this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
138
+
139
+				return false;
140
+			}
141
+		}
142
+
143
+		return true;
144
+	}
145
+
146
+	protected abstract function providerSpecificSetup();
147
+
148
+	protected function setupPartial()
149
+	{
150
+		$database = $this->getDatabase();
151
+
152
+		// default stuff
153
+		$this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
154
+
155
+		// is this stage one?
156
+		list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
157
+		if ($partialStage === null || $partialId === null) {
158
+			WebRequest::clearAuthPartialLogin();
159
+		}
160
+
161
+		// Check to see if we have a partial login in progress
162
+		$username = null;
163
+		if ($partialId !== null) {
164
+			// Yes, enforce this username
165
+			$this->partialUser = User::getById($partialId, $database);
166
+			$username = $this->partialUser->getUsername();
167
+
168
+			$this->setupAlternates($this->partialUser, $partialStage, $database);
169
+		}
170
+		else {
171
+			// No, see if we've preloaded a username
172
+			$preloadUsername = WebRequest::getString('tplUsername');
173
+			if ($preloadUsername !== null) {
174
+				$username = $preloadUsername;
175
+			}
176
+		}
177
+
178
+		if ($partialStage === null) {
179
+			$partialStage = 1;
180
+		}
181
+
182
+		$this->assign('partialStage', $partialStage);
183
+		$this->assign('username', $username);
184
+	}
185
+
186
+	/**
187
+	 * Redirect the user back to wherever they came from after a successful login
188
+	 *
189
+	 * @param User $user
190
+	 */
191
+	protected function goBackWhenceYouCame(User $user)
192
+	{
193
+		// Redirect to wherever the user came from
194
+		$redirectDestination = WebRequest::clearPostLoginRedirect();
195
+		if ($redirectDestination !== null) {
196
+			$this->redirectUrl($redirectDestination);
197
+		}
198
+		else {
199
+			if ($user->isNewUser()) {
200
+				// home page isn't allowed, go to preferences instead
201
+				$this->redirect('preferences');
202
+			}
203
+			else {
204
+				// go to the home page
205
+				$this->redirect('');
206
+			}
207
+		}
208
+	}
209
+
210
+	private function processLoginSuccess(User $user)
211
+	{
212
+		// Touch force logout
213
+		$user->setForceLogout(false);
214
+		$user->save();
215
+
216
+		$oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
217
+			$this->getSiteConfiguration());
218
+
219
+		if ($oauth->isFullyLinked()) {
220
+			try {
221
+				// Reload the user's identity ticket.
222
+				$oauth->refreshIdentity();
223
+
224
+				// Check for blocks
225
+				if ($oauth->getIdentity()->getBlocked()) {
226
+					// blocked!
227
+					SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
228
+					$this->redirect('login');
229
+
230
+					return;
231
+				}
232
+			}
233
+			catch (OAuthException $ex) {
234
+				// Oops. Refreshing ticket failed. Force a re-auth.
235
+				$authoriseUrl = $oauth->getRequestToken();
236
+				WebRequest::setOAuthPartialLogin($user);
237
+				$this->redirectUrl($authoriseUrl);
238
+
239
+				return;
240
+			}
241
+		}
242
+
243
+		if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
244
+			|| $oauth->isPartiallyLinked()
245
+		) {
246
+			$authoriseUrl = $oauth->getRequestToken();
247
+			WebRequest::setOAuthPartialLogin($user);
248
+			$this->redirectUrl($authoriseUrl);
249
+
250
+			return;
251
+		}
252
+
253
+		WebRequest::setLoggedInUser($user);
254
+
255
+		$this->goBackWhenceYouCame($user);
256
+	}
257
+
258
+	protected abstract function getProviderCredentials();
259
+
260
+	/**
261
+	 * @param User        $user
262
+	 * @param int         $partialStage
263
+	 * @param PdoDatabase $database
264
+	 *
265
+	 * @throws ApplicationLogicException
266
+	 */
267
+	private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
268
+	{
269
+		WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
270
+
271
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
272
+		$statement = $database->prepare($sql);
273
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
274
+		$nextStage = $statement->fetchColumn();
275
+		$statement->closeCursor();
276
+
277
+		if (!isset($this->nextPageMap[$nextStage])) {
278
+			throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
279
+		}
280
+
281
+		$this->redirect("login/" . $this->nextPageMap[$nextStage]);
282
+	}
283
+
284
+	private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
285
+	{
286
+		// get the providers available
287
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
288
+		$statement = $database->prepare($sql);
289
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
290
+		$alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
291
+
292
+		$types = array();
293
+		foreach ($alternates as $item) {
294
+			$type = $this->nextPageMap[$item];
295
+			if (!isset($types[$type])) {
296
+				$types[$type] = array();
297
+			}
298
+
299
+			$types[$type][] = $item;
300
+		}
301
+
302
+		$userOptions = array();
303
+		if (get_called_class() === PageOtpLogin::class) {
304
+			$userOptions = $this->setupUserOptionsForType($types, 'u2f', $userOptions);
305
+		}
306
+
307
+		if (get_called_class() === PageU2FLogin::class) {
308
+			$userOptions = $this->setupUserOptionsForType($types, 'otp', $userOptions);
309
+		}
310
+
311
+		$this->assign('alternatives', $userOptions);
312
+	}
313
+
314
+	/**
315
+	 * @param $types
316
+	 * @param $type
317
+	 * @param $userOptions
318
+	 *
319
+	 * @return mixed
320
+	 */
321
+	private function setupUserOptionsForType($types, $type, $userOptions)
322
+	{
323
+		if (isset($types[$type])) {
324
+			$options = $types[$type];
325
+
326
+			array_walk($options, function(&$val) {
327
+				$val = $this->names[$val];
328
+			});
329
+
330
+			$userOptions[$type] = $options;
331
+		}
332
+
333
+		return $userOptions;
334
+	}
335 335
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
             }
135 135
             else {
136 136
                 // This is the login form, not the request form. We need protection here.
137
-                $this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
137
+                $this->redirectUrl('https://'.WebRequest::serverName().WebRequest::requestUri());
138 138
 
139 139
                 return false;
140 140
             }
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
             throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
279 279
         }
280 280
 
281
-        $this->redirect("login/" . $this->nextPageMap[$nextStage]);
281
+        $this->redirect("login/".$this->nextPageMap[$nextStage]);
282 282
     }
283 283
 
284 284
     private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
Please login to merge, or discard this patch.
includes/Router/RequestRouter.php 2 patches
Unused Use Statements   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -15,30 +15,20 @@  discard block
 block discarded – undo
15 15
 use Waca\Pages\PageEmailManagement;
16 16
 use Waca\Pages\PageExpandedRequestList;
17 17
 use Waca\Pages\PageJobQueue;
18
-use Waca\Pages\RequestAction\PageCreateRequest;
19
-use Waca\Pages\UserAuth\Login\PageOtpLogin;
20
-use Waca\Pages\UserAuth\Login\PagePasswordLogin;
21
-use Waca\Pages\UserAuth\Login\PageU2FLogin;
22
-use Waca\Pages\UserAuth\PageChangePassword;
23
-use Waca\Pages\UserAuth\PageForgotPassword;
24 18
 use Waca\Pages\PageLog;
25
-use Waca\Pages\UserAuth\PageLogout;
26 19
 use Waca\Pages\PageMain;
27
-use Waca\Pages\UserAuth\MultiFactor\PageMultiFactor;
28
-use Waca\Pages\UserAuth\PageOAuth;
29
-use Waca\Pages\UserAuth\PageOAuthCallback;
30
-use Waca\Pages\UserAuth\PagePreferences;
31
-use Waca\Pages\Registration\PageRegisterStandard;
32
-use Waca\Pages\Registration\PageRegisterOption;
33 20
 use Waca\Pages\PageSearch;
34 21
 use Waca\Pages\PageSiteNotice;
35 22
 use Waca\Pages\PageTeam;
36 23
 use Waca\Pages\PageUserManagement;
37 24
 use Waca\Pages\PageViewRequest;
38 25
 use Waca\Pages\PageWelcomeTemplateManagement;
26
+use Waca\Pages\Registration\PageRegisterOption;
27
+use Waca\Pages\Registration\PageRegisterStandard;
39 28
 use Waca\Pages\RequestAction\PageBreakReservation;
40 29
 use Waca\Pages\RequestAction\PageCloseRequest;
41 30
 use Waca\Pages\RequestAction\PageComment;
31
+use Waca\Pages\RequestAction\PageCreateRequest;
42 32
 use Waca\Pages\RequestAction\PageCustomClose;
43 33
 use Waca\Pages\RequestAction\PageDeferRequest;
44 34
 use Waca\Pages\RequestAction\PageDropRequest;
@@ -52,6 +42,16 @@  discard block
 block discarded – undo
52 42
 use Waca\Pages\Statistics\StatsTemplateStats;
53 43
 use Waca\Pages\Statistics\StatsTopCreators;
54 44
 use Waca\Pages\Statistics\StatsUsers;
45
+use Waca\Pages\UserAuth\Login\PageOtpLogin;
46
+use Waca\Pages\UserAuth\Login\PagePasswordLogin;
47
+use Waca\Pages\UserAuth\Login\PageU2FLogin;
48
+use Waca\Pages\UserAuth\MultiFactor\PageMultiFactor;
49
+use Waca\Pages\UserAuth\PageChangePassword;
50
+use Waca\Pages\UserAuth\PageForgotPassword;
51
+use Waca\Pages\UserAuth\PageLogout;
52
+use Waca\Pages\UserAuth\PageOAuth;
53
+use Waca\Pages\UserAuth\PageOAuthCallback;
54
+use Waca\Pages\UserAuth\PagePreferences;
55 55
 use Waca\Tasks\IRoutedTask;
56 56
 use Waca\WebRequest;
57 57
 
Please login to merge, or discard this patch.
Indentation   +434 added lines, -434 removed lines patch added patch discarded remove patch
@@ -62,438 +62,438 @@
 block discarded – undo
62 62
  */
63 63
 class RequestRouter implements IRequestRouter
64 64
 {
65
-    /**
66
-     * This is the core routing table for the application. The basic idea is:
67
-     *
68
-     *      array(
69
-     *          "foo" =>
70
-     *              array(
71
-     *                  "class"   => PageFoo::class,
72
-     *                  "actions" => array("bar", "other")
73
-     *              ),
74
-     * );
75
-     *
76
-     * Things to note:
77
-     *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
78
-     *
79
-     *     - If a page is defined and requested, but no action is requested, go to that page's main() method
80
-     *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
81
-     *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
82
-     *       method.
83
-     *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
84
-     *
85
-     *     - Query parameters are ignored.
86
-     *
87
-     * The key point here is request routing with validation that this is allowed, before we start hitting the
88
-     * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
89
-     * before we start calling random methods through the web UI.
90
-     *
91
-     * Examples:
92
-     * /internal.php                => returns instance of PageMain, routed to main()
93
-     * /internal.php?query          => returns instance of PageMain, routed to main()
94
-     * /internal.php/foo            => returns instance of PageFoo, routed to main()
95
-     * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
96
-     * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
97
-     * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
98
-     * /internal.php/foo/baz        => returns instance of Page404, routed to main()
99
-     * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
100
-     * /internal.php/bar            => returns instance of Page404, routed to main()
101
-     * /internal.php/bar?query      => returns instance of Page404, routed to main()
102
-     * /internal.php/bar/baz        => returns instance of Page404, routed to main()
103
-     * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
104
-     *
105
-     * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
106
-     * to change the key, then you'll likely have to update a lot of files.
107
-     *
108
-     * @var array
109
-     */
110
-    private $routeMap = array(
111
-
112
-        //////////////////////////////////////////////////////////////////////////////////////////////////
113
-        // Login and registration
114
-        'logout'                      =>
115
-            array(
116
-                'class'   => PageLogout::class,
117
-                'actions' => array(),
118
-            ),
119
-        'login'                       =>
120
-            array(
121
-                'class'   => PagePasswordLogin::class,
122
-                'actions' => array(),
123
-            ),
124
-        'login/otp'                   =>
125
-            array(
126
-                'class'   => PageOtpLogin::class,
127
-                'actions' => array(),
128
-            ),
129
-        'login/u2f'                   =>
130
-            array(
131
-                'class'   => PageU2FLogin::class,
132
-                'actions' => array(),
133
-            ),
134
-        'forgotPassword'              =>
135
-            array(
136
-                'class'   => PageForgotPassword::class,
137
-                'actions' => array('reset'),
138
-            ),
139
-        'register'                    =>
140
-            array(
141
-                'class'   => PageRegisterOption::class,
142
-                'actions' => array(),
143
-            ),
144
-        'register/standard'           =>
145
-            array(
146
-                'class'   => PageRegisterStandard::class,
147
-                'actions' => array('done'),
148
-            ),
149
-
150
-        //////////////////////////////////////////////////////////////////////////////////////////////////
151
-        // Discovery
152
-        'search'                      =>
153
-            array(
154
-                'class'   => PageSearch::class,
155
-                'actions' => array(),
156
-            ),
157
-        'logs'                        =>
158
-            array(
159
-                'class'   => PageLog::class,
160
-                'actions' => array(),
161
-            ),
162
-
163
-        //////////////////////////////////////////////////////////////////////////////////////////////////
164
-        // Administration
165
-        'bans'                        =>
166
-            array(
167
-                'class'   => PageBan::class,
168
-                'actions' => array('set', 'remove'),
169
-            ),
170
-        'userManagement'              =>
171
-            array(
172
-                'class'   => PageUserManagement::class,
173
-                'actions' => array(
174
-                    'approve',
175
-                    'decline',
176
-                    'rename',
177
-                    'editUser',
178
-                    'suspend',
179
-                    'editRoles',
180
-                ),
181
-            ),
182
-        'siteNotice'                  =>
183
-            array(
184
-                'class'   => PageSiteNotice::class,
185
-                'actions' => array(),
186
-            ),
187
-        'emailManagement'             =>
188
-            array(
189
-                'class'   => PageEmailManagement::class,
190
-                'actions' => array('create', 'edit', 'view'),
191
-            ),
192
-        'jobQueue'                    =>
193
-            array(
194
-                'class'   => PageJobQueue::class,
195
-                'actions' => array('acknowledge', 'requeue', 'view', 'all'),
196
-            ),
197
-
198
-        //////////////////////////////////////////////////////////////////////////////////////////////////
199
-        // Personal preferences
200
-        'preferences'                 =>
201
-            array(
202
-                'class'   => PagePreferences::class,
203
-                'actions' => array(),
204
-            ),
205
-        'changePassword'              =>
206
-            array(
207
-                'class'   => PageChangePassword::class,
208
-                'actions' => array(),
209
-            ),
210
-        'multiFactor'                 =>
211
-            array(
212
-                'class'   => PageMultiFactor::class,
213
-                'actions' => array(
214
-                    'scratch',
215
-                    'enableYubikeyOtp',
216
-                    'disableYubikeyOtp',
217
-                    'enableTotp',
218
-                    'disableTotp',
219
-                    'enableU2F',
220
-                    'disableU2F',
221
-                ),
222
-            ),
223
-        'oauth'                       =>
224
-            array(
225
-                'class'   => PageOAuth::class,
226
-                'actions' => array('detach', 'attach'),
227
-            ),
228
-        'oauth/callback'              =>
229
-            array(
230
-                'class'   => PageOAuthCallback::class,
231
-                'actions' => array('authorise', 'create'),
232
-            ),
233
-
234
-        //////////////////////////////////////////////////////////////////////////////////////////////////
235
-        // Welcomer configuration
236
-        'welcomeTemplates'            =>
237
-            array(
238
-                'class'   => PageWelcomeTemplateManagement::class,
239
-                'actions' => array('select', 'edit', 'delete', 'add', 'view'),
240
-            ),
241
-
242
-        //////////////////////////////////////////////////////////////////////////////////////////////////
243
-        // Statistics
244
-        'statistics'                  =>
245
-            array(
246
-                'class'   => StatsMain::class,
247
-                'actions' => array(),
248
-            ),
249
-        'statistics/fastCloses'       =>
250
-            array(
251
-                'class'   => StatsFastCloses::class,
252
-                'actions' => array(),
253
-            ),
254
-        'statistics/inactiveUsers'    =>
255
-            array(
256
-                'class'   => StatsInactiveUsers::class,
257
-                'actions' => array(),
258
-            ),
259
-        'statistics/monthlyStats'     =>
260
-            array(
261
-                'class'   => StatsMonthlyStats::class,
262
-                'actions' => array(),
263
-            ),
264
-        'statistics/reservedRequests' =>
265
-            array(
266
-                'class'   => StatsReservedRequests::class,
267
-                'actions' => array(),
268
-            ),
269
-        'statistics/templateStats'    =>
270
-            array(
271
-                'class'   => StatsTemplateStats::class,
272
-                'actions' => array(),
273
-            ),
274
-        'statistics/topCreators'      =>
275
-            array(
276
-                'class'   => StatsTopCreators::class,
277
-                'actions' => array(),
278
-            ),
279
-        'statistics/users'            =>
280
-            array(
281
-                'class'   => StatsUsers::class,
282
-                'actions' => array('detail'),
283
-            ),
284
-
285
-        //////////////////////////////////////////////////////////////////////////////////////////////////
286
-        // Zoom page
287
-        'viewRequest'                 =>
288
-            array(
289
-                'class'   => PageViewRequest::class,
290
-                'actions' => array(),
291
-            ),
292
-        'viewRequest/reserve'         =>
293
-            array(
294
-                'class'   => PageReservation::class,
295
-                'actions' => array(),
296
-            ),
297
-        'viewRequest/breakReserve'    =>
298
-            array(
299
-                'class'   => PageBreakReservation::class,
300
-                'actions' => array(),
301
-            ),
302
-        'viewRequest/defer'           =>
303
-            array(
304
-                'class'   => PageDeferRequest::class,
305
-                'actions' => array(),
306
-            ),
307
-        'viewRequest/comment'         =>
308
-            array(
309
-                'class'   => PageComment::class,
310
-                'actions' => array(),
311
-            ),
312
-        'viewRequest/sendToUser'      =>
313
-            array(
314
-                'class'   => PageSendToUser::class,
315
-                'actions' => array(),
316
-            ),
317
-        'viewRequest/close'           =>
318
-            array(
319
-                'class'   => PageCloseRequest::class,
320
-                'actions' => array(),
321
-            ),
322
-        'viewRequest/create'          =>
323
-            array(
324
-                'class'   => PageCreateRequest::class,
325
-                'actions' => array(),
326
-            ),
327
-        'viewRequest/drop'            =>
328
-            array(
329
-                'class'   => PageDropRequest::class,
330
-                'actions' => array(),
331
-            ),
332
-        'viewRequest/custom'          =>
333
-            array(
334
-                'class'   => PageCustomClose::class,
335
-                'actions' => array(),
336
-            ),
337
-        'editComment'                 =>
338
-            array(
339
-                'class'   => PageEditComment::class,
340
-                'actions' => array(),
341
-            ),
342
-
343
-        //////////////////////////////////////////////////////////////////////////////////////////////////
344
-        // Misc stuff
345
-        'team'                        =>
346
-            array(
347
-                'class'   => PageTeam::class,
348
-                'actions' => array(),
349
-            ),
350
-        'requestList'                 =>
351
-            array(
352
-                'class'   => PageExpandedRequestList::class,
353
-                'actions' => array(),
354
-            ),
355
-    );
356
-
357
-    /**
358
-     * @return IRoutedTask
359
-     * @throws Exception
360
-     */
361
-    final public function route()
362
-    {
363
-        $pathInfo = WebRequest::pathInfo();
364
-
365
-        list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
366
-
367
-        /** @var IRoutedTask $page */
368
-        $page = new $pageClass();
369
-
370
-        // Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
371
-        // let's use our own.
372
-        if (!($page instanceof IRoutedTask)) {
373
-            throw new Exception('Expected a page, but this is not a page.');
374
-        }
375
-
376
-        // OK, I'm happy at this point that we know we're running a page, and we know it's probably what we want if it
377
-        // inherits PageBase and has been created from the routing map.
378
-        $page->setRoute($action);
379
-
380
-        return $page;
381
-    }
382
-
383
-    /**
384
-     * @param $pathInfo
385
-     *
386
-     * @return array
387
-     */
388
-    protected function getRouteFromPath($pathInfo)
389
-    {
390
-        if (count($pathInfo) === 0) {
391
-            // No pathInfo, so no page to load. Load the main page.
392
-            return $this->getDefaultRoute();
393
-        }
394
-        elseif (count($pathInfo) === 1) {
395
-            // Exactly one path info segment, it's got to be a page.
396
-            $classSegment = $pathInfo[0];
397
-
398
-            return $this->routeSinglePathSegment($classSegment);
399
-        }
400
-
401
-        // OK, we have two or more segments now.
402
-        if (count($pathInfo) > 2) {
403
-            // Let's handle more than two, and collapse it down into two.
404
-            $requestedAction = array_pop($pathInfo);
405
-            $classSegment = implode('/', $pathInfo);
406
-        }
407
-        else {
408
-            // Two path info segments.
409
-            $classSegment = $pathInfo[0];
410
-            $requestedAction = $pathInfo[1];
411
-        }
412
-
413
-        $routeMap = $this->routePathSegments($classSegment, $requestedAction);
414
-
415
-        if ($routeMap[0] === Page404::class) {
416
-            $routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
417
-        }
418
-
419
-        return $routeMap;
420
-    }
421
-
422
-    /**
423
-     * @param $classSegment
424
-     *
425
-     * @return array
426
-     */
427
-    final protected function routeSinglePathSegment($classSegment)
428
-    {
429
-        $routeMap = $this->getRouteMap();
430
-        if (array_key_exists($classSegment, $routeMap)) {
431
-            // Route exists, but we don't have an action in path info, so default to main.
432
-            $pageClass = $routeMap[$classSegment]['class'];
433
-            $action = 'main';
434
-
435
-            return array($pageClass, $action);
436
-        }
437
-        else {
438
-            // Doesn't exist in map. Fall back to 404
439
-            $pageClass = Page404::class;
440
-            $action = "main";
441
-
442
-            return array($pageClass, $action);
443
-        }
444
-    }
445
-
446
-    /**
447
-     * @param $classSegment
448
-     * @param $requestedAction
449
-     *
450
-     * @return array
451
-     */
452
-    final protected function routePathSegments($classSegment, $requestedAction)
453
-    {
454
-        $routeMap = $this->getRouteMap();
455
-        if (array_key_exists($classSegment, $routeMap)) {
456
-            // Route exists, but we don't have an action in path info, so default to main.
457
-
458
-            if (isset($routeMap[$classSegment]['actions'])
459
-                && array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
460
-            ) {
461
-                // Action exists in allowed action list. Allow both the page and the action
462
-                $pageClass = $routeMap[$classSegment]['class'];
463
-                $action = $requestedAction;
464
-
465
-                return array($pageClass, $action);
466
-            }
467
-            else {
468
-                // Valid page, invalid action. 404 our way out.
469
-                $pageClass = Page404::class;
470
-                $action = 'main';
471
-
472
-                return array($pageClass, $action);
473
-            }
474
-        }
475
-        else {
476
-            // Class doesn't exist in map. Fall back to 404
477
-            $pageClass = Page404::class;
478
-            $action = 'main';
479
-
480
-            return array($pageClass, $action);
481
-        }
482
-    }
483
-
484
-    /**
485
-     * @return array
486
-     */
487
-    protected function getRouteMap()
488
-    {
489
-        return $this->routeMap;
490
-    }
491
-
492
-    /**
493
-     * @return callable
494
-     */
495
-    protected function getDefaultRoute()
496
-    {
497
-        return array(PageMain::class, "main");
498
-    }
65
+	/**
66
+	 * This is the core routing table for the application. The basic idea is:
67
+	 *
68
+	 *      array(
69
+	 *          "foo" =>
70
+	 *              array(
71
+	 *                  "class"   => PageFoo::class,
72
+	 *                  "actions" => array("bar", "other")
73
+	 *              ),
74
+	 * );
75
+	 *
76
+	 * Things to note:
77
+	 *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
78
+	 *
79
+	 *     - If a page is defined and requested, but no action is requested, go to that page's main() method
80
+	 *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
81
+	 *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
82
+	 *       method.
83
+	 *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
84
+	 *
85
+	 *     - Query parameters are ignored.
86
+	 *
87
+	 * The key point here is request routing with validation that this is allowed, before we start hitting the
88
+	 * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
89
+	 * before we start calling random methods through the web UI.
90
+	 *
91
+	 * Examples:
92
+	 * /internal.php                => returns instance of PageMain, routed to main()
93
+	 * /internal.php?query          => returns instance of PageMain, routed to main()
94
+	 * /internal.php/foo            => returns instance of PageFoo, routed to main()
95
+	 * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
96
+	 * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
97
+	 * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
98
+	 * /internal.php/foo/baz        => returns instance of Page404, routed to main()
99
+	 * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
100
+	 * /internal.php/bar            => returns instance of Page404, routed to main()
101
+	 * /internal.php/bar?query      => returns instance of Page404, routed to main()
102
+	 * /internal.php/bar/baz        => returns instance of Page404, routed to main()
103
+	 * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
104
+	 *
105
+	 * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
106
+	 * to change the key, then you'll likely have to update a lot of files.
107
+	 *
108
+	 * @var array
109
+	 */
110
+	private $routeMap = array(
111
+
112
+		//////////////////////////////////////////////////////////////////////////////////////////////////
113
+		// Login and registration
114
+		'logout'                      =>
115
+			array(
116
+				'class'   => PageLogout::class,
117
+				'actions' => array(),
118
+			),
119
+		'login'                       =>
120
+			array(
121
+				'class'   => PagePasswordLogin::class,
122
+				'actions' => array(),
123
+			),
124
+		'login/otp'                   =>
125
+			array(
126
+				'class'   => PageOtpLogin::class,
127
+				'actions' => array(),
128
+			),
129
+		'login/u2f'                   =>
130
+			array(
131
+				'class'   => PageU2FLogin::class,
132
+				'actions' => array(),
133
+			),
134
+		'forgotPassword'              =>
135
+			array(
136
+				'class'   => PageForgotPassword::class,
137
+				'actions' => array('reset'),
138
+			),
139
+		'register'                    =>
140
+			array(
141
+				'class'   => PageRegisterOption::class,
142
+				'actions' => array(),
143
+			),
144
+		'register/standard'           =>
145
+			array(
146
+				'class'   => PageRegisterStandard::class,
147
+				'actions' => array('done'),
148
+			),
149
+
150
+		//////////////////////////////////////////////////////////////////////////////////////////////////
151
+		// Discovery
152
+		'search'                      =>
153
+			array(
154
+				'class'   => PageSearch::class,
155
+				'actions' => array(),
156
+			),
157
+		'logs'                        =>
158
+			array(
159
+				'class'   => PageLog::class,
160
+				'actions' => array(),
161
+			),
162
+
163
+		//////////////////////////////////////////////////////////////////////////////////////////////////
164
+		// Administration
165
+		'bans'                        =>
166
+			array(
167
+				'class'   => PageBan::class,
168
+				'actions' => array('set', 'remove'),
169
+			),
170
+		'userManagement'              =>
171
+			array(
172
+				'class'   => PageUserManagement::class,
173
+				'actions' => array(
174
+					'approve',
175
+					'decline',
176
+					'rename',
177
+					'editUser',
178
+					'suspend',
179
+					'editRoles',
180
+				),
181
+			),
182
+		'siteNotice'                  =>
183
+			array(
184
+				'class'   => PageSiteNotice::class,
185
+				'actions' => array(),
186
+			),
187
+		'emailManagement'             =>
188
+			array(
189
+				'class'   => PageEmailManagement::class,
190
+				'actions' => array('create', 'edit', 'view'),
191
+			),
192
+		'jobQueue'                    =>
193
+			array(
194
+				'class'   => PageJobQueue::class,
195
+				'actions' => array('acknowledge', 'requeue', 'view', 'all'),
196
+			),
197
+
198
+		//////////////////////////////////////////////////////////////////////////////////////////////////
199
+		// Personal preferences
200
+		'preferences'                 =>
201
+			array(
202
+				'class'   => PagePreferences::class,
203
+				'actions' => array(),
204
+			),
205
+		'changePassword'              =>
206
+			array(
207
+				'class'   => PageChangePassword::class,
208
+				'actions' => array(),
209
+			),
210
+		'multiFactor'                 =>
211
+			array(
212
+				'class'   => PageMultiFactor::class,
213
+				'actions' => array(
214
+					'scratch',
215
+					'enableYubikeyOtp',
216
+					'disableYubikeyOtp',
217
+					'enableTotp',
218
+					'disableTotp',
219
+					'enableU2F',
220
+					'disableU2F',
221
+				),
222
+			),
223
+		'oauth'                       =>
224
+			array(
225
+				'class'   => PageOAuth::class,
226
+				'actions' => array('detach', 'attach'),
227
+			),
228
+		'oauth/callback'              =>
229
+			array(
230
+				'class'   => PageOAuthCallback::class,
231
+				'actions' => array('authorise', 'create'),
232
+			),
233
+
234
+		//////////////////////////////////////////////////////////////////////////////////////////////////
235
+		// Welcomer configuration
236
+		'welcomeTemplates'            =>
237
+			array(
238
+				'class'   => PageWelcomeTemplateManagement::class,
239
+				'actions' => array('select', 'edit', 'delete', 'add', 'view'),
240
+			),
241
+
242
+		//////////////////////////////////////////////////////////////////////////////////////////////////
243
+		// Statistics
244
+		'statistics'                  =>
245
+			array(
246
+				'class'   => StatsMain::class,
247
+				'actions' => array(),
248
+			),
249
+		'statistics/fastCloses'       =>
250
+			array(
251
+				'class'   => StatsFastCloses::class,
252
+				'actions' => array(),
253
+			),
254
+		'statistics/inactiveUsers'    =>
255
+			array(
256
+				'class'   => StatsInactiveUsers::class,
257
+				'actions' => array(),
258
+			),
259
+		'statistics/monthlyStats'     =>
260
+			array(
261
+				'class'   => StatsMonthlyStats::class,
262
+				'actions' => array(),
263
+			),
264
+		'statistics/reservedRequests' =>
265
+			array(
266
+				'class'   => StatsReservedRequests::class,
267
+				'actions' => array(),
268
+			),
269
+		'statistics/templateStats'    =>
270
+			array(
271
+				'class'   => StatsTemplateStats::class,
272
+				'actions' => array(),
273
+			),
274
+		'statistics/topCreators'      =>
275
+			array(
276
+				'class'   => StatsTopCreators::class,
277
+				'actions' => array(),
278
+			),
279
+		'statistics/users'            =>
280
+			array(
281
+				'class'   => StatsUsers::class,
282
+				'actions' => array('detail'),
283
+			),
284
+
285
+		//////////////////////////////////////////////////////////////////////////////////////////////////
286
+		// Zoom page
287
+		'viewRequest'                 =>
288
+			array(
289
+				'class'   => PageViewRequest::class,
290
+				'actions' => array(),
291
+			),
292
+		'viewRequest/reserve'         =>
293
+			array(
294
+				'class'   => PageReservation::class,
295
+				'actions' => array(),
296
+			),
297
+		'viewRequest/breakReserve'    =>
298
+			array(
299
+				'class'   => PageBreakReservation::class,
300
+				'actions' => array(),
301
+			),
302
+		'viewRequest/defer'           =>
303
+			array(
304
+				'class'   => PageDeferRequest::class,
305
+				'actions' => array(),
306
+			),
307
+		'viewRequest/comment'         =>
308
+			array(
309
+				'class'   => PageComment::class,
310
+				'actions' => array(),
311
+			),
312
+		'viewRequest/sendToUser'      =>
313
+			array(
314
+				'class'   => PageSendToUser::class,
315
+				'actions' => array(),
316
+			),
317
+		'viewRequest/close'           =>
318
+			array(
319
+				'class'   => PageCloseRequest::class,
320
+				'actions' => array(),
321
+			),
322
+		'viewRequest/create'          =>
323
+			array(
324
+				'class'   => PageCreateRequest::class,
325
+				'actions' => array(),
326
+			),
327
+		'viewRequest/drop'            =>
328
+			array(
329
+				'class'   => PageDropRequest::class,
330
+				'actions' => array(),
331
+			),
332
+		'viewRequest/custom'          =>
333
+			array(
334
+				'class'   => PageCustomClose::class,
335
+				'actions' => array(),
336
+			),
337
+		'editComment'                 =>
338
+			array(
339
+				'class'   => PageEditComment::class,
340
+				'actions' => array(),
341
+			),
342
+
343
+		//////////////////////////////////////////////////////////////////////////////////////////////////
344
+		// Misc stuff
345
+		'team'                        =>
346
+			array(
347
+				'class'   => PageTeam::class,
348
+				'actions' => array(),
349
+			),
350
+		'requestList'                 =>
351
+			array(
352
+				'class'   => PageExpandedRequestList::class,
353
+				'actions' => array(),
354
+			),
355
+	);
356
+
357
+	/**
358
+	 * @return IRoutedTask
359
+	 * @throws Exception
360
+	 */
361
+	final public function route()
362
+	{
363
+		$pathInfo = WebRequest::pathInfo();
364
+
365
+		list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
366
+
367
+		/** @var IRoutedTask $page */
368
+		$page = new $pageClass();
369
+
370
+		// Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
371
+		// let's use our own.
372
+		if (!($page instanceof IRoutedTask)) {
373
+			throw new Exception('Expected a page, but this is not a page.');
374
+		}
375
+
376
+		// OK, I'm happy at this point that we know we're running a page, and we know it's probably what we want if it
377
+		// inherits PageBase and has been created from the routing map.
378
+		$page->setRoute($action);
379
+
380
+		return $page;
381
+	}
382
+
383
+	/**
384
+	 * @param $pathInfo
385
+	 *
386
+	 * @return array
387
+	 */
388
+	protected function getRouteFromPath($pathInfo)
389
+	{
390
+		if (count($pathInfo) === 0) {
391
+			// No pathInfo, so no page to load. Load the main page.
392
+			return $this->getDefaultRoute();
393
+		}
394
+		elseif (count($pathInfo) === 1) {
395
+			// Exactly one path info segment, it's got to be a page.
396
+			$classSegment = $pathInfo[0];
397
+
398
+			return $this->routeSinglePathSegment($classSegment);
399
+		}
400
+
401
+		// OK, we have two or more segments now.
402
+		if (count($pathInfo) > 2) {
403
+			// Let's handle more than two, and collapse it down into two.
404
+			$requestedAction = array_pop($pathInfo);
405
+			$classSegment = implode('/', $pathInfo);
406
+		}
407
+		else {
408
+			// Two path info segments.
409
+			$classSegment = $pathInfo[0];
410
+			$requestedAction = $pathInfo[1];
411
+		}
412
+
413
+		$routeMap = $this->routePathSegments($classSegment, $requestedAction);
414
+
415
+		if ($routeMap[0] === Page404::class) {
416
+			$routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
417
+		}
418
+
419
+		return $routeMap;
420
+	}
421
+
422
+	/**
423
+	 * @param $classSegment
424
+	 *
425
+	 * @return array
426
+	 */
427
+	final protected function routeSinglePathSegment($classSegment)
428
+	{
429
+		$routeMap = $this->getRouteMap();
430
+		if (array_key_exists($classSegment, $routeMap)) {
431
+			// Route exists, but we don't have an action in path info, so default to main.
432
+			$pageClass = $routeMap[$classSegment]['class'];
433
+			$action = 'main';
434
+
435
+			return array($pageClass, $action);
436
+		}
437
+		else {
438
+			// Doesn't exist in map. Fall back to 404
439
+			$pageClass = Page404::class;
440
+			$action = "main";
441
+
442
+			return array($pageClass, $action);
443
+		}
444
+	}
445
+
446
+	/**
447
+	 * @param $classSegment
448
+	 * @param $requestedAction
449
+	 *
450
+	 * @return array
451
+	 */
452
+	final protected function routePathSegments($classSegment, $requestedAction)
453
+	{
454
+		$routeMap = $this->getRouteMap();
455
+		if (array_key_exists($classSegment, $routeMap)) {
456
+			// Route exists, but we don't have an action in path info, so default to main.
457
+
458
+			if (isset($routeMap[$classSegment]['actions'])
459
+				&& array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
460
+			) {
461
+				// Action exists in allowed action list. Allow both the page and the action
462
+				$pageClass = $routeMap[$classSegment]['class'];
463
+				$action = $requestedAction;
464
+
465
+				return array($pageClass, $action);
466
+			}
467
+			else {
468
+				// Valid page, invalid action. 404 our way out.
469
+				$pageClass = Page404::class;
470
+				$action = 'main';
471
+
472
+				return array($pageClass, $action);
473
+			}
474
+		}
475
+		else {
476
+			// Class doesn't exist in map. Fall back to 404
477
+			$pageClass = Page404::class;
478
+			$action = 'main';
479
+
480
+			return array($pageClass, $action);
481
+		}
482
+	}
483
+
484
+	/**
485
+	 * @return array
486
+	 */
487
+	protected function getRouteMap()
488
+	{
489
+		return $this->routeMap;
490
+	}
491
+
492
+	/**
493
+	 * @return callable
494
+	 */
495
+	protected function getDefaultRoute()
496
+	{
497
+		return array(PageMain::class, "main");
498
+	}
499 499
 }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/ICredentialProvider.php 2 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -31,6 +31,7 @@
 block discarded – undo
31 31
 
32 32
     /**
33 33
      * @param User $user
34
+     * @return void
34 35
      */
35 36
     public function deleteCredential(User $user);
36 37
 
Please login to merge, or discard this patch.
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -12,32 +12,32 @@
 block discarded – undo
12 12
 
13 13
 interface ICredentialProvider
14 14
 {
15
-    /**
16
-     * Validates a user-provided credential
17
-     *
18
-     * @param User $user The user to test the authentication against
19
-     * @param string $data The raw credential data to be validated
20
-     *
21
-     * @return bool
22
-     */
23
-    public function authenticate(User $user, $data);
15
+	/**
16
+	 * Validates a user-provided credential
17
+	 *
18
+	 * @param User $user The user to test the authentication against
19
+	 * @param string $data The raw credential data to be validated
20
+	 *
21
+	 * @return bool
22
+	 */
23
+	public function authenticate(User $user, $data);
24 24
 
25
-    /**
26
-     * @param User $user The user the credential belongs to
27
-     * @param int $factor The factor this credential provides
28
-     * @param string $data
29
-     */
30
-    public function setCredential(User $user, $factor, $data);
25
+	/**
26
+	 * @param User $user The user the credential belongs to
27
+	 * @param int $factor The factor this credential provides
28
+	 * @param string $data
29
+	 */
30
+	public function setCredential(User $user, $factor, $data);
31 31
 
32
-    /**
33
-     * @param User $user
34
-     */
35
-    public function deleteCredential(User $user);
32
+	/**
33
+	 * @param User $user
34
+	 */
35
+	public function deleteCredential(User $user);
36 36
 
37
-    /**
38
-     * @param int $userId
39
-     *
40
-     * @return bool
41
-     */
42
-    public function userIsEnrolled($userId);
37
+	/**
38
+	 * @param int $userId
39
+	 *
40
+	 * @return bool
41
+	 */
42
+	public function userIsEnrolled($userId);
43 43
 }
44 44
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/TotpCredentialProvider.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -61,6 +61,9 @@
 block discarded – undo
61 61
         return $totp->verify($data, null, 2);
62 62
     }
63 63
 
64
+    /**
65
+     * @param null|string $data
66
+     */
64 67
     public function verifyEnable(User $user, $data)
65 68
     {
66 69
         $storedData = $this->getCredentialData($user->getId(), true);
Please login to merge, or discard this patch.
Indentation   +129 added lines, -129 removed lines patch added patch discarded remove patch
@@ -19,136 +19,136 @@
 block discarded – undo
19 19
 
20 20
 class TotpCredentialProvider extends CredentialProviderBase
21 21
 {
22
-    /** @var EncryptionHelper */
23
-    private $encryptionHelper;
24
-
25
-    /**
26
-     * TotpCredentialProvider constructor.
27
-     *
28
-     * @param PdoDatabase       $database
29
-     * @param SiteConfiguration $configuration
30
-     */
31
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
-    {
33
-        parent::__construct($database, $configuration, 'totp');
34
-        $this->encryptionHelper = new EncryptionHelper($configuration);
35
-    }
36
-
37
-    /**
38
-     * Validates a user-provided credential
39
-     *
40
-     * @param User   $user The user to test the authentication against
41
-     * @param string $data The raw credential data to be validated
42
-     *
43
-     * @return bool
44
-     * @throws ApplicationLogicException
45
-     */
46
-    public function authenticate(User $user, $data)
47
-    {
48
-        if (is_array($data)) {
49
-            return false;
50
-        }
51
-
52
-        $storedData = $this->getCredentialData($user->getId());
53
-
54
-        if ($storedData === null) {
55
-            throw new ApplicationLogicException('Credential data not found');
56
-        }
57
-
58
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
-
61
-        return $totp->verify($data, null, 2);
62
-    }
63
-
64
-    public function verifyEnable(User $user, $data)
65
-    {
66
-        $storedData = $this->getCredentialData($user->getId(), true);
67
-
68
-        if ($storedData === null) {
69
-            throw new ApplicationLogicException('Credential data not found');
70
-        }
71
-
72
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
-
75
-        $result = $totp->verify($data, null, 2);
76
-
77
-        if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
-            $storedData->setDisabled(0);
79
-            $storedData->setPriority(5);
80
-            $storedData->setTimeout(null);
81
-            $storedData->save();
82
-        }
83
-
84
-        return $result;
85
-    }
86
-
87
-    /**
88
-     * @param User   $user   The user the credential belongs to
89
-     * @param int    $factor The factor this credential provides
90
-     * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
-     */
92
-    public function setCredential(User $user, $factor, $data)
93
-    {
94
-        $issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
-        $totp = new TOTP($user->getUsername());
96
-        $totp->setIssuer($issuer);
97
-
98
-        $storedData = $this->getCredentialData($user->getId(), null);
99
-
100
-        if ($storedData !== null) {
101
-            $storedData->delete();
102
-        }
103
-
104
-        $storedData = $this->createNewCredential($user);
105
-
106
-        $storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
107
-        $storedData->setFactor($factor);
108
-        $storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
109
-        $storedData->setDisabled(1);
110
-        $storedData->setVersion(1);
111
-
112
-        $storedData->save();
113
-    }
114
-
115
-    public function getProvisioningUrl(User $user)
116
-    {
117
-        $storedData = $this->getCredentialData($user->getId(), true);
118
-
119
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
120
-            $storedData->delete();
121
-            $storedData = null;
122
-        }
123
-
124
-        if ($storedData === null) {
125
-            throw new ApplicationLogicException('Credential data not found');
126
-        }
127
-
128
-        return $this->encryptionHelper->decryptData($storedData->getData());
129
-    }
130
-
131
-    public function isPartiallyEnrolled(User $user)
132
-    {
133
-        $storedData = $this->getCredentialData($user->getId(), true);
134
-
135
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
136
-            $storedData->delete();
137
-
138
-            return false;
139
-        }
140
-
141
-        if ($storedData === null) {
142
-            return false;
143
-        }
22
+	/** @var EncryptionHelper */
23
+	private $encryptionHelper;
24
+
25
+	/**
26
+	 * TotpCredentialProvider constructor.
27
+	 *
28
+	 * @param PdoDatabase       $database
29
+	 * @param SiteConfiguration $configuration
30
+	 */
31
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
+	{
33
+		parent::__construct($database, $configuration, 'totp');
34
+		$this->encryptionHelper = new EncryptionHelper($configuration);
35
+	}
36
+
37
+	/**
38
+	 * Validates a user-provided credential
39
+	 *
40
+	 * @param User   $user The user to test the authentication against
41
+	 * @param string $data The raw credential data to be validated
42
+	 *
43
+	 * @return bool
44
+	 * @throws ApplicationLogicException
45
+	 */
46
+	public function authenticate(User $user, $data)
47
+	{
48
+		if (is_array($data)) {
49
+			return false;
50
+		}
51
+
52
+		$storedData = $this->getCredentialData($user->getId());
53
+
54
+		if ($storedData === null) {
55
+			throw new ApplicationLogicException('Credential data not found');
56
+		}
57
+
58
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
+
61
+		return $totp->verify($data, null, 2);
62
+	}
63
+
64
+	public function verifyEnable(User $user, $data)
65
+	{
66
+		$storedData = $this->getCredentialData($user->getId(), true);
67
+
68
+		if ($storedData === null) {
69
+			throw new ApplicationLogicException('Credential data not found');
70
+		}
71
+
72
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
+
75
+		$result = $totp->verify($data, null, 2);
76
+
77
+		if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
+			$storedData->setDisabled(0);
79
+			$storedData->setPriority(5);
80
+			$storedData->setTimeout(null);
81
+			$storedData->save();
82
+		}
83
+
84
+		return $result;
85
+	}
86
+
87
+	/**
88
+	 * @param User   $user   The user the credential belongs to
89
+	 * @param int    $factor The factor this credential provides
90
+	 * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
+	 */
92
+	public function setCredential(User $user, $factor, $data)
93
+	{
94
+		$issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
+		$totp = new TOTP($user->getUsername());
96
+		$totp->setIssuer($issuer);
97
+
98
+		$storedData = $this->getCredentialData($user->getId(), null);
99
+
100
+		if ($storedData !== null) {
101
+			$storedData->delete();
102
+		}
103
+
104
+		$storedData = $this->createNewCredential($user);
105
+
106
+		$storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
107
+		$storedData->setFactor($factor);
108
+		$storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
109
+		$storedData->setDisabled(1);
110
+		$storedData->setVersion(1);
111
+
112
+		$storedData->save();
113
+	}
114
+
115
+	public function getProvisioningUrl(User $user)
116
+	{
117
+		$storedData = $this->getCredentialData($user->getId(), true);
118
+
119
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
120
+			$storedData->delete();
121
+			$storedData = null;
122
+		}
123
+
124
+		if ($storedData === null) {
125
+			throw new ApplicationLogicException('Credential data not found');
126
+		}
127
+
128
+		return $this->encryptionHelper->decryptData($storedData->getData());
129
+	}
130
+
131
+	public function isPartiallyEnrolled(User $user)
132
+	{
133
+		$storedData = $this->getCredentialData($user->getId(), true);
134
+
135
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
136
+			$storedData->delete();
137
+
138
+			return false;
139
+		}
140
+
141
+		if ($storedData === null) {
142
+			return false;
143
+		}
144 144
 
145
-        return true;
146
-    }
145
+		return true;
146
+	}
147 147
 
148
-    public function getSecret(User $user)
149
-    {
150
-        $totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
148
+	public function getSecret(User $user)
149
+	{
150
+		$totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
151 151
 
152
-        return $totp->getSecret();
153
-    }
152
+		return $totp->getSecret();
153
+	}
154 154
 }
155 155
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -91,7 +91,7 @@
 block discarded – undo
91 91
      */
92 92
     public function setCredential(User $user, $factor, $data)
93 93
     {
94
-        $issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
94
+        $issuer = 'ACC - '.$this->getConfiguration()->getIrcNotificationsInstance();
95 95
         $totp = new TOTP($user->getUsername());
96 96
         $totp->setIssuer($issuer);
97 97
 
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/YubikeyOtpCredentialProvider.php 3 patches
Doc Comments   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
     }
105 105
 
106 106
     /**
107
-     * @param $result
107
+     * @param string $result
108 108
      *
109 109
      * @return array
110 110
      */
@@ -123,6 +123,9 @@  discard block
 block discarded – undo
123 123
         return $data;
124 124
     }
125 125
 
126
+    /**
127
+     * @param string $data
128
+     */
126 129
     private function getYubikeyId($data)
127 130
     {
128 131
         return substr($data, 0, -32);
@@ -146,7 +149,7 @@  discard block
 block discarded – undo
146 149
     }
147 150
 
148 151
     /**
149
-     * @param $data
152
+     * @param string $data
150 153
      *
151 154
      * @return bool
152 155
      */
Please login to merge, or discard this patch.
Indentation   +150 added lines, -150 removed lines patch added patch discarded remove patch
@@ -16,154 +16,154 @@
 block discarded – undo
16 16
 
17 17
 class YubikeyOtpCredentialProvider extends CredentialProviderBase
18 18
 {
19
-    /** @var HttpHelper */
20
-    private $httpHelper;
21
-    /**
22
-     * @var SiteConfiguration
23
-     */
24
-    private $configuration;
25
-
26
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration, HttpHelper $httpHelper)
27
-    {
28
-        parent::__construct($database, $configuration, 'yubikeyotp');
29
-        $this->httpHelper = $httpHelper;
30
-        $this->configuration = $configuration;
31
-    }
32
-
33
-    public function authenticate(User $user, $data)
34
-    {
35
-        if (is_array($data)) {
36
-            return false;
37
-        }
38
-
39
-        $credentialData = $this->getCredentialData($user->getId());
40
-
41
-        if ($credentialData === null) {
42
-            return false;
43
-        }
44
-
45
-        if ($credentialData->getData() !== $this->getYubikeyId($data)) {
46
-            // different device
47
-            return false;
48
-        }
49
-
50
-        return $this->verifyToken($data);
51
-    }
52
-
53
-    public function setCredential(User $user, $factor, $data)
54
-    {
55
-        $keyId = $this->getYubikeyId($data);
56
-        $valid = $this->verifyToken($data);
57
-
58
-        if (!$valid) {
59
-            throw new ApplicationLogicException("Provided token is not valid.");
60
-        }
61
-
62
-        $storedData = $this->getCredentialData($user->getId());
63
-
64
-        if ($storedData === null) {
65
-            $storedData = $this->createNewCredential($user);
66
-        }
67
-
68
-        $storedData->setData($keyId);
69
-        $storedData->setFactor($factor);
70
-        $storedData->setVersion(1);
71
-        $storedData->setPriority(8);
72
-
73
-        $storedData->save();
74
-    }
75
-
76
-    /**
77
-     * Get the Yubikey ID.
78
-     *
79
-     * This looks like it's just dumping the "password" that's stored in the database, but it's actually fine.
80
-     *
81
-     * We only store the "serial number" of the Yubikey - if we get a validated (by webservice) token prefixed with the
82
-     * serial number, that's a successful OTP authentication. Thus, retrieving the stored data is just retrieving the
83
-     * yubikey's serial number (in modhex format), since the actual security credentials are stored on the device.
84
-     *
85
-     * Note that the serial number is actually the credential serial number - it's possible to regenerate the keys on
86
-     * the device, and that will change the serial number too.
87
-     *
88
-     * More information about the structure of OTPs can be found here:
89
-     * https://developers.yubico.com/OTP/OTPs_Explained.html
90
-     *
91
-     * @param int $userId
92
-     *
93
-     * @return null|string
94
-     */
95
-    public function getYubikeyData($userId)
96
-    {
97
-        $credential = $this->getCredentialData($userId);
98
-
99
-        if ($credential === null) {
100
-            return null;
101
-        }
102
-
103
-        return $credential->getData();
104
-    }
105
-
106
-    /**
107
-     * @param $result
108
-     *
109
-     * @return array
110
-     */
111
-    private function parseYubicoApiResult($result)
112
-    {
113
-        $data = array();
114
-        foreach (explode("\r\n", $result) as $line) {
115
-            $pos = strpos($line, '=');
116
-            if ($pos === false) {
117
-                continue;
118
-            }
119
-
120
-            $data[substr($line, 0, $pos)] = substr($line, $pos + 1);
121
-        }
122
-
123
-        return $data;
124
-    }
125
-
126
-    private function getYubikeyId($data)
127
-    {
128
-        return substr($data, 0, -32);
129
-    }
130
-
131
-    private function verifyHmac($apiResponse, $apiKey)
132
-    {
133
-        ksort($apiResponse);
134
-        $signature = $apiResponse['h'];
135
-        unset($apiResponse['h']);
136
-
137
-        $data = array();
138
-        foreach ($apiResponse as $key => $value) {
139
-            $data[] = $key . "=" . $value;
140
-        }
141
-        $dataString = implode('&', $data);
142
-
143
-        $hmac = base64_encode(hash_hmac('sha1', $dataString, base64_decode($apiKey), true));
144
-
145
-        return $hmac === $signature;
146
-    }
147
-
148
-    /**
149
-     * @param $data
150
-     *
151
-     * @return bool
152
-     */
153
-    private function verifyToken($data)
154
-    {
155
-        $result = $this->httpHelper->get('https://api.yubico.com/wsapi/2.0/verify', array(
156
-            'id'    => $this->configuration->getYubicoApiId(),
157
-            'otp'   => $data,
158
-            'nonce' => md5(openssl_random_pseudo_bytes(64)),
159
-        ));
160
-
161
-        $apiResponse = $this->parseYubicoApiResult($result);
162
-
163
-        if (!$this->verifyHmac($apiResponse, $this->configuration->getYubicoApiKey())) {
164
-            return false;
165
-        }
166
-
167
-        return $apiResponse['status'] == 'OK';
168
-    }
19
+	/** @var HttpHelper */
20
+	private $httpHelper;
21
+	/**
22
+	 * @var SiteConfiguration
23
+	 */
24
+	private $configuration;
25
+
26
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration, HttpHelper $httpHelper)
27
+	{
28
+		parent::__construct($database, $configuration, 'yubikeyotp');
29
+		$this->httpHelper = $httpHelper;
30
+		$this->configuration = $configuration;
31
+	}
32
+
33
+	public function authenticate(User $user, $data)
34
+	{
35
+		if (is_array($data)) {
36
+			return false;
37
+		}
38
+
39
+		$credentialData = $this->getCredentialData($user->getId());
40
+
41
+		if ($credentialData === null) {
42
+			return false;
43
+		}
44
+
45
+		if ($credentialData->getData() !== $this->getYubikeyId($data)) {
46
+			// different device
47
+			return false;
48
+		}
49
+
50
+		return $this->verifyToken($data);
51
+	}
52
+
53
+	public function setCredential(User $user, $factor, $data)
54
+	{
55
+		$keyId = $this->getYubikeyId($data);
56
+		$valid = $this->verifyToken($data);
57
+
58
+		if (!$valid) {
59
+			throw new ApplicationLogicException("Provided token is not valid.");
60
+		}
61
+
62
+		$storedData = $this->getCredentialData($user->getId());
63
+
64
+		if ($storedData === null) {
65
+			$storedData = $this->createNewCredential($user);
66
+		}
67
+
68
+		$storedData->setData($keyId);
69
+		$storedData->setFactor($factor);
70
+		$storedData->setVersion(1);
71
+		$storedData->setPriority(8);
72
+
73
+		$storedData->save();
74
+	}
75
+
76
+	/**
77
+	 * Get the Yubikey ID.
78
+	 *
79
+	 * This looks like it's just dumping the "password" that's stored in the database, but it's actually fine.
80
+	 *
81
+	 * We only store the "serial number" of the Yubikey - if we get a validated (by webservice) token prefixed with the
82
+	 * serial number, that's a successful OTP authentication. Thus, retrieving the stored data is just retrieving the
83
+	 * yubikey's serial number (in modhex format), since the actual security credentials are stored on the device.
84
+	 *
85
+	 * Note that the serial number is actually the credential serial number - it's possible to regenerate the keys on
86
+	 * the device, and that will change the serial number too.
87
+	 *
88
+	 * More information about the structure of OTPs can be found here:
89
+	 * https://developers.yubico.com/OTP/OTPs_Explained.html
90
+	 *
91
+	 * @param int $userId
92
+	 *
93
+	 * @return null|string
94
+	 */
95
+	public function getYubikeyData($userId)
96
+	{
97
+		$credential = $this->getCredentialData($userId);
98
+
99
+		if ($credential === null) {
100
+			return null;
101
+		}
102
+
103
+		return $credential->getData();
104
+	}
105
+
106
+	/**
107
+	 * @param $result
108
+	 *
109
+	 * @return array
110
+	 */
111
+	private function parseYubicoApiResult($result)
112
+	{
113
+		$data = array();
114
+		foreach (explode("\r\n", $result) as $line) {
115
+			$pos = strpos($line, '=');
116
+			if ($pos === false) {
117
+				continue;
118
+			}
119
+
120
+			$data[substr($line, 0, $pos)] = substr($line, $pos + 1);
121
+		}
122
+
123
+		return $data;
124
+	}
125
+
126
+	private function getYubikeyId($data)
127
+	{
128
+		return substr($data, 0, -32);
129
+	}
130
+
131
+	private function verifyHmac($apiResponse, $apiKey)
132
+	{
133
+		ksort($apiResponse);
134
+		$signature = $apiResponse['h'];
135
+		unset($apiResponse['h']);
136
+
137
+		$data = array();
138
+		foreach ($apiResponse as $key => $value) {
139
+			$data[] = $key . "=" . $value;
140
+		}
141
+		$dataString = implode('&', $data);
142
+
143
+		$hmac = base64_encode(hash_hmac('sha1', $dataString, base64_decode($apiKey), true));
144
+
145
+		return $hmac === $signature;
146
+	}
147
+
148
+	/**
149
+	 * @param $data
150
+	 *
151
+	 * @return bool
152
+	 */
153
+	private function verifyToken($data)
154
+	{
155
+		$result = $this->httpHelper->get('https://api.yubico.com/wsapi/2.0/verify', array(
156
+			'id'    => $this->configuration->getYubicoApiId(),
157
+			'otp'   => $data,
158
+			'nonce' => md5(openssl_random_pseudo_bytes(64)),
159
+		));
160
+
161
+		$apiResponse = $this->parseYubicoApiResult($result);
162
+
163
+		if (!$this->verifyHmac($apiResponse, $this->configuration->getYubicoApiKey())) {
164
+			return false;
165
+		}
166
+
167
+		return $apiResponse['status'] == 'OK';
168
+	}
169 169
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -136,7 +136,7 @@
 block discarded – undo
136 136
 
137 137
         $data = array();
138 138
         foreach ($apiResponse as $key => $value) {
139
-            $data[] = $key . "=" . $value;
139
+            $data[] = $key."=".$value;
140 140
         }
141 141
         $dataString = implode('&', $data);
142 142
 
Please login to merge, or discard this patch.
includes/Security/RoleConfiguration.php 2 patches
Unused Use Statements   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -16,11 +16,6 @@  discard block
 block discarded – undo
16 16
 use Waca\Pages\PageJobQueue;
17 17
 use Waca\Pages\PageLog;
18 18
 use Waca\Pages\PageMain;
19
-use Waca\Pages\RequestAction\PageCreateRequest;
20
-use Waca\Pages\UserAuth\PageChangePassword;
21
-use Waca\Pages\UserAuth\MultiFactor\PageMultiFactor;
22
-use Waca\Pages\UserAuth\PageOAuth;
23
-use Waca\Pages\UserAuth\PagePreferences;
24 19
 use Waca\Pages\PageSearch;
25 20
 use Waca\Pages\PageSiteNotice;
26 21
 use Waca\Pages\PageTeam;
@@ -30,6 +25,7 @@  discard block
 block discarded – undo
30 25
 use Waca\Pages\RequestAction\PageBreakReservation;
31 26
 use Waca\Pages\RequestAction\PageCloseRequest;
32 27
 use Waca\Pages\RequestAction\PageComment;
28
+use Waca\Pages\RequestAction\PageCreateRequest;
33 29
 use Waca\Pages\RequestAction\PageCustomClose;
34 30
 use Waca\Pages\RequestAction\PageDeferRequest;
35 31
 use Waca\Pages\RequestAction\PageDropRequest;
@@ -43,6 +39,10 @@  discard block
 block discarded – undo
43 39
 use Waca\Pages\Statistics\StatsTemplateStats;
44 40
 use Waca\Pages\Statistics\StatsTopCreators;
45 41
 use Waca\Pages\Statistics\StatsUsers;
42
+use Waca\Pages\UserAuth\MultiFactor\PageMultiFactor;
43
+use Waca\Pages\UserAuth\PageChangePassword;
44
+use Waca\Pages\UserAuth\PageOAuth;
45
+use Waca\Pages\UserAuth\PagePreferences;
46 46
 
47 47
 class RoleConfiguration
48 48
 {
Please login to merge, or discard this patch.
Indentation   +344 added lines, -344 removed lines patch added patch discarded remove patch
@@ -46,374 +46,374 @@
 block discarded – undo
46 46
 
47 47
 class RoleConfiguration
48 48
 {
49
-    const ACCESS_ALLOW = 1;
50
-    const ACCESS_DENY = -1;
51
-    const ACCESS_DEFAULT = 0;
52
-    const MAIN = 'main';
53
-    const ALL = '*';
54
-    /**
55
-     * A map of roles to rights
56
-     *
57
-     * For example:
58
-     *
59
-     * array(
60
-     *   'myrole' => array(
61
-     *       PageMyPage::class => array(
62
-     *           'edit' => self::ACCESS_ALLOW,
63
-     *           'create' => self::ACCESS_DENY,
64
-     *       )
65
-     *   )
66
-     * )
67
-     *
68
-     * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
69
-     * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
70
-     * be the expected result:
71
-     *
72
-     * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
73
-     * - (A,-,-) = A
74
-     * - (D,-,-) = D
75
-     * - (A,D,-) = D (deny takes precedence over allow)
76
-     * - (A,A,A) = A (repetition has no effect)
77
-     *
78
-     * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
79
-     *
80
-     * @var array
81
-     */
82
-    private $roleConfig = array(
83
-        'public'            => array(
84
-            /*
49
+	const ACCESS_ALLOW = 1;
50
+	const ACCESS_DENY = -1;
51
+	const ACCESS_DEFAULT = 0;
52
+	const MAIN = 'main';
53
+	const ALL = '*';
54
+	/**
55
+	 * A map of roles to rights
56
+	 *
57
+	 * For example:
58
+	 *
59
+	 * array(
60
+	 *   'myrole' => array(
61
+	 *       PageMyPage::class => array(
62
+	 *           'edit' => self::ACCESS_ALLOW,
63
+	 *           'create' => self::ACCESS_DENY,
64
+	 *       )
65
+	 *   )
66
+	 * )
67
+	 *
68
+	 * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
69
+	 * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
70
+	 * be the expected result:
71
+	 *
72
+	 * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
73
+	 * - (A,-,-) = A
74
+	 * - (D,-,-) = D
75
+	 * - (A,D,-) = D (deny takes precedence over allow)
76
+	 * - (A,A,A) = A (repetition has no effect)
77
+	 *
78
+	 * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
79
+	 *
80
+	 * @var array
81
+	 */
82
+	private $roleConfig = array(
83
+		'public'            => array(
84
+			/*
85 85
              * THIS ROLE IS GRANTED TO ALL LOGGED *OUT* USERS IMPLICITLY.
86 86
              *
87 87
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
88 88
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
89 89
              */
90
-            '_childRoles'   => array(
91
-                'publicStats',
92
-            ),
93
-            PageTeam::class => array(
94
-                self::MAIN => self::ACCESS_ALLOW,
95
-            ),
96
-        ),
97
-        'loggedIn'          => array(
98
-            /*
90
+			'_childRoles'   => array(
91
+				'publicStats',
92
+			),
93
+			PageTeam::class => array(
94
+				self::MAIN => self::ACCESS_ALLOW,
95
+			),
96
+		),
97
+		'loggedIn'          => array(
98
+			/*
99 99
              * THIS ROLE IS GRANTED TO ALL LOGGED IN USERS IMPLICITLY.
100 100
              *
101 101
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
102 102
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
103 103
              */
104
-            '_childRoles'             => array(
105
-                'public',
106
-            ),
107
-            PagePreferences::class    => array(
108
-                self::MAIN => self::ACCESS_ALLOW,
109
-            ),
110
-            PageChangePassword::class => array(
111
-                self::MAIN => self::ACCESS_ALLOW,
112
-            ),
113
-            PageMultiFactor::class    => array(
114
-                self::MAIN          => self::ACCESS_ALLOW,
115
-                'scratch'           => self::ACCESS_ALLOW,
116
-                'enableYubikeyOtp'  => self::ACCESS_ALLOW,
117
-                'disableYubikeyOtp' => self::ACCESS_ALLOW,
118
-                'enableTotp'        => self::ACCESS_ALLOW,
119
-                'disableTotp'       => self::ACCESS_ALLOW,
120
-                'enableU2F'       => self::ACCESS_ALLOW,
121
-                'disableU2F'       => self::ACCESS_ALLOW,
122
-            ),
123
-            PageOAuth::class          => array(
124
-                'attach' => self::ACCESS_ALLOW,
125
-                'detach' => self::ACCESS_ALLOW,
126
-            ),
127
-        ),
128
-        'user'              => array(
129
-            '_description'                       => 'A standard tool user.',
130
-            '_editableBy'                        => array('admin', 'toolRoot'),
131
-            '_childRoles'                        => array(
132
-                'internalStats',
133
-            ),
134
-            PageMain::class                      => array(
135
-                self::MAIN => self::ACCESS_ALLOW,
136
-            ),
137
-            PageBan::class                       => array(
138
-                self::MAIN => self::ACCESS_ALLOW,
139
-            ),
140
-            PageEditComment::class               => array(
141
-                self::MAIN => self::ACCESS_ALLOW,
142
-            ),
143
-            PageEmailManagement::class           => array(
144
-                self::MAIN => self::ACCESS_ALLOW,
145
-                'view'     => self::ACCESS_ALLOW,
146
-            ),
147
-            PageExpandedRequestList::class       => array(
148
-                self::MAIN => self::ACCESS_ALLOW,
149
-            ),
150
-            PageLog::class                       => array(
151
-                self::MAIN => self::ACCESS_ALLOW,
152
-            ),
153
-            PageSearch::class                    => array(
154
-                self::MAIN => self::ACCESS_ALLOW,
155
-            ),
156
-            PageWelcomeTemplateManagement::class => array(
157
-                self::MAIN => self::ACCESS_ALLOW,
158
-                'select'   => self::ACCESS_ALLOW,
159
-                'view'     => self::ACCESS_ALLOW,
160
-            ),
161
-            PageViewRequest::class               => array(
162
-                self::MAIN       => self::ACCESS_ALLOW,
163
-                'seeAllRequests' => self::ACCESS_ALLOW,
164
-            ),
165
-            'RequestData'                        => array(
166
-                'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
167
-                'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
168
-            ),
169
-            PageCustomClose::class               => array(
170
-                self::MAIN => self::ACCESS_ALLOW,
171
-            ),
172
-            PageComment::class                   => array(
173
-                self::MAIN => self::ACCESS_ALLOW,
174
-            ),
175
-            PageCloseRequest::class              => array(
176
-                self::MAIN => self::ACCESS_ALLOW,
177
-            ),
178
-            PageCreateRequest::class             => array(
179
-                self::MAIN => self::ACCESS_ALLOW,
180
-            ),
181
-            PageDeferRequest::class              => array(
182
-                self::MAIN => self::ACCESS_ALLOW,
183
-            ),
184
-            PageDropRequest::class               => array(
185
-                self::MAIN => self::ACCESS_ALLOW,
186
-            ),
187
-            PageReservation::class               => array(
188
-                self::MAIN => self::ACCESS_ALLOW,
189
-            ),
190
-            PageSendToUser::class                => array(
191
-                self::MAIN => self::ACCESS_ALLOW,
192
-            ),
193
-            PageBreakReservation::class          => array(
194
-                self::MAIN => self::ACCESS_ALLOW,
195
-            ),
196
-            PageJobQueue::class                  => array(
197
-                self::MAIN => self::ACCESS_ALLOW,
198
-                'view'     => self::ACCESS_ALLOW,
199
-                'all'      => self::ACCESS_ALLOW,
200
-            ),
201
-            'RequestCreation'                    => array(
202
-                User::CREATION_MANUAL => self::ACCESS_ALLOW,
203
-                User::CREATION_OAUTH  => self::ACCESS_ALLOW,
204
-            ),
205
-        ),
206
-        'admin'             => array(
207
-            '_description'                       => 'A tool administrator.',
208
-            '_editableBy'                        => array('admin', 'toolRoot'),
209
-            '_childRoles'                        => array(
210
-                'user',
211
-                'requestAdminTools',
212
-            ),
213
-            PageEmailManagement::class           => array(
214
-                'edit'   => self::ACCESS_ALLOW,
215
-                'create' => self::ACCESS_ALLOW,
216
-            ),
217
-            PageSiteNotice::class                => array(
218
-                self::MAIN => self::ACCESS_ALLOW,
219
-            ),
220
-            PageUserManagement::class            => array(
221
-                self::MAIN  => self::ACCESS_ALLOW,
222
-                'approve'   => self::ACCESS_ALLOW,
223
-                'decline'   => self::ACCESS_ALLOW,
224
-                'rename'    => self::ACCESS_ALLOW,
225
-                'editUser'  => self::ACCESS_ALLOW,
226
-                'suspend'   => self::ACCESS_ALLOW,
227
-                'editRoles' => self::ACCESS_ALLOW,
228
-            ),
229
-            PageWelcomeTemplateManagement::class => array(
230
-                'edit'   => self::ACCESS_ALLOW,
231
-                'delete' => self::ACCESS_ALLOW,
232
-                'add'    => self::ACCESS_ALLOW,
233
-            ),
234
-            PageJobQueue::class                  => array(
235
-                'acknowledge' => self::ACCESS_ALLOW,
236
-                'requeue'     => self::ACCESS_ALLOW,
237
-            ),
238
-        ),
239
-        'checkuser'         => array(
240
-            '_description'            => 'A user with CheckUser access',
241
-            '_editableBy'             => array('checkuser', 'toolRoot'),
242
-            '_childRoles'             => array(
243
-                'user',
244
-                'requestAdminTools',
245
-            ),
246
-            PageUserManagement::class => array(
247
-                self::MAIN  => self::ACCESS_ALLOW,
248
-                'suspend'   => self::ACCESS_ALLOW,
249
-                'editRoles' => self::ACCESS_ALLOW,
250
-            ),
251
-            'RequestData'             => array(
252
-                'seeUserAgentData' => self::ACCESS_ALLOW,
253
-            ),
254
-        ),
255
-        'toolRoot'          => array(
256
-            '_description' => 'A user with shell access to the servers running the tool',
257
-            '_editableBy'  => array('toolRoot'),
258
-            '_childRoles'  => array(
259
-                'admin',
260
-                'checkuser',
261
-            ),
262
-        ),
263
-        'botCreation'       => array(
264
-            '_description'    => 'A user allowed to use the bot to perform account creations',
265
-            '_editableBy'     => array('admin', 'toolRoot'),
266
-            '_childRoles'     => array(),
267
-            'RequestCreation' => array(
268
-                User::CREATION_BOT => self::ACCESS_ALLOW,
269
-            ),
270
-        ),
104
+			'_childRoles'             => array(
105
+				'public',
106
+			),
107
+			PagePreferences::class    => array(
108
+				self::MAIN => self::ACCESS_ALLOW,
109
+			),
110
+			PageChangePassword::class => array(
111
+				self::MAIN => self::ACCESS_ALLOW,
112
+			),
113
+			PageMultiFactor::class    => array(
114
+				self::MAIN          => self::ACCESS_ALLOW,
115
+				'scratch'           => self::ACCESS_ALLOW,
116
+				'enableYubikeyOtp'  => self::ACCESS_ALLOW,
117
+				'disableYubikeyOtp' => self::ACCESS_ALLOW,
118
+				'enableTotp'        => self::ACCESS_ALLOW,
119
+				'disableTotp'       => self::ACCESS_ALLOW,
120
+				'enableU2F'       => self::ACCESS_ALLOW,
121
+				'disableU2F'       => self::ACCESS_ALLOW,
122
+			),
123
+			PageOAuth::class          => array(
124
+				'attach' => self::ACCESS_ALLOW,
125
+				'detach' => self::ACCESS_ALLOW,
126
+			),
127
+		),
128
+		'user'              => array(
129
+			'_description'                       => 'A standard tool user.',
130
+			'_editableBy'                        => array('admin', 'toolRoot'),
131
+			'_childRoles'                        => array(
132
+				'internalStats',
133
+			),
134
+			PageMain::class                      => array(
135
+				self::MAIN => self::ACCESS_ALLOW,
136
+			),
137
+			PageBan::class                       => array(
138
+				self::MAIN => self::ACCESS_ALLOW,
139
+			),
140
+			PageEditComment::class               => array(
141
+				self::MAIN => self::ACCESS_ALLOW,
142
+			),
143
+			PageEmailManagement::class           => array(
144
+				self::MAIN => self::ACCESS_ALLOW,
145
+				'view'     => self::ACCESS_ALLOW,
146
+			),
147
+			PageExpandedRequestList::class       => array(
148
+				self::MAIN => self::ACCESS_ALLOW,
149
+			),
150
+			PageLog::class                       => array(
151
+				self::MAIN => self::ACCESS_ALLOW,
152
+			),
153
+			PageSearch::class                    => array(
154
+				self::MAIN => self::ACCESS_ALLOW,
155
+			),
156
+			PageWelcomeTemplateManagement::class => array(
157
+				self::MAIN => self::ACCESS_ALLOW,
158
+				'select'   => self::ACCESS_ALLOW,
159
+				'view'     => self::ACCESS_ALLOW,
160
+			),
161
+			PageViewRequest::class               => array(
162
+				self::MAIN       => self::ACCESS_ALLOW,
163
+				'seeAllRequests' => self::ACCESS_ALLOW,
164
+			),
165
+			'RequestData'                        => array(
166
+				'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
167
+				'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
168
+			),
169
+			PageCustomClose::class               => array(
170
+				self::MAIN => self::ACCESS_ALLOW,
171
+			),
172
+			PageComment::class                   => array(
173
+				self::MAIN => self::ACCESS_ALLOW,
174
+			),
175
+			PageCloseRequest::class              => array(
176
+				self::MAIN => self::ACCESS_ALLOW,
177
+			),
178
+			PageCreateRequest::class             => array(
179
+				self::MAIN => self::ACCESS_ALLOW,
180
+			),
181
+			PageDeferRequest::class              => array(
182
+				self::MAIN => self::ACCESS_ALLOW,
183
+			),
184
+			PageDropRequest::class               => array(
185
+				self::MAIN => self::ACCESS_ALLOW,
186
+			),
187
+			PageReservation::class               => array(
188
+				self::MAIN => self::ACCESS_ALLOW,
189
+			),
190
+			PageSendToUser::class                => array(
191
+				self::MAIN => self::ACCESS_ALLOW,
192
+			),
193
+			PageBreakReservation::class          => array(
194
+				self::MAIN => self::ACCESS_ALLOW,
195
+			),
196
+			PageJobQueue::class                  => array(
197
+				self::MAIN => self::ACCESS_ALLOW,
198
+				'view'     => self::ACCESS_ALLOW,
199
+				'all'      => self::ACCESS_ALLOW,
200
+			),
201
+			'RequestCreation'                    => array(
202
+				User::CREATION_MANUAL => self::ACCESS_ALLOW,
203
+				User::CREATION_OAUTH  => self::ACCESS_ALLOW,
204
+			),
205
+		),
206
+		'admin'             => array(
207
+			'_description'                       => 'A tool administrator.',
208
+			'_editableBy'                        => array('admin', 'toolRoot'),
209
+			'_childRoles'                        => array(
210
+				'user',
211
+				'requestAdminTools',
212
+			),
213
+			PageEmailManagement::class           => array(
214
+				'edit'   => self::ACCESS_ALLOW,
215
+				'create' => self::ACCESS_ALLOW,
216
+			),
217
+			PageSiteNotice::class                => array(
218
+				self::MAIN => self::ACCESS_ALLOW,
219
+			),
220
+			PageUserManagement::class            => array(
221
+				self::MAIN  => self::ACCESS_ALLOW,
222
+				'approve'   => self::ACCESS_ALLOW,
223
+				'decline'   => self::ACCESS_ALLOW,
224
+				'rename'    => self::ACCESS_ALLOW,
225
+				'editUser'  => self::ACCESS_ALLOW,
226
+				'suspend'   => self::ACCESS_ALLOW,
227
+				'editRoles' => self::ACCESS_ALLOW,
228
+			),
229
+			PageWelcomeTemplateManagement::class => array(
230
+				'edit'   => self::ACCESS_ALLOW,
231
+				'delete' => self::ACCESS_ALLOW,
232
+				'add'    => self::ACCESS_ALLOW,
233
+			),
234
+			PageJobQueue::class                  => array(
235
+				'acknowledge' => self::ACCESS_ALLOW,
236
+				'requeue'     => self::ACCESS_ALLOW,
237
+			),
238
+		),
239
+		'checkuser'         => array(
240
+			'_description'            => 'A user with CheckUser access',
241
+			'_editableBy'             => array('checkuser', 'toolRoot'),
242
+			'_childRoles'             => array(
243
+				'user',
244
+				'requestAdminTools',
245
+			),
246
+			PageUserManagement::class => array(
247
+				self::MAIN  => self::ACCESS_ALLOW,
248
+				'suspend'   => self::ACCESS_ALLOW,
249
+				'editRoles' => self::ACCESS_ALLOW,
250
+			),
251
+			'RequestData'             => array(
252
+				'seeUserAgentData' => self::ACCESS_ALLOW,
253
+			),
254
+		),
255
+		'toolRoot'          => array(
256
+			'_description' => 'A user with shell access to the servers running the tool',
257
+			'_editableBy'  => array('toolRoot'),
258
+			'_childRoles'  => array(
259
+				'admin',
260
+				'checkuser',
261
+			),
262
+		),
263
+		'botCreation'       => array(
264
+			'_description'    => 'A user allowed to use the bot to perform account creations',
265
+			'_editableBy'     => array('admin', 'toolRoot'),
266
+			'_childRoles'     => array(),
267
+			'RequestCreation' => array(
268
+				User::CREATION_BOT => self::ACCESS_ALLOW,
269
+			),
270
+		),
271 271
 
272
-        // Child roles go below this point
273
-        'publicStats'       => array(
274
-            '_hidden'               => true,
275
-            StatsUsers::class       => array(
276
-                self::MAIN => self::ACCESS_ALLOW,
277
-                'detail'   => self::ACCESS_ALLOW,
278
-            ),
279
-            StatsTopCreators::class => array(
280
-                self::MAIN => self::ACCESS_ALLOW,
281
-            ),
282
-        ),
283
-        'internalStats'     => array(
284
-            '_hidden'                    => true,
285
-            StatsMain::class             => array(
286
-                self::MAIN => self::ACCESS_ALLOW,
287
-            ),
288
-            StatsFastCloses::class       => array(
289
-                self::MAIN => self::ACCESS_ALLOW,
290
-            ),
291
-            StatsInactiveUsers::class    => array(
292
-                self::MAIN => self::ACCESS_ALLOW,
293
-            ),
294
-            StatsMonthlyStats::class     => array(
295
-                self::MAIN => self::ACCESS_ALLOW,
296
-            ),
297
-            StatsReservedRequests::class => array(
298
-                self::MAIN => self::ACCESS_ALLOW,
299
-            ),
300
-            StatsTemplateStats::class    => array(
301
-                self::MAIN => self::ACCESS_ALLOW,
302
-            ),
303
-        ),
304
-        'requestAdminTools' => array(
305
-            '_hidden'                   => true,
306
-            PageBan::class              => array(
307
-                self::MAIN => self::ACCESS_ALLOW,
308
-                'set'      => self::ACCESS_ALLOW,
309
-                'remove'   => self::ACCESS_ALLOW,
310
-            ),
311
-            PageEditComment::class      => array(
312
-                'editOthers' => self::ACCESS_ALLOW,
313
-            ),
314
-            PageBreakReservation::class => array(
315
-                'force' => self::ACCESS_ALLOW,
316
-            ),
317
-            PageCustomClose::class      => array(
318
-                'skipCcMailingList' => self::ACCESS_ALLOW,
319
-            ),
320
-            'RequestData'               => array(
321
-                'reopenOldRequest'      => self::ACCESS_ALLOW,
322
-                'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
323
-                'alwaysSeeHash'         => self::ACCESS_ALLOW,
324
-                'seeRestrictedComments' => self::ACCESS_ALLOW,
325
-            ),
326
-        ),
327
-    );
328
-    /** @var array
329
-     * List of roles which are *exempt* from the identification requirements
330
-     *
331
-     * Think twice about adding roles to this list.
332
-     *
333
-     * @category Security-Critical
334
-     */
335
-    private $identificationExempt = array('public', 'loggedIn');
272
+		// Child roles go below this point
273
+		'publicStats'       => array(
274
+			'_hidden'               => true,
275
+			StatsUsers::class       => array(
276
+				self::MAIN => self::ACCESS_ALLOW,
277
+				'detail'   => self::ACCESS_ALLOW,
278
+			),
279
+			StatsTopCreators::class => array(
280
+				self::MAIN => self::ACCESS_ALLOW,
281
+			),
282
+		),
283
+		'internalStats'     => array(
284
+			'_hidden'                    => true,
285
+			StatsMain::class             => array(
286
+				self::MAIN => self::ACCESS_ALLOW,
287
+			),
288
+			StatsFastCloses::class       => array(
289
+				self::MAIN => self::ACCESS_ALLOW,
290
+			),
291
+			StatsInactiveUsers::class    => array(
292
+				self::MAIN => self::ACCESS_ALLOW,
293
+			),
294
+			StatsMonthlyStats::class     => array(
295
+				self::MAIN => self::ACCESS_ALLOW,
296
+			),
297
+			StatsReservedRequests::class => array(
298
+				self::MAIN => self::ACCESS_ALLOW,
299
+			),
300
+			StatsTemplateStats::class    => array(
301
+				self::MAIN => self::ACCESS_ALLOW,
302
+			),
303
+		),
304
+		'requestAdminTools' => array(
305
+			'_hidden'                   => true,
306
+			PageBan::class              => array(
307
+				self::MAIN => self::ACCESS_ALLOW,
308
+				'set'      => self::ACCESS_ALLOW,
309
+				'remove'   => self::ACCESS_ALLOW,
310
+			),
311
+			PageEditComment::class      => array(
312
+				'editOthers' => self::ACCESS_ALLOW,
313
+			),
314
+			PageBreakReservation::class => array(
315
+				'force' => self::ACCESS_ALLOW,
316
+			),
317
+			PageCustomClose::class      => array(
318
+				'skipCcMailingList' => self::ACCESS_ALLOW,
319
+			),
320
+			'RequestData'               => array(
321
+				'reopenOldRequest'      => self::ACCESS_ALLOW,
322
+				'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
323
+				'alwaysSeeHash'         => self::ACCESS_ALLOW,
324
+				'seeRestrictedComments' => self::ACCESS_ALLOW,
325
+			),
326
+		),
327
+	);
328
+	/** @var array
329
+	 * List of roles which are *exempt* from the identification requirements
330
+	 *
331
+	 * Think twice about adding roles to this list.
332
+	 *
333
+	 * @category Security-Critical
334
+	 */
335
+	private $identificationExempt = array('public', 'loggedIn');
336 336
 
337
-    /**
338
-     * RoleConfiguration constructor.
339
-     *
340
-     * @param array $roleConfig           Set to non-null to override the default configuration.
341
-     * @param array $identificationExempt Set to non-null to override the default configuration.
342
-     */
343
-    public function __construct(array $roleConfig = null, array $identificationExempt = null)
344
-    {
345
-        if ($roleConfig !== null) {
346
-            $this->roleConfig = $roleConfig;
347
-        }
337
+	/**
338
+	 * RoleConfiguration constructor.
339
+	 *
340
+	 * @param array $roleConfig           Set to non-null to override the default configuration.
341
+	 * @param array $identificationExempt Set to non-null to override the default configuration.
342
+	 */
343
+	public function __construct(array $roleConfig = null, array $identificationExempt = null)
344
+	{
345
+		if ($roleConfig !== null) {
346
+			$this->roleConfig = $roleConfig;
347
+		}
348 348
 
349
-        if ($identificationExempt !== null) {
350
-            $this->identificationExempt = $identificationExempt;
351
-        }
352
-    }
349
+		if ($identificationExempt !== null) {
350
+			$this->identificationExempt = $identificationExempt;
351
+		}
352
+	}
353 353
 
354
-    /**
355
-     * @param array $roles The roles to check
356
-     *
357
-     * @return array
358
-     */
359
-    public function getApplicableRoles(array $roles)
360
-    {
361
-        $available = array();
354
+	/**
355
+	 * @param array $roles The roles to check
356
+	 *
357
+	 * @return array
358
+	 */
359
+	public function getApplicableRoles(array $roles)
360
+	{
361
+		$available = array();
362 362
 
363
-        foreach ($roles as $role) {
364
-            if (!isset($this->roleConfig[$role])) {
365
-                // wat
366
-                continue;
367
-            }
363
+		foreach ($roles as $role) {
364
+			if (!isset($this->roleConfig[$role])) {
365
+				// wat
366
+				continue;
367
+			}
368 368
 
369
-            $available[$role] = $this->roleConfig[$role];
369
+			$available[$role] = $this->roleConfig[$role];
370 370
 
371
-            if (isset($available[$role]['_childRoles'])) {
372
-                $childRoles = self::getApplicableRoles($available[$role]['_childRoles']);
373
-                $available = array_merge($available, $childRoles);
371
+			if (isset($available[$role]['_childRoles'])) {
372
+				$childRoles = self::getApplicableRoles($available[$role]['_childRoles']);
373
+				$available = array_merge($available, $childRoles);
374 374
 
375
-                unset($available[$role]['_childRoles']);
376
-            }
375
+				unset($available[$role]['_childRoles']);
376
+			}
377 377
 
378
-            foreach (array('_hidden', '_editableBy', '_description') as $item) {
379
-                if (isset($available[$role][$item])) {
380
-                    unset($available[$role][$item]);
381
-                }
382
-            }
383
-        }
378
+			foreach (array('_hidden', '_editableBy', '_description') as $item) {
379
+				if (isset($available[$role][$item])) {
380
+					unset($available[$role][$item]);
381
+				}
382
+			}
383
+		}
384 384
 
385
-        return $available;
386
-    }
385
+		return $available;
386
+	}
387 387
 
388
-    public function getAvailableRoles()
389
-    {
390
-        $possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
388
+	public function getAvailableRoles()
389
+	{
390
+		$possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
391 391
 
392
-        $actual = array();
392
+		$actual = array();
393 393
 
394
-        foreach ($possible as $role) {
395
-            if (!isset($this->roleConfig[$role]['_hidden'])) {
396
-                $actual[$role] = array(
397
-                    'description' => $this->roleConfig[$role]['_description'],
398
-                    'editableBy'  => $this->roleConfig[$role]['_editableBy'],
399
-                );
400
-            }
401
-        }
394
+		foreach ($possible as $role) {
395
+			if (!isset($this->roleConfig[$role]['_hidden'])) {
396
+				$actual[$role] = array(
397
+					'description' => $this->roleConfig[$role]['_description'],
398
+					'editableBy'  => $this->roleConfig[$role]['_editableBy'],
399
+				);
400
+			}
401
+		}
402 402
 
403
-        return $actual;
404
-    }
403
+		return $actual;
404
+	}
405 405
 
406
-    /**
407
-     * @param string $role
408
-     *
409
-     * @return bool
410
-     */
411
-    public function roleNeedsIdentification($role)
412
-    {
413
-        if (in_array($role, $this->identificationExempt)) {
414
-            return false;
415
-        }
406
+	/**
407
+	 * @param string $role
408
+	 *
409
+	 * @return bool
410
+	 */
411
+	public function roleNeedsIdentification($role)
412
+	{
413
+		if (in_array($role, $this->identificationExempt)) {
414
+			return false;
415
+		}
416 416
 
417
-        return true;
418
-    }
417
+		return true;
418
+	}
419 419
 }
Please login to merge, or discard this patch.
includes/WebRequest.php 2 patches
Doc Comments   +4 added lines patch added patch discarded remove patch
@@ -513,6 +513,10 @@
 block discarded – undo
513 513
         return isset($session['oauthPartialLogin']) ? (int)$session['oauthPartialLogin'] : null;
514 514
     }
515 515
 
516
+    /**
517
+     * @param integer $userId
518
+     * @param integer $stage
519
+     */
516 520
     public static function setAuthPartialLogin($userId, $stage)
517 521
     {
518 522
         $session = &self::$globalStateProvider->getSessionSuperGlobal();
Please login to merge, or discard this patch.
Indentation   +556 added lines, -556 removed lines patch added patch discarded remove patch
@@ -22,560 +22,560 @@
 block discarded – undo
22 22
  */
23 23
 class WebRequest
24 24
 {
25
-    /**
26
-     * @var \Waca\Providers\GlobalState\IGlobalStateProvider Provides access to the global state.
27
-     */
28
-    private static $globalStateProvider;
29
-
30
-    /**
31
-     * Returns a boolean value if the request was submitted with the HTTP POST method.
32
-     * @return bool
33
-     */
34
-    public static function wasPosted()
35
-    {
36
-        return self::method() === 'POST';
37
-    }
38
-
39
-    /**
40
-     * Gets the HTTP Method used
41
-     * @return string|null
42
-     */
43
-    public static function method()
44
-    {
45
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
46
-
47
-        if (isset($server['REQUEST_METHOD'])) {
48
-            return $server['REQUEST_METHOD'];
49
-        }
50
-
51
-        return null;
52
-    }
53
-
54
-    /**
55
-     * Gets a boolean value stating whether the request was served over HTTPS or not.
56
-     * @return bool
57
-     */
58
-    public static function isHttps()
59
-    {
60
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
61
-
62
-        if (isset($server['HTTP_X_FORWARDED_PROTO'])) {
63
-            if ($server['HTTP_X_FORWARDED_PROTO'] === 'https') {
64
-                // Client <=> Proxy is encrypted
65
-                return true;
66
-            }
67
-            else {
68
-                // Proxy <=> Server link unknown, Client <=> Proxy is not encrypted.
69
-                return false;
70
-            }
71
-        }
72
-
73
-        if (isset($server['HTTPS'])) {
74
-            if ($server['HTTPS'] === 'off') {
75
-                // ISAPI on IIS breaks the spec. :(
76
-                return false;
77
-            }
78
-
79
-            if ($server['HTTPS'] !== '') {
80
-                // Set to a non-empty value
81
-                return true;
82
-            }
83
-        }
84
-
85
-        return false;
86
-    }
87
-
88
-    /**
89
-     * Gets the path info
90
-     *
91
-     * @return array Array of path info segments
92
-     */
93
-    public static function pathInfo()
94
-    {
95
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
96
-        if (!isset($server['PATH_INFO'])) {
97
-            return array();
98
-        }
99
-
100
-        $exploded = explode('/', $server['PATH_INFO']);
101
-
102
-        // filter out empty values, and reindex from zero. Notably, the first element is always zero, since it starts
103
-        // with a /
104
-        return array_values(array_filter($exploded));
105
-    }
106
-
107
-    /**
108
-     * Gets the remote address of the web request
109
-     * @return null|string
110
-     */
111
-    public static function remoteAddress()
112
-    {
113
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
114
-
115
-        if (isset($server['REMOTE_ADDR'])) {
116
-            return $server['REMOTE_ADDR'];
117
-        }
118
-
119
-        return null;
120
-    }
121
-
122
-    /**
123
-     * Gets the remote address of the web request
124
-     * @return null|string
125
-     */
126
-    public static function httpHost()
127
-    {
128
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
129
-
130
-        if (isset($server['HTTP_HOST'])) {
131
-            return $server['HTTP_HOST'];
132
-        }
133
-
134
-        return null;
135
-    }
136
-
137
-    /**
138
-     * Gets the XFF header contents for the web request
139
-     * @return null|string
140
-     */
141
-    public static function forwardedAddress()
142
-    {
143
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
144
-
145
-        if (isset($server['HTTP_X_FORWARDED_FOR'])) {
146
-            return $server['HTTP_X_FORWARDED_FOR'];
147
-        }
148
-
149
-        return null;
150
-    }
151
-
152
-    /**
153
-     * Sets the global state provider.
154
-     *
155
-     * Almost guaranteed this is not the method you want in production code.
156
-     *
157
-     * @param \Waca\Providers\GlobalState\IGlobalStateProvider $globalState
158
-     */
159
-    public static function setGlobalStateProvider($globalState)
160
-    {
161
-        self::$globalStateProvider = $globalState;
162
-    }
163
-
164
-    #region POST variables
165
-
166
-    /**
167
-     * @param string $key
168
-     *
169
-     * @return null|string
170
-     */
171
-    public static function postString($key)
172
-    {
173
-        $post = &self::$globalStateProvider->getPostSuperGlobal();
174
-        if (!array_key_exists($key, $post)) {
175
-            return null;
176
-        }
177
-
178
-        if ($post[$key] === "") {
179
-            return null;
180
-        }
181
-
182
-        return (string)$post[$key];
183
-    }
184
-
185
-    /**
186
-     * @param string $key
187
-     *
188
-     * @return null|string
189
-     */
190
-    public static function postEmail($key)
191
-    {
192
-        $post = &self::$globalStateProvider->getPostSuperGlobal();
193
-        if (!array_key_exists($key, $post)) {
194
-            return null;
195
-        }
196
-
197
-        $filteredValue = filter_var($post[$key], FILTER_SANITIZE_EMAIL);
198
-
199
-        if ($filteredValue === false) {
200
-            return null;
201
-        }
202
-
203
-        return (string)$filteredValue;
204
-    }
205
-
206
-    /**
207
-     * @param string $key
208
-     *
209
-     * @return int|null
210
-     */
211
-    public static function postInt($key)
212
-    {
213
-        $post = &self::$globalStateProvider->getPostSuperGlobal();
214
-        if (!array_key_exists($key, $post)) {
215
-            return null;
216
-        }
217
-
218
-        $filteredValue = filter_var($post[$key], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
219
-
220
-        if ($filteredValue === null) {
221
-            return null;
222
-        }
223
-
224
-        return (int)$filteredValue;
225
-    }
226
-
227
-    /**
228
-     * @param string $key
229
-     *
230
-     * @return bool
231
-     */
232
-    public static function postBoolean($key)
233
-    {
234
-        $get = &self::$globalStateProvider->getPostSuperGlobal();
235
-        if (!array_key_exists($key, $get)) {
236
-            return false;
237
-        }
238
-
239
-        // presence of parameter only
240
-        if ($get[$key] === "") {
241
-            return true;
242
-        }
243
-
244
-        if (in_array($get[$key], array(false, 'no', 'off', 0, 'false'), true)) {
245
-            return false;
246
-        }
247
-
248
-        return true;
249
-    }
250
-
251
-    #endregion
252
-
253
-    #region GET variables
254
-
255
-    /**
256
-     * @param string $key
257
-     *
258
-     * @return bool
259
-     */
260
-    public static function getBoolean($key)
261
-    {
262
-        $get = &self::$globalStateProvider->getGetSuperGlobal();
263
-        if (!array_key_exists($key, $get)) {
264
-            return false;
265
-        }
266
-
267
-        // presence of parameter only
268
-        if ($get[$key] === "") {
269
-            return true;
270
-        }
271
-
272
-        if (in_array($get[$key], array(false, 'no', 'off', 0, 'false'), true)) {
273
-            return false;
274
-        }
275
-
276
-        return true;
277
-    }
278
-
279
-    /**
280
-     * @param string $key
281
-     *
282
-     * @return int|null
283
-     */
284
-    public static function getInt($key)
285
-    {
286
-        $get = &self::$globalStateProvider->getGetSuperGlobal();
287
-        if (!array_key_exists($key, $get)) {
288
-            return null;
289
-        }
290
-
291
-        $filteredValue = filter_var($get[$key], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
292
-
293
-        if ($filteredValue === null) {
294
-            return null;
295
-        }
296
-
297
-        return (int)$filteredValue;
298
-    }
299
-
300
-    /**
301
-     * @param string $key
302
-     *
303
-     * @return null|string
304
-     */
305
-    public static function getString($key)
306
-    {
307
-        $get = &self::$globalStateProvider->getGetSuperGlobal();
308
-        if (!array_key_exists($key, $get)) {
309
-            return null;
310
-        }
311
-
312
-        if ($get[$key] === "") {
313
-            return null;
314
-        }
315
-
316
-        return (string)$get[$key];
317
-    }
318
-
319
-    #endregion
320
-
321
-    /**
322
-     * Sets the logged-in user to the specified user.
323
-     *
324
-     * @param User $user
325
-     */
326
-    public static function setLoggedInUser(User $user)
327
-    {
328
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
329
-
330
-        $session['userID'] = $user->getId();
331
-        unset($session['partialLogin']);
332
-    }
333
-
334
-    /**
335
-     * Sets the post-login redirect
336
-     */
337
-    public static function setPostLoginRedirect()
338
-    {
339
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
340
-        $session['returnTo'] = self::requestUri();
341
-    }
342
-
343
-    /**
344
-     * @return string|null
345
-     */
346
-    public static function requestUri()
347
-    {
348
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
349
-
350
-        if (isset($server['REQUEST_URI'])) {
351
-            return $server['REQUEST_URI'];
352
-        }
353
-
354
-        return null;
355
-    }
356
-
357
-    /**
358
-     * Clears the post-login redirect
359
-     * @return string
360
-     */
361
-    public static function clearPostLoginRedirect()
362
-    {
363
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
364
-        if (array_key_exists('returnTo', $session)) {
365
-            $path = $session['returnTo'];
366
-            unset($session['returnTo']);
367
-
368
-            return $path;
369
-        }
370
-
371
-        return null;
372
-    }
373
-
374
-    /**
375
-     * @return string|null
376
-     */
377
-    public static function serverName()
378
-    {
379
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
380
-
381
-        if (isset($server['SERVER_NAME'])) {
382
-            return $server['SERVER_NAME'];
383
-        }
384
-
385
-        return null;
386
-    }
387
-
388
-    /**
389
-     * You probably only want to deal with this through SessionAlert.
390
-     * @return void
391
-     */
392
-    public static function clearSessionAlertData()
393
-    {
394
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
395
-        if (array_key_exists('alerts', $session)) {
396
-            unset($session['alerts']);
397
-        }
398
-    }
399
-
400
-    /**
401
-     * You probably only want to deal with this through SessionAlert.
402
-     *
403
-     * @return string[]
404
-     */
405
-    public static function getSessionAlertData()
406
-    {
407
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
408
-        if (array_key_exists('alerts', $session)) {
409
-            return $session['alerts'];
410
-        }
411
-
412
-        return array();
413
-    }
414
-
415
-    /**
416
-     * You probably only want to deal with this through SessionAlert.
417
-     *
418
-     * @param string[] $data
419
-     */
420
-    public static function setSessionAlertData($data)
421
-    {
422
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
423
-        $session['alerts'] = $data;
424
-    }
425
-
426
-    /**
427
-     * You probably only want to deal with this through TokenManager.
428
-     *
429
-     * @return string[]
430
-     */
431
-    public static function getSessionTokenData()
432
-    {
433
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
434
-        if (array_key_exists('tokens', $session)) {
435
-            return $session['tokens'];
436
-        }
437
-
438
-        return array();
439
-    }
440
-
441
-    /**
442
-     * You probably only want to deal with this through TokenManager.
443
-     *
444
-     * @param string[] $data
445
-     */
446
-    public static function setSessionTokenData($data)
447
-    {
448
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
449
-        $session['tokens'] = $data;
450
-    }
451
-
452
-    /**
453
-     * @param string $key
454
-     *
455
-     * @return mixed
456
-     */
457
-    public static function getSessionContext($key)
458
-    {
459
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
460
-
461
-        if (!isset($session['context'])) {
462
-            $session['context'] = array();
463
-        }
464
-
465
-        if (!isset($session['context'][$key])) {
466
-            return null;
467
-        }
468
-
469
-        return $session['context'][$key];
470
-    }
471
-
472
-    /**
473
-     * @param string $key
474
-     * @param mixed  $data
475
-     */
476
-    public static function setSessionContext($key, $data)
477
-    {
478
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
479
-
480
-        if (!isset($session['context'])) {
481
-            $session['context'] = array();
482
-        }
483
-
484
-        $session['context'][$key] = $data;
485
-    }
486
-
487
-    /**
488
-     * @return int|null
489
-     */
490
-    public static function getSessionUserId()
491
-    {
492
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
493
-
494
-        return isset($session['userID']) ? (int)$session['userID'] : null;
495
-    }
496
-
497
-    /**
498
-     * @param User $user
499
-     */
500
-    public static function setOAuthPartialLogin(User $user)
501
-    {
502
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
503
-        $session['oauthPartialLogin'] = $user->getId();
504
-    }
505
-
506
-    /**
507
-     * @return int|null
508
-     */
509
-    public static function getOAuthPartialLogin()
510
-    {
511
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
512
-
513
-        return isset($session['oauthPartialLogin']) ? (int)$session['oauthPartialLogin'] : null;
514
-    }
515
-
516
-    public static function setAuthPartialLogin($userId, $stage)
517
-    {
518
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
519
-        $session['authPartialLoginId'] = $userId;
520
-        $session['authPartialLoginStage'] = $stage;
521
-    }
522
-
523
-    public static function getAuthPartialLogin()
524
-    {
525
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
526
-
527
-        $userId = isset($session['authPartialLoginId']) ? (int)$session['authPartialLoginId'] : null;
528
-        $stage = isset($session['authPartialLoginStage']) ? (int)$session['authPartialLoginStage'] : null;
529
-
530
-        return array($userId, $stage);
531
-    }
532
-
533
-    public static function clearAuthPartialLogin()
534
-    {
535
-        $session = &self::$globalStateProvider->getSessionSuperGlobal();
536
-        unset($session['authPartialLoginId']);
537
-        unset($session['authPartialLoginStage']);
538
-    }
539
-
540
-    /**
541
-     * @return null|string
542
-     */
543
-    public static function userAgent()
544
-    {
545
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
546
-
547
-        if (isset($server['HTTP_USER_AGENT'])) {
548
-            return $server['HTTP_USER_AGENT'];
549
-        }
550
-
551
-        return null;
552
-    }
553
-
554
-    /**
555
-     * @return null|string
556
-     */
557
-    public static function scriptName()
558
-    {
559
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
560
-
561
-        if (isset($server['SCRIPT_NAME'])) {
562
-            return $server['SCRIPT_NAME'];
563
-        }
564
-
565
-        return null;
566
-    }
567
-
568
-    /**
569
-     * @return null|string
570
-     */
571
-    public static function origin()
572
-    {
573
-        $server = &self::$globalStateProvider->getServerSuperGlobal();
574
-
575
-        if (isset($server['HTTP_ORIGIN'])) {
576
-            return $server['HTTP_ORIGIN'];
577
-        }
578
-
579
-        return null;
580
-    }
25
+	/**
26
+	 * @var \Waca\Providers\GlobalState\IGlobalStateProvider Provides access to the global state.
27
+	 */
28
+	private static $globalStateProvider;
29
+
30
+	/**
31
+	 * Returns a boolean value if the request was submitted with the HTTP POST method.
32
+	 * @return bool
33
+	 */
34
+	public static function wasPosted()
35
+	{
36
+		return self::method() === 'POST';
37
+	}
38
+
39
+	/**
40
+	 * Gets the HTTP Method used
41
+	 * @return string|null
42
+	 */
43
+	public static function method()
44
+	{
45
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
46
+
47
+		if (isset($server['REQUEST_METHOD'])) {
48
+			return $server['REQUEST_METHOD'];
49
+		}
50
+
51
+		return null;
52
+	}
53
+
54
+	/**
55
+	 * Gets a boolean value stating whether the request was served over HTTPS or not.
56
+	 * @return bool
57
+	 */
58
+	public static function isHttps()
59
+	{
60
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
61
+
62
+		if (isset($server['HTTP_X_FORWARDED_PROTO'])) {
63
+			if ($server['HTTP_X_FORWARDED_PROTO'] === 'https') {
64
+				// Client <=> Proxy is encrypted
65
+				return true;
66
+			}
67
+			else {
68
+				// Proxy <=> Server link unknown, Client <=> Proxy is not encrypted.
69
+				return false;
70
+			}
71
+		}
72
+
73
+		if (isset($server['HTTPS'])) {
74
+			if ($server['HTTPS'] === 'off') {
75
+				// ISAPI on IIS breaks the spec. :(
76
+				return false;
77
+			}
78
+
79
+			if ($server['HTTPS'] !== '') {
80
+				// Set to a non-empty value
81
+				return true;
82
+			}
83
+		}
84
+
85
+		return false;
86
+	}
87
+
88
+	/**
89
+	 * Gets the path info
90
+	 *
91
+	 * @return array Array of path info segments
92
+	 */
93
+	public static function pathInfo()
94
+	{
95
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
96
+		if (!isset($server['PATH_INFO'])) {
97
+			return array();
98
+		}
99
+
100
+		$exploded = explode('/', $server['PATH_INFO']);
101
+
102
+		// filter out empty values, and reindex from zero. Notably, the first element is always zero, since it starts
103
+		// with a /
104
+		return array_values(array_filter($exploded));
105
+	}
106
+
107
+	/**
108
+	 * Gets the remote address of the web request
109
+	 * @return null|string
110
+	 */
111
+	public static function remoteAddress()
112
+	{
113
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
114
+
115
+		if (isset($server['REMOTE_ADDR'])) {
116
+			return $server['REMOTE_ADDR'];
117
+		}
118
+
119
+		return null;
120
+	}
121
+
122
+	/**
123
+	 * Gets the remote address of the web request
124
+	 * @return null|string
125
+	 */
126
+	public static function httpHost()
127
+	{
128
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
129
+
130
+		if (isset($server['HTTP_HOST'])) {
131
+			return $server['HTTP_HOST'];
132
+		}
133
+
134
+		return null;
135
+	}
136
+
137
+	/**
138
+	 * Gets the XFF header contents for the web request
139
+	 * @return null|string
140
+	 */
141
+	public static function forwardedAddress()
142
+	{
143
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
144
+
145
+		if (isset($server['HTTP_X_FORWARDED_FOR'])) {
146
+			return $server['HTTP_X_FORWARDED_FOR'];
147
+		}
148
+
149
+		return null;
150
+	}
151
+
152
+	/**
153
+	 * Sets the global state provider.
154
+	 *
155
+	 * Almost guaranteed this is not the method you want in production code.
156
+	 *
157
+	 * @param \Waca\Providers\GlobalState\IGlobalStateProvider $globalState
158
+	 */
159
+	public static function setGlobalStateProvider($globalState)
160
+	{
161
+		self::$globalStateProvider = $globalState;
162
+	}
163
+
164
+	#region POST variables
165
+
166
+	/**
167
+	 * @param string $key
168
+	 *
169
+	 * @return null|string
170
+	 */
171
+	public static function postString($key)
172
+	{
173
+		$post = &self::$globalStateProvider->getPostSuperGlobal();
174
+		if (!array_key_exists($key, $post)) {
175
+			return null;
176
+		}
177
+
178
+		if ($post[$key] === "") {
179
+			return null;
180
+		}
181
+
182
+		return (string)$post[$key];
183
+	}
184
+
185
+	/**
186
+	 * @param string $key
187
+	 *
188
+	 * @return null|string
189
+	 */
190
+	public static function postEmail($key)
191
+	{
192
+		$post = &self::$globalStateProvider->getPostSuperGlobal();
193
+		if (!array_key_exists($key, $post)) {
194
+			return null;
195
+		}
196
+
197
+		$filteredValue = filter_var($post[$key], FILTER_SANITIZE_EMAIL);
198
+
199
+		if ($filteredValue === false) {
200
+			return null;
201
+		}
202
+
203
+		return (string)$filteredValue;
204
+	}
205
+
206
+	/**
207
+	 * @param string $key
208
+	 *
209
+	 * @return int|null
210
+	 */
211
+	public static function postInt($key)
212
+	{
213
+		$post = &self::$globalStateProvider->getPostSuperGlobal();
214
+		if (!array_key_exists($key, $post)) {
215
+			return null;
216
+		}
217
+
218
+		$filteredValue = filter_var($post[$key], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
219
+
220
+		if ($filteredValue === null) {
221
+			return null;
222
+		}
223
+
224
+		return (int)$filteredValue;
225
+	}
226
+
227
+	/**
228
+	 * @param string $key
229
+	 *
230
+	 * @return bool
231
+	 */
232
+	public static function postBoolean($key)
233
+	{
234
+		$get = &self::$globalStateProvider->getPostSuperGlobal();
235
+		if (!array_key_exists($key, $get)) {
236
+			return false;
237
+		}
238
+
239
+		// presence of parameter only
240
+		if ($get[$key] === "") {
241
+			return true;
242
+		}
243
+
244
+		if (in_array($get[$key], array(false, 'no', 'off', 0, 'false'), true)) {
245
+			return false;
246
+		}
247
+
248
+		return true;
249
+	}
250
+
251
+	#endregion
252
+
253
+	#region GET variables
254
+
255
+	/**
256
+	 * @param string $key
257
+	 *
258
+	 * @return bool
259
+	 */
260
+	public static function getBoolean($key)
261
+	{
262
+		$get = &self::$globalStateProvider->getGetSuperGlobal();
263
+		if (!array_key_exists($key, $get)) {
264
+			return false;
265
+		}
266
+
267
+		// presence of parameter only
268
+		if ($get[$key] === "") {
269
+			return true;
270
+		}
271
+
272
+		if (in_array($get[$key], array(false, 'no', 'off', 0, 'false'), true)) {
273
+			return false;
274
+		}
275
+
276
+		return true;
277
+	}
278
+
279
+	/**
280
+	 * @param string $key
281
+	 *
282
+	 * @return int|null
283
+	 */
284
+	public static function getInt($key)
285
+	{
286
+		$get = &self::$globalStateProvider->getGetSuperGlobal();
287
+		if (!array_key_exists($key, $get)) {
288
+			return null;
289
+		}
290
+
291
+		$filteredValue = filter_var($get[$key], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
292
+
293
+		if ($filteredValue === null) {
294
+			return null;
295
+		}
296
+
297
+		return (int)$filteredValue;
298
+	}
299
+
300
+	/**
301
+	 * @param string $key
302
+	 *
303
+	 * @return null|string
304
+	 */
305
+	public static function getString($key)
306
+	{
307
+		$get = &self::$globalStateProvider->getGetSuperGlobal();
308
+		if (!array_key_exists($key, $get)) {
309
+			return null;
310
+		}
311
+
312
+		if ($get[$key] === "") {
313
+			return null;
314
+		}
315
+
316
+		return (string)$get[$key];
317
+	}
318
+
319
+	#endregion
320
+
321
+	/**
322
+	 * Sets the logged-in user to the specified user.
323
+	 *
324
+	 * @param User $user
325
+	 */
326
+	public static function setLoggedInUser(User $user)
327
+	{
328
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
329
+
330
+		$session['userID'] = $user->getId();
331
+		unset($session['partialLogin']);
332
+	}
333
+
334
+	/**
335
+	 * Sets the post-login redirect
336
+	 */
337
+	public static function setPostLoginRedirect()
338
+	{
339
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
340
+		$session['returnTo'] = self::requestUri();
341
+	}
342
+
343
+	/**
344
+	 * @return string|null
345
+	 */
346
+	public static function requestUri()
347
+	{
348
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
349
+
350
+		if (isset($server['REQUEST_URI'])) {
351
+			return $server['REQUEST_URI'];
352
+		}
353
+
354
+		return null;
355
+	}
356
+
357
+	/**
358
+	 * Clears the post-login redirect
359
+	 * @return string
360
+	 */
361
+	public static function clearPostLoginRedirect()
362
+	{
363
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
364
+		if (array_key_exists('returnTo', $session)) {
365
+			$path = $session['returnTo'];
366
+			unset($session['returnTo']);
367
+
368
+			return $path;
369
+		}
370
+
371
+		return null;
372
+	}
373
+
374
+	/**
375
+	 * @return string|null
376
+	 */
377
+	public static function serverName()
378
+	{
379
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
380
+
381
+		if (isset($server['SERVER_NAME'])) {
382
+			return $server['SERVER_NAME'];
383
+		}
384
+
385
+		return null;
386
+	}
387
+
388
+	/**
389
+	 * You probably only want to deal with this through SessionAlert.
390
+	 * @return void
391
+	 */
392
+	public static function clearSessionAlertData()
393
+	{
394
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
395
+		if (array_key_exists('alerts', $session)) {
396
+			unset($session['alerts']);
397
+		}
398
+	}
399
+
400
+	/**
401
+	 * You probably only want to deal with this through SessionAlert.
402
+	 *
403
+	 * @return string[]
404
+	 */
405
+	public static function getSessionAlertData()
406
+	{
407
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
408
+		if (array_key_exists('alerts', $session)) {
409
+			return $session['alerts'];
410
+		}
411
+
412
+		return array();
413
+	}
414
+
415
+	/**
416
+	 * You probably only want to deal with this through SessionAlert.
417
+	 *
418
+	 * @param string[] $data
419
+	 */
420
+	public static function setSessionAlertData($data)
421
+	{
422
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
423
+		$session['alerts'] = $data;
424
+	}
425
+
426
+	/**
427
+	 * You probably only want to deal with this through TokenManager.
428
+	 *
429
+	 * @return string[]
430
+	 */
431
+	public static function getSessionTokenData()
432
+	{
433
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
434
+		if (array_key_exists('tokens', $session)) {
435
+			return $session['tokens'];
436
+		}
437
+
438
+		return array();
439
+	}
440
+
441
+	/**
442
+	 * You probably only want to deal with this through TokenManager.
443
+	 *
444
+	 * @param string[] $data
445
+	 */
446
+	public static function setSessionTokenData($data)
447
+	{
448
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
449
+		$session['tokens'] = $data;
450
+	}
451
+
452
+	/**
453
+	 * @param string $key
454
+	 *
455
+	 * @return mixed
456
+	 */
457
+	public static function getSessionContext($key)
458
+	{
459
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
460
+
461
+		if (!isset($session['context'])) {
462
+			$session['context'] = array();
463
+		}
464
+
465
+		if (!isset($session['context'][$key])) {
466
+			return null;
467
+		}
468
+
469
+		return $session['context'][$key];
470
+	}
471
+
472
+	/**
473
+	 * @param string $key
474
+	 * @param mixed  $data
475
+	 */
476
+	public static function setSessionContext($key, $data)
477
+	{
478
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
479
+
480
+		if (!isset($session['context'])) {
481
+			$session['context'] = array();
482
+		}
483
+
484
+		$session['context'][$key] = $data;
485
+	}
486
+
487
+	/**
488
+	 * @return int|null
489
+	 */
490
+	public static function getSessionUserId()
491
+	{
492
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
493
+
494
+		return isset($session['userID']) ? (int)$session['userID'] : null;
495
+	}
496
+
497
+	/**
498
+	 * @param User $user
499
+	 */
500
+	public static function setOAuthPartialLogin(User $user)
501
+	{
502
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
503
+		$session['oauthPartialLogin'] = $user->getId();
504
+	}
505
+
506
+	/**
507
+	 * @return int|null
508
+	 */
509
+	public static function getOAuthPartialLogin()
510
+	{
511
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
512
+
513
+		return isset($session['oauthPartialLogin']) ? (int)$session['oauthPartialLogin'] : null;
514
+	}
515
+
516
+	public static function setAuthPartialLogin($userId, $stage)
517
+	{
518
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
519
+		$session['authPartialLoginId'] = $userId;
520
+		$session['authPartialLoginStage'] = $stage;
521
+	}
522
+
523
+	public static function getAuthPartialLogin()
524
+	{
525
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
526
+
527
+		$userId = isset($session['authPartialLoginId']) ? (int)$session['authPartialLoginId'] : null;
528
+		$stage = isset($session['authPartialLoginStage']) ? (int)$session['authPartialLoginStage'] : null;
529
+
530
+		return array($userId, $stage);
531
+	}
532
+
533
+	public static function clearAuthPartialLogin()
534
+	{
535
+		$session = &self::$globalStateProvider->getSessionSuperGlobal();
536
+		unset($session['authPartialLoginId']);
537
+		unset($session['authPartialLoginStage']);
538
+	}
539
+
540
+	/**
541
+	 * @return null|string
542
+	 */
543
+	public static function userAgent()
544
+	{
545
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
546
+
547
+		if (isset($server['HTTP_USER_AGENT'])) {
548
+			return $server['HTTP_USER_AGENT'];
549
+		}
550
+
551
+		return null;
552
+	}
553
+
554
+	/**
555
+	 * @return null|string
556
+	 */
557
+	public static function scriptName()
558
+	{
559
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
560
+
561
+		if (isset($server['SCRIPT_NAME'])) {
562
+			return $server['SCRIPT_NAME'];
563
+		}
564
+
565
+		return null;
566
+	}
567
+
568
+	/**
569
+	 * @return null|string
570
+	 */
571
+	public static function origin()
572
+	{
573
+		$server = &self::$globalStateProvider->getServerSuperGlobal();
574
+
575
+		if (isset($server['HTTP_ORIGIN'])) {
576
+			return $server['HTTP_ORIGIN'];
577
+		}
578
+
579
+		return null;
580
+	}
581 581
 }
582 582
\ No newline at end of file
Please login to merge, or discard this patch.
config.inc.php 2 patches
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -200,24 +200,24 @@  discard block
 block discarded – undo
200 200
 
201 201
 // request states
202 202
 $availableRequestStates = array(
203
-    'Open'          => array(
204
-        'defertolog' => 'users', // don't change or you'll break old logs
205
-        'deferto'    => 'users',
206
-        'header'     => 'Open requests',
207
-        'api'        => "open",
208
-    ),
209
-    'Flagged users' => array(
210
-        'defertolog' => 'flagged users', // don't change or you'll break old logs
211
-        'deferto'    => 'flagged users',
212
-        'header'     => 'Flagged user needed',
213
-        'api'        => "admin",
214
-    ),
215
-    'Checkuser'     => array(
216
-        'defertolog' => 'checkusers', // don't change or you'll break old logs
217
-        'deferto'    => 'checkusers',
218
-        'header'     => 'Checkuser needed',
219
-        'api'        => "checkuser",
220
-    ),
203
+	'Open'          => array(
204
+		'defertolog' => 'users', // don't change or you'll break old logs
205
+		'deferto'    => 'users',
206
+		'header'     => 'Open requests',
207
+		'api'        => "open",
208
+	),
209
+	'Flagged users' => array(
210
+		'defertolog' => 'flagged users', // don't change or you'll break old logs
211
+		'deferto'    => 'flagged users',
212
+		'header'     => 'Flagged user needed',
213
+		'api'        => "admin",
214
+	),
215
+	'Checkuser'     => array(
216
+		'defertolog' => 'checkusers', // don't change or you'll break old logs
217
+		'deferto'    => 'checkusers',
218
+		'header'     => 'Checkuser needed',
219
+		'api'        => "checkuser",
220
+	),
221 221
 );
222 222
 
223 223
 $defaultRequestStateKey = 'Open';
@@ -264,21 +264,21 @@  discard block
 block discarded – undo
264 264
 require_once('config.local.inc.php');
265 265
 
266 266
 $cDatabaseConfig = array(
267
-    "acc"           => array(
268
-        "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database,
269
-        "username" => $toolserver_username,
270
-        "password" => $toolserver_password,
271
-    ),
272
-    "wikipedia"     => array(
273
-        "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db,
274
-        "username" => $toolserver_username,
275
-        "password" => $toolserver_password,
276
-    ),
277
-    "notifications" => array(
278
-        "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database,
279
-        "username" => $notifications_username,
280
-        "password" => $notifications_password,
281
-    ),
267
+	"acc"           => array(
268
+		"dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database,
269
+		"username" => $toolserver_username,
270
+		"password" => $toolserver_password,
271
+	),
272
+	"wikipedia"     => array(
273
+		"dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db,
274
+		"username" => $toolserver_username,
275
+		"password" => $toolserver_password,
276
+	),
277
+	"notifications" => array(
278
+		"dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database,
279
+		"username" => $notifications_username,
280
+		"password" => $notifications_password,
281
+	),
282 282
 );
283 283
 
284 284
 // //Keep the included files from being executed.
@@ -290,18 +290,18 @@  discard block
 block discarded – undo
290 290
 ini_set('user_agent', $toolUserAgent);
291 291
 
292 292
 foreach (array(
293
-    "mbstring", // unicode and stuff
294
-    "pdo",
295
-    "pdo_mysql", // new database module
296
-    "session",
297
-    "date",
298
-    "pcre", // core stuff
299
-    "curl", // mediawiki api access etc
300
-    "openssl", // token generation
293
+	"mbstring", // unicode and stuff
294
+	"pdo",
295
+	"pdo_mysql", // new database module
296
+	"session",
297
+	"date",
298
+	"pcre", // core stuff
299
+	"curl", // mediawiki api access etc
300
+	"openssl", // token generation
301 301
 ) as $x) {
302
-    if (!extension_loaded($x)) {
303
-        die("extension $x is required.");
304
-    }
302
+	if (!extension_loaded($x)) {
303
+		die("extension $x is required.");
304
+	}
305 305
 }
306 306
 
307 307
 // Set up the AutoLoader
@@ -328,39 +328,39 @@  discard block
 block discarded – undo
328 328
 $siteConfiguration = new \Waca\SiteConfiguration();
329 329
 
330 330
 $siteConfiguration->setBaseUrl($baseurl)
331
-    ->setFilePath(__DIR__)
332
-    ->setDebuggingTraceEnabled($enableErrorTrace)
333
-    ->setForceIdentification($forceIdentification)
334
-    ->setIdentificationCacheExpiry($identificationCacheExpiry)
335
-    ->setMediawikiScriptPath($mediawikiScriptPath)
336
-    ->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint)
337
-    ->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint)
338
-    ->setEnforceOAuth($enforceOAuth)
339
-    ->setEmailConfirmationEnabled($enableEmailConfirm == 1)
340
-    ->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays)
341
-    ->setMiserModeLimit($requestLimitShowOnly)
342
-    ->setRequestStates($availableRequestStates)
343
-    ->setSquidList($squidIpList)
344
-    ->setDefaultCreatedTemplateId($createdid)
345
-    ->setDefaultRequestStateKey($defaultRequestStateKey)
346
-    ->setUseStrictTransportSecurity($strictTransportSecurityExpiry)
347
-    ->setUserAgent($toolUserAgent)
348
-    ->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer)
349
-    ->setUseOAuthSignup($useOauthSignup)
350
-    ->setOAuthBaseUrl($oauthBaseUrl)
351
-    ->setOAuthConsumerToken($oauthConsumerToken)
352
-    ->setOAuthConsumerSecret($oauthSecretToken)
353
-    ->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer)
354
-    ->setDataClearInterval($dataclear_interval)
355
-    ->setXffTrustedHostsFile($xff_trusted_hosts_file)
356
-    ->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1)
357
-    ->setIrcNotificationType($ircBotNotificationType)
358
-    ->setIrcNotificationsInstance($whichami)
359
-    ->setTitleBlacklistEnabled($enableTitleblacklist == 1)
360
-    ->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org')))
361
-    ->setCreationBotUsername($creationBotUsername)
362
-    ->setCreationBotPassword($creationBotPassword)
363
-    ->setCurlCookieJar($curlCookieJar)
364
-    ->setYubicoApiId($yubicoApiId)
365
-    ->setYubicoApiKey($yubicoApiKey)
366
-    ->setTotpEncryptionKey($totpEncryptionKey);
331
+	->setFilePath(__DIR__)
332
+	->setDebuggingTraceEnabled($enableErrorTrace)
333
+	->setForceIdentification($forceIdentification)
334
+	->setIdentificationCacheExpiry($identificationCacheExpiry)
335
+	->setMediawikiScriptPath($mediawikiScriptPath)
336
+	->setMediawikiWebServiceEndpoint($mediawikiWebServiceEndpoint)
337
+	->setMetaWikimediaWebServiceEndpoint($metaWikimediaWebServiceEndpoint)
338
+	->setEnforceOAuth($enforceOAuth)
339
+	->setEmailConfirmationEnabled($enableEmailConfirm == 1)
340
+	->setEmailConfirmationExpiryDays($emailConfirmationExpiryDays)
341
+	->setMiserModeLimit($requestLimitShowOnly)
342
+	->setRequestStates($availableRequestStates)
343
+	->setSquidList($squidIpList)
344
+	->setDefaultCreatedTemplateId($createdid)
345
+	->setDefaultRequestStateKey($defaultRequestStateKey)
346
+	->setUseStrictTransportSecurity($strictTransportSecurityExpiry)
347
+	->setUserAgent($toolUserAgent)
348
+	->setCurlDisableVerifyPeer($curlDisableSSLVerifyPeer)
349
+	->setUseOAuthSignup($useOauthSignup)
350
+	->setOAuthBaseUrl($oauthBaseUrl)
351
+	->setOAuthConsumerToken($oauthConsumerToken)
352
+	->setOAuthConsumerSecret($oauthSecretToken)
353
+	->setOauthMediaWikiCanonicalServer($oauthMediaWikiCanonicalServer)
354
+	->setDataClearInterval($dataclear_interval)
355
+	->setXffTrustedHostsFile($xff_trusted_hosts_file)
356
+	->setIrcNotificationsEnabled($ircBotNotificationsEnabled == 1)
357
+	->setIrcNotificationType($ircBotNotificationType)
358
+	->setIrcNotificationsInstance($whichami)
359
+	->setTitleBlacklistEnabled($enableTitleblacklist == 1)
360
+	->setTorExitPaths(array_merge(gethostbynamel('en.wikipedia.org'), gethostbynamel('accounts.wmflabs.org')))
361
+	->setCreationBotUsername($creationBotUsername)
362
+	->setCreationBotPassword($creationBotPassword)
363
+	->setCurlCookieJar($curlCookieJar)
364
+	->setYubicoApiId($yubicoApiId)
365
+	->setYubicoApiKey($yubicoApiKey)
366
+	->setTotpEncryptionKey($totpEncryptionKey);
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
 
131 131
 $BUbasefile = "backup"; // The basefile's name.
132 132
 $BUdir = "/home/project/a/c/c/acc/backups"; // The directory where backups should be stored.
133
-$BUmonthdir = $BUdir . "/monthly"; // The directory where monthly backups should be stored.
133
+$BUmonthdir = $BUdir."/monthly"; // The directory where monthly backups should be stored.
134 134
 $BUdumper = "/opt/ts/mysql/5.1/bin/mysqldump --defaults-file=~/.my.cnf p_acc_live"; // Add parameters here if they are needed.
135 135
 $BUgzip = "/usr/bin/gzip"; // Add the gzip parameters here if needed.
136 136
 $BUtar = "/bin/tar -cvf"; // Add the tar parameters here if needed.
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
 $curlDisableSSLVerifyPeer = false;
247 247
 
248 248
 // Change this to be outside the web directory.
249
-$curlCookieJar = __DIR__ . '/../cookies.txt';
249
+$curlCookieJar = __DIR__.'/../cookies.txt';
250 250
 
251 251
 $yubicoApiId = 0;
252 252
 $yubicoApiKey = "";
@@ -265,17 +265,17 @@  discard block
 block discarded – undo
265 265
 
266 266
 $cDatabaseConfig = array(
267 267
     "acc"           => array(
268
-        "dsrcname" => "mysql:host=" . $toolserver_host . ";dbname=" . $toolserver_database,
268
+        "dsrcname" => "mysql:host=".$toolserver_host.";dbname=".$toolserver_database,
269 269
         "username" => $toolserver_username,
270 270
         "password" => $toolserver_password,
271 271
     ),
272 272
     "wikipedia"     => array(
273
-        "dsrcname" => "mysql:host=" . $antispoof_host . ";dbname=" . $antispoof_db,
273
+        "dsrcname" => "mysql:host=".$antispoof_host.";dbname=".$antispoof_db,
274 274
         "username" => $toolserver_username,
275 275
         "password" => $toolserver_password,
276 276
     ),
277 277
     "notifications" => array(
278
-        "dsrcname" => "mysql:host=" . $toolserver_notification_dbhost . ";dbname=" . $toolserver_notification_database,
278
+        "dsrcname" => "mysql:host=".$toolserver_notification_dbhost.";dbname=".$toolserver_notification_database,
279 279
         "username" => $notifications_username,
280 280
         "password" => $notifications_password,
281 281
     ),
@@ -305,13 +305,13 @@  discard block
 block discarded – undo
305 305
 }
306 306
 
307 307
 // Set up the AutoLoader
308
-require_once(__DIR__ . "/includes/AutoLoader.php");
308
+require_once(__DIR__."/includes/AutoLoader.php");
309 309
 spl_autoload_register('Waca\\AutoLoader::load');
310
-require_once(__DIR__ . '/vendor/autoload.php');
310
+require_once(__DIR__.'/vendor/autoload.php');
311 311
 
312 312
 // Extra includes which are just plain awkward wherever they are.
313
-require_once(__DIR__ . '/lib/mediawiki-extensions-OAuth/lib/OAuth.php');
314
-require_once(__DIR__ . '/lib/mediawiki-extensions-OAuth/lib/JWT.php');
313
+require_once(__DIR__.'/lib/mediawiki-extensions-OAuth/lib/OAuth.php');
314
+require_once(__DIR__.'/lib/mediawiki-extensions-OAuth/lib/JWT.php');
315 315
 
316 316
 // Crap that's needed for libraries. >:(
317 317
 /**
Please login to merge, or discard this patch.