Passed
Push — dependabot/composer/php8/media... ( e6d0f9 )
by
unknown
34:23 queued 29:40
created
includes/Pages/UserAuth/Login/LoginCredentialPageBase.php 2 patches
Braces   +8 added lines, -13 removed lines patch added patch discarded remove patch
@@ -65,8 +65,7 @@  discard block
 block discarded – undo
65 65
                     }
66 66
 
67 67
                     $user = User::getByUsername($username, $database);
68
-                }
69
-                else {
68
+                } else {
70 69
                     $user = User::getById($partialId, $database);
71 70
                 }
72 71
 
@@ -105,8 +104,7 @@  discard block
 block discarded – undo
105 104
 
106 105
                 return;
107 106
             }
108
-        }
109
-        else {
107
+        } else {
110 108
             $this->assign('showSignIn', true);
111 109
 
112 110
             $this->setupPartial();
@@ -131,8 +129,7 @@  discard block
 block discarded – undo
131 129
             if (WebRequest::isHttps()) {
132 130
                 // Client can clearly use HTTPS, so let's enforce it for all connections.
133 131
                 $this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
134
-            }
135
-            else {
132
+            } else {
136 133
                 // This is the login form, not the request form. We need protection here.
137 134
                 $this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
138 135
 
@@ -166,8 +163,7 @@  discard block
 block discarded – undo
166 163
             $username = $this->partialUser->getUsername();
167 164
 
168 165
             $this->setupAlternates($this->partialUser, $partialStage, $database);
169
-        }
170
-        else {
166
+        } else {
171 167
             // No, see if we've preloaded a username
172 168
             $preloadUsername = WebRequest::getString('tplUsername');
173 169
             if ($preloadUsername !== null) {
@@ -194,13 +190,11 @@  discard block
 block discarded – undo
194 190
         $redirectDestination = WebRequest::clearPostLoginRedirect();
195 191
         if ($redirectDestination !== null) {
196 192
             $this->redirectUrl($redirectDestination);
197
-        }
198
-        else {
193
+        } else {
199 194
             if ($user->isNewUser()) {
200 195
                 // home page isn't allowed, go to preferences instead
201 196
                 $this->redirect('preferences');
202
-            }
203
-            else {
197
+            } else {
204 198
                 // go to the home page
205 199
                 $this->redirect('');
206 200
             }
@@ -323,7 +317,8 @@  discard block
 block discarded – undo
323 317
         if (isset($types[$type])) {
324 318
             $options = $types[$type];
325 319
 
326
-            array_walk($options, function(&$val) {
320
+            array_walk($options, function(&$val)
321
+            {
327 322
                 $val = $this->names[$val];
328 323
             });
329 324
 
Please login to merge, or discard this patch.
Indentation   +306 added lines, -306 removed lines patch added patch discarded remove patch
@@ -21,310 +21,310 @@
 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
-    );
31
-    protected $names = array(
32
-        'yubikeyotp' => 'Yubikey OTP',
33
-        'totp'       => 'TOTP (phone code generator)',
34
-        'scratch'    => 'scratch token',
35
-    );
36
-
37
-    /**
38
-     * Main function for this page, when no specific actions are called.
39
-     * @return void
40
-     */
41
-    protected function main()
42
-    {
43
-        if (!$this->enforceHttps()) {
44
-            return;
45
-        }
46
-
47
-        if (WebRequest::wasPosted()) {
48
-            $this->validateCSRFToken();
49
-
50
-            $database = $this->getDatabase();
51
-            try {
52
-                list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
53
-
54
-                if ($partialStage === null) {
55
-                    $partialStage = 1;
56
-                }
57
-
58
-                if ($partialId === null) {
59
-                    $username = WebRequest::postString('username');
60
-
61
-                    if ($username === null || trim($username) === '') {
62
-                        throw new ApplicationLogicException('No username specified.');
63
-                    }
64
-
65
-                    $user = User::getByUsername($username, $database);
66
-                }
67
-                else {
68
-                    $user = User::getById($partialId, $database);
69
-                }
70
-
71
-                if ($user === false) {
72
-                    throw new ApplicationLogicException("Authentication failed");
73
-                }
74
-
75
-                $authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
76
-                    $this->getHttpHelper());
77
-
78
-                $credential = $this->getProviderCredentials();
79
-
80
-                $authResult = $authMan->authenticate($user, $credential, $partialStage);
81
-
82
-                if ($authResult === AuthenticationManager::AUTH_FAIL) {
83
-                    throw new ApplicationLogicException("Authentication failed");
84
-                }
85
-
86
-                if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
87
-                    $this->processJumpNextStage($user, $partialStage, $database);
88
-
89
-                    return;
90
-                }
91
-
92
-                if ($authResult === AuthenticationManager::AUTH_OK) {
93
-                    $this->processLoginSuccess($user);
94
-
95
-                    return;
96
-                }
97
-            }
98
-            catch (ApplicationLogicException $ex) {
99
-                WebRequest::clearAuthPartialLogin();
100
-
101
-                SessionAlert::error($ex->getMessage());
102
-                $this->redirect('login');
103
-
104
-                return;
105
-            }
106
-        }
107
-        else {
108
-            $this->assign('showSignIn', true);
109
-
110
-            $this->setupPartial();
111
-            $this->assignCSRFToken();
112
-            $this->providerSpecificSetup();
113
-        }
114
-    }
115
-
116
-    protected function isProtectedPage()
117
-    {
118
-        return false;
119
-    }
120
-
121
-    /**
122
-     * Enforces HTTPS on the login form
123
-     *
124
-     * @return bool
125
-     */
126
-    private function enforceHttps()
127
-    {
128
-        if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
129
-            if (WebRequest::isHttps()) {
130
-                // Client can clearly use HTTPS, so let's enforce it for all connections.
131
-                $this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
132
-            }
133
-            else {
134
-                // This is the login form, not the request form. We need protection here.
135
-                $this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
136
-
137
-                return false;
138
-            }
139
-        }
140
-
141
-        return true;
142
-    }
143
-
144
-    protected abstract function providerSpecificSetup();
145
-
146
-    protected function setupPartial()
147
-    {
148
-        $database = $this->getDatabase();
149
-
150
-        // default stuff
151
-        $this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
152
-
153
-        // is this stage one?
154
-        list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
155
-        if ($partialStage === null || $partialId === null) {
156
-            WebRequest::clearAuthPartialLogin();
157
-        }
158
-
159
-        // Check to see if we have a partial login in progress
160
-        $username = null;
161
-        if ($partialId !== null) {
162
-            // Yes, enforce this username
163
-            $this->partialUser = User::getById($partialId, $database);
164
-            $username = $this->partialUser->getUsername();
165
-
166
-            $this->setupAlternates($this->partialUser, $partialStage, $database);
167
-        }
168
-        else {
169
-            // No, see if we've preloaded a username
170
-            $preloadUsername = WebRequest::getString('tplUsername');
171
-            if ($preloadUsername !== null) {
172
-                $username = $preloadUsername;
173
-            }
174
-        }
175
-
176
-        if ($partialStage === null) {
177
-            $partialStage = 1;
178
-        }
179
-
180
-        $this->assign('partialStage', $partialStage);
181
-        $this->assign('username', $username);
182
-    }
183
-
184
-    /**
185
-     * Redirect the user back to wherever they came from after a successful login
186
-     *
187
-     * @param User $user
188
-     */
189
-    protected function goBackWhenceYouCame(User $user)
190
-    {
191
-        // Redirect to wherever the user came from
192
-        $redirectDestination = WebRequest::clearPostLoginRedirect();
193
-        if ($redirectDestination !== null) {
194
-            $this->redirectUrl($redirectDestination);
195
-        }
196
-        else {
197
-            if ($user->isNewUser()) {
198
-                // home page isn't allowed, go to preferences instead
199
-                $this->redirect('preferences');
200
-            }
201
-            else {
202
-                // go to the home page
203
-                $this->redirect('');
204
-            }
205
-        }
206
-    }
207
-
208
-    private function processLoginSuccess(User $user)
209
-    {
210
-        // Touch force logout
211
-        $user->setForceLogout(false);
212
-        $user->save();
213
-
214
-        $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
215
-            $this->getSiteConfiguration());
216
-
217
-        if ($oauth->isFullyLinked()) {
218
-            try {
219
-                // Reload the user's identity ticket.
220
-                $oauth->refreshIdentity();
221
-
222
-                // Check for blocks
223
-                if ($oauth->getIdentity()->getBlocked()) {
224
-                    // blocked!
225
-                    SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
226
-                    $this->redirect('login');
227
-
228
-                    return;
229
-                }
230
-            }
231
-            catch (OAuthException $ex) {
232
-                // Oops. Refreshing ticket failed. Force a re-auth.
233
-                $authoriseUrl = $oauth->getRequestToken();
234
-                WebRequest::setOAuthPartialLogin($user);
235
-                $this->redirectUrl($authoriseUrl);
236
-
237
-                return;
238
-            }
239
-        }
240
-
241
-        if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
242
-            || $oauth->isPartiallyLinked()
243
-        ) {
244
-            $authoriseUrl = $oauth->getRequestToken();
245
-            WebRequest::setOAuthPartialLogin($user);
246
-            $this->redirectUrl($authoriseUrl);
247
-
248
-            return;
249
-        }
250
-
251
-        WebRequest::setLoggedInUser($user);
252
-        $this->getDomainAccessManager()->switchToDefaultDomain($user);
253
-
254
-        $this->goBackWhenceYouCame($user);
255
-    }
256
-
257
-    protected abstract function getProviderCredentials();
258
-
259
-    /**
260
-     * @param User        $user
261
-     * @param int         $partialStage
262
-     * @param PdoDatabase $database
263
-     *
264
-     * @throws ApplicationLogicException
265
-     */
266
-    private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
267
-    {
268
-        WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
269
-
270
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
271
-        $statement = $database->prepare($sql);
272
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
273
-        $nextStage = $statement->fetchColumn();
274
-        $statement->closeCursor();
275
-
276
-        if (!isset($this->nextPageMap[$nextStage])) {
277
-            throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
278
-        }
279
-
280
-        $this->redirect("login/" . $this->nextPageMap[$nextStage]);
281
-    }
282
-
283
-    private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
284
-    {
285
-        // get the providers available
286
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
287
-        $statement = $database->prepare($sql);
288
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
289
-        $alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
290
-
291
-        $types = array();
292
-        foreach ($alternates as $item) {
293
-            $type = $this->nextPageMap[$item];
294
-            if (!isset($types[$type])) {
295
-                $types[$type] = array();
296
-            }
297
-
298
-            $types[$type][] = $item;
299
-        }
300
-
301
-        $userOptions = array();
302
-        if (get_called_class() !== PageOtpLogin::class) {
303
-            $userOptions = array_merge($userOptions, $this->setupUserOptionsForType($types, 'otp', $userOptions));
304
-        }
305
-
306
-        $this->assign('alternatives', $userOptions);
307
-    }
308
-
309
-    /**
310
-     * @param $types
311
-     * @param $type
312
-     * @param $userOptions
313
-     *
314
-     * @return mixed
315
-     */
316
-    private function setupUserOptionsForType($types, $type, $userOptions)
317
-    {
318
-        if (isset($types[$type])) {
319
-            $options = $types[$type];
320
-
321
-            array_walk($options, function(&$val) {
322
-                $val = $this->names[$val];
323
-            });
324
-
325
-            $userOptions[$type] = $options;
326
-        }
327
-
328
-        return $userOptions;
329
-    }
24
+	/** @var User */
25
+	protected $partialUser = null;
26
+	protected $nextPageMap = array(
27
+		'yubikeyotp' => 'otp',
28
+		'totp'       => 'otp',
29
+		'scratch'    => 'otp',
30
+	);
31
+	protected $names = array(
32
+		'yubikeyotp' => 'Yubikey OTP',
33
+		'totp'       => 'TOTP (phone code generator)',
34
+		'scratch'    => 'scratch token',
35
+	);
36
+
37
+	/**
38
+	 * Main function for this page, when no specific actions are called.
39
+	 * @return void
40
+	 */
41
+	protected function main()
42
+	{
43
+		if (!$this->enforceHttps()) {
44
+			return;
45
+		}
46
+
47
+		if (WebRequest::wasPosted()) {
48
+			$this->validateCSRFToken();
49
+
50
+			$database = $this->getDatabase();
51
+			try {
52
+				list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
53
+
54
+				if ($partialStage === null) {
55
+					$partialStage = 1;
56
+				}
57
+
58
+				if ($partialId === null) {
59
+					$username = WebRequest::postString('username');
60
+
61
+					if ($username === null || trim($username) === '') {
62
+						throw new ApplicationLogicException('No username specified.');
63
+					}
64
+
65
+					$user = User::getByUsername($username, $database);
66
+				}
67
+				else {
68
+					$user = User::getById($partialId, $database);
69
+				}
70
+
71
+				if ($user === false) {
72
+					throw new ApplicationLogicException("Authentication failed");
73
+				}
74
+
75
+				$authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
76
+					$this->getHttpHelper());
77
+
78
+				$credential = $this->getProviderCredentials();
79
+
80
+				$authResult = $authMan->authenticate($user, $credential, $partialStage);
81
+
82
+				if ($authResult === AuthenticationManager::AUTH_FAIL) {
83
+					throw new ApplicationLogicException("Authentication failed");
84
+				}
85
+
86
+				if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
87
+					$this->processJumpNextStage($user, $partialStage, $database);
88
+
89
+					return;
90
+				}
91
+
92
+				if ($authResult === AuthenticationManager::AUTH_OK) {
93
+					$this->processLoginSuccess($user);
94
+
95
+					return;
96
+				}
97
+			}
98
+			catch (ApplicationLogicException $ex) {
99
+				WebRequest::clearAuthPartialLogin();
100
+
101
+				SessionAlert::error($ex->getMessage());
102
+				$this->redirect('login');
103
+
104
+				return;
105
+			}
106
+		}
107
+		else {
108
+			$this->assign('showSignIn', true);
109
+
110
+			$this->setupPartial();
111
+			$this->assignCSRFToken();
112
+			$this->providerSpecificSetup();
113
+		}
114
+	}
115
+
116
+	protected function isProtectedPage()
117
+	{
118
+		return false;
119
+	}
120
+
121
+	/**
122
+	 * Enforces HTTPS on the login form
123
+	 *
124
+	 * @return bool
125
+	 */
126
+	private function enforceHttps()
127
+	{
128
+		if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
129
+			if (WebRequest::isHttps()) {
130
+				// Client can clearly use HTTPS, so let's enforce it for all connections.
131
+				$this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
132
+			}
133
+			else {
134
+				// This is the login form, not the request form. We need protection here.
135
+				$this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
136
+
137
+				return false;
138
+			}
139
+		}
140
+
141
+		return true;
142
+	}
143
+
144
+	protected abstract function providerSpecificSetup();
145
+
146
+	protected function setupPartial()
147
+	{
148
+		$database = $this->getDatabase();
149
+
150
+		// default stuff
151
+		$this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
152
+
153
+		// is this stage one?
154
+		list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
155
+		if ($partialStage === null || $partialId === null) {
156
+			WebRequest::clearAuthPartialLogin();
157
+		}
158
+
159
+		// Check to see if we have a partial login in progress
160
+		$username = null;
161
+		if ($partialId !== null) {
162
+			// Yes, enforce this username
163
+			$this->partialUser = User::getById($partialId, $database);
164
+			$username = $this->partialUser->getUsername();
165
+
166
+			$this->setupAlternates($this->partialUser, $partialStage, $database);
167
+		}
168
+		else {
169
+			// No, see if we've preloaded a username
170
+			$preloadUsername = WebRequest::getString('tplUsername');
171
+			if ($preloadUsername !== null) {
172
+				$username = $preloadUsername;
173
+			}
174
+		}
175
+
176
+		if ($partialStage === null) {
177
+			$partialStage = 1;
178
+		}
179
+
180
+		$this->assign('partialStage', $partialStage);
181
+		$this->assign('username', $username);
182
+	}
183
+
184
+	/**
185
+	 * Redirect the user back to wherever they came from after a successful login
186
+	 *
187
+	 * @param User $user
188
+	 */
189
+	protected function goBackWhenceYouCame(User $user)
190
+	{
191
+		// Redirect to wherever the user came from
192
+		$redirectDestination = WebRequest::clearPostLoginRedirect();
193
+		if ($redirectDestination !== null) {
194
+			$this->redirectUrl($redirectDestination);
195
+		}
196
+		else {
197
+			if ($user->isNewUser()) {
198
+				// home page isn't allowed, go to preferences instead
199
+				$this->redirect('preferences');
200
+			}
201
+			else {
202
+				// go to the home page
203
+				$this->redirect('');
204
+			}
205
+		}
206
+	}
207
+
208
+	private function processLoginSuccess(User $user)
209
+	{
210
+		// Touch force logout
211
+		$user->setForceLogout(false);
212
+		$user->save();
213
+
214
+		$oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
215
+			$this->getSiteConfiguration());
216
+
217
+		if ($oauth->isFullyLinked()) {
218
+			try {
219
+				// Reload the user's identity ticket.
220
+				$oauth->refreshIdentity();
221
+
222
+				// Check for blocks
223
+				if ($oauth->getIdentity()->getBlocked()) {
224
+					// blocked!
225
+					SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
226
+					$this->redirect('login');
227
+
228
+					return;
229
+				}
230
+			}
231
+			catch (OAuthException $ex) {
232
+				// Oops. Refreshing ticket failed. Force a re-auth.
233
+				$authoriseUrl = $oauth->getRequestToken();
234
+				WebRequest::setOAuthPartialLogin($user);
235
+				$this->redirectUrl($authoriseUrl);
236
+
237
+				return;
238
+			}
239
+		}
240
+
241
+		if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
242
+			|| $oauth->isPartiallyLinked()
243
+		) {
244
+			$authoriseUrl = $oauth->getRequestToken();
245
+			WebRequest::setOAuthPartialLogin($user);
246
+			$this->redirectUrl($authoriseUrl);
247
+
248
+			return;
249
+		}
250
+
251
+		WebRequest::setLoggedInUser($user);
252
+		$this->getDomainAccessManager()->switchToDefaultDomain($user);
253
+
254
+		$this->goBackWhenceYouCame($user);
255
+	}
256
+
257
+	protected abstract function getProviderCredentials();
258
+
259
+	/**
260
+	 * @param User        $user
261
+	 * @param int         $partialStage
262
+	 * @param PdoDatabase $database
263
+	 *
264
+	 * @throws ApplicationLogicException
265
+	 */
266
+	private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
267
+	{
268
+		WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
269
+
270
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
271
+		$statement = $database->prepare($sql);
272
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
273
+		$nextStage = $statement->fetchColumn();
274
+		$statement->closeCursor();
275
+
276
+		if (!isset($this->nextPageMap[$nextStage])) {
277
+			throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
278
+		}
279
+
280
+		$this->redirect("login/" . $this->nextPageMap[$nextStage]);
281
+	}
282
+
283
+	private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
284
+	{
285
+		// get the providers available
286
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
287
+		$statement = $database->prepare($sql);
288
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
289
+		$alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
290
+
291
+		$types = array();
292
+		foreach ($alternates as $item) {
293
+			$type = $this->nextPageMap[$item];
294
+			if (!isset($types[$type])) {
295
+				$types[$type] = array();
296
+			}
297
+
298
+			$types[$type][] = $item;
299
+		}
300
+
301
+		$userOptions = array();
302
+		if (get_called_class() !== PageOtpLogin::class) {
303
+			$userOptions = array_merge($userOptions, $this->setupUserOptionsForType($types, 'otp', $userOptions));
304
+		}
305
+
306
+		$this->assign('alternatives', $userOptions);
307
+	}
308
+
309
+	/**
310
+	 * @param $types
311
+	 * @param $type
312
+	 * @param $userOptions
313
+	 *
314
+	 * @return mixed
315
+	 */
316
+	private function setupUserOptionsForType($types, $type, $userOptions)
317
+	{
318
+		if (isset($types[$type])) {
319
+			$options = $types[$type];
320
+
321
+			array_walk($options, function(&$val) {
322
+				$val = $this->names[$val];
323
+			});
324
+
325
+			$userOptions[$type] = $options;
326
+		}
327
+
328
+		return $userOptions;
329
+	}
330 330
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/PageOtpLogin.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -13,18 +13,18 @@
 block discarded – undo
13 13
 
14 14
 class PageOtpLogin extends LoginCredentialPageBase
15 15
 {
16
-    protected function providerSpecificSetup()
17
-    {
18
-        $this->setTemplate('login/otp.tpl');
19
-    }
16
+	protected function providerSpecificSetup()
17
+	{
18
+		$this->setTemplate('login/otp.tpl');
19
+	}
20 20
 
21
-    protected function getProviderCredentials()
22
-    {
23
-        $otp = WebRequest::postString("otp");
24
-        if ($otp === null || $otp === "") {
25
-            throw new ApplicationLogicException("No one-time code specified");
26
-        }
21
+	protected function getProviderCredentials()
22
+	{
23
+		$otp = WebRequest::postString("otp");
24
+		if ($otp === null || $otp === "") {
25
+			throw new ApplicationLogicException("No one-time code specified");
26
+		}
27 27
 
28
-        return $otp;
29
-    }
28
+		return $otp;
29
+	}
30 30
 }
31 31
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageOAuthCallback.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -116,8 +116,7 @@
 block discarded – undo
116 116
         $redirectDestination = WebRequest::clearPostLoginRedirect();
117 117
         if ($redirectDestination !== null && !$user->isNewUser()) {
118 118
             $this->redirectUrl($redirectDestination);
119
-        }
120
-        else {
119
+        } else {
121 120
             $this->redirect('preferences', null, null, 'internal.php');
122 121
         }
123 122
     }
Please login to merge, or discard this patch.
Indentation   +78 added lines, -78 removed lines patch added patch discarded remove patch
@@ -18,93 +18,93 @@
 block discarded – undo
18 18
 
19 19
 class PageOAuthCallback extends InternalPageBase
20 20
 {
21
-    /**
22
-     * @return bool
23
-     */
24
-    protected function isProtectedPage()
25
-    {
26
-        // This page is critical to ensuring OAuth functionality is operational.
27
-        return false;
28
-    }
21
+	/**
22
+	 * @return bool
23
+	 */
24
+	protected function isProtectedPage()
25
+	{
26
+		// This page is critical to ensuring OAuth functionality is operational.
27
+		return false;
28
+	}
29 29
 
30
-    /**
31
-     * Main function for this page, when no specific actions are called.
32
-     * @return void
33
-     */
34
-    protected function main()
35
-    {
36
-        // This should never get hit except by URL manipulation.
37
-        $this->redirect('');
38
-    }
30
+	/**
31
+	 * Main function for this page, when no specific actions are called.
32
+	 * @return void
33
+	 */
34
+	protected function main()
35
+	{
36
+		// This should never get hit except by URL manipulation.
37
+		$this->redirect('');
38
+	}
39 39
 
40
-    /**
41
-     * Registered endpoint for the account creation callback.
42
-     *
43
-     * If this ever gets hit, something is wrong somewhere.
44
-     */
45
-    protected function create()
46
-    {
47
-        throw new Exception('OAuth account creation endpoint triggered.');
48
-    }
40
+	/**
41
+	 * Registered endpoint for the account creation callback.
42
+	 *
43
+	 * If this ever gets hit, something is wrong somewhere.
44
+	 */
45
+	protected function create()
46
+	{
47
+		throw new Exception('OAuth account creation endpoint triggered.');
48
+	}
49 49
 
50
-    /**
51
-     * Callback entry point
52
-     * @throws ApplicationLogicException
53
-     * @throws OptimisticLockFailedException
54
-     */
55
-    protected function authorise()
56
-    {
57
-        $oauthToken = WebRequest::getString('oauth_token');
58
-        $oauthVerifier = WebRequest::getString('oauth_verifier');
50
+	/**
51
+	 * Callback entry point
52
+	 * @throws ApplicationLogicException
53
+	 * @throws OptimisticLockFailedException
54
+	 */
55
+	protected function authorise()
56
+	{
57
+		$oauthToken = WebRequest::getString('oauth_token');
58
+		$oauthVerifier = WebRequest::getString('oauth_verifier');
59 59
 
60
-        $this->doCallbackValidation($oauthToken, $oauthVerifier);
60
+		$this->doCallbackValidation($oauthToken, $oauthVerifier);
61 61
 
62
-        $database = $this->getDatabase();
62
+		$database = $this->getDatabase();
63 63
 
64
-        $user = OAuthUserHelper::findUserByRequestToken($oauthToken, $database);
65
-        $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
64
+		$user = OAuthUserHelper::findUserByRequestToken($oauthToken, $database);
65
+		$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
66 66
 
67
-        try {
68
-            $oauth->completeHandshake($oauthVerifier);
69
-        }
70
-        catch (CurlException $ex) {
71
-            throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
72
-        }
67
+		try {
68
+			$oauth->completeHandshake($oauthVerifier);
69
+		}
70
+		catch (CurlException $ex) {
71
+			throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
72
+		}
73 73
 
74
-        // OK, we're the same session that just did a partial login that was redirected to OAuth. Let's upgrade the
75
-        // login to a full login
76
-        if (WebRequest::getOAuthPartialLogin() === $user->getId()) {
77
-            WebRequest::setLoggedInUser($user);
78
-            $this->getDomainAccessManager()->switchToDefaultDomain($user);
79
-        }
74
+		// OK, we're the same session that just did a partial login that was redirected to OAuth. Let's upgrade the
75
+		// login to a full login
76
+		if (WebRequest::getOAuthPartialLogin() === $user->getId()) {
77
+			WebRequest::setLoggedInUser($user);
78
+			$this->getDomainAccessManager()->switchToDefaultDomain($user);
79
+		}
80 80
 
81
-        // My thinking is there are three cases here:
82
-        //   a) new user => redirect to prefs - it's the only thing they can access other than stats
83
-        //   b) existing user hit the connect button in prefs => redirect to prefs since it's where they were
84
-        //   c) existing user logging in => redirect to wherever they came from
85
-        $redirectDestination = WebRequest::clearPostLoginRedirect();
86
-        if ($redirectDestination !== null && !$user->isNewUser()) {
87
-            $this->redirectUrl($redirectDestination);
88
-        }
89
-        else {
90
-            $this->redirect('preferences', null, null, 'internal.php');
91
-        }
92
-    }
81
+		// My thinking is there are three cases here:
82
+		//   a) new user => redirect to prefs - it's the only thing they can access other than stats
83
+		//   b) existing user hit the connect button in prefs => redirect to prefs since it's where they were
84
+		//   c) existing user logging in => redirect to wherever they came from
85
+		$redirectDestination = WebRequest::clearPostLoginRedirect();
86
+		if ($redirectDestination !== null && !$user->isNewUser()) {
87
+			$this->redirectUrl($redirectDestination);
88
+		}
89
+		else {
90
+			$this->redirect('preferences', null, null, 'internal.php');
91
+		}
92
+	}
93 93
 
94
-    /**
95
-     * @param string $oauthToken
96
-     * @param string $oauthVerifier
97
-     *
98
-     * @throws ApplicationLogicException
99
-     */
100
-    private function doCallbackValidation($oauthToken, $oauthVerifier)
101
-    {
102
-        if ($oauthToken === null) {
103
-            throw new ApplicationLogicException('No token provided');
104
-        }
94
+	/**
95
+	 * @param string $oauthToken
96
+	 * @param string $oauthVerifier
97
+	 *
98
+	 * @throws ApplicationLogicException
99
+	 */
100
+	private function doCallbackValidation($oauthToken, $oauthVerifier)
101
+	{
102
+		if ($oauthToken === null) {
103
+			throw new ApplicationLogicException('No token provided');
104
+		}
105 105
 
106
-        if ($oauthVerifier === null) {
107
-            throw new ApplicationLogicException('No oauth verifier provided.');
108
-        }
109
-    }
106
+		if ($oauthVerifier === null) {
107
+			throw new ApplicationLogicException('No oauth verifier provided.');
108
+		}
109
+	}
110 110
 }
111 111
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageChangePassword.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -52,8 +52,7 @@
 block discarded – undo
52 52
             SessionAlert::success('Password changed successfully!');
53 53
 
54 54
             $this->redirect('preferences');
55
-        }
56
-        else {
55
+        } else {
57 56
             $this->assignCSRFToken();
58 57
             $this->setTemplate('preferences/changePassword.tpl');
59 58
             $this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
Please login to merge, or discard this patch.
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -17,71 +17,71 @@
 block discarded – undo
17 17
 
18 18
 class PageChangePassword extends InternalPageBase
19 19
 {
20
-    /**
21
-     * Main function for this page, when no specific actions are called.
22
-     * @return void
23
-     */
24
-    protected function main()
25
-    {
26
-        $this->setHtmlTitle('Change Password');
20
+	/**
21
+	 * Main function for this page, when no specific actions are called.
22
+	 * @return void
23
+	 */
24
+	protected function main()
25
+	{
26
+		$this->setHtmlTitle('Change Password');
27 27
 
28
-        if (WebRequest::wasPosted()) {
29
-            $this->validateCSRFToken();
30
-            try {
31
-                $oldPassword = WebRequest::postString('password');
32
-                $newPassword = WebRequest::postString('newpassword');
33
-                $newPasswordConfirmation = WebRequest::postString('newpasswordconfirm');
28
+		if (WebRequest::wasPosted()) {
29
+			$this->validateCSRFToken();
30
+			try {
31
+				$oldPassword = WebRequest::postString('password');
32
+				$newPassword = WebRequest::postString('newpassword');
33
+				$newPasswordConfirmation = WebRequest::postString('newpasswordconfirm');
34 34
 
35
-                $user = User::getCurrent($this->getDatabase());
36
-                if (!$user instanceof User) {
37
-                    throw new ApplicationLogicException('User not found');
38
-                }
35
+				$user = User::getCurrent($this->getDatabase());
36
+				if (!$user instanceof User) {
37
+					throw new ApplicationLogicException('User not found');
38
+				}
39 39
 
40
-                $this->validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, $user);
40
+				$this->validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, $user);
41 41
 
42
-                $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
43
-                $passwordProvider->setCredential($user, 1, $newPassword);
44
-            }
45
-            catch (ApplicationLogicException $ex) {
46
-                SessionAlert::error($ex->getMessage());
47
-                $this->redirect('changePassword');
42
+				$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
43
+				$passwordProvider->setCredential($user, 1, $newPassword);
44
+			}
45
+			catch (ApplicationLogicException $ex) {
46
+				SessionAlert::error($ex->getMessage());
47
+				$this->redirect('changePassword');
48 48
 
49
-                return;
50
-            }
49
+				return;
50
+			}
51 51
 
52
-            SessionAlert::success('Password changed successfully!');
52
+			SessionAlert::success('Password changed successfully!');
53 53
 
54
-            $this->redirect('preferences');
55
-        }
56
-        else {
57
-            $this->assignCSRFToken();
58
-            $this->setTemplate('preferences/changePassword.tpl');
59
-            $this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
60
-        }
61
-    }
54
+			$this->redirect('preferences');
55
+		}
56
+		else {
57
+			$this->assignCSRFToken();
58
+			$this->setTemplate('preferences/changePassword.tpl');
59
+			$this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
60
+		}
61
+	}
62 62
 
63
-    /**
64
-     * @param string $oldPassword
65
-     * @param string $newPassword
66
-     * @param string $newPasswordConfirmation
67
-     * @param User   $user
68
-     *
69
-     * @throws ApplicationLogicException
70
-     */
71
-    protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
72
-    {
73
-        if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
74
-            throw new ApplicationLogicException('All three fields must be completed to change your password');
75
-        }
63
+	/**
64
+	 * @param string $oldPassword
65
+	 * @param string $newPassword
66
+	 * @param string $newPasswordConfirmation
67
+	 * @param User   $user
68
+	 *
69
+	 * @throws ApplicationLogicException
70
+	 */
71
+	protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
72
+	{
73
+		if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
74
+			throw new ApplicationLogicException('All three fields must be completed to change your password');
75
+		}
76 76
 
77
-        if ($newPassword !== $newPasswordConfirmation) {
78
-            throw new ApplicationLogicException('Your new passwords did not match!');
79
-        }
77
+		if ($newPassword !== $newPasswordConfirmation) {
78
+			throw new ApplicationLogicException('Your new passwords did not match!');
79
+		}
80 80
 
81
-        // TODO: adapt for MFA support
82
-        $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
83
-        if (!$passwordProvider->authenticate($user, $oldPassword)) {
84
-            throw new ApplicationLogicException('The password you entered was incorrect.');
85
-        }
86
-    }
81
+		// TODO: adapt for MFA support
82
+		$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
83
+		if (!$passwordProvider->authenticate($user, $oldPassword)) {
84
+			throw new ApplicationLogicException('The password you entered was incorrect.');
85
+		}
86
+	}
87 87
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageForgotPassword.php 2 patches
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -46,8 +46,7 @@  discard block
 block discarded – undo
46 46
             SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47 47
 
48 48
             $this->redirect('login');
49
-        }
50
-        else {
49
+        } else {
51 50
             $this->assignCSRFToken();
52 51
             $this->setTemplate('forgot-password/forgotpw.tpl');
53 52
         }
@@ -130,8 +129,7 @@  discard block
 block discarded – undo
130 129
 
131 130
                 return;
132 131
             }
133
-        }
134
-        else {
132
+        } else {
135 133
             $this->assignCSRFToken();
136 134
             $this->assign('user', $user);
137 135
             $this->setTemplate('forgot-password/forgotpwreset.tpl');
Please login to merge, or discard this patch.
Indentation   +209 added lines, -209 removed lines patch added patch discarded remove patch
@@ -23,213 +23,213 @@
 block discarded – undo
23 23
 
24 24
 class PageForgotPassword extends InternalPageBase
25 25
 {
26
-    /**
27
-     * Main function for this page, when no specific actions are called.
28
-     *
29
-     * This is the forgotten password reset form
30
-     * @category Security-Critical
31
-     */
32
-    protected function main()
33
-    {
34
-        if (WebRequest::wasPosted()) {
35
-            $this->validateCSRFToken();
36
-            $username = WebRequest::postString('username');
37
-            $email = WebRequest::postEmail('email');
38
-            $database = $this->getDatabase();
39
-
40
-            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
41
-                throw new ApplicationLogicException("Both username and email address must be specified!");
42
-            }
43
-
44
-            $user = User::getByUsername($username, $database);
45
-            $this->sendResetMail($user, $email);
46
-
47
-            SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
48
-
49
-            $this->redirect('login');
50
-        }
51
-        else {
52
-            $this->assignCSRFToken();
53
-            $this->setTemplate('forgot-password/forgotpw.tpl');
54
-        }
55
-    }
56
-
57
-    /**
58
-     * Sends a reset email if the user is authenticated
59
-     *
60
-     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
61
-     *                            check anyway within this method and silently skip if we don't have a user.
62
-     * @param string       $email The provided email address
63
-     */
64
-    private function sendResetMail($user, $email)
65
-    {
66
-        // If the user isn't found, or the email address is wrong, skip sending the details silently.
67
-        if (!$user instanceof User) {
68
-            return;
69
-        }
70
-
71
-        if (strtolower($user->getEmail()) === strtolower($email)) {
72
-            $clientIp = $this->getXffTrustProvider()
73
-                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
74
-
75
-            $this->cleanExistingTokens($user);
76
-
77
-            $hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
78
-
79
-            $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
80
-
81
-            $cred = new Credential();
82
-            $cred->setDatabase($this->getDatabase());
83
-            $cred->setFactor(-1);
84
-            $cred->setUserId($user->getId());
85
-            $cred->setType('reset');
86
-            $cred->setData($encryptionHelper->encryptData($hash));
87
-            $cred->setVersion(0);
88
-            $cred->setDisabled(0);
89
-            $cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
90
-            $cred->setPriority(9);
91
-            $cred->save();
92
-
93
-            $this->assign("user", $user);
94
-            $this->assign("hash", $hash);
95
-            $this->assign("remoteAddress", $clientIp);
96
-
97
-            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
98
-
99
-            // FIXME: domains!
100
-            /** @var Domain $domain */
101
-            $domain = Domain::getById(1, $this->getDatabase());
102
-            $this->getEmailHelper()->sendMail(
103
-                null, $user->getEmail(), "WP:ACC password reset", $emailContent);
104
-        }
105
-    }
106
-
107
-    /**
108
-     * Entry point for the reset action
109
-     *
110
-     * This is the reset password part of the form.
111
-     * @category Security-Critical
112
-     */
113
-    protected function reset()
114
-    {
115
-        $si = WebRequest::getString('si');
116
-        $id = WebRequest::getString('id');
117
-
118
-        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
119
-            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
120
-        }
121
-
122
-        $database = $this->getDatabase();
123
-        $user = $this->getResettingUser($id, $database, $si);
124
-
125
-        // Dual mode
126
-        if (WebRequest::wasPosted()) {
127
-            $this->validateCSRFToken();
128
-            try {
129
-                $this->doReset($user);
130
-                $this->cleanExistingTokens($user);
131
-            }
132
-            catch (ApplicationLogicException $ex) {
133
-                SessionAlert::error($ex->getMessage());
134
-                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
135
-
136
-                return;
137
-            }
138
-        }
139
-        else {
140
-            $this->assignCSRFToken();
141
-            $this->assign('user', $user);
142
-            $this->setTemplate('forgot-password/forgotpwreset.tpl');
143
-            $this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
144
-        }
145
-    }
146
-
147
-    /**
148
-     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
149
-     *
150
-     * @param integer     $id       The ID of the user to retrieve
151
-     * @param PdoDatabase $database The database object to use
152
-     * @param string      $si       The reset hash provided
153
-     *
154
-     * @return User
155
-     * @throws ApplicationLogicException
156
-     */
157
-    private function getResettingUser($id, $database, $si)
158
-    {
159
-        $user = User::getById($id, $database);
160
-
161
-        if ($user === false || $user->isCommunityUser()) {
162
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
163
-        }
164
-
165
-        $statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
166
-        $statement->execute([':user' => $user->getId()]);
167
-
168
-        /** @var Credential $credential */
169
-        $credential = $statement->fetchObject(Credential::class);
170
-
171
-        $statement->closeCursor();
172
-
173
-        if ($credential === false) {
174
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
175
-        }
176
-
177
-        $credential->setDatabase($database);
178
-
179
-        $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
180
-        if ($encryptionHelper->decryptData($credential->getData()) != $si) {
181
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
182
-        }
183
-
184
-        if ($credential->getTimeout() < new DateTimeImmutable()) {
185
-            $credential->delete();
186
-            throw new ApplicationLogicException("Password reset token expired. Please try again.");
187
-        }
188
-
189
-        return $user;
190
-    }
191
-
192
-    /**
193
-     * Performs the setting of the new password
194
-     *
195
-     * @param User $user The user to set the password for
196
-     *
197
-     * @throws ApplicationLogicException
198
-     */
199
-    private function doReset(User $user)
200
-    {
201
-        $pw = WebRequest::postString('newpassword');
202
-        $pw2 = WebRequest::postString('newpasswordconfirm');
203
-
204
-        if ($pw !== $pw2) {
205
-            throw new ApplicationLogicException('Passwords do not match!');
206
-        }
207
-
208
-        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
209
-        $passwordCredentialProvider->setCredential($user, 1, $pw);
210
-
211
-        SessionAlert::success('You may now log in!');
212
-        $this->redirect('login');
213
-    }
214
-
215
-    protected function isProtectedPage()
216
-    {
217
-        return false;
218
-    }
219
-
220
-    /**
221
-     * @param $user
222
-     */
223
-    private function cleanExistingTokens($user): void
224
-    {
225
-        // clean out existing reset tokens
226
-        $statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
227
-        $statement->execute([':user' => $user->getId()]);
228
-        $existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
229
-
230
-        foreach ($existing as $c) {
231
-            $c->setDatabase($this->getDatabase());
232
-            $c->delete();
233
-        }
234
-    }
26
+	/**
27
+	 * Main function for this page, when no specific actions are called.
28
+	 *
29
+	 * This is the forgotten password reset form
30
+	 * @category Security-Critical
31
+	 */
32
+	protected function main()
33
+	{
34
+		if (WebRequest::wasPosted()) {
35
+			$this->validateCSRFToken();
36
+			$username = WebRequest::postString('username');
37
+			$email = WebRequest::postEmail('email');
38
+			$database = $this->getDatabase();
39
+
40
+			if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
41
+				throw new ApplicationLogicException("Both username and email address must be specified!");
42
+			}
43
+
44
+			$user = User::getByUsername($username, $database);
45
+			$this->sendResetMail($user, $email);
46
+
47
+			SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
48
+
49
+			$this->redirect('login');
50
+		}
51
+		else {
52
+			$this->assignCSRFToken();
53
+			$this->setTemplate('forgot-password/forgotpw.tpl');
54
+		}
55
+	}
56
+
57
+	/**
58
+	 * Sends a reset email if the user is authenticated
59
+	 *
60
+	 * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
61
+	 *                            check anyway within this method and silently skip if we don't have a user.
62
+	 * @param string       $email The provided email address
63
+	 */
64
+	private function sendResetMail($user, $email)
65
+	{
66
+		// If the user isn't found, or the email address is wrong, skip sending the details silently.
67
+		if (!$user instanceof User) {
68
+			return;
69
+		}
70
+
71
+		if (strtolower($user->getEmail()) === strtolower($email)) {
72
+			$clientIp = $this->getXffTrustProvider()
73
+				->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
74
+
75
+			$this->cleanExistingTokens($user);
76
+
77
+			$hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
78
+
79
+			$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
80
+
81
+			$cred = new Credential();
82
+			$cred->setDatabase($this->getDatabase());
83
+			$cred->setFactor(-1);
84
+			$cred->setUserId($user->getId());
85
+			$cred->setType('reset');
86
+			$cred->setData($encryptionHelper->encryptData($hash));
87
+			$cred->setVersion(0);
88
+			$cred->setDisabled(0);
89
+			$cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
90
+			$cred->setPriority(9);
91
+			$cred->save();
92
+
93
+			$this->assign("user", $user);
94
+			$this->assign("hash", $hash);
95
+			$this->assign("remoteAddress", $clientIp);
96
+
97
+			$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
98
+
99
+			// FIXME: domains!
100
+			/** @var Domain $domain */
101
+			$domain = Domain::getById(1, $this->getDatabase());
102
+			$this->getEmailHelper()->sendMail(
103
+				null, $user->getEmail(), "WP:ACC password reset", $emailContent);
104
+		}
105
+	}
106
+
107
+	/**
108
+	 * Entry point for the reset action
109
+	 *
110
+	 * This is the reset password part of the form.
111
+	 * @category Security-Critical
112
+	 */
113
+	protected function reset()
114
+	{
115
+		$si = WebRequest::getString('si');
116
+		$id = WebRequest::getString('id');
117
+
118
+		if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
119
+			throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
120
+		}
121
+
122
+		$database = $this->getDatabase();
123
+		$user = $this->getResettingUser($id, $database, $si);
124
+
125
+		// Dual mode
126
+		if (WebRequest::wasPosted()) {
127
+			$this->validateCSRFToken();
128
+			try {
129
+				$this->doReset($user);
130
+				$this->cleanExistingTokens($user);
131
+			}
132
+			catch (ApplicationLogicException $ex) {
133
+				SessionAlert::error($ex->getMessage());
134
+				$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
135
+
136
+				return;
137
+			}
138
+		}
139
+		else {
140
+			$this->assignCSRFToken();
141
+			$this->assign('user', $user);
142
+			$this->setTemplate('forgot-password/forgotpwreset.tpl');
143
+			$this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
144
+		}
145
+	}
146
+
147
+	/**
148
+	 * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
149
+	 *
150
+	 * @param integer     $id       The ID of the user to retrieve
151
+	 * @param PdoDatabase $database The database object to use
152
+	 * @param string      $si       The reset hash provided
153
+	 *
154
+	 * @return User
155
+	 * @throws ApplicationLogicException
156
+	 */
157
+	private function getResettingUser($id, $database, $si)
158
+	{
159
+		$user = User::getById($id, $database);
160
+
161
+		if ($user === false || $user->isCommunityUser()) {
162
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
163
+		}
164
+
165
+		$statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
166
+		$statement->execute([':user' => $user->getId()]);
167
+
168
+		/** @var Credential $credential */
169
+		$credential = $statement->fetchObject(Credential::class);
170
+
171
+		$statement->closeCursor();
172
+
173
+		if ($credential === false) {
174
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
175
+		}
176
+
177
+		$credential->setDatabase($database);
178
+
179
+		$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
180
+		if ($encryptionHelper->decryptData($credential->getData()) != $si) {
181
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
182
+		}
183
+
184
+		if ($credential->getTimeout() < new DateTimeImmutable()) {
185
+			$credential->delete();
186
+			throw new ApplicationLogicException("Password reset token expired. Please try again.");
187
+		}
188
+
189
+		return $user;
190
+	}
191
+
192
+	/**
193
+	 * Performs the setting of the new password
194
+	 *
195
+	 * @param User $user The user to set the password for
196
+	 *
197
+	 * @throws ApplicationLogicException
198
+	 */
199
+	private function doReset(User $user)
200
+	{
201
+		$pw = WebRequest::postString('newpassword');
202
+		$pw2 = WebRequest::postString('newpasswordconfirm');
203
+
204
+		if ($pw !== $pw2) {
205
+			throw new ApplicationLogicException('Passwords do not match!');
206
+		}
207
+
208
+		$passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
209
+		$passwordCredentialProvider->setCredential($user, 1, $pw);
210
+
211
+		SessionAlert::success('You may now log in!');
212
+		$this->redirect('login');
213
+	}
214
+
215
+	protected function isProtectedPage()
216
+	{
217
+		return false;
218
+	}
219
+
220
+	/**
221
+	 * @param $user
222
+	 */
223
+	private function cleanExistingTokens($user): void
224
+	{
225
+		// clean out existing reset tokens
226
+		$statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
227
+		$statement->execute([':user' => $user->getId()]);
228
+		$existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
229
+
230
+		foreach ($existing as $c) {
231
+			$c->setDatabase($this->getDatabase());
232
+			$c->delete();
233
+		}
234
+	}
235 235
 }
Please login to merge, or discard this patch.
includes/Pages/PageJobQueue.php 2 patches
Braces   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -116,7 +116,8 @@  discard block
 block discarded – undo
116 116
             $job->setDatabase($database);
117 117
         }
118 118
 
119
-        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
119
+        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database)
120
+        {
120 121
             return UserSearchHelper::get($database)->fetchColumn('username');
121 122
         });
122 123
 
@@ -158,8 +159,7 @@  discard block
 block discarded – undo
158 159
             ->byObjectId($job->getId())->getRecordCount($logCount)->fetch();
159 160
         if ($logCount === 0) {
160 161
             $this->assign('log', array());
161
-        }
162
-        else {
162
+        } else {
163 163
             list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
164 164
 
165 165
             $this->assign("log", $logData);
Please login to merge, or discard this patch.
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -28,309 +28,309 @@
 block discarded – undo
28 28
 
29 29
 class PageJobQueue extends PagedInternalPageBase
30 30
 {
31
-    /**
32
-     * Main function for this page, when no specific actions are called.
33
-     * @return void
34
-     */
35
-    protected function main()
36
-    {
37
-        $this->setHtmlTitle('Job Queue Management');
38
-
39
-        $this->prepareMaps();
40
-
41
-        $database = $this->getDatabase();
42
-
43
-        /** @var JobQueue[] $jobList */
44
-        // FIXME: domains
45
-        $jobList = JobQueueSearchHelper::get($database, 1)
46
-            ->statusIn([
47
-                JobQueue::STATUS_QUEUED,
48
-                JobQueue::STATUS_READY,
49
-                JobQueue::STATUS_WAITING,
50
-                JobQueue::STATUS_RUNNING,
51
-                JobQueue::STATUS_FAILED,
52
-            ])
53
-            ->notAcknowledged()
54
-            ->fetch();
55
-
56
-        $userIds = array();
57
-        $requestIds = array();
58
-
59
-        foreach ($jobList as $job) {
60
-            $userIds[] = $job->getTriggerUserId();
61
-            $requestIds[] = $job->getRequest();
62
-
63
-            $job->setDatabase($database);
64
-        }
65
-
66
-        $this->assign('canSeeAll', $this->barrierTest('all', User::getCurrent($database)));
67
-
68
-        $this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
69
-        // FIXME: domains
70
-        $this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
71
-
72
-        $this->assign('joblist', $jobList);
73
-        $this->setTemplate('jobqueue/main.tpl');
74
-    }
75
-
76
-    protected function all()
77
-    {
78
-        $this->setHtmlTitle('All Jobs');
79
-
80
-        $this->prepareMaps();
81
-
82
-        $database = $this->getDatabase();
83
-
84
-        // FIXME: domains
85
-        $searchHelper = JobQueueSearchHelper::get($database, 1);
86
-        $this->setSearchHelper($searchHelper);
87
-        $this->setupLimits();
88
-
89
-        $filterUser = WebRequest::getString('filterUser');
90
-        $filterTask = WebRequest::getString('filterTask');
91
-        $filterStatus = WebRequest::getString('filterStatus');
92
-        $filterRequest = WebRequest::getString('filterRequest');
93
-        $order = WebRequest::getString('order');
94
-
95
-        if ($filterUser !== null) {
96
-            $searchHelper->byUser(User::getByUsername($filterUser, $database)->getId());
97
-        }
98
-
99
-        if ($filterTask !== null) {
100
-            $searchHelper->byTask($filterTask);
101
-        }
102
-
103
-        if ($filterStatus !== null) {
104
-            $searchHelper->byStatus($filterStatus);
105
-        }
106
-
107
-        if ($filterRequest !== null) {
108
-            $searchHelper->byRequest($filterRequest);
109
-        }
31
+	/**
32
+	 * Main function for this page, when no specific actions are called.
33
+	 * @return void
34
+	 */
35
+	protected function main()
36
+	{
37
+		$this->setHtmlTitle('Job Queue Management');
38
+
39
+		$this->prepareMaps();
40
+
41
+		$database = $this->getDatabase();
42
+
43
+		/** @var JobQueue[] $jobList */
44
+		// FIXME: domains
45
+		$jobList = JobQueueSearchHelper::get($database, 1)
46
+			->statusIn([
47
+				JobQueue::STATUS_QUEUED,
48
+				JobQueue::STATUS_READY,
49
+				JobQueue::STATUS_WAITING,
50
+				JobQueue::STATUS_RUNNING,
51
+				JobQueue::STATUS_FAILED,
52
+			])
53
+			->notAcknowledged()
54
+			->fetch();
55
+
56
+		$userIds = array();
57
+		$requestIds = array();
58
+
59
+		foreach ($jobList as $job) {
60
+			$userIds[] = $job->getTriggerUserId();
61
+			$requestIds[] = $job->getRequest();
62
+
63
+			$job->setDatabase($database);
64
+		}
65
+
66
+		$this->assign('canSeeAll', $this->barrierTest('all', User::getCurrent($database)));
67
+
68
+		$this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
69
+		// FIXME: domains
70
+		$this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
71
+
72
+		$this->assign('joblist', $jobList);
73
+		$this->setTemplate('jobqueue/main.tpl');
74
+	}
75
+
76
+	protected function all()
77
+	{
78
+		$this->setHtmlTitle('All Jobs');
79
+
80
+		$this->prepareMaps();
81
+
82
+		$database = $this->getDatabase();
83
+
84
+		// FIXME: domains
85
+		$searchHelper = JobQueueSearchHelper::get($database, 1);
86
+		$this->setSearchHelper($searchHelper);
87
+		$this->setupLimits();
88
+
89
+		$filterUser = WebRequest::getString('filterUser');
90
+		$filterTask = WebRequest::getString('filterTask');
91
+		$filterStatus = WebRequest::getString('filterStatus');
92
+		$filterRequest = WebRequest::getString('filterRequest');
93
+		$order = WebRequest::getString('order');
94
+
95
+		if ($filterUser !== null) {
96
+			$searchHelper->byUser(User::getByUsername($filterUser, $database)->getId());
97
+		}
98
+
99
+		if ($filterTask !== null) {
100
+			$searchHelper->byTask($filterTask);
101
+		}
102
+
103
+		if ($filterStatus !== null) {
104
+			$searchHelper->byStatus($filterStatus);
105
+		}
106
+
107
+		if ($filterRequest !== null) {
108
+			$searchHelper->byRequest($filterRequest);
109
+		}
110 110
         
111
-        if ($order === null) {
112
-            $searchHelper->newestFirst();
113
-        }
114
-
115
-        /** @var JobQueue[] $jobList */
116
-        $jobList = $searchHelper->getRecordCount($count)->fetch();
111
+		if ($order === null) {
112
+			$searchHelper->newestFirst();
113
+		}
114
+
115
+		/** @var JobQueue[] $jobList */
116
+		$jobList = $searchHelper->getRecordCount($count)->fetch();
117 117
 
118
-        $this->setupPageData($count, array(
119
-            'filterUser' => $filterUser,
120
-            'filterTask' => $filterTask,
121
-            'filterStatus' => $filterStatus,
122
-            'filterRequest' => $filterRequest,
123
-            'order' => $order,
124
-        ));
118
+		$this->setupPageData($count, array(
119
+			'filterUser' => $filterUser,
120
+			'filterTask' => $filterTask,
121
+			'filterStatus' => $filterStatus,
122
+			'filterRequest' => $filterRequest,
123
+			'order' => $order,
124
+		));
125 125
 
126
-        $userIds = array();
127
-        $requestIds = array();
126
+		$userIds = array();
127
+		$requestIds = array();
128 128
 
129
-        foreach ($jobList as $job) {
130
-            $userIds[] = $job->getTriggerUserId();
131
-            $requestIds[] = $job->getRequest();
129
+		foreach ($jobList as $job) {
130
+			$userIds[] = $job->getTriggerUserId();
131
+			$requestIds[] = $job->getRequest();
132 132
 
133
-            $job->setDatabase($database);
134
-        }
133
+			$job->setDatabase($database);
134
+		}
135 135
 
136
-        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
137
-            return UserSearchHelper::get($database)->fetchColumn('username');
138
-        });
136
+		$this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
137
+			return UserSearchHelper::get($database)->fetchColumn('username');
138
+		});
139 139
 
140
-        $this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
141
-        // FIXME: domains!
142
-        $this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
140
+		$this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
141
+		// FIXME: domains!
142
+		$this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
143 143
 
144
-        $this->assign('joblist', $jobList);
144
+		$this->assign('joblist', $jobList);
145 145
 
146
-        $this->addJs("/api.php?action=users&all=true&targetVariable=typeaheaddata");
146
+		$this->addJs("/api.php?action=users&all=true&targetVariable=typeaheaddata");
147 147
 
148
-        $this->setTemplate('jobqueue/all.tpl');
149
-    }
148
+		$this->setTemplate('jobqueue/all.tpl');
149
+	}
150 150
 
151
-    protected function view()
152
-    {
153
-        $jobId = WebRequest::getInt('id');
154
-        $database = $this->getDatabase();
151
+	protected function view()
152
+	{
153
+		$jobId = WebRequest::getInt('id');
154
+		$database = $this->getDatabase();
155 155
 
156
-        if ($jobId === null) {
157
-            throw new ApplicationLogicException('No job specified');
158
-        }
156
+		if ($jobId === null) {
157
+			throw new ApplicationLogicException('No job specified');
158
+		}
159 159
 
160
-        /** @var JobQueue $job */
161
-        $job = JobQueue::getById($jobId, $database);
160
+		/** @var JobQueue $job */
161
+		$job = JobQueue::getById($jobId, $database);
162 162
 
163
-        if ($job === false) {
164
-            throw new ApplicationLogicException('Could not find requested job');
165
-        }
163
+		if ($job === false) {
164
+			throw new ApplicationLogicException('Could not find requested job');
165
+		}
166 166
 
167
-        $this->prepareMaps();
167
+		$this->prepareMaps();
168 168
 
169
-        $this->assign('user', User::getById($job->getTriggerUserId(), $database));
170
-        $this->assign('request', Request::getById($job->getRequest(), $database));
171
-        $this->assign('emailTemplate', EmailTemplate::getById($job->getEmailTemplate(), $database));
172
-        $this->assign('parent', JobQueue::getById($job->getParent(), $database));
169
+		$this->assign('user', User::getById($job->getTriggerUserId(), $database));
170
+		$this->assign('request', Request::getById($job->getRequest(), $database));
171
+		$this->assign('emailTemplate', EmailTemplate::getById($job->getEmailTemplate(), $database));
172
+		$this->assign('parent', JobQueue::getById($job->getParent(), $database));
173 173
 
174
-        /** @var Log[] $logs */
175
-        // FIXME: domains
176
-        $logs = LogSearchHelper::get($database, 1)->byObjectType('JobQueue')
177
-            ->byObjectId($job->getId())->getRecordCount($logCount)->fetch();
178
-        if ($logCount === 0) {
179
-            $this->assign('log', array());
180
-        }
181
-        else {
182
-            list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
174
+		/** @var Log[] $logs */
175
+		// FIXME: domains
176
+		$logs = LogSearchHelper::get($database, 1)->byObjectType('JobQueue')
177
+			->byObjectId($job->getId())->getRecordCount($logCount)->fetch();
178
+		if ($logCount === 0) {
179
+			$this->assign('log', array());
180
+		}
181
+		else {
182
+			list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
183 183
 
184
-            $this->assign("log", $logData);
185
-            $this->assign("users", $users);
186
-        }
184
+			$this->assign("log", $logData);
185
+			$this->assign("users", $users);
186
+		}
187 187
 
188
-        $this->assignCSRFToken();
188
+		$this->assignCSRFToken();
189 189
 
190
-        $this->assign('job', $job);
190
+		$this->assign('job', $job);
191 191
 
192
-        $this->assign('canAcknowledge', $this->barrierTest('acknowledge', User::getCurrent($database)));
193
-        $this->assign('canRequeue', $this->barrierTest('requeue', User::getCurrent($database)));
194
-        $this->assign('canCancel', $this->barrierTest('cancel', User::getCurrent($database)));
192
+		$this->assign('canAcknowledge', $this->barrierTest('acknowledge', User::getCurrent($database)));
193
+		$this->assign('canRequeue', $this->barrierTest('requeue', User::getCurrent($database)));
194
+		$this->assign('canCancel', $this->barrierTest('cancel', User::getCurrent($database)));
195 195
 
196
-        if ($job->getTask() === UserCreationTask::class || $job->getTask() === BotCreationTask::class) {
197
-            if ($job->getEmailTemplate() === null) {
198
-                $params = json_decode($job->getParameters());
196
+		if ($job->getTask() === UserCreationTask::class || $job->getTask() === BotCreationTask::class) {
197
+			if ($job->getEmailTemplate() === null) {
198
+				$params = json_decode($job->getParameters());
199 199
 
200
-                if (isset($params->emailText)) {
201
-                    $this->assign("creationEmailText", $params->emailText);
202
-                }
203
-            }
204
-        }
200
+				if (isset($params->emailText)) {
201
+					$this->assign("creationEmailText", $params->emailText);
202
+				}
203
+			}
204
+		}
205 205
 
206
-        $this->setHtmlTitle('Job #{$job->getId()|escape}');
207
-        $this->setTemplate('jobqueue/view.tpl');
208
-    }
206
+		$this->setHtmlTitle('Job #{$job->getId()|escape}');
207
+		$this->setTemplate('jobqueue/view.tpl');
208
+	}
209 209
 
210
-    protected function acknowledge()
211
-    {
212
-        if (!WebRequest::wasPosted()) {
213
-            throw new ApplicationLogicException('This page does not support GET methods.');
214
-        }
210
+	protected function acknowledge()
211
+	{
212
+		if (!WebRequest::wasPosted()) {
213
+			throw new ApplicationLogicException('This page does not support GET methods.');
214
+		}
215 215
 
216
-        $this->validateCSRFToken();
216
+		$this->validateCSRFToken();
217 217
 
218
-        $jobId = WebRequest::postInt('job');
219
-        $database = $this->getDatabase();
218
+		$jobId = WebRequest::postInt('job');
219
+		$database = $this->getDatabase();
220 220
 
221
-        if ($jobId === null) {
222
-            throw new ApplicationLogicException('No job specified');
223
-        }
221
+		if ($jobId === null) {
222
+			throw new ApplicationLogicException('No job specified');
223
+		}
224 224
 
225
-        /** @var JobQueue $job */
226
-        $job = JobQueue::getById($jobId, $database);
225
+		/** @var JobQueue $job */
226
+		$job = JobQueue::getById($jobId, $database);
227 227
 
228
-        if ($job === false) {
229
-            throw new ApplicationLogicException('Could not find requested job');
230
-        }
228
+		if ($job === false) {
229
+			throw new ApplicationLogicException('Could not find requested job');
230
+		}
231 231
 
232
-        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
233
-        $job->setAcknowledged(true);
234
-        $job->save();
232
+		$job->setUpdateVersion(WebRequest::postInt('updateVersion'));
233
+		$job->setAcknowledged(true);
234
+		$job->save();
235 235
 
236
-        Logger::backgroundJobAcknowledged($database, $job);
236
+		Logger::backgroundJobAcknowledged($database, $job);
237 237
 
238
-        $this->redirect('jobQueue', 'view', array('id' => $jobId));
239
-    }
240
-
241
-    protected function cancel()
242
-    {
243
-        if (!WebRequest::wasPosted()) {
244
-            throw new ApplicationLogicException('This page does not support GET methods.');
245
-        }
246
-
247
-        $this->validateCSRFToken();
248
-
249
-        $jobId = WebRequest::postInt('job');
250
-        $database = $this->getDatabase();
251
-
252
-        if ($jobId === null) {
253
-            throw new ApplicationLogicException('No job specified');
254
-        }
255
-
256
-        /** @var JobQueue $job */
257
-        $job = JobQueue::getById($jobId, $database);
258
-
259
-        if ($job === false) {
260
-            throw new ApplicationLogicException('Could not find requested job');
261
-        }
262
-
263
-        if ($job->getStatus() !== JobQueue::STATUS_READY
264
-            && $job->getStatus() !== JobQueue::STATUS_QUEUED
265
-            && $job->getStatus() === JobQueue::STATUS_WAITING) {
266
-            throw new ApplicationLogicException('Cannot cancel job not queued for execution');
267
-        }
268
-
269
-        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
270
-        $job->setStatus(JobQueue::STATUS_CANCELLED);
271
-        $job->setError("Manually cancelled");
272
-        $job->setAcknowledged(null);
273
-        $job->save();
274
-
275
-        Logger::backgroundJobCancelled($this->getDatabase(), $job);
276
-
277
-        $this->redirect('jobQueue', 'view', array('id' => $jobId));
278
-    }
279
-
280
-    protected function requeue()
281
-    {
282
-        if (!WebRequest::wasPosted()) {
283
-            throw new ApplicationLogicException('This page does not support GET methods.');
284
-        }
238
+		$this->redirect('jobQueue', 'view', array('id' => $jobId));
239
+	}
240
+
241
+	protected function cancel()
242
+	{
243
+		if (!WebRequest::wasPosted()) {
244
+			throw new ApplicationLogicException('This page does not support GET methods.');
245
+		}
246
+
247
+		$this->validateCSRFToken();
248
+
249
+		$jobId = WebRequest::postInt('job');
250
+		$database = $this->getDatabase();
251
+
252
+		if ($jobId === null) {
253
+			throw new ApplicationLogicException('No job specified');
254
+		}
255
+
256
+		/** @var JobQueue $job */
257
+		$job = JobQueue::getById($jobId, $database);
258
+
259
+		if ($job === false) {
260
+			throw new ApplicationLogicException('Could not find requested job');
261
+		}
262
+
263
+		if ($job->getStatus() !== JobQueue::STATUS_READY
264
+			&& $job->getStatus() !== JobQueue::STATUS_QUEUED
265
+			&& $job->getStatus() === JobQueue::STATUS_WAITING) {
266
+			throw new ApplicationLogicException('Cannot cancel job not queued for execution');
267
+		}
268
+
269
+		$job->setUpdateVersion(WebRequest::postInt('updateVersion'));
270
+		$job->setStatus(JobQueue::STATUS_CANCELLED);
271
+		$job->setError("Manually cancelled");
272
+		$job->setAcknowledged(null);
273
+		$job->save();
274
+
275
+		Logger::backgroundJobCancelled($this->getDatabase(), $job);
276
+
277
+		$this->redirect('jobQueue', 'view', array('id' => $jobId));
278
+	}
279
+
280
+	protected function requeue()
281
+	{
282
+		if (!WebRequest::wasPosted()) {
283
+			throw new ApplicationLogicException('This page does not support GET methods.');
284
+		}
285 285
 
286
-        $this->validateCSRFToken();
286
+		$this->validateCSRFToken();
287 287
 
288
-        $jobId = WebRequest::postInt('job');
289
-        $database = $this->getDatabase();
290
-
291
-        if ($jobId === null) {
292
-            throw new ApplicationLogicException('No job specified');
293
-        }
294
-
295
-        /** @var JobQueue|false $job */
296
-        $job = JobQueue::getById($jobId, $database);
297
-
298
-        if ($job === false) {
299
-            throw new ApplicationLogicException('Could not find requested job');
300
-        }
301
-
302
-        $job->setStatus(JobQueue::STATUS_QUEUED);
303
-        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
304
-        $job->setAcknowledged(null);
305
-        $job->setError(null);
306
-        $job->save();
307
-
308
-        /** @var Request $request */
309
-        $request = Request::getById($job->getRequest(), $database);
310
-        $request->setStatus(RequestStatus::JOBQUEUE);
311
-        $request->save();
312
-
313
-        Logger::enqueuedJobQueue($database, $request);
314
-        Logger::backgroundJobRequeued($database, $job);
288
+		$jobId = WebRequest::postInt('job');
289
+		$database = $this->getDatabase();
290
+
291
+		if ($jobId === null) {
292
+			throw new ApplicationLogicException('No job specified');
293
+		}
294
+
295
+		/** @var JobQueue|false $job */
296
+		$job = JobQueue::getById($jobId, $database);
297
+
298
+		if ($job === false) {
299
+			throw new ApplicationLogicException('Could not find requested job');
300
+		}
301
+
302
+		$job->setStatus(JobQueue::STATUS_QUEUED);
303
+		$job->setUpdateVersion(WebRequest::postInt('updateVersion'));
304
+		$job->setAcknowledged(null);
305
+		$job->setError(null);
306
+		$job->save();
307
+
308
+		/** @var Request $request */
309
+		$request = Request::getById($job->getRequest(), $database);
310
+		$request->setStatus(RequestStatus::JOBQUEUE);
311
+		$request->save();
312
+
313
+		Logger::enqueuedJobQueue($database, $request);
314
+		Logger::backgroundJobRequeued($database, $job);
315 315
 
316
-        $this->redirect('jobQueue', 'view', array('id' => $jobId));
317
-    }
318
-
319
-    protected function prepareMaps()
320
-    {
321
-        $taskNameMap = JobQueue::getTaskDescriptions();
322
-
323
-        $statusDecriptionMap = array(
324
-            JobQueue::STATUS_CANCELLED => 'The job was cancelled',
325
-            JobQueue::STATUS_COMPLETE  => 'The job completed successfully',
326
-            JobQueue::STATUS_FAILED    => 'The job encountered an error',
327
-            JobQueue::STATUS_QUEUED    => 'The job is in the queue',
328
-            JobQueue::STATUS_READY     => 'The job is ready to be picked up by the next job runner execution',
329
-            JobQueue::STATUS_RUNNING   => 'The job is being run right now by the job runner',
330
-            JobQueue::STATUS_WAITING   => 'The job has been picked up by a job runner',
331
-            JobQueue::STATUS_HELD      => 'The job has manually held from processing',
332
-        );
333
-        $this->assign('taskNameMap', $taskNameMap);
334
-        $this->assign('statusDescriptionMap', $statusDecriptionMap);
335
-    }
316
+		$this->redirect('jobQueue', 'view', array('id' => $jobId));
317
+	}
318
+
319
+	protected function prepareMaps()
320
+	{
321
+		$taskNameMap = JobQueue::getTaskDescriptions();
322
+
323
+		$statusDecriptionMap = array(
324
+			JobQueue::STATUS_CANCELLED => 'The job was cancelled',
325
+			JobQueue::STATUS_COMPLETE  => 'The job completed successfully',
326
+			JobQueue::STATUS_FAILED    => 'The job encountered an error',
327
+			JobQueue::STATUS_QUEUED    => 'The job is in the queue',
328
+			JobQueue::STATUS_READY     => 'The job is ready to be picked up by the next job runner execution',
329
+			JobQueue::STATUS_RUNNING   => 'The job is being run right now by the job runner',
330
+			JobQueue::STATUS_WAITING   => 'The job has been picked up by a job runner',
331
+			JobQueue::STATUS_HELD      => 'The job has manually held from processing',
332
+		);
333
+		$this->assign('taskNameMap', $taskNameMap);
334
+		$this->assign('statusDescriptionMap', $statusDecriptionMap);
335
+	}
336 336
 }
Please login to merge, or discard this patch.
includes/API/IXmlApiAction.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -16,12 +16,12 @@
 block discarded – undo
16 16
  */
17 17
 interface IXmlApiAction extends IRoutedTask, IApiAction
18 18
 {
19
-    /**
20
-     * Method that runs API action
21
-     *
22
-     * @param DOMElement $apiDocument
23
-     *
24
-     * @return DOMElement The modified API document
25
-     */
26
-    public function executeApiAction(DOMElement $apiDocument);
19
+	/**
20
+	 * Method that runs API action
21
+	 *
22
+	 * @param DOMElement $apiDocument
23
+	 *
24
+	 * @return DOMElement The modified API document
25
+	 */
26
+	public function executeApiAction(DOMElement $apiDocument);
27 27
 }
Please login to merge, or discard this patch.
includes/API/IJsonApiAction.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -15,10 +15,10 @@
 block discarded – undo
15 15
  */
16 16
 interface IJsonApiAction extends IRoutedTask, IApiAction
17 17
 {
18
-    /**
19
-     * Method that runs API action
20
-     *
21
-     * @return object|array The modified API document
22
-     */
23
-    public function executeApiAction();
18
+	/**
19
+	 * Method that runs API action
20
+	 *
21
+	 * @return object|array The modified API document
22
+	 */
23
+	public function executeApiAction();
24 24
 }
Please login to merge, or discard this patch.
includes/API/Actions/UnknownAction.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -16,15 +16,15 @@
 block discarded – undo
16 16
  */
17 17
 class UnknownAction extends HelpAction implements IXmlApiAction
18 18
 {
19
-    public function executeApiAction(DOMElement $apiDocument)
20
-    {
21
-        $errorText = "Unknown API action specified.";
22
-        $errorNode = $this->document->createElement("error", $errorText);
23
-        $apiDocument->appendChild($errorNode);
19
+	public function executeApiAction(DOMElement $apiDocument)
20
+	{
21
+		$errorText = "Unknown API action specified.";
22
+		$errorNode = $this->document->createElement("error", $errorText);
23
+		$apiDocument->appendChild($errorNode);
24 24
 
25
-        $helpElement = $this->getHelpElement();
26
-        $apiDocument->appendChild($helpElement);
25
+		$helpElement = $this->getHelpElement();
26
+		$apiDocument->appendChild($helpElement);
27 27
 
28
-        return $apiDocument;
29
-    }
28
+		return $apiDocument;
29
+	}
30 30
 }
Please login to merge, or discard this patch.