Failed Conditions
Push — newinternal ( b66232...216d62 )
by Simon
16:33 queued 06:35
created
includes/Pages/PageViewRequest.php 3 patches
Indentation   +245 added lines, -245 removed lines patch added patch discarded remove patch
@@ -25,72 +25,72 @@  discard block
 block discarded – undo
25 25
 
26 26
 class PageViewRequest extends InternalPageBase
27 27
 {
28
-    use RequestData;
29
-    const STATUS_SYMBOL_OPEN = '&#x2610';
30
-    const STATUS_SYMBOL_ACCEPTED = '&#x2611';
31
-    const STATUS_SYMBOL_REJECTED = '&#x2612';
32
-
33
-    /**
34
-     * Main function for this page, when no specific actions are called.
35
-     * @throws ApplicationLogicException
36
-     */
37
-    protected function main()
38
-    {
39
-        // set up csrf protection
40
-        $this->assignCSRFToken();
41
-
42
-        // get some useful objects
43
-        $database = $this->getDatabase();
44
-        $request = $this->getRequest($database, WebRequest::getInt('id'));
45
-        $config = $this->getSiteConfiguration();
46
-        $currentUser = User::getCurrent($database);
47
-
48
-        // Test we should be able to look at this request
49
-        if ($config->getEmailConfirmationEnabled()) {
50
-            if ($request->getEmailConfirm() !== 'Confirmed') {
51
-                // Not allowed to look at this yet.
52
-                throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
53
-            }
54
-        }
55
-
56
-        $this->setupBasicData($request, $config);
57
-
58
-        $this->setupUsernameData($request);
59
-
60
-        $this->setupTitle($request);
61
-
62
-        $this->setupReservationDetails($request->getReserved(), $database, $currentUser);
63
-        $this->setupGeneralData($database);
64
-
65
-        $this->assign('requestDataCleared', false);
66
-        if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
67
-            $this->assign('requestDataCleared', true);
68
-        }
69
-
70
-        $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
71
-
72
-        $this->setupCreationTypes($currentUser);
73
-
74
-        $this->setupLogData($request, $database);
75
-
76
-        if ($allowedPrivateData) {
77
-            $this->setTemplate('view-request/main-with-data.tpl');
78
-            $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
79
-
80
-            $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
81
-            $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
82
-
83
-            if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
84
-                $this->setTemplate('view-request/main-with-checkuser-data.tpl');
85
-                $this->setupCheckUserData($request);
86
-            }
87
-        }
88
-        else {
89
-            $this->setTemplate('view-request/main.tpl');
90
-        }
91
-
92
-        /** @noinspection JSUnusedGlobalSymbols */
93
-        $this->setTailScript(<<<'JS'
28
+	use RequestData;
29
+	const STATUS_SYMBOL_OPEN = '&#x2610';
30
+	const STATUS_SYMBOL_ACCEPTED = '&#x2611';
31
+	const STATUS_SYMBOL_REJECTED = '&#x2612';
32
+
33
+	/**
34
+	 * Main function for this page, when no specific actions are called.
35
+	 * @throws ApplicationLogicException
36
+	 */
37
+	protected function main()
38
+	{
39
+		// set up csrf protection
40
+		$this->assignCSRFToken();
41
+
42
+		// get some useful objects
43
+		$database = $this->getDatabase();
44
+		$request = $this->getRequest($database, WebRequest::getInt('id'));
45
+		$config = $this->getSiteConfiguration();
46
+		$currentUser = User::getCurrent($database);
47
+
48
+		// Test we should be able to look at this request
49
+		if ($config->getEmailConfirmationEnabled()) {
50
+			if ($request->getEmailConfirm() !== 'Confirmed') {
51
+				// Not allowed to look at this yet.
52
+				throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
53
+			}
54
+		}
55
+
56
+		$this->setupBasicData($request, $config);
57
+
58
+		$this->setupUsernameData($request);
59
+
60
+		$this->setupTitle($request);
61
+
62
+		$this->setupReservationDetails($request->getReserved(), $database, $currentUser);
63
+		$this->setupGeneralData($database);
64
+
65
+		$this->assign('requestDataCleared', false);
66
+		if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
67
+			$this->assign('requestDataCleared', true);
68
+		}
69
+
70
+		$allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
71
+
72
+		$this->setupCreationTypes($currentUser);
73
+
74
+		$this->setupLogData($request, $database);
75
+
76
+		if ($allowedPrivateData) {
77
+			$this->setTemplate('view-request/main-with-data.tpl');
78
+			$this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
79
+
80
+			$this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
81
+			$this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
82
+
83
+			if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
84
+				$this->setTemplate('view-request/main-with-checkuser-data.tpl');
85
+				$this->setupCheckUserData($request);
86
+			}
87
+		}
88
+		else {
89
+			$this->setTemplate('view-request/main.tpl');
90
+		}
91
+
92
+		/** @noinspection JSUnusedGlobalSymbols */
93
+		$this->setTailScript(<<<'JS'
94 94
     var $requestLogs = $('#requestLog');
95 95
     $requestLogs.scrollTop($requestLogs[0].scrollHeight);
96 96
     
@@ -112,183 +112,183 @@  discard block
 block discarded – undo
112 112
         }
113 113
     }
114 114
 JS
115
-        );
116
-    }
117
-
118
-    /**
119
-     * @param Request $request
120
-     */
121
-    protected function setupTitle(Request $request)
122
-    {
123
-        $statusSymbol = self::STATUS_SYMBOL_OPEN;
124
-        if ($request->getStatus() === 'Closed') {
125
-            if ($request->getWasCreated()) {
126
-                $statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
127
-            }
128
-            else {
129
-                $statusSymbol = self::STATUS_SYMBOL_REJECTED;
130
-            }
131
-        }
132
-
133
-        $this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
134
-    }
135
-
136
-    /**
137
-     * Sets up data unrelated to the request, such as the email template information
138
-     *
139
-     * @param PdoDatabase $database
140
-     */
141
-    protected function setupGeneralData(PdoDatabase $database)
142
-    {
143
-        $config = $this->getSiteConfiguration();
144
-
145
-        $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
146
-
147
-        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
148
-
149
-        $this->assign('requestStates', $config->getRequestStates());
150
-
151
-        /** @var EmailTemplate $createdTemplate */
152
-        $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
153
-
154
-        $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
155
-        $this->assign('createdJsQuestion', $createdTemplate->getJsquestion());
156
-        $this->assign('createdId', $createdTemplate->getId());
157
-        $this->assign('createdName', $createdTemplate->getName());
158
-
159
-        $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
160
-        $this->assign("createReasons", $createReasons);
161
-        $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
162
-        $this->assign("declineReasons", $declineReasons);
163
-
164
-        $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
165
-        $this->assign("allCreateReasons", $allCreateReasons);
166
-        $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
167
-        $this->assign("allDeclineReasons", $allDeclineReasons);
168
-        $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
169
-        $this->assign("allOtherReasons", $allOtherReasons);
170
-
171
-        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
172
-            return UserSearchHelper::get($database)->byStatus('Active')->fetchColumn('username');
173
-        });
174
-    }
175
-
176
-    private function setupLogData(Request $request, PdoDatabase $database)
177
-    {
178
-        $currentUser = User::getCurrent($database);
179
-
180
-        $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
181
-        $requestLogs = array();
182
-
183
-        if (trim($request->getComment()) !== "") {
184
-            $requestLogs[] = array(
185
-                'type'     => 'comment',
186
-                'security' => 'user',
187
-                'userid'   => null,
188
-                'user'     => $request->getName(),
189
-                'entry'    => null,
190
-                'time'     => $request->getDate(),
191
-                'canedit'  => false,
192
-                'id'       => $request->getId(),
193
-                'comment'  => $request->getComment(),
194
-            );
195
-        }
196
-
197
-        /** @var User[] $nameCache */
198
-        $nameCache = array();
199
-
200
-        $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
201
-
202
-        /** @var Log|Comment $entry */
203
-        foreach ($logs as $entry) {
204
-            // both log and comment have a 'user' field
205
-            if (!array_key_exists($entry->getUser(), $nameCache)) {
206
-                $entryUser = User::getById($entry->getUser(), $database);
207
-                $nameCache[$entry->getUser()] = $entryUser;
208
-            }
209
-
210
-            if ($entry instanceof Comment) {
211
-                $requestLogs[] = array(
212
-                    'type'     => 'comment',
213
-                    'security' => $entry->getVisibility(),
214
-                    'user'     => $nameCache[$entry->getUser()]->getUsername(),
215
-                    'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
216
-                    'entry'    => null,
217
-                    'time'     => $entry->getTime(),
218
-                    'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
219
-                    'id'       => $entry->getId(),
220
-                    'comment'  => $entry->getComment(),
221
-                );
222
-            }
223
-
224
-            if ($entry instanceof Log) {
225
-                $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
226
-                $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
227
-
228
-                $entryComment = $entry->getComment();
229
-
230
-                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
231
-                    $data = unserialize($entry->getComment());
232
-                    /** @var JobQueue $job */
233
-                    $job = JobQueue::getById($data['job'], $database);
234
-                    $requestLogs[] = array(
235
-                        'type'     => 'joblog',
236
-                        'security' => 'user',
237
-                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
238
-                        'user'     => $entryUser->getUsername(),
239
-                        'entry'    => LogHelper::getLogDescription($entry),
240
-                        'time'     => $entry->getTimestamp(),
241
-                        'canedit'  => false,
242
-                        'id'       => $entry->getId(),
243
-                        'jobId'    => $job->getId(),
244
-                        'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
245
-                    );
246
-                } else {
247
-                    $requestLogs[] = array(
248
-                        'type'     => 'log',
249
-                        'security' => 'user',
250
-                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
251
-                        'user'     => $entryUser->getUsername(),
252
-                        'entry'    => LogHelper::getLogDescription($entry),
253
-                        'time'     => $entry->getTimestamp(),
254
-                        'canedit'  => false,
255
-                        'id'       => $entry->getId(),
256
-                        'comment'  => $entryComment,
257
-                    );
258
-                }
259
-            }
260
-        }
261
-
262
-        $this->assign("requestLogs", $requestLogs);
263
-    }
264
-
265
-    /**
266
-     * @param Request $request
267
-     */
268
-    protected function setupUsernameData(Request $request)
269
-    {
270
-        $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
271
-
272
-        $this->assign('requestIsBlacklisted', $blacklistData !== false);
273
-        $this->assign('requestBlacklist', $blacklistData);
274
-
275
-        try {
276
-            $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
277
-        }
278
-        catch (Exception $ex) {
279
-            $spoofs = $ex->getMessage();
280
-        }
281
-
282
-        $this->assign("spoofs", $spoofs);
283
-    }
284
-
285
-    private function setupCreationTypes(User $user)
286
-    {
287
-        $this->assign('canManualCreate',
288
-            $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'));
289
-        $this->assign('canOauthCreate',
290
-            $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'));
291
-        $this->assign('canBotCreate',
292
-            $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'));
293
-    }
115
+		);
116
+	}
117
+
118
+	/**
119
+	 * @param Request $request
120
+	 */
121
+	protected function setupTitle(Request $request)
122
+	{
123
+		$statusSymbol = self::STATUS_SYMBOL_OPEN;
124
+		if ($request->getStatus() === 'Closed') {
125
+			if ($request->getWasCreated()) {
126
+				$statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
127
+			}
128
+			else {
129
+				$statusSymbol = self::STATUS_SYMBOL_REJECTED;
130
+			}
131
+		}
132
+
133
+		$this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
134
+	}
135
+
136
+	/**
137
+	 * Sets up data unrelated to the request, such as the email template information
138
+	 *
139
+	 * @param PdoDatabase $database
140
+	 */
141
+	protected function setupGeneralData(PdoDatabase $database)
142
+	{
143
+		$config = $this->getSiteConfiguration();
144
+
145
+		$this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
146
+
147
+		$this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
148
+
149
+		$this->assign('requestStates', $config->getRequestStates());
150
+
151
+		/** @var EmailTemplate $createdTemplate */
152
+		$createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
153
+
154
+		$this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
155
+		$this->assign('createdJsQuestion', $createdTemplate->getJsquestion());
156
+		$this->assign('createdId', $createdTemplate->getId());
157
+		$this->assign('createdName', $createdTemplate->getName());
158
+
159
+		$createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
160
+		$this->assign("createReasons", $createReasons);
161
+		$declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
162
+		$this->assign("declineReasons", $declineReasons);
163
+
164
+		$allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
165
+		$this->assign("allCreateReasons", $allCreateReasons);
166
+		$allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
167
+		$this->assign("allDeclineReasons", $allDeclineReasons);
168
+		$allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
169
+		$this->assign("allOtherReasons", $allOtherReasons);
170
+
171
+		$this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
172
+			return UserSearchHelper::get($database)->byStatus('Active')->fetchColumn('username');
173
+		});
174
+	}
175
+
176
+	private function setupLogData(Request $request, PdoDatabase $database)
177
+	{
178
+		$currentUser = User::getCurrent($database);
179
+
180
+		$logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
181
+		$requestLogs = array();
182
+
183
+		if (trim($request->getComment()) !== "") {
184
+			$requestLogs[] = array(
185
+				'type'     => 'comment',
186
+				'security' => 'user',
187
+				'userid'   => null,
188
+				'user'     => $request->getName(),
189
+				'entry'    => null,
190
+				'time'     => $request->getDate(),
191
+				'canedit'  => false,
192
+				'id'       => $request->getId(),
193
+				'comment'  => $request->getComment(),
194
+			);
195
+		}
196
+
197
+		/** @var User[] $nameCache */
198
+		$nameCache = array();
199
+
200
+		$editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
201
+
202
+		/** @var Log|Comment $entry */
203
+		foreach ($logs as $entry) {
204
+			// both log and comment have a 'user' field
205
+			if (!array_key_exists($entry->getUser(), $nameCache)) {
206
+				$entryUser = User::getById($entry->getUser(), $database);
207
+				$nameCache[$entry->getUser()] = $entryUser;
208
+			}
209
+
210
+			if ($entry instanceof Comment) {
211
+				$requestLogs[] = array(
212
+					'type'     => 'comment',
213
+					'security' => $entry->getVisibility(),
214
+					'user'     => $nameCache[$entry->getUser()]->getUsername(),
215
+					'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
216
+					'entry'    => null,
217
+					'time'     => $entry->getTime(),
218
+					'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
219
+					'id'       => $entry->getId(),
220
+					'comment'  => $entry->getComment(),
221
+				);
222
+			}
223
+
224
+			if ($entry instanceof Log) {
225
+				$invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
226
+				$entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
227
+
228
+				$entryComment = $entry->getComment();
229
+
230
+				if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
231
+					$data = unserialize($entry->getComment());
232
+					/** @var JobQueue $job */
233
+					$job = JobQueue::getById($data['job'], $database);
234
+					$requestLogs[] = array(
235
+						'type'     => 'joblog',
236
+						'security' => 'user',
237
+						'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
238
+						'user'     => $entryUser->getUsername(),
239
+						'entry'    => LogHelper::getLogDescription($entry),
240
+						'time'     => $entry->getTimestamp(),
241
+						'canedit'  => false,
242
+						'id'       => $entry->getId(),
243
+						'jobId'    => $job->getId(),
244
+						'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
245
+					);
246
+				} else {
247
+					$requestLogs[] = array(
248
+						'type'     => 'log',
249
+						'security' => 'user',
250
+						'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
251
+						'user'     => $entryUser->getUsername(),
252
+						'entry'    => LogHelper::getLogDescription($entry),
253
+						'time'     => $entry->getTimestamp(),
254
+						'canedit'  => false,
255
+						'id'       => $entry->getId(),
256
+						'comment'  => $entryComment,
257
+					);
258
+				}
259
+			}
260
+		}
261
+
262
+		$this->assign("requestLogs", $requestLogs);
263
+	}
264
+
265
+	/**
266
+	 * @param Request $request
267
+	 */
268
+	protected function setupUsernameData(Request $request)
269
+	{
270
+		$blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
271
+
272
+		$this->assign('requestIsBlacklisted', $blacklistData !== false);
273
+		$this->assign('requestBlacklist', $blacklistData);
274
+
275
+		try {
276
+			$spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
277
+		}
278
+		catch (Exception $ex) {
279
+			$spoofs = $ex->getMessage();
280
+		}
281
+
282
+		$this->assign("spoofs", $spoofs);
283
+	}
284
+
285
+	private function setupCreationTypes(User $user)
286
+	{
287
+		$this->assign('canManualCreate',
288
+			$this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'));
289
+		$this->assign('canOauthCreate',
290
+			$this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'));
291
+		$this->assign('canBotCreate',
292
+			$this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'));
293
+	}
294 294
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
             }
131 131
         }
132 132
 
133
-        $this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
133
+        $this->setHtmlTitle($statusSymbol.' #'.$request->getId());
134 134
     }
135 135
 
136 136
     /**
@@ -227,7 +227,7 @@  discard block
 block discarded – undo
227 227
 
228 228
                 $entryComment = $entry->getComment();
229 229
 
230
-                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
230
+                if ($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest') {
231 231
                     $data = unserialize($entry->getComment());
232 232
                     /** @var JobQueue $job */
233 233
                     $job = JobQueue::getById($data['job'], $database);
Please login to merge, or discard this patch.
Braces   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -227,7 +227,7 @@  discard block
 block discarded – undo
227 227
 
228 228
                 $entryComment = $entry->getComment();
229 229
 
230
-                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
230
+                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest') {
231 231
                     $data = unserialize($entry->getComment());
232 232
                     /** @var JobQueue $job */
233 233
                     $job = JobQueue::getById($data['job'], $database);
@@ -243,7 +243,8 @@  discard block
 block discarded – undo
243 243
                         'jobId'    => $job->getId(),
244 244
                         'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
245 245
                     );
246
-                } else {
246
+                }
247
+                else {
247 248
                     $requestLogs[] = array(
248 249
                         'type'     => 'log',
249 250
                         'security' => 'user',
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PagePreferences.php 3 patches
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -16,73 +16,73 @@
 block discarded – undo
16 16
 
17 17
 class PagePreferences extends InternalPageBase
18 18
 {
19
-    /**
20
-     * Main function for this page, when no specific actions are called.
21
-     * @return void
22
-     */
23
-    protected function main()
24
-    {
25
-        $this->setHtmlTitle('Preferences');
19
+	/**
20
+	 * Main function for this page, when no specific actions are called.
21
+	 * @return void
22
+	 */
23
+	protected function main()
24
+	{
25
+		$this->setHtmlTitle('Preferences');
26 26
 
27
-        $enforceOAuth = $this->getSiteConfiguration()->getEnforceOAuth();
28
-        $database = $this->getDatabase();
29
-        $user = User::getCurrent($database);
27
+		$enforceOAuth = $this->getSiteConfiguration()->getEnforceOAuth();
28
+		$database = $this->getDatabase();
29
+		$user = User::getCurrent($database);
30 30
 
31
-        // Dual mode
32
-        if (WebRequest::wasPosted()) {
33
-            $this->validateCSRFToken();
34
-            $user->setWelcomeSig(WebRequest::postString('sig'));
35
-            $user->setEmailSig(WebRequest::postString('emailsig'));
36
-            $user->setAbortPref(WebRequest::getBoolean('sig') ? 1 : 0);
37
-            $this->setCreationMode($user);
31
+		// Dual mode
32
+		if (WebRequest::wasPosted()) {
33
+			$this->validateCSRFToken();
34
+			$user->setWelcomeSig(WebRequest::postString('sig'));
35
+			$user->setEmailSig(WebRequest::postString('emailsig'));
36
+			$user->setAbortPref(WebRequest::getBoolean('sig') ? 1 : 0);
37
+			$this->setCreationMode($user);
38 38
 
39
-            $email = WebRequest::postEmail('email');
40
-            if ($email !== null) {
41
-                $user->setEmail($email);
42
-            }
39
+			$email = WebRequest::postEmail('email');
40
+			if ($email !== null) {
41
+				$user->setEmail($email);
42
+			}
43 43
 
44
-            $user->save();
45
-            SessionAlert::success("Preferences updated!");
44
+			$user->save();
45
+			SessionAlert::success("Preferences updated!");
46 46
 
47
-            $this->redirect('');
48
-        }
49
-        else {
50
-            $this->assignCSRFToken();
51
-            $this->setTemplate('preferences/prefs.tpl');
52
-            $this->assign("enforceOAuth", $enforceOAuth);
47
+			$this->redirect('');
48
+		}
49
+		else {
50
+			$this->assignCSRFToken();
51
+			$this->setTemplate('preferences/prefs.tpl');
52
+			$this->assign("enforceOAuth", $enforceOAuth);
53 53
 
54
-            $this->assign('canManualCreate',
55
-                $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'));
56
-            $this->assign('canOauthCreate',
57
-                $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'));
58
-            $this->assign('canBotCreate',
59
-                $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'));
54
+			$this->assign('canManualCreate',
55
+				$this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'));
56
+			$this->assign('canOauthCreate',
57
+				$this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'));
58
+			$this->assign('canBotCreate',
59
+				$this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'));
60 60
 
61
-            $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(),
62
-                $this->getSiteConfiguration());
63
-            $this->assign('oauth', $oauth);
61
+			$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(),
62
+				$this->getSiteConfiguration());
63
+			$this->assign('oauth', $oauth);
64 64
 
65
-            $identity = null;
66
-            if ($oauth->isFullyLinked()) {
67
-                $identity = $oauth->getIdentity();
68
-            }
65
+			$identity = null;
66
+			if ($oauth->isFullyLinked()) {
67
+				$identity = $oauth->getIdentity();
68
+			}
69 69
 
70
-            $this->assign('identity', $identity);
71
-            $this->assign('graceTime', $this->getSiteConfiguration()->getOauthIdentityGraceTime());
72
-        }
73
-    }
70
+			$this->assign('identity', $identity);
71
+			$this->assign('graceTime', $this->getSiteConfiguration()->getOauthIdentityGraceTime());
72
+		}
73
+	}
74 74
 
75
-    /**
76
-     * @param User $user
77
-     */
78
-    protected function setCreationMode(User $user)
79
-    {
80
-        // if the user is selecting a creation mode that they are not allowed, do nothing.
81
-        // this has the side effect of allowing them to keep a selected mode that either has been changed for them,
82
-        // or that they have kept from when they previously had certain access.
83
-        $creationMode = WebRequest::postInt('creationmode');
84
-        if($this->barrierTest($creationMode, $user, 'RequestCreation')){
85
-            $user->setCreationMode($creationMode);
86
-        }
87
-    }
75
+	/**
76
+	 * @param User $user
77
+	 */
78
+	protected function setCreationMode(User $user)
79
+	{
80
+		// if the user is selecting a creation mode that they are not allowed, do nothing.
81
+		// this has the side effect of allowing them to keep a selected mode that either has been changed for them,
82
+		// or that they have kept from when they previously had certain access.
83
+		$creationMode = WebRequest::postInt('creationmode');
84
+		if($this->barrierTest($creationMode, $user, 'RequestCreation')){
85
+			$user->setCreationMode($creationMode);
86
+		}
87
+	}
88 88
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -81,7 +81,7 @@
 block discarded – undo
81 81
         // this has the side effect of allowing them to keep a selected mode that either has been changed for them,
82 82
         // or that they have kept from when they previously had certain access.
83 83
         $creationMode = WebRequest::postInt('creationmode');
84
-        if($this->barrierTest($creationMode, $user, 'RequestCreation')){
84
+        if ($this->barrierTest($creationMode, $user, 'RequestCreation')) {
85 85
             $user->setCreationMode($creationMode);
86 86
         }
87 87
     }
Please login to merge, or discard this patch.
Braces   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -81,7 +81,7 @@
 block discarded – undo
81 81
         // this has the side effect of allowing them to keep a selected mode that either has been changed for them,
82 82
         // or that they have kept from when they previously had certain access.
83 83
         $creationMode = WebRequest::postInt('creationmode');
84
-        if($this->barrierTest($creationMode, $user, 'RequestCreation')){
84
+        if($this->barrierTest($creationMode, $user, 'RequestCreation')) {
85 85
             $user->setCreationMode($creationMode);
86 86
         }
87 87
     }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageOAuth.php 1 patch
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -21,77 +21,77 @@
 block discarded – undo
21 21
 
22 22
 class PageOAuth extends InternalPageBase
23 23
 {
24
-    /**
25
-     * Attach entry point
26
-     *
27
-     * must be posted, or will redirect to preferences
28
-     */
29
-    protected function attach()
30
-    {
31
-        if (!WebRequest::wasPosted()) {
32
-            $this->redirect('preferences');
33
-
34
-            return;
35
-        }
36
-
37
-        $database = $this->getDatabase();
38
-
39
-        $this->validateCSRFToken();
40
-
41
-        $oauthProtocolHelper = $this->getOAuthProtocolHelper();
42
-        $user = User::getCurrent($database);
43
-        $oauth = new OAuthUserHelper($user, $database, $oauthProtocolHelper, $this->getSiteConfiguration());
44
-
45
-        try {
46
-            $authoriseUrl = $oauth->getRequestToken();
47
-            $this->redirectUrl($authoriseUrl);
48
-        }
49
-        catch (CurlException $ex) {
50
-            throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
51
-        }
52
-    }
53
-
54
-    /**
55
-     * Detach account entry point
56
-     */
57
-    protected function detach()
58
-    {
59
-        if ($this->getSiteConfiguration()->getEnforceOAuth()) {
60
-            throw new AccessDeniedException($this->getSecurityManager());
61
-        }
62
-
63
-        $database = $this->getDatabase();
64
-        $user = User::getCurrent($database);
65
-        $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
66
-
67
-        try {
68
-            $oauth->refreshIdentity();
69
-        }
70
-        catch (CurlException $ex) {
71
-            // do nothing. The user's already revoked this access anyway.
72
-        }
73
-        catch (OAuthException $ex) {
74
-            // do nothing. The user's already revoked this access anyway.
75
-        }
76
-
77
-        $oauth->detach();
78
-
79
-        // TODO: figure out why we need to force logout after a detach.
80
-        $user->setForcelogout(true);
81
-        $user->save();
82
-
83
-        // force the user to log out
84
-        Session::destroy();
85
-
86
-        $this->redirect('login');
87
-    }
88
-
89
-    /**
90
-     * Main function for this page, when no specific actions are called.
91
-     * @return void
92
-     */
93
-    protected function main()
94
-    {
95
-        $this->redirect('preferences');
96
-    }
24
+	/**
25
+	 * Attach entry point
26
+	 *
27
+	 * must be posted, or will redirect to preferences
28
+	 */
29
+	protected function attach()
30
+	{
31
+		if (!WebRequest::wasPosted()) {
32
+			$this->redirect('preferences');
33
+
34
+			return;
35
+		}
36
+
37
+		$database = $this->getDatabase();
38
+
39
+		$this->validateCSRFToken();
40
+
41
+		$oauthProtocolHelper = $this->getOAuthProtocolHelper();
42
+		$user = User::getCurrent($database);
43
+		$oauth = new OAuthUserHelper($user, $database, $oauthProtocolHelper, $this->getSiteConfiguration());
44
+
45
+		try {
46
+			$authoriseUrl = $oauth->getRequestToken();
47
+			$this->redirectUrl($authoriseUrl);
48
+		}
49
+		catch (CurlException $ex) {
50
+			throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
51
+		}
52
+	}
53
+
54
+	/**
55
+	 * Detach account entry point
56
+	 */
57
+	protected function detach()
58
+	{
59
+		if ($this->getSiteConfiguration()->getEnforceOAuth()) {
60
+			throw new AccessDeniedException($this->getSecurityManager());
61
+		}
62
+
63
+		$database = $this->getDatabase();
64
+		$user = User::getCurrent($database);
65
+		$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
66
+
67
+		try {
68
+			$oauth->refreshIdentity();
69
+		}
70
+		catch (CurlException $ex) {
71
+			// do nothing. The user's already revoked this access anyway.
72
+		}
73
+		catch (OAuthException $ex) {
74
+			// do nothing. The user's already revoked this access anyway.
75
+		}
76
+
77
+		$oauth->detach();
78
+
79
+		// TODO: figure out why we need to force logout after a detach.
80
+		$user->setForcelogout(true);
81
+		$user->save();
82
+
83
+		// force the user to log out
84
+		Session::destroy();
85
+
86
+		$this->redirect('login');
87
+	}
88
+
89
+	/**
90
+	 * Main function for this page, when no specific actions are called.
91
+	 * @return void
92
+	 */
93
+	protected function main()
94
+	{
95
+		$this->redirect('preferences');
96
+	}
97 97
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageChangePassword.php 1 patch
Indentation   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -17,70 +17,70 @@
 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('oldpassword');
32
-                $newPassword = WebRequest::postString('newpassword');
33
-                $newPasswordConfirmation = WebRequest::postString('newpasswordconfirm');
28
+		if (WebRequest::wasPosted()) {
29
+			$this->validateCSRFToken();
30
+			try {
31
+				$oldPassword = WebRequest::postString('oldpassword');
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);
41
-            }
42
-            catch (ApplicationLogicException $ex) {
43
-                SessionAlert::error($ex->getMessage());
44
-                $this->redirect('changePassword');
40
+				$this->validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, $user);
41
+			}
42
+			catch (ApplicationLogicException $ex) {
43
+				SessionAlert::error($ex->getMessage());
44
+				$this->redirect('changePassword');
45 45
 
46
-                return;
47
-            }
46
+				return;
47
+			}
48 48
 
49
-            $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
50
-            $passwordProvider->setCredential($user, 1, $newPassword);
49
+			$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
50
+			$passwordProvider->setCredential($user, 1, $newPassword);
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
-        }
60
-    }
54
+			$this->redirect('preferences');
55
+		}
56
+		else {
57
+			$this->assignCSRFToken();
58
+			$this->setTemplate('preferences/changePassword.tpl');
59
+		}
60
+	}
61 61
 
62
-    /**
63
-     * @param string $oldPassword
64
-     * @param string $newPassword
65
-     * @param string $newPasswordConfirmation
66
-     * @param User   $user
67
-     *
68
-     * @throws ApplicationLogicException
69
-     */
70
-    protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
71
-    {
72
-        if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
73
-            throw new ApplicationLogicException('All three fields must be completed to change your password');
74
-        }
62
+	/**
63
+	 * @param string $oldPassword
64
+	 * @param string $newPassword
65
+	 * @param string $newPasswordConfirmation
66
+	 * @param User   $user
67
+	 *
68
+	 * @throws ApplicationLogicException
69
+	 */
70
+	protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
71
+	{
72
+		if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
73
+			throw new ApplicationLogicException('All three fields must be completed to change your password');
74
+		}
75 75
 
76
-        if ($newPassword !== $newPasswordConfirmation) {
77
-            throw new ApplicationLogicException('Your new passwords did not match!');
78
-        }
76
+		if ($newPassword !== $newPasswordConfirmation) {
77
+			throw new ApplicationLogicException('Your new passwords did not match!');
78
+		}
79 79
 
80
-        // TODO: adapt for MFA support
81
-        $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
82
-        if (!$passwordProvider->authenticate($user, $oldPassword)) {
83
-            throw new ApplicationLogicException('The password you entered was incorrect.');
84
-        }
85
-    }
80
+		// TODO: adapt for MFA support
81
+		$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
82
+		if (!$passwordProvider->authenticate($user, $oldPassword)) {
83
+			throw new ApplicationLogicException('The password you entered was incorrect.');
84
+		}
85
+	}
86 86
 }
87 87
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageForgotPassword.php 1 patch
Indentation   +145 added lines, -145 removed lines patch added patch discarded remove patch
@@ -18,149 +18,149 @@
 block discarded – undo
18 18
 
19 19
 class PageForgotPassword extends InternalPageBase
20 20
 {
21
-    /**
22
-     * Main function for this page, when no specific actions are called.
23
-     *
24
-     * This is the forgotten password reset form
25
-     * @category Security-Critical
26
-     */
27
-    protected function main()
28
-    {
29
-        if (WebRequest::wasPosted()) {
30
-            $this->validateCSRFToken();
31
-            $username = WebRequest::postString('username');
32
-            $email = WebRequest::postEmail('email');
33
-            $database = $this->getDatabase();
34
-
35
-            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
36
-                throw new ApplicationLogicException("Both username and email address must be specified!");
37
-            }
38
-
39
-            $user = User::getByUsername($username, $database);
40
-            $this->sendResetMail($user, $email);
41
-
42
-            SessionAlert::success('<strong>Your password reset request has been completed.</strong> Please check your e-mail.');
43
-
44
-            $this->redirect('login');
45
-        }
46
-        else {
47
-            $this->assignCSRFToken();
48
-            $this->setTemplate('forgot-password/forgotpw.tpl');
49
-        }
50
-    }
51
-
52
-    /**
53
-     * Sends a reset email if the user is authenticated
54
-     *
55
-     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
56
-     *                            check anyway within this method and silently skip if we don't have a user.
57
-     * @param string       $email The provided email address
58
-     */
59
-    private function sendResetMail($user, $email)
60
-    {
61
-        // If the user isn't found, or the email address is wrong, skip sending the details silently.
62
-        if (!$user instanceof User) {
63
-            return;
64
-        }
65
-
66
-        if (strtolower($user->getEmail()) === strtolower($email)) {
67
-            $clientIp = $this->getXffTrustProvider()
68
-                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
69
-
70
-            $this->assign("user", $user);
71
-            $this->assign("hash", $user->getForgottenPasswordHash());
72
-            $this->assign("remoteAddress", $clientIp);
73
-
74
-            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
75
-
76
-            $this->getEmailHelper()->sendMail($user->getEmail(), "", $emailContent);
77
-        }
78
-    }
79
-
80
-    /**
81
-     * Entry point for the reset action
82
-     *
83
-     * This is the reset password part of the form.
84
-     * @category Security-Critical
85
-     */
86
-    protected function reset()
87
-    {
88
-        $si = WebRequest::getString('si');
89
-        $id = WebRequest::getString('id');
90
-
91
-        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
92
-            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
93
-        }
94
-
95
-        $database = $this->getDatabase();
96
-        $user = $this->getResettingUser($id, $database, $si);
97
-
98
-        // Dual mode
99
-        if (WebRequest::wasPosted()) {
100
-            $this->validateCSRFToken();
101
-            try {
102
-                $this->doReset($user);
103
-            }
104
-            catch (ApplicationLogicException $ex) {
105
-                SessionAlert::error($ex->getMessage());
106
-                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
107
-
108
-                return;
109
-            }
110
-        }
111
-        else {
112
-            $this->assignCSRFToken();
113
-            $this->assign('user', $user);
114
-            $this->setTemplate('forgot-password/forgotpwreset.tpl');
115
-        }
116
-    }
117
-
118
-    /**
119
-     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
120
-     *
121
-     * @param integer     $id       The ID of the user to retrieve
122
-     * @param PdoDatabase $database The database object to use
123
-     * @param string      $si       The reset hash provided
124
-     *
125
-     * @return User
126
-     * @throws ApplicationLogicException
127
-     */
128
-    private function getResettingUser($id, $database, $si)
129
-    {
130
-        $user = User::getById($id, $database);
131
-
132
-        if ($user === false || $user->getForgottenPasswordHash() !== $si || $user->isCommunityUser()) {
133
-            throw new ApplicationLogicException("User not found");
134
-        }
135
-
136
-        return $user;
137
-    }
138
-
139
-    /**
140
-     * Performs the setting of the new password
141
-     *
142
-     * @param User $user The user to set the password for
143
-     *
144
-     * @throws ApplicationLogicException
145
-     */
146
-    private function doReset(User $user)
147
-    {
148
-        $pw = WebRequest::postString('pw');
149
-        $pw2 = WebRequest::postString('pw2');
150
-
151
-        if ($pw !== $pw2) {
152
-            throw new ApplicationLogicException('Passwords do not match!');
153
-        }
154
-
155
-        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
156
-        $passwordCredentialProvider->setCredential($user, 1, $pw);
157
-
158
-        SessionAlert::success('You may now log in!');
159
-        $this->redirect('login');
160
-    }
161
-
162
-    protected function isProtectedPage()
163
-    {
164
-        return false;
165
-    }
21
+	/**
22
+	 * Main function for this page, when no specific actions are called.
23
+	 *
24
+	 * This is the forgotten password reset form
25
+	 * @category Security-Critical
26
+	 */
27
+	protected function main()
28
+	{
29
+		if (WebRequest::wasPosted()) {
30
+			$this->validateCSRFToken();
31
+			$username = WebRequest::postString('username');
32
+			$email = WebRequest::postEmail('email');
33
+			$database = $this->getDatabase();
34
+
35
+			if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
36
+				throw new ApplicationLogicException("Both username and email address must be specified!");
37
+			}
38
+
39
+			$user = User::getByUsername($username, $database);
40
+			$this->sendResetMail($user, $email);
41
+
42
+			SessionAlert::success('<strong>Your password reset request has been completed.</strong> Please check your e-mail.');
43
+
44
+			$this->redirect('login');
45
+		}
46
+		else {
47
+			$this->assignCSRFToken();
48
+			$this->setTemplate('forgot-password/forgotpw.tpl');
49
+		}
50
+	}
51
+
52
+	/**
53
+	 * Sends a reset email if the user is authenticated
54
+	 *
55
+	 * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
56
+	 *                            check anyway within this method and silently skip if we don't have a user.
57
+	 * @param string       $email The provided email address
58
+	 */
59
+	private function sendResetMail($user, $email)
60
+	{
61
+		// If the user isn't found, or the email address is wrong, skip sending the details silently.
62
+		if (!$user instanceof User) {
63
+			return;
64
+		}
65
+
66
+		if (strtolower($user->getEmail()) === strtolower($email)) {
67
+			$clientIp = $this->getXffTrustProvider()
68
+				->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
69
+
70
+			$this->assign("user", $user);
71
+			$this->assign("hash", $user->getForgottenPasswordHash());
72
+			$this->assign("remoteAddress", $clientIp);
73
+
74
+			$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
75
+
76
+			$this->getEmailHelper()->sendMail($user->getEmail(), "", $emailContent);
77
+		}
78
+	}
79
+
80
+	/**
81
+	 * Entry point for the reset action
82
+	 *
83
+	 * This is the reset password part of the form.
84
+	 * @category Security-Critical
85
+	 */
86
+	protected function reset()
87
+	{
88
+		$si = WebRequest::getString('si');
89
+		$id = WebRequest::getString('id');
90
+
91
+		if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
92
+			throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
93
+		}
94
+
95
+		$database = $this->getDatabase();
96
+		$user = $this->getResettingUser($id, $database, $si);
97
+
98
+		// Dual mode
99
+		if (WebRequest::wasPosted()) {
100
+			$this->validateCSRFToken();
101
+			try {
102
+				$this->doReset($user);
103
+			}
104
+			catch (ApplicationLogicException $ex) {
105
+				SessionAlert::error($ex->getMessage());
106
+				$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
107
+
108
+				return;
109
+			}
110
+		}
111
+		else {
112
+			$this->assignCSRFToken();
113
+			$this->assign('user', $user);
114
+			$this->setTemplate('forgot-password/forgotpwreset.tpl');
115
+		}
116
+	}
117
+
118
+	/**
119
+	 * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
120
+	 *
121
+	 * @param integer     $id       The ID of the user to retrieve
122
+	 * @param PdoDatabase $database The database object to use
123
+	 * @param string      $si       The reset hash provided
124
+	 *
125
+	 * @return User
126
+	 * @throws ApplicationLogicException
127
+	 */
128
+	private function getResettingUser($id, $database, $si)
129
+	{
130
+		$user = User::getById($id, $database);
131
+
132
+		if ($user === false || $user->getForgottenPasswordHash() !== $si || $user->isCommunityUser()) {
133
+			throw new ApplicationLogicException("User not found");
134
+		}
135
+
136
+		return $user;
137
+	}
138
+
139
+	/**
140
+	 * Performs the setting of the new password
141
+	 *
142
+	 * @param User $user The user to set the password for
143
+	 *
144
+	 * @throws ApplicationLogicException
145
+	 */
146
+	private function doReset(User $user)
147
+	{
148
+		$pw = WebRequest::postString('pw');
149
+		$pw2 = WebRequest::postString('pw2');
150
+
151
+		if ($pw !== $pw2) {
152
+			throw new ApplicationLogicException('Passwords do not match!');
153
+		}
154
+
155
+		$passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
156
+		$passwordCredentialProvider->setCredential($user, 1, $pw);
157
+
158
+		SessionAlert::success('You may now log in!');
159
+		$this->redirect('login');
160
+	}
161
+
162
+	protected function isProtectedPage()
163
+	{
164
+		return false;
165
+	}
166 166
 }
Please login to merge, or discard this patch.
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.