Completed
Push — newinternal ( 65a0f5...5b021c )
by Simon
08:29
created
includes/Helpers/SearchHelpers/RequestSearchHelper.php 1 patch
Indentation   +113 added lines, -113 removed lines patch added patch discarded remove patch
@@ -14,117 +14,117 @@
 block discarded – undo
14 14
 
15 15
 class RequestSearchHelper extends SearchHelperBase
16 16
 {
17
-    /**
18
-     * RequestSearchHelper constructor.
19
-     *
20
-     * @param PdoDatabase $database
21
-     */
22
-    protected function __construct(PdoDatabase $database)
23
-    {
24
-        parent::__construct($database, 'request', Request::class);
25
-    }
26
-
27
-    /**
28
-     * Initiates a search for requests
29
-     *
30
-     * @param PdoDatabase $database
31
-     *
32
-     * @return RequestSearchHelper
33
-     */
34
-    public static function get(PdoDatabase $database)
35
-    {
36
-        $helper = new RequestSearchHelper($database);
37
-
38
-        return $helper;
39
-    }
40
-
41
-    /**
42
-     * Filters the results by IP address
43
-     *
44
-     * @param string $ipAddress
45
-     *
46
-     * @return $this
47
-     */
48
-    public function byIp($ipAddress)
49
-    {
50
-        $this->whereClause .= ' AND (ip LIKE ? OR forwardedip LIKE ?)';
51
-        $this->parameterList[] = $ipAddress;
52
-        $this->parameterList[] = '%' . trim($ipAddress, '%') . '%';
53
-
54
-        return $this;
55
-    }
56
-
57
-    /**
58
-     * Filters the results by email address
59
-     *
60
-     * @param string $emailAddress
61
-     *
62
-     * @return $this
63
-     */
64
-    public function byEmailAddress($emailAddress)
65
-    {
66
-        $this->whereClause .= ' AND email LIKE ?';
67
-        $this->parameterList[] = $emailAddress;
68
-
69
-        return $this;
70
-    }
71
-
72
-    /**
73
-     * Filters the results by name
74
-     *
75
-     * @param string $name
76
-     *
77
-     * @return $this
78
-     */
79
-    public function byName($name)
80
-    {
81
-        $this->whereClause .= ' AND name LIKE ?';
82
-        $this->parameterList[] = $name;
83
-
84
-        return $this;
85
-    }
86
-
87
-    /**
88
-     * Excludes a request from the results
89
-     *
90
-     * @param int $requestId
91
-     *
92
-     * @return $this
93
-     */
94
-    public function excludingRequest($requestId)
95
-    {
96
-        $this->whereClause .= ' AND id <> ?';
97
-        $this->parameterList[] = $requestId;
98
-
99
-        return $this;
100
-    }
101
-
102
-    /**
103
-     * Filters the results to only those with a confirmed email address
104
-     *
105
-     * @return $this
106
-     */
107
-    public function withConfirmedEmail()
108
-    {
109
-        $this->whereClause .= ' AND emailconfirm = ?';
110
-        $this->parameterList[] = 'Confirmed';
111
-
112
-        return $this;
113
-    }
114
-
115
-    /**
116
-     * Filters the results to exclude purged data
117
-     *
118
-     * @param SiteConfiguration $configuration
119
-     *
120
-     * @return $this
121
-     */
122
-    public function excludingPurgedData(SiteConfiguration $configuration)
123
-    {
124
-        $this->whereClause .= ' AND ip <> ? AND email <> ?';
125
-        $this->parameterList[] = $configuration->getDataClearIp();
126
-        $this->parameterList[] = $configuration->getDataClearEmail();
127
-
128
-        return $this;
129
-    }
17
+	/**
18
+	 * RequestSearchHelper constructor.
19
+	 *
20
+	 * @param PdoDatabase $database
21
+	 */
22
+	protected function __construct(PdoDatabase $database)
23
+	{
24
+		parent::__construct($database, 'request', Request::class);
25
+	}
26
+
27
+	/**
28
+	 * Initiates a search for requests
29
+	 *
30
+	 * @param PdoDatabase $database
31
+	 *
32
+	 * @return RequestSearchHelper
33
+	 */
34
+	public static function get(PdoDatabase $database)
35
+	{
36
+		$helper = new RequestSearchHelper($database);
37
+
38
+		return $helper;
39
+	}
40
+
41
+	/**
42
+	 * Filters the results by IP address
43
+	 *
44
+	 * @param string $ipAddress
45
+	 *
46
+	 * @return $this
47
+	 */
48
+	public function byIp($ipAddress)
49
+	{
50
+		$this->whereClause .= ' AND (ip LIKE ? OR forwardedip LIKE ?)';
51
+		$this->parameterList[] = $ipAddress;
52
+		$this->parameterList[] = '%' . trim($ipAddress, '%') . '%';
53
+
54
+		return $this;
55
+	}
56
+
57
+	/**
58
+	 * Filters the results by email address
59
+	 *
60
+	 * @param string $emailAddress
61
+	 *
62
+	 * @return $this
63
+	 */
64
+	public function byEmailAddress($emailAddress)
65
+	{
66
+		$this->whereClause .= ' AND email LIKE ?';
67
+		$this->parameterList[] = $emailAddress;
68
+
69
+		return $this;
70
+	}
71
+
72
+	/**
73
+	 * Filters the results by name
74
+	 *
75
+	 * @param string $name
76
+	 *
77
+	 * @return $this
78
+	 */
79
+	public function byName($name)
80
+	{
81
+		$this->whereClause .= ' AND name LIKE ?';
82
+		$this->parameterList[] = $name;
83
+
84
+		return $this;
85
+	}
86
+
87
+	/**
88
+	 * Excludes a request from the results
89
+	 *
90
+	 * @param int $requestId
91
+	 *
92
+	 * @return $this
93
+	 */
94
+	public function excludingRequest($requestId)
95
+	{
96
+		$this->whereClause .= ' AND id <> ?';
97
+		$this->parameterList[] = $requestId;
98
+
99
+		return $this;
100
+	}
101
+
102
+	/**
103
+	 * Filters the results to only those with a confirmed email address
104
+	 *
105
+	 * @return $this
106
+	 */
107
+	public function withConfirmedEmail()
108
+	{
109
+		$this->whereClause .= ' AND emailconfirm = ?';
110
+		$this->parameterList[] = 'Confirmed';
111
+
112
+		return $this;
113
+	}
114
+
115
+	/**
116
+	 * Filters the results to exclude purged data
117
+	 *
118
+	 * @param SiteConfiguration $configuration
119
+	 *
120
+	 * @return $this
121
+	 */
122
+	public function excludingPurgedData(SiteConfiguration $configuration)
123
+	{
124
+		$this->whereClause .= ' AND ip <> ? AND email <> ?';
125
+		$this->parameterList[] = $configuration->getDataClearIp();
126
+		$this->parameterList[] = $configuration->getDataClearEmail();
127
+
128
+		return $this;
129
+	}
130 130
 }
131 131
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Helpers/SearchHelpers/LogSearchHelper.php 1 patch
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -13,87 +13,87 @@
 block discarded – undo
13 13
 
14 14
 class LogSearchHelper extends SearchHelperBase
15 15
 {
16
-    /**
17
-     * LogSearchHelper constructor.
18
-     *
19
-     * @param PdoDatabase $database
20
-     */
21
-    protected function __construct(PdoDatabase $database)
22
-    {
23
-        parent::__construct($database, 'log', Log::class, 'timestamp DESC');
24
-    }
16
+	/**
17
+	 * LogSearchHelper constructor.
18
+	 *
19
+	 * @param PdoDatabase $database
20
+	 */
21
+	protected function __construct(PdoDatabase $database)
22
+	{
23
+		parent::__construct($database, 'log', Log::class, 'timestamp DESC');
24
+	}
25 25
 
26
-    /**
27
-     * Initiates a search for requests
28
-     *
29
-     * @param PdoDatabase $database
30
-     *
31
-     * @return LogSearchHelper
32
-     */
33
-    public static function get(PdoDatabase $database)
34
-    {
35
-        $helper = new LogSearchHelper($database);
26
+	/**
27
+	 * Initiates a search for requests
28
+	 *
29
+	 * @param PdoDatabase $database
30
+	 *
31
+	 * @return LogSearchHelper
32
+	 */
33
+	public static function get(PdoDatabase $database)
34
+	{
35
+		$helper = new LogSearchHelper($database);
36 36
 
37
-        return $helper;
38
-    }
37
+		return $helper;
38
+	}
39 39
 
40
-    /**
41
-     * Filters the results by user
42
-     *
43
-     * @param int $userId
44
-     *
45
-     * @return $this
46
-     */
47
-    public function byUser($userId)
48
-    {
49
-        $this->whereClause .= ' AND user = ?';
50
-        $this->parameterList[] = $userId;
40
+	/**
41
+	 * Filters the results by user
42
+	 *
43
+	 * @param int $userId
44
+	 *
45
+	 * @return $this
46
+	 */
47
+	public function byUser($userId)
48
+	{
49
+		$this->whereClause .= ' AND user = ?';
50
+		$this->parameterList[] = $userId;
51 51
 
52
-        return $this;
53
-    }
52
+		return $this;
53
+	}
54 54
 
55
-    /**
56
-     * Filters the results by log action
57
-     *
58
-     * @param string $action
59
-     *
60
-     * @return $this
61
-     */
62
-    public function byAction($action)
63
-    {
64
-        $this->whereClause .= ' AND action = ?';
65
-        $this->parameterList[] = $action;
55
+	/**
56
+	 * Filters the results by log action
57
+	 *
58
+	 * @param string $action
59
+	 *
60
+	 * @return $this
61
+	 */
62
+	public function byAction($action)
63
+	{
64
+		$this->whereClause .= ' AND action = ?';
65
+		$this->parameterList[] = $action;
66 66
 
67
-        return $this;
68
-    }
67
+		return $this;
68
+	}
69 69
 
70
-    /**
71
-     * Filters the results by object type
72
-     *
73
-     * @param string $objectType
74
-     *
75
-     * @return $this
76
-     */
77
-    public function byObjectType($objectType)
78
-    {
79
-        $this->whereClause .= ' AND objecttype = ?';
80
-        $this->parameterList[] = $objectType;
70
+	/**
71
+	 * Filters the results by object type
72
+	 *
73
+	 * @param string $objectType
74
+	 *
75
+	 * @return $this
76
+	 */
77
+	public function byObjectType($objectType)
78
+	{
79
+		$this->whereClause .= ' AND objecttype = ?';
80
+		$this->parameterList[] = $objectType;
81 81
 
82
-        return $this;
83
-    }
82
+		return $this;
83
+	}
84 84
 
85
-    /**
86
-     * Filters the results by object type
87
-     *
88
-     * @param integer $objectId
89
-     *
90
-     * @return $this
91
-     */
92
-    public function byObjectId($objectId)
93
-    {
94
-        $this->whereClause .= ' AND objectid = ?';
95
-        $this->parameterList[] = $objectId;
85
+	/**
86
+	 * Filters the results by object type
87
+	 *
88
+	 * @param integer $objectId
89
+	 *
90
+	 * @return $this
91
+	 */
92
+	public function byObjectId($objectId)
93
+	{
94
+		$this->whereClause .= ' AND objectid = ?';
95
+		$this->parameterList[] = $objectId;
96 96
 
97
-        return $this;
98
-    }
97
+		return $this;
98
+	}
99 99
 }
100 100
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Tasks/PageBase.php 3 patches
Indentation   +337 added lines, -337 removed lines patch added patch discarded remove patch
@@ -20,341 +20,341 @@
 block discarded – undo
20 20
 
21 21
 abstract class PageBase extends TaskBase implements IRoutedTask
22 22
 {
23
-    use TemplateOutput;
24
-    /** @var string Smarty template to display */
25
-    protected $template = "base.tpl";
26
-    /** @var string HTML title. Currently unused. */
27
-    protected $htmlTitle;
28
-    /** @var bool Determines if the page is a redirect or not */
29
-    protected $isRedirecting = false;
30
-    /** @var array Queue of headers to be sent on successful completion */
31
-    protected $headerQueue = array();
32
-    /** @var string The name of the route to use, as determined by the request router. */
33
-    private $routeName = null;
34
-    /** @var TokenManager */
35
-    protected $tokenManager;
36
-    /** @var string[] Extra CSS files to include */
37
-    private $extraCss = array();
38
-    /** @var string[] Extra JS files to include */
39
-    private $extraJs = array();
40
-
41
-    /**
42
-     * Sets the route the request will take. Only should be called from the request router or barrier test.
43
-     *
44
-     * @param string $routeName        The name of the route
45
-     * @param bool   $skipCallableTest Don't use this unless you know what you're doing, and what the implications are.
46
-     *
47
-     * @throws Exception
48
-     * @category Security-Critical
49
-     */
50
-    final public function setRoute($routeName, $skipCallableTest = false)
51
-    {
52
-        // Test the new route is callable before adopting it.
53
-        if (!$skipCallableTest && !is_callable(array($this, $routeName))) {
54
-            throw new Exception("Proposed route '$routeName' is not callable.");
55
-        }
56
-
57
-        // Adopt the new route
58
-        $this->routeName = $routeName;
59
-    }
60
-
61
-    /**
62
-     * Gets the name of the route that has been passed from the request router.
63
-     * @return string
64
-     */
65
-    final public function getRouteName()
66
-    {
67
-        return $this->routeName;
68
-    }
69
-
70
-    /**
71
-     * Performs generic page setup actions
72
-     */
73
-    final protected function setupPage()
74
-    {
75
-        $this->setUpSmarty();
76
-
77
-        $siteNoticeText = SiteNotice::get($this->getDatabase());
78
-
79
-        $this->assign('siteNoticeText', $siteNoticeText);
80
-
81
-        $currentUser = User::getCurrent($this->getDatabase());
82
-        $this->assign('currentUser', $currentUser);
83
-        $this->assign('loggedIn', (!$currentUser->isCommunityUser()));
84
-    }
85
-
86
-    /**
87
-     * Runs the page logic as routed by the RequestRouter
88
-     *
89
-     * Only should be called after a security barrier! That means only from execute().
90
-     */
91
-    final protected function runPage()
92
-    {
93
-        $database = $this->getDatabase();
94
-
95
-        // initialise a database transaction
96
-        if (!$database->beginTransaction()) {
97
-            throw new Exception('Failed to start transaction on primary database.');
98
-        }
99
-
100
-        try {
101
-            // run the page code
102
-            $this->{$this->getRouteName()}();
103
-
104
-            $database->commit();
105
-        }
106
-        catch (ApplicationLogicException $ex) {
107
-            // it's an application logic exception, so nothing went seriously wrong with the site. We can use the
108
-            // standard templating system for this.
109
-
110
-            // Firstly, let's undo anything that happened to the database.
111
-            $database->rollBack();
112
-
113
-            // Reset smarty
114
-            $this->setUpSmarty();
115
-
116
-            // Set the template
117
-            $this->setTemplate('exception/application-logic.tpl');
118
-            $this->assign('message', $ex->getMessage());
119
-
120
-            // Force this back to false
121
-            $this->isRedirecting = false;
122
-            $this->headerQueue = array();
123
-        }
124
-        catch (OptimisticLockFailedException $ex) {
125
-            // it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the
126
-            // standard templating system for this.
127
-
128
-            // Firstly, let's undo anything that happened to the database.
129
-            $database->rollBack();
130
-
131
-            // Reset smarty
132
-            $this->setUpSmarty();
133
-
134
-            // Set the template
135
-            $this->setTemplate('exception/optimistic-lock-failure.tpl');
136
-            $this->assign('message', $ex->getMessage());
137
-
138
-            // Force this back to false
139
-            $this->isRedirecting = false;
140
-            $this->headerQueue = array();
141
-        }
142
-        finally {
143
-            // Catch any hanging on transactions
144
-            if ($database->hasActiveTransaction()) {
145
-                $database->rollBack();
146
-            }
147
-        }
148
-
149
-        // run any finalisation code needed before we send the output to the browser.
150
-        $this->finalisePage();
151
-
152
-        // Send the headers
153
-        $this->sendResponseHeaders();
154
-
155
-        // Check we have a template to use!
156
-        if ($this->template !== null) {
157
-            $content = $this->fetchTemplate($this->template);
158
-            ob_clean();
159
-            print($content);
160
-            ob_flush();
161
-
162
-            return;
163
-        }
164
-    }
165
-
166
-    /**
167
-     * Performs final tasks needed before rendering the page.
168
-     */
169
-    protected function finalisePage()
170
-    {
171
-        if ($this->isRedirecting) {
172
-            $this->template = null;
173
-
174
-            return;
175
-        }
176
-
177
-        $this->assign('extraCss', $this->extraCss);
178
-        $this->assign('extraJs', $this->extraJs);
179
-
180
-        // If we're actually displaying content, we want to add the session alerts here!
181
-        $this->assign('alerts', SessionAlert::getAlerts());
182
-        SessionAlert::clearAlerts();
183
-
184
-        $this->assign('htmlTitle', $this->htmlTitle);
185
-    }
186
-
187
-    /**
188
-     * @return TokenManager
189
-     */
190
-    public function getTokenManager()
191
-    {
192
-        return $this->tokenManager;
193
-    }
194
-
195
-    /**
196
-     * @param TokenManager $tokenManager
197
-     */
198
-    public function setTokenManager($tokenManager)
199
-    {
200
-        $this->tokenManager = $tokenManager;
201
-    }
202
-
203
-    /**
204
-     * Sends the redirect headers to perform a GET at the destination page.
205
-     *
206
-     * Also nullifies the set template so Smarty does not render it.
207
-     *
208
-     * @param string      $page   The page to redirect requests to (as used in the UR)
209
-     * @param null|string $action The action to use on the page.
210
-     * @param null|array  $parameters
211
-     * @param null|string $script The script (relative to index.php) to redirect to
212
-     */
213
-    final protected function redirect($page = '', $action = null, $parameters = null, $script = null)
214
-    {
215
-        $currentScriptName = WebRequest::scriptName();
216
-
217
-        // Are we changing script?
218
-        if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) {
219
-            $targetScriptName = $currentScriptName;
220
-        }
221
-        else {
222
-            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
223
-        }
224
-
225
-        $pathInfo = array($targetScriptName);
226
-
227
-        $pathInfo[1] = $page;
228
-
229
-        if ($action !== null) {
230
-            $pathInfo[2] = $action;
231
-        }
232
-
233
-        $url = implode('/', $pathInfo);
234
-
235
-        if (is_array($parameters) && count($parameters) > 0) {
236
-            $url .= '?' . http_build_query($parameters);
237
-        }
238
-
239
-        $this->redirectUrl($url);
240
-    }
241
-
242
-    /**
243
-     * Sends the redirect headers to perform a GET at the new address.
244
-     *
245
-     * Also nullifies the set template so Smarty does not render it.
246
-     *
247
-     * @param string $path URL to redirect to
248
-     */
249
-    final protected function redirectUrl($path)
250
-    {
251
-        // 303 See Other = re-request at new address with a GET.
252
-        $this->headerQueue[] = 'HTTP/1.1 303 See Other';
253
-        $this->headerQueue[] = "Location: $path";
254
-
255
-        $this->setTemplate(null);
256
-        $this->isRedirecting = true;
257
-    }
258
-
259
-    /**
260
-     * Sets the name of the template this page should display.
261
-     *
262
-     * @param string $name
263
-     *
264
-     * @throws Exception
265
-     */
266
-    final protected function setTemplate($name)
267
-    {
268
-        if ($this->isRedirecting) {
269
-            throw new Exception('This page has been set as a redirect, no template can be displayed!');
270
-        }
271
-
272
-        $this->template = $name;
273
-    }
274
-
275
-    /**
276
-     * Adds an extra CSS file to to the page
277
-     *
278
-     * @param string $path The path (relative to the application root) of the file
279
-     */
280
-    final protected function addCss($path) {
281
-        if(in_array($path, $this->extraCss)){
282
-            // nothing to do
283
-            return;
284
-        }
285
-
286
-        $this->extraCss[] = $path;
287
-    }
288
-
289
-    /**
290
-     * Adds an extra JS file to to the page
291
-     *
292
-     * @param string $path The path (relative to the application root) of the file
293
-     */
294
-    final protected function addJs($path){
295
-        if(in_array($path, $this->extraJs)){
296
-            // nothing to do
297
-            return;
298
-        }
299
-
300
-        $this->extraJs[] = $path;
301
-    }
302
-
303
-    /**
304
-     * Main function for this page, when no specific actions are called.
305
-     * @return void
306
-     */
307
-    abstract protected function main();
308
-
309
-    /**
310
-     * @param string $title
311
-     */
312
-    final protected function setHtmlTitle($title)
313
-    {
314
-        $this->htmlTitle = $title;
315
-    }
316
-
317
-    public function execute()
318
-    {
319
-        if ($this->getRouteName() === null) {
320
-            throw new Exception('Request is unrouted.');
321
-        }
322
-
323
-        if ($this->getSiteConfiguration() === null) {
324
-            throw new Exception('Page has no configuration!');
325
-        }
326
-
327
-        $this->setupPage();
328
-
329
-        $this->runPage();
330
-    }
331
-
332
-    public function assignCSRFToken()
333
-    {
334
-        $token = $this->tokenManager->getNewToken();
335
-        $this->assign('csrfTokenData', $token->getTokenData());
336
-    }
337
-
338
-    public function validateCSRFToken()
339
-    {
340
-        if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) {
341
-            throw new ApplicationLogicException('Form token is not valid, please reload and try again');
342
-        }
343
-    }
344
-
345
-    protected function sendResponseHeaders()
346
-    {
347
-        if (headers_sent()) {
348
-            throw new ApplicationLogicException          ('Headers have already been sent! This is likely a bug in the application.');
349
-        }
350
-
351
-        foreach ($this->headerQueue as $item) {
352
-            if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) {
353
-                // Oops. We're not allowed to do this.
354
-                throw new Exception('Unable to split header');
355
-            }
356
-
357
-            header($item);
358
-        }
359
-    }
23
+	use TemplateOutput;
24
+	/** @var string Smarty template to display */
25
+	protected $template = "base.tpl";
26
+	/** @var string HTML title. Currently unused. */
27
+	protected $htmlTitle;
28
+	/** @var bool Determines if the page is a redirect or not */
29
+	protected $isRedirecting = false;
30
+	/** @var array Queue of headers to be sent on successful completion */
31
+	protected $headerQueue = array();
32
+	/** @var string The name of the route to use, as determined by the request router. */
33
+	private $routeName = null;
34
+	/** @var TokenManager */
35
+	protected $tokenManager;
36
+	/** @var string[] Extra CSS files to include */
37
+	private $extraCss = array();
38
+	/** @var string[] Extra JS files to include */
39
+	private $extraJs = array();
40
+
41
+	/**
42
+	 * Sets the route the request will take. Only should be called from the request router or barrier test.
43
+	 *
44
+	 * @param string $routeName        The name of the route
45
+	 * @param bool   $skipCallableTest Don't use this unless you know what you're doing, and what the implications are.
46
+	 *
47
+	 * @throws Exception
48
+	 * @category Security-Critical
49
+	 */
50
+	final public function setRoute($routeName, $skipCallableTest = false)
51
+	{
52
+		// Test the new route is callable before adopting it.
53
+		if (!$skipCallableTest && !is_callable(array($this, $routeName))) {
54
+			throw new Exception("Proposed route '$routeName' is not callable.");
55
+		}
56
+
57
+		// Adopt the new route
58
+		$this->routeName = $routeName;
59
+	}
60
+
61
+	/**
62
+	 * Gets the name of the route that has been passed from the request router.
63
+	 * @return string
64
+	 */
65
+	final public function getRouteName()
66
+	{
67
+		return $this->routeName;
68
+	}
69
+
70
+	/**
71
+	 * Performs generic page setup actions
72
+	 */
73
+	final protected function setupPage()
74
+	{
75
+		$this->setUpSmarty();
76
+
77
+		$siteNoticeText = SiteNotice::get($this->getDatabase());
78
+
79
+		$this->assign('siteNoticeText', $siteNoticeText);
80
+
81
+		$currentUser = User::getCurrent($this->getDatabase());
82
+		$this->assign('currentUser', $currentUser);
83
+		$this->assign('loggedIn', (!$currentUser->isCommunityUser()));
84
+	}
85
+
86
+	/**
87
+	 * Runs the page logic as routed by the RequestRouter
88
+	 *
89
+	 * Only should be called after a security barrier! That means only from execute().
90
+	 */
91
+	final protected function runPage()
92
+	{
93
+		$database = $this->getDatabase();
94
+
95
+		// initialise a database transaction
96
+		if (!$database->beginTransaction()) {
97
+			throw new Exception('Failed to start transaction on primary database.');
98
+		}
99
+
100
+		try {
101
+			// run the page code
102
+			$this->{$this->getRouteName()}();
103
+
104
+			$database->commit();
105
+		}
106
+		catch (ApplicationLogicException $ex) {
107
+			// it's an application logic exception, so nothing went seriously wrong with the site. We can use the
108
+			// standard templating system for this.
109
+
110
+			// Firstly, let's undo anything that happened to the database.
111
+			$database->rollBack();
112
+
113
+			// Reset smarty
114
+			$this->setUpSmarty();
115
+
116
+			// Set the template
117
+			$this->setTemplate('exception/application-logic.tpl');
118
+			$this->assign('message', $ex->getMessage());
119
+
120
+			// Force this back to false
121
+			$this->isRedirecting = false;
122
+			$this->headerQueue = array();
123
+		}
124
+		catch (OptimisticLockFailedException $ex) {
125
+			// it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the
126
+			// standard templating system for this.
127
+
128
+			// Firstly, let's undo anything that happened to the database.
129
+			$database->rollBack();
130
+
131
+			// Reset smarty
132
+			$this->setUpSmarty();
133
+
134
+			// Set the template
135
+			$this->setTemplate('exception/optimistic-lock-failure.tpl');
136
+			$this->assign('message', $ex->getMessage());
137
+
138
+			// Force this back to false
139
+			$this->isRedirecting = false;
140
+			$this->headerQueue = array();
141
+		}
142
+		finally {
143
+			// Catch any hanging on transactions
144
+			if ($database->hasActiveTransaction()) {
145
+				$database->rollBack();
146
+			}
147
+		}
148
+
149
+		// run any finalisation code needed before we send the output to the browser.
150
+		$this->finalisePage();
151
+
152
+		// Send the headers
153
+		$this->sendResponseHeaders();
154
+
155
+		// Check we have a template to use!
156
+		if ($this->template !== null) {
157
+			$content = $this->fetchTemplate($this->template);
158
+			ob_clean();
159
+			print($content);
160
+			ob_flush();
161
+
162
+			return;
163
+		}
164
+	}
165
+
166
+	/**
167
+	 * Performs final tasks needed before rendering the page.
168
+	 */
169
+	protected function finalisePage()
170
+	{
171
+		if ($this->isRedirecting) {
172
+			$this->template = null;
173
+
174
+			return;
175
+		}
176
+
177
+		$this->assign('extraCss', $this->extraCss);
178
+		$this->assign('extraJs', $this->extraJs);
179
+
180
+		// If we're actually displaying content, we want to add the session alerts here!
181
+		$this->assign('alerts', SessionAlert::getAlerts());
182
+		SessionAlert::clearAlerts();
183
+
184
+		$this->assign('htmlTitle', $this->htmlTitle);
185
+	}
186
+
187
+	/**
188
+	 * @return TokenManager
189
+	 */
190
+	public function getTokenManager()
191
+	{
192
+		return $this->tokenManager;
193
+	}
194
+
195
+	/**
196
+	 * @param TokenManager $tokenManager
197
+	 */
198
+	public function setTokenManager($tokenManager)
199
+	{
200
+		$this->tokenManager = $tokenManager;
201
+	}
202
+
203
+	/**
204
+	 * Sends the redirect headers to perform a GET at the destination page.
205
+	 *
206
+	 * Also nullifies the set template so Smarty does not render it.
207
+	 *
208
+	 * @param string      $page   The page to redirect requests to (as used in the UR)
209
+	 * @param null|string $action The action to use on the page.
210
+	 * @param null|array  $parameters
211
+	 * @param null|string $script The script (relative to index.php) to redirect to
212
+	 */
213
+	final protected function redirect($page = '', $action = null, $parameters = null, $script = null)
214
+	{
215
+		$currentScriptName = WebRequest::scriptName();
216
+
217
+		// Are we changing script?
218
+		if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) {
219
+			$targetScriptName = $currentScriptName;
220
+		}
221
+		else {
222
+			$targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
223
+		}
224
+
225
+		$pathInfo = array($targetScriptName);
226
+
227
+		$pathInfo[1] = $page;
228
+
229
+		if ($action !== null) {
230
+			$pathInfo[2] = $action;
231
+		}
232
+
233
+		$url = implode('/', $pathInfo);
234
+
235
+		if (is_array($parameters) && count($parameters) > 0) {
236
+			$url .= '?' . http_build_query($parameters);
237
+		}
238
+
239
+		$this->redirectUrl($url);
240
+	}
241
+
242
+	/**
243
+	 * Sends the redirect headers to perform a GET at the new address.
244
+	 *
245
+	 * Also nullifies the set template so Smarty does not render it.
246
+	 *
247
+	 * @param string $path URL to redirect to
248
+	 */
249
+	final protected function redirectUrl($path)
250
+	{
251
+		// 303 See Other = re-request at new address with a GET.
252
+		$this->headerQueue[] = 'HTTP/1.1 303 See Other';
253
+		$this->headerQueue[] = "Location: $path";
254
+
255
+		$this->setTemplate(null);
256
+		$this->isRedirecting = true;
257
+	}
258
+
259
+	/**
260
+	 * Sets the name of the template this page should display.
261
+	 *
262
+	 * @param string $name
263
+	 *
264
+	 * @throws Exception
265
+	 */
266
+	final protected function setTemplate($name)
267
+	{
268
+		if ($this->isRedirecting) {
269
+			throw new Exception('This page has been set as a redirect, no template can be displayed!');
270
+		}
271
+
272
+		$this->template = $name;
273
+	}
274
+
275
+	/**
276
+	 * Adds an extra CSS file to to the page
277
+	 *
278
+	 * @param string $path The path (relative to the application root) of the file
279
+	 */
280
+	final protected function addCss($path) {
281
+		if(in_array($path, $this->extraCss)){
282
+			// nothing to do
283
+			return;
284
+		}
285
+
286
+		$this->extraCss[] = $path;
287
+	}
288
+
289
+	/**
290
+	 * Adds an extra JS file to to the page
291
+	 *
292
+	 * @param string $path The path (relative to the application root) of the file
293
+	 */
294
+	final protected function addJs($path){
295
+		if(in_array($path, $this->extraJs)){
296
+			// nothing to do
297
+			return;
298
+		}
299
+
300
+		$this->extraJs[] = $path;
301
+	}
302
+
303
+	/**
304
+	 * Main function for this page, when no specific actions are called.
305
+	 * @return void
306
+	 */
307
+	abstract protected function main();
308
+
309
+	/**
310
+	 * @param string $title
311
+	 */
312
+	final protected function setHtmlTitle($title)
313
+	{
314
+		$this->htmlTitle = $title;
315
+	}
316
+
317
+	public function execute()
318
+	{
319
+		if ($this->getRouteName() === null) {
320
+			throw new Exception('Request is unrouted.');
321
+		}
322
+
323
+		if ($this->getSiteConfiguration() === null) {
324
+			throw new Exception('Page has no configuration!');
325
+		}
326
+
327
+		$this->setupPage();
328
+
329
+		$this->runPage();
330
+	}
331
+
332
+	public function assignCSRFToken()
333
+	{
334
+		$token = $this->tokenManager->getNewToken();
335
+		$this->assign('csrfTokenData', $token->getTokenData());
336
+	}
337
+
338
+	public function validateCSRFToken()
339
+	{
340
+		if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) {
341
+			throw new ApplicationLogicException('Form token is not valid, please reload and try again');
342
+		}
343
+	}
344
+
345
+	protected function sendResponseHeaders()
346
+	{
347
+		if (headers_sent()) {
348
+			throw new ApplicationLogicException          ('Headers have already been sent! This is likely a bug in the application.');
349
+		}
350
+
351
+		foreach ($this->headerQueue as $item) {
352
+			if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) {
353
+				// Oops. We're not allowed to do this.
354
+				throw new Exception('Unable to split header');
355
+			}
356
+
357
+			header($item);
358
+		}
359
+	}
360 360
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
             $targetScriptName = $currentScriptName;
220 220
         }
221 221
         else {
222
-            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
222
+            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl().'/'.$script;
223 223
         }
224 224
 
225 225
         $pathInfo = array($targetScriptName);
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
         $url = implode('/', $pathInfo);
234 234
 
235 235
         if (is_array($parameters) && count($parameters) > 0) {
236
-            $url .= '?' . http_build_query($parameters);
236
+            $url .= '?'.http_build_query($parameters);
237 237
         }
238 238
 
239 239
         $this->redirectUrl($url);
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
      * @param string $path The path (relative to the application root) of the file
279 279
      */
280 280
     final protected function addCss($path) {
281
-        if(in_array($path, $this->extraCss)){
281
+        if (in_array($path, $this->extraCss)) {
282 282
             // nothing to do
283 283
             return;
284 284
         }
@@ -291,8 +291,8 @@  discard block
 block discarded – undo
291 291
      *
292 292
      * @param string $path The path (relative to the application root) of the file
293 293
      */
294
-    final protected function addJs($path){
295
-        if(in_array($path, $this->extraJs)){
294
+    final protected function addJs($path) {
295
+        if (in_array($path, $this->extraJs)) {
296 296
             // nothing to do
297 297
             return;
298 298
         }
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
     protected function sendResponseHeaders()
346 346
     {
347 347
         if (headers_sent()) {
348
-            throw new ApplicationLogicException          ('Headers have already been sent! This is likely a bug in the application.');
348
+            throw new ApplicationLogicException('Headers have already been sent! This is likely a bug in the application.');
349 349
         }
350 350
 
351 351
         foreach ($this->headerQueue as $item) {
Please login to merge, or discard this patch.
Braces   +6 added lines, -4 removed lines patch added patch discarded remove patch
@@ -277,8 +277,9 @@  discard block
 block discarded – undo
277 277
      *
278 278
      * @param string $path The path (relative to the application root) of the file
279 279
      */
280
-    final protected function addCss($path) {
281
-        if(in_array($path, $this->extraCss)){
280
+    final protected function addCss($path)
281
+    {
282
+        if(in_array($path, $this->extraCss)) {
282 283
             // nothing to do
283 284
             return;
284 285
         }
@@ -291,8 +292,9 @@  discard block
 block discarded – undo
291 292
      *
292 293
      * @param string $path The path (relative to the application root) of the file
293 294
      */
294
-    final protected function addJs($path){
295
-        if(in_array($path, $this->extraJs)){
295
+    final protected function addJs($path)
296
+    {
297
+        if(in_array($path, $this->extraJs)) {
296 298
             // nothing to do
297 299
             return;
298 300
         }
Please login to merge, or discard this patch.
includes/IdentificationVerifier.php 3 patches
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -26,131 +26,131 @@  discard block
 block discarded – undo
26 26
  */
27 27
 class IdentificationVerifier
28 28
 {
29
-    /**
30
-     * This field is an array of parameters, in key => value format, that should be appended to the Meta Wikimedia
31
-     * Web Service Endpoint URL to query if a user is listed on the Identification Noticeboard.  Note that URL encoding
32
-     * of these values is *not* necessary; this is done automatically.
33
-     *
34
-     * @var string[]
35
-     * @category Security-Critical
36
-     */
37
-    private static $apiQueryParameters = array(
38
-        'action'   => 'query',
39
-        'format'   => 'json',
40
-        'prop'     => 'links',
41
-        'titles'   => 'Access to nonpublic information policy/Noticeboard',
42
-        // Username of the user to be checked, with User: prefix, goes here!  Set in isIdentifiedOnWiki()
43
-        'pltitles' => '',
44
-    );
45
-    /** @var HttpHelper */
46
-    private $httpHelper;
47
-    /** @var SiteConfiguration */
48
-    private $siteConfiguration;
49
-    /** @var PdoDatabase */
50
-    private $dbObject;
51
-
52
-    /**
53
-     * IdentificationVerifier constructor.
54
-     *
55
-     * @param HttpHelper        $httpHelper
56
-     * @param SiteConfiguration $siteConfiguration
57
-     * @param PdoDatabase       $dbObject
58
-     */
59
-    public function __construct(HttpHelper $httpHelper, SiteConfiguration $siteConfiguration, PdoDatabase $dbObject)
60
-    {
61
-        $this->httpHelper = $httpHelper;
62
-        $this->siteConfiguration = $siteConfiguration;
63
-        $this->dbObject = $dbObject;
64
-    }
65
-
66
-    /**
67
-     * Checks if the given user is identified to the Wikimedia Foundation.
68
-     *
69
-     * @param string $onWikiName The Wikipedia username of the user
70
-     *
71
-     * @return bool
72
-     * @category Security-Critical
73
-     */
74
-    public function isUserIdentified($onWikiName)
75
-    {
76
-        if ($this->checkIdentificationCache($onWikiName)) {
77
-            return true;
78
-        }
79
-        else {
80
-            if ($this->isIdentifiedOnWiki($onWikiName)) {
81
-                $this->cacheIdentificationStatus($onWikiName);
82
-
83
-                return true;
84
-            }
85
-            else {
86
-                return false;
87
-            }
88
-        }
89
-    }
90
-
91
-    /**
92
-     * Checks if the given user has a valid entry in the idcache table.
93
-     *
94
-     * @param string $onWikiName The Wikipedia username of the user
95
-     *
96
-     * @return bool
97
-     * @category Security-Critical
98
-     */
99
-    private function checkIdentificationCache($onWikiName)
100
-    {
101
-        $interval = $this->siteConfiguration->getIdentificationCacheExpiry();
102
-
103
-        $query = <<<SQL
29
+	/**
30
+	 * This field is an array of parameters, in key => value format, that should be appended to the Meta Wikimedia
31
+	 * Web Service Endpoint URL to query if a user is listed on the Identification Noticeboard.  Note that URL encoding
32
+	 * of these values is *not* necessary; this is done automatically.
33
+	 *
34
+	 * @var string[]
35
+	 * @category Security-Critical
36
+	 */
37
+	private static $apiQueryParameters = array(
38
+		'action'   => 'query',
39
+		'format'   => 'json',
40
+		'prop'     => 'links',
41
+		'titles'   => 'Access to nonpublic information policy/Noticeboard',
42
+		// Username of the user to be checked, with User: prefix, goes here!  Set in isIdentifiedOnWiki()
43
+		'pltitles' => '',
44
+	);
45
+	/** @var HttpHelper */
46
+	private $httpHelper;
47
+	/** @var SiteConfiguration */
48
+	private $siteConfiguration;
49
+	/** @var PdoDatabase */
50
+	private $dbObject;
51
+
52
+	/**
53
+	 * IdentificationVerifier constructor.
54
+	 *
55
+	 * @param HttpHelper        $httpHelper
56
+	 * @param SiteConfiguration $siteConfiguration
57
+	 * @param PdoDatabase       $dbObject
58
+	 */
59
+	public function __construct(HttpHelper $httpHelper, SiteConfiguration $siteConfiguration, PdoDatabase $dbObject)
60
+	{
61
+		$this->httpHelper = $httpHelper;
62
+		$this->siteConfiguration = $siteConfiguration;
63
+		$this->dbObject = $dbObject;
64
+	}
65
+
66
+	/**
67
+	 * Checks if the given user is identified to the Wikimedia Foundation.
68
+	 *
69
+	 * @param string $onWikiName The Wikipedia username of the user
70
+	 *
71
+	 * @return bool
72
+	 * @category Security-Critical
73
+	 */
74
+	public function isUserIdentified($onWikiName)
75
+	{
76
+		if ($this->checkIdentificationCache($onWikiName)) {
77
+			return true;
78
+		}
79
+		else {
80
+			if ($this->isIdentifiedOnWiki($onWikiName)) {
81
+				$this->cacheIdentificationStatus($onWikiName);
82
+
83
+				return true;
84
+			}
85
+			else {
86
+				return false;
87
+			}
88
+		}
89
+	}
90
+
91
+	/**
92
+	 * Checks if the given user has a valid entry in the idcache table.
93
+	 *
94
+	 * @param string $onWikiName The Wikipedia username of the user
95
+	 *
96
+	 * @return bool
97
+	 * @category Security-Critical
98
+	 */
99
+	private function checkIdentificationCache($onWikiName)
100
+	{
101
+		$interval = $this->siteConfiguration->getIdentificationCacheExpiry();
102
+
103
+		$query = <<<SQL
104 104
 			SELECT COUNT(`id`)
105 105
 			FROM `idcache`
106 106
 			WHERE `onwikiusername` = :onwikiname
107 107
 				AND DATE_ADD(`checktime`, INTERVAL {$interval}) >= NOW();
108 108
 SQL;
109
-        $stmt = $this->dbObject->prepare($query);
110
-        $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR);
111
-        $stmt->execute();
112
-
113
-        // Guaranteed by the query to only return a single row with a single column
114
-        $results = $stmt->fetch(PDO::FETCH_NUM);
115
-
116
-        // I don't expect this to ever be a value other than 0 or 1 since the `onwikiusername` column is declared as a
117
-        // unique key - but meh.
118
-        return $results[0] != 0;
119
-    }
120
-
121
-    /**
122
-     * Does pretty much exactly what it says on the label - this method will clear all expired idcache entries from the
123
-     * idcache table.  Meant to be called periodically by a maintenance script.
124
-     *
125
-     * @param SiteConfiguration $siteConfiguration
126
-     * @param PdoDatabase       $dbObject
127
-     *
128
-     * @return void
129
-     */
130
-    public static function clearExpiredCacheEntries(SiteConfiguration $siteConfiguration, PdoDatabase $dbObject)
131
-    {
132
-        $interval = $siteConfiguration->getIdentificationCacheExpiry();
133
-
134
-        $query = <<<SQL
109
+		$stmt = $this->dbObject->prepare($query);
110
+		$stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR);
111
+		$stmt->execute();
112
+
113
+		// Guaranteed by the query to only return a single row with a single column
114
+		$results = $stmt->fetch(PDO::FETCH_NUM);
115
+
116
+		// I don't expect this to ever be a value other than 0 or 1 since the `onwikiusername` column is declared as a
117
+		// unique key - but meh.
118
+		return $results[0] != 0;
119
+	}
120
+
121
+	/**
122
+	 * Does pretty much exactly what it says on the label - this method will clear all expired idcache entries from the
123
+	 * idcache table.  Meant to be called periodically by a maintenance script.
124
+	 *
125
+	 * @param SiteConfiguration $siteConfiguration
126
+	 * @param PdoDatabase       $dbObject
127
+	 *
128
+	 * @return void
129
+	 */
130
+	public static function clearExpiredCacheEntries(SiteConfiguration $siteConfiguration, PdoDatabase $dbObject)
131
+	{
132
+		$interval = $siteConfiguration->getIdentificationCacheExpiry();
133
+
134
+		$query = <<<SQL
135 135
 			DELETE FROM `idcache`
136 136
 			WHERE DATE_ADD(`checktime`, INTERVAL {$interval}) < NOW();
137 137
 SQL;
138
-        $dbObject->prepare($query)->execute();
139
-    }
140
-
141
-    /**
142
-     * This method will add an entry to the idcache that the given Wikipedia user has been verified as identified.  This
143
-     * is so we don't have to hit the API every single time we check.  The cache entry is valid for as long as specified
144
-     * in the ACC configuration (validity enforced by checkIdentificationCache() and clearExpiredCacheEntries()).
145
-     *
146
-     * @param string $onWikiName The Wikipedia username of the user
147
-     *
148
-     * @return void
149
-     * @category Security-Critical
150
-     */
151
-    private function cacheIdentificationStatus($onWikiName)
152
-    {
153
-        $query = <<<SQL
138
+		$dbObject->prepare($query)->execute();
139
+	}
140
+
141
+	/**
142
+	 * This method will add an entry to the idcache that the given Wikipedia user has been verified as identified.  This
143
+	 * is so we don't have to hit the API every single time we check.  The cache entry is valid for as long as specified
144
+	 * in the ACC configuration (validity enforced by checkIdentificationCache() and clearExpiredCacheEntries()).
145
+	 *
146
+	 * @param string $onWikiName The Wikipedia username of the user
147
+	 *
148
+	 * @return void
149
+	 * @category Security-Critical
150
+	 */
151
+	private function cacheIdentificationStatus($onWikiName)
152
+	{
153
+		$query = <<<SQL
154 154
 			INSERT INTO `idcache`
155 155
 				(`onwikiusername`)
156 156
 			VALUES
@@ -159,44 +159,44 @@  discard block
 block discarded – undo
159 159
 				`onwikiusername` = VALUES(`onwikiusername`),
160 160
 				`checktime` = CURRENT_TIMESTAMP;
161 161
 SQL;
162
-        $stmt = $this->dbObject->prepare($query);
163
-        $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR);
164
-        $stmt->execute();
165
-    }
166
-
167
-    /**
168
-     * Queries the Wikimedia API to determine if the specified user is listed on the identification noticeboard.
169
-     *
170
-     * @param string $onWikiName The Wikipedia username of the user
171
-     *
172
-     * @return bool
173
-     * @throws EnvironmentException
174
-     * @category Security-Critical
175
-     */
176
-    private function isIdentifiedOnWiki($onWikiName)
177
-    {
178
-        $strings = new StringFunctions();
179
-
180
-        // First character of Wikipedia usernames is always capitalized.
181
-        $onWikiName = $strings->ucfirst($onWikiName);
182
-
183
-        $parameters = self::$apiQueryParameters;
184
-        $parameters['pltitles'] = "User:" . $onWikiName;
185
-
186
-        try {
187
-            $endpoint = $this->siteConfiguration->getMetaWikimediaWebServiceEndpoint();
188
-            $response = $this->httpHelper->get($endpoint, $parameters);
189
-            $response = json_decode($response, true);
190
-        } catch (CurlException $ex) {
191
-            // failed getting identification status, so throw a nicer error.
192
-            $m = 'Could not contact metawiki API to determine user\' identification status. '
193
-                . 'This is probably a transient error, so please try again.';
194
-
195
-            throw new EnvironmentException($m, 0, $ex);
196
-        }
197
-
198
-        $page = @array_pop($response['query']['pages']);
199
-
200
-        return @$page['links'][0]['title'] === "User:" . $onWikiName;
201
-    }
162
+		$stmt = $this->dbObject->prepare($query);
163
+		$stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR);
164
+		$stmt->execute();
165
+	}
166
+
167
+	/**
168
+	 * Queries the Wikimedia API to determine if the specified user is listed on the identification noticeboard.
169
+	 *
170
+	 * @param string $onWikiName The Wikipedia username of the user
171
+	 *
172
+	 * @return bool
173
+	 * @throws EnvironmentException
174
+	 * @category Security-Critical
175
+	 */
176
+	private function isIdentifiedOnWiki($onWikiName)
177
+	{
178
+		$strings = new StringFunctions();
179
+
180
+		// First character of Wikipedia usernames is always capitalized.
181
+		$onWikiName = $strings->ucfirst($onWikiName);
182
+
183
+		$parameters = self::$apiQueryParameters;
184
+		$parameters['pltitles'] = "User:" . $onWikiName;
185
+
186
+		try {
187
+			$endpoint = $this->siteConfiguration->getMetaWikimediaWebServiceEndpoint();
188
+			$response = $this->httpHelper->get($endpoint, $parameters);
189
+			$response = json_decode($response, true);
190
+		} catch (CurlException $ex) {
191
+			// failed getting identification status, so throw a nicer error.
192
+			$m = 'Could not contact metawiki API to determine user\' identification status. '
193
+				. 'This is probably a transient error, so please try again.';
194
+
195
+			throw new EnvironmentException($m, 0, $ex);
196
+		}
197
+
198
+		$page = @array_pop($response['query']['pages']);
199
+
200
+		return @$page['links'][0]['title'] === "User:" . $onWikiName;
201
+	}
202 202
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -187,7 +187,8 @@
 block discarded – undo
187 187
             $endpoint = $this->siteConfiguration->getMetaWikimediaWebServiceEndpoint();
188 188
             $response = $this->httpHelper->get($endpoint, $parameters);
189 189
             $response = json_decode($response, true);
190
-        } catch (CurlException $ex) {
190
+        }
191
+        catch (CurlException $ex) {
191 192
             // failed getting identification status, so throw a nicer error.
192 193
             $m = 'Could not contact metawiki API to determine user\' identification status. '
193 194
                 . 'This is probably a transient error, so please try again.';
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
         $onWikiName = $strings->ucfirst($onWikiName);
182 182
 
183 183
         $parameters = self::$apiQueryParameters;
184
-        $parameters['pltitles'] = "User:" . $onWikiName;
184
+        $parameters['pltitles'] = "User:".$onWikiName;
185 185
 
186 186
         try {
187 187
             $endpoint = $this->siteConfiguration->getMetaWikimediaWebServiceEndpoint();
@@ -197,6 +197,6 @@  discard block
 block discarded – undo
197 197
 
198 198
         $page = @array_pop($response['query']['pages']);
199 199
 
200
-        return @$page['links'][0]['title'] === "User:" . $onWikiName;
200
+        return @$page['links'][0]['title'] === "User:".$onWikiName;
201 201
     }
202 202
 }
Please login to merge, or discard this patch.
includes/Exceptions/AccessDeniedException.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -11,9 +11,7 @@
 block discarded – undo
11 11
 use Waca\DataObjects\Log;
12 12
 use Waca\DataObjects\User;
13 13
 use Waca\Fragments\NavigationMenuAccessControl;
14
-use Waca\Helpers\HttpHelper;
15 14
 use Waca\Helpers\SearchHelpers\LogSearchHelper;
16
-use Waca\IdentificationVerifier;
17 15
 use Waca\PdoDatabase;
18 16
 use Waca\Security\SecurityManager;
19 17
 
Please login to merge, or discard this patch.
Indentation   +85 added lines, -85 removed lines patch added patch discarded remove patch
@@ -26,89 +26,89 @@
 block discarded – undo
26 26
  */
27 27
 class AccessDeniedException extends ReadableException
28 28
 {
29
-    use NavigationMenuAccessControl;
30
-
31
-    /**
32
-     * @var SecurityManager
33
-     */
34
-    private $securityManager;
35
-
36
-    /**
37
-     * AccessDeniedException constructor.
38
-     *
39
-     * @param SecurityManager $securityManager
40
-     */
41
-    public function __construct(SecurityManager $securityManager = null)
42
-    {
43
-        $this->securityManager = $securityManager;
44
-    }
45
-
46
-    public function getReadableError()
47
-    {
48
-        if (!headers_sent()) {
49
-            header("HTTP/1.1 403 Forbidden");
50
-        }
51
-
52
-        $this->setUpSmarty();
53
-
54
-        // uck. We should still be able to access the database in this situation though.
55
-        $database = PdoDatabase::getDatabaseConnection('acc');
56
-        $currentUser = User::getCurrent($database);
57
-        $this->assign('currentUser', $currentUser);
58
-        $this->assign("loggedIn", (!$currentUser->isCommunityUser()));
59
-
60
-        if($this->securityManager !== null) {
61
-            $this->setupNavMenuAccess($currentUser);
62
-        }
63
-
64
-        if ($currentUser->isDeclined()) {
65
-            $this->assign('htmlTitle', 'Account Declined');
66
-            $this->assign('declineReason', $this->getLogEntry('Declined', $currentUser, $database));
67
-
68
-            return $this->fetchTemplate("exception/account-declined.tpl");
69
-        }
70
-
71
-        if ($currentUser->isSuspended()) {
72
-            $this->assign('htmlTitle', 'Account Suspended');
73
-            $this->assign('suspendReason', $this->getLogEntry('Suspended', $currentUser, $database));
74
-
75
-            return $this->fetchTemplate("exception/account-suspended.tpl");
76
-        }
77
-
78
-        if ($currentUser->isNewUser()) {
79
-            $this->assign('htmlTitle', 'Account Pending');
80
-
81
-            return $this->fetchTemplate("exception/account-new.tpl");
82
-        }
83
-
84
-        return $this->fetchTemplate("exception/access-denied.tpl");
85
-    }
86
-
87
-    /**
88
-     * @param string      $action
89
-     * @param User        $user
90
-     * @param PdoDatabase $database
91
-     *
92
-     * @return null|string
93
-     */
94
-    private function getLogEntry($action, User $user, PdoDatabase $database)
95
-    {
96
-        /** @var Log[] $logs */
97
-        $logs = LogSearchHelper::get($database)
98
-            ->byAction($action)
99
-            ->byObjectType('User')
100
-            ->byObjectId($user->getId())
101
-            ->limit(1)
102
-            ->fetch();
103
-
104
-        return $logs[0]->getComment();
105
-    }
106
-
107
-    /**
108
-     * @return SecurityManager
109
-     */
110
-    protected function getSecurityManager()
111
-    {
112
-        return $this->securityManager;
113
-    }
29
+	use NavigationMenuAccessControl;
30
+
31
+	/**
32
+	 * @var SecurityManager
33
+	 */
34
+	private $securityManager;
35
+
36
+	/**
37
+	 * AccessDeniedException constructor.
38
+	 *
39
+	 * @param SecurityManager $securityManager
40
+	 */
41
+	public function __construct(SecurityManager $securityManager = null)
42
+	{
43
+		$this->securityManager = $securityManager;
44
+	}
45
+
46
+	public function getReadableError()
47
+	{
48
+		if (!headers_sent()) {
49
+			header("HTTP/1.1 403 Forbidden");
50
+		}
51
+
52
+		$this->setUpSmarty();
53
+
54
+		// uck. We should still be able to access the database in this situation though.
55
+		$database = PdoDatabase::getDatabaseConnection('acc');
56
+		$currentUser = User::getCurrent($database);
57
+		$this->assign('currentUser', $currentUser);
58
+		$this->assign("loggedIn", (!$currentUser->isCommunityUser()));
59
+
60
+		if($this->securityManager !== null) {
61
+			$this->setupNavMenuAccess($currentUser);
62
+		}
63
+
64
+		if ($currentUser->isDeclined()) {
65
+			$this->assign('htmlTitle', 'Account Declined');
66
+			$this->assign('declineReason', $this->getLogEntry('Declined', $currentUser, $database));
67
+
68
+			return $this->fetchTemplate("exception/account-declined.tpl");
69
+		}
70
+
71
+		if ($currentUser->isSuspended()) {
72
+			$this->assign('htmlTitle', 'Account Suspended');
73
+			$this->assign('suspendReason', $this->getLogEntry('Suspended', $currentUser, $database));
74
+
75
+			return $this->fetchTemplate("exception/account-suspended.tpl");
76
+		}
77
+
78
+		if ($currentUser->isNewUser()) {
79
+			$this->assign('htmlTitle', 'Account Pending');
80
+
81
+			return $this->fetchTemplate("exception/account-new.tpl");
82
+		}
83
+
84
+		return $this->fetchTemplate("exception/access-denied.tpl");
85
+	}
86
+
87
+	/**
88
+	 * @param string      $action
89
+	 * @param User        $user
90
+	 * @param PdoDatabase $database
91
+	 *
92
+	 * @return null|string
93
+	 */
94
+	private function getLogEntry($action, User $user, PdoDatabase $database)
95
+	{
96
+		/** @var Log[] $logs */
97
+		$logs = LogSearchHelper::get($database)
98
+			->byAction($action)
99
+			->byObjectType('User')
100
+			->byObjectId($user->getId())
101
+			->limit(1)
102
+			->fetch();
103
+
104
+		return $logs[0]->getComment();
105
+	}
106
+
107
+	/**
108
+	 * @return SecurityManager
109
+	 */
110
+	protected function getSecurityManager()
111
+	{
112
+		return $this->securityManager;
113
+	}
114 114
 }
115 115
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
         $this->assign('currentUser', $currentUser);
58 58
         $this->assign("loggedIn", (!$currentUser->isCommunityUser()));
59 59
 
60
-        if($this->securityManager !== null) {
60
+        if ($this->securityManager !== null) {
61 61
             $this->setupNavMenuAccess($currentUser);
62 62
         }
63 63
 
Please login to merge, or discard this patch.
includes/Fragments/NavigationMenuAccessControl.php 2 patches
Doc Comments   +5 added lines, -1 removed lines patch added patch discarded remove patch
@@ -24,6 +24,10 @@  discard block
 block discarded – undo
24 24
 
25 25
 trait NavigationMenuAccessControl
26 26
 {
27
+    /**
28
+     * @param string $name
29
+     * @param boolean $value
30
+     */
27 31
     protected abstract function assign($name, $value);
28 32
 
29 33
     /**
@@ -32,7 +36,7 @@  discard block
 block discarded – undo
32 36
     protected abstract function getSecurityManager();
33 37
 
34 38
     /**
35
-     * @param $currentUser
39
+     * @param \Waca\DataObjects\User $currentUser
36 40
      */
37 41
     protected function setupNavMenuAccess($currentUser)
38 42
     {
Please login to merge, or discard this patch.
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -24,45 +24,45 @@
 block discarded – undo
24 24
 
25 25
 trait NavigationMenuAccessControl
26 26
 {
27
-    protected abstract function assign($name, $value);
27
+	protected abstract function assign($name, $value);
28 28
 
29
-    /**
30
-     * @return SecurityManager
31
-     */
32
-    protected abstract function getSecurityManager();
29
+	/**
30
+	 * @return SecurityManager
31
+	 */
32
+	protected abstract function getSecurityManager();
33 33
 
34
-    /**
35
-     * @param $currentUser
36
-     */
37
-    protected function setupNavMenuAccess($currentUser)
38
-    {
39
-        $this->assign('nav__canRequests', $this->getSecurityManager()
40
-                ->allows(PageMain::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
34
+	/**
35
+	 * @param $currentUser
36
+	 */
37
+	protected function setupNavMenuAccess($currentUser)
38
+	{
39
+		$this->assign('nav__canRequests', $this->getSecurityManager()
40
+				->allows(PageMain::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
41 41
 
42
-        $this->assign('nav__canLogs', $this->getSecurityManager()
43
-                ->allows(PageLog::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
44
-        $this->assign('nav__canUsers', $this->getSecurityManager()
45
-                ->allows(StatsUsers::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
46
-        $this->assign('nav__canSearch', $this->getSecurityManager()
47
-                ->allows(PageSearch::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
48
-        $this->assign('nav__canStats', $this->getSecurityManager()
49
-                ->allows(StatsMain::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
42
+		$this->assign('nav__canLogs', $this->getSecurityManager()
43
+				->allows(PageLog::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
44
+		$this->assign('nav__canUsers', $this->getSecurityManager()
45
+				->allows(StatsUsers::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
46
+		$this->assign('nav__canSearch', $this->getSecurityManager()
47
+				->allows(PageSearch::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
48
+		$this->assign('nav__canStats', $this->getSecurityManager()
49
+				->allows(StatsMain::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
50 50
 
51
-        $this->assign('nav__canBan', $this->getSecurityManager()
52
-                ->allows(PageBan::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
53
-        $this->assign('nav__canEmailMgmt', $this->getSecurityManager()
54
-                ->allows(PageEmailManagement::class, RoleConfiguration::MAIN,
55
-                    $currentUser) === SecurityManager::ALLOWED);
56
-        $this->assign('nav__canWelcomeMgmt', $this->getSecurityManager()
57
-                ->allows(PageWelcomeTemplateManagement::class, RoleConfiguration::MAIN,
58
-                    $currentUser) === SecurityManager::ALLOWED);
59
-        $this->assign('nav__canSiteNoticeMgmt', $this->getSecurityManager()
60
-                ->allows(PageSiteNotice::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
61
-        $this->assign('nav__canUserMgmt', $this->getSecurityManager()
62
-                ->allows(PageUserManagement::class, RoleConfiguration::MAIN,
63
-                    $currentUser) === SecurityManager::ALLOWED);
51
+		$this->assign('nav__canBan', $this->getSecurityManager()
52
+				->allows(PageBan::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
53
+		$this->assign('nav__canEmailMgmt', $this->getSecurityManager()
54
+				->allows(PageEmailManagement::class, RoleConfiguration::MAIN,
55
+					$currentUser) === SecurityManager::ALLOWED);
56
+		$this->assign('nav__canWelcomeMgmt', $this->getSecurityManager()
57
+				->allows(PageWelcomeTemplateManagement::class, RoleConfiguration::MAIN,
58
+					$currentUser) === SecurityManager::ALLOWED);
59
+		$this->assign('nav__canSiteNoticeMgmt', $this->getSecurityManager()
60
+				->allows(PageSiteNotice::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
61
+		$this->assign('nav__canUserMgmt', $this->getSecurityManager()
62
+				->allows(PageUserManagement::class, RoleConfiguration::MAIN,
63
+					$currentUser) === SecurityManager::ALLOWED);
64 64
 
65
-        $this->assign('nav__canViewRequest', $this->getSecurityManager()
66
-                ->allows(PageViewRequest::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
67
-    }
65
+		$this->assign('nav__canViewRequest', $this->getSecurityManager()
66
+				->allows(PageViewRequest::class, RoleConfiguration::MAIN, $currentUser) === SecurityManager::ALLOWED);
67
+	}
68 68
 }
69 69
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/Registration/PageRegisterBase.php 2 patches
Doc Comments   +8 added lines, -5 removed lines patch added patch discarded remove patch
@@ -44,6 +44,9 @@  discard block
 block discarded – undo
44 44
         }
45 45
     }
46 46
 
47
+    /**
48
+     * @return string
49
+     */
47 50
     protected abstract function getRegistrationTemplate();
48 51
 
49 52
     protected function isProtectedPage()
@@ -70,12 +73,12 @@  discard block
 block discarded – undo
70 73
     }
71 74
 
72 75
     /**
73
-     * @param $emailAddress
74
-     * @param $password
75
-     * @param $username
76
+     * @param null|string $emailAddress
77
+     * @param null|string $password
78
+     * @param null|string $username
76 79
      * @param $useOAuthSignup
77
-     * @param $confirmationId
78
-     * @param $onwikiUsername
80
+     * @param null|integer $confirmationId
81
+     * @param null|string $onwikiUsername
79 82
      *
80 83
      * @throws ApplicationLogicException
81 84
      */
Please login to merge, or discard this patch.
Indentation   +198 added lines, -198 removed lines patch added patch discarded remove patch
@@ -18,202 +18,202 @@
 block discarded – undo
18 18
 
19 19
 abstract class PageRegisterBase extends InternalPageBase
20 20
 {
21
-    /**
22
-     * Main function for this page, when no specific actions are called.
23
-     */
24
-    protected function main()
25
-    {
26
-        $useOAuthSignup = $this->getSiteConfiguration()->getUseOAuthSignup();
27
-
28
-        // Dual-mode page
29
-        if (WebRequest::wasPosted()) {
30
-            $this->validateCSRFToken();
31
-
32
-            try {
33
-                $this->handlePost($useOAuthSignup);
34
-            }
35
-            catch (ApplicationLogicException $ex) {
36
-                SessionAlert::error($ex->getMessage());
37
-                $this->redirect('register');
38
-            }
39
-        }
40
-        else {
41
-            $this->assignCSRFToken();
42
-            $this->assign("useOAuthSignup", $useOAuthSignup);
43
-            $this->setTemplate($this->getRegistrationTemplate());
44
-        }
45
-    }
46
-
47
-    protected abstract function getRegistrationTemplate();
48
-
49
-    protected function isProtectedPage()
50
-    {
51
-        return false;
52
-    }
53
-
54
-    /**
55
-     * @param string $emailAddress
56
-     *
57
-     * @throws ApplicationLogicException
58
-     */
59
-    protected function validateUniqueEmail($emailAddress)
60
-    {
61
-        $query = 'SELECT COUNT(id) FROM user WHERE email = :email';
62
-        $statement = $this->getDatabase()->prepare($query);
63
-        $statement->execute(array(':email' => $emailAddress));
64
-
65
-        if ($statement->fetchColumn() > 0) {
66
-            throw new ApplicationLogicException('That email address is already in use on this system.');
67
-        }
68
-
69
-        $statement->closeCursor();
70
-    }
71
-
72
-    /**
73
-     * @param $emailAddress
74
-     * @param $password
75
-     * @param $username
76
-     * @param $useOAuthSignup
77
-     * @param $confirmationId
78
-     * @param $onwikiUsername
79
-     *
80
-     * @throws ApplicationLogicException
81
-     */
82
-    protected function validateRequest(
83
-        $emailAddress,
84
-        $password,
85
-        $username,
86
-        $useOAuthSignup,
87
-        $confirmationId,
88
-        $onwikiUsername
89
-    ) {
90
-        if (!WebRequest::postBoolean('guidelines')) {
91
-            throw new ApplicationLogicException('You must read the interface guidelines before your request may be submitted.');
92
-        }
93
-
94
-        $this->validateGeneralInformation($emailAddress, $password, $username);
95
-        $this->validateUniqueEmail($emailAddress);
96
-        $this->validateNonOAuthFields($useOAuthSignup, $confirmationId, $onwikiUsername);
97
-    }
98
-
99
-    /**
100
-     * @param $useOAuthSignup
101
-     * @param $confirmationId
102
-     * @param $onwikiUsername
103
-     *
104
-     * @throws ApplicationLogicException
105
-     */
106
-    protected function validateNonOAuthFields($useOAuthSignup, $confirmationId, $onwikiUsername)
107
-    {
108
-        if (!$useOAuthSignup) {
109
-            if ($confirmationId === null || $confirmationId <= 0) {
110
-                throw new ApplicationLogicException('Please enter the revision id of your confirmation edit.');
111
-            }
112
-
113
-            if ($onwikiUsername === null) {
114
-                throw new ApplicationLogicException('Please specify your on-wiki username.');
115
-            }
116
-        }
117
-    }
118
-
119
-    /**
120
-     * @param $emailAddress
121
-     * @param $password
122
-     * @param $username
123
-     *
124
-     * @throws ApplicationLogicException
125
-     */
126
-    protected function validateGeneralInformation($emailAddress, $password, $username)
127
-    {
128
-        if ($emailAddress === null) {
129
-            throw new ApplicationLogicException('Your email address appears to be invalid!');
130
-        }
131
-
132
-        if ($password !== WebRequest::postString('pass2')) {
133
-            throw new ApplicationLogicException('Your passwords did not match, please try again.');
134
-        }
135
-
136
-        if (User::getByUsername($username, $this->getDatabase()) !== false) {
137
-            throw new ApplicationLogicException('That username is already in use on this system.');
138
-        }
139
-    }
140
-
141
-    /**
142
-     * @param $useOAuthSignup
143
-     *
144
-     * @throws ApplicationLogicException
145
-     * @throws \Exception
146
-     */
147
-    protected function handlePost($useOAuthSignup)
148
-    {
149
-        // Get the data
150
-        $emailAddress = WebRequest::postEmail('email');
151
-        $password = WebRequest::postString('pass');
152
-        $username = WebRequest::postString('name');
153
-
154
-        // Only set if OAuth is disabled
155
-        $confirmationId = WebRequest::postInt('conf_revid');
156
-        $onwikiUsername = WebRequest::postString('wname');
157
-
158
-        // Do some validation
159
-        $this->validateRequest($emailAddress, $password, $username, $useOAuthSignup, $confirmationId,
160
-            $onwikiUsername);
161
-
162
-        $database = $this->getDatabase();
163
-
164
-        $user = new User();
165
-        $user->setDatabase($database);
166
-
167
-        $user->setUsername($username);
168
-        $user->setPassword($password);
169
-        $user->setEmail($emailAddress);
170
-
171
-        if (!$useOAuthSignup) {
172
-            $user->setOnWikiName($onwikiUsername);
173
-            $user->setConfirmationDiff($confirmationId);
174
-        }
175
-
176
-        $user->save();
177
-
178
-        $defaultRole = $this->getDefaultRole();
179
-
180
-        $role = new UserRole();
181
-        $role->setDatabase($database);
182
-        $role->setUser($user->getId());
183
-        $role->setRole($defaultRole);
184
-        $role->save();
185
-
186
-        // Log now to get the signup date.
187
-        Logger::newUser($database, $user);
188
-        Logger::userRolesEdited($database, $user, 'Registration', array($defaultRole), array());
189
-
190
-        if ($useOAuthSignup) {
191
-            $oauthHelper = $this->getOAuthHelper();
192
-
193
-            $requestToken = $oauthHelper->getRequestToken();
194
-            $user->setOAuthRequestToken($requestToken->key);
195
-            $user->setOAuthRequestSecret($requestToken->secret);
196
-            $user->save();
197
-
198
-            WebRequest::setPartialLogin($user);
199
-
200
-            $this->redirectUrl($oauthHelper->getAuthoriseUrl($requestToken->key));
201
-        }
202
-        else {
203
-            // only notify if we're not using the oauth signup.
204
-            $this->getNotificationHelper()->userNew($user);
205
-            WebRequest::setLoggedInUser($user);
206
-            $this->redirect('preferences');
207
-        }
208
-    }
209
-
210
-    protected abstract function getDefaultRole();
211
-
212
-    /**
213
-     * Entry point for registration complete
214
-     */
215
-    protected function done()
216
-    {
217
-        $this->setTemplate('registration/alert-registrationcomplete.tpl');
218
-    }
21
+	/**
22
+	 * Main function for this page, when no specific actions are called.
23
+	 */
24
+	protected function main()
25
+	{
26
+		$useOAuthSignup = $this->getSiteConfiguration()->getUseOAuthSignup();
27
+
28
+		// Dual-mode page
29
+		if (WebRequest::wasPosted()) {
30
+			$this->validateCSRFToken();
31
+
32
+			try {
33
+				$this->handlePost($useOAuthSignup);
34
+			}
35
+			catch (ApplicationLogicException $ex) {
36
+				SessionAlert::error($ex->getMessage());
37
+				$this->redirect('register');
38
+			}
39
+		}
40
+		else {
41
+			$this->assignCSRFToken();
42
+			$this->assign("useOAuthSignup", $useOAuthSignup);
43
+			$this->setTemplate($this->getRegistrationTemplate());
44
+		}
45
+	}
46
+
47
+	protected abstract function getRegistrationTemplate();
48
+
49
+	protected function isProtectedPage()
50
+	{
51
+		return false;
52
+	}
53
+
54
+	/**
55
+	 * @param string $emailAddress
56
+	 *
57
+	 * @throws ApplicationLogicException
58
+	 */
59
+	protected function validateUniqueEmail($emailAddress)
60
+	{
61
+		$query = 'SELECT COUNT(id) FROM user WHERE email = :email';
62
+		$statement = $this->getDatabase()->prepare($query);
63
+		$statement->execute(array(':email' => $emailAddress));
64
+
65
+		if ($statement->fetchColumn() > 0) {
66
+			throw new ApplicationLogicException('That email address is already in use on this system.');
67
+		}
68
+
69
+		$statement->closeCursor();
70
+	}
71
+
72
+	/**
73
+	 * @param $emailAddress
74
+	 * @param $password
75
+	 * @param $username
76
+	 * @param $useOAuthSignup
77
+	 * @param $confirmationId
78
+	 * @param $onwikiUsername
79
+	 *
80
+	 * @throws ApplicationLogicException
81
+	 */
82
+	protected function validateRequest(
83
+		$emailAddress,
84
+		$password,
85
+		$username,
86
+		$useOAuthSignup,
87
+		$confirmationId,
88
+		$onwikiUsername
89
+	) {
90
+		if (!WebRequest::postBoolean('guidelines')) {
91
+			throw new ApplicationLogicException('You must read the interface guidelines before your request may be submitted.');
92
+		}
93
+
94
+		$this->validateGeneralInformation($emailAddress, $password, $username);
95
+		$this->validateUniqueEmail($emailAddress);
96
+		$this->validateNonOAuthFields($useOAuthSignup, $confirmationId, $onwikiUsername);
97
+	}
98
+
99
+	/**
100
+	 * @param $useOAuthSignup
101
+	 * @param $confirmationId
102
+	 * @param $onwikiUsername
103
+	 *
104
+	 * @throws ApplicationLogicException
105
+	 */
106
+	protected function validateNonOAuthFields($useOAuthSignup, $confirmationId, $onwikiUsername)
107
+	{
108
+		if (!$useOAuthSignup) {
109
+			if ($confirmationId === null || $confirmationId <= 0) {
110
+				throw new ApplicationLogicException('Please enter the revision id of your confirmation edit.');
111
+			}
112
+
113
+			if ($onwikiUsername === null) {
114
+				throw new ApplicationLogicException('Please specify your on-wiki username.');
115
+			}
116
+		}
117
+	}
118
+
119
+	/**
120
+	 * @param $emailAddress
121
+	 * @param $password
122
+	 * @param $username
123
+	 *
124
+	 * @throws ApplicationLogicException
125
+	 */
126
+	protected function validateGeneralInformation($emailAddress, $password, $username)
127
+	{
128
+		if ($emailAddress === null) {
129
+			throw new ApplicationLogicException('Your email address appears to be invalid!');
130
+		}
131
+
132
+		if ($password !== WebRequest::postString('pass2')) {
133
+			throw new ApplicationLogicException('Your passwords did not match, please try again.');
134
+		}
135
+
136
+		if (User::getByUsername($username, $this->getDatabase()) !== false) {
137
+			throw new ApplicationLogicException('That username is already in use on this system.');
138
+		}
139
+	}
140
+
141
+	/**
142
+	 * @param $useOAuthSignup
143
+	 *
144
+	 * @throws ApplicationLogicException
145
+	 * @throws \Exception
146
+	 */
147
+	protected function handlePost($useOAuthSignup)
148
+	{
149
+		// Get the data
150
+		$emailAddress = WebRequest::postEmail('email');
151
+		$password = WebRequest::postString('pass');
152
+		$username = WebRequest::postString('name');
153
+
154
+		// Only set if OAuth is disabled
155
+		$confirmationId = WebRequest::postInt('conf_revid');
156
+		$onwikiUsername = WebRequest::postString('wname');
157
+
158
+		// Do some validation
159
+		$this->validateRequest($emailAddress, $password, $username, $useOAuthSignup, $confirmationId,
160
+			$onwikiUsername);
161
+
162
+		$database = $this->getDatabase();
163
+
164
+		$user = new User();
165
+		$user->setDatabase($database);
166
+
167
+		$user->setUsername($username);
168
+		$user->setPassword($password);
169
+		$user->setEmail($emailAddress);
170
+
171
+		if (!$useOAuthSignup) {
172
+			$user->setOnWikiName($onwikiUsername);
173
+			$user->setConfirmationDiff($confirmationId);
174
+		}
175
+
176
+		$user->save();
177
+
178
+		$defaultRole = $this->getDefaultRole();
179
+
180
+		$role = new UserRole();
181
+		$role->setDatabase($database);
182
+		$role->setUser($user->getId());
183
+		$role->setRole($defaultRole);
184
+		$role->save();
185
+
186
+		// Log now to get the signup date.
187
+		Logger::newUser($database, $user);
188
+		Logger::userRolesEdited($database, $user, 'Registration', array($defaultRole), array());
189
+
190
+		if ($useOAuthSignup) {
191
+			$oauthHelper = $this->getOAuthHelper();
192
+
193
+			$requestToken = $oauthHelper->getRequestToken();
194
+			$user->setOAuthRequestToken($requestToken->key);
195
+			$user->setOAuthRequestSecret($requestToken->secret);
196
+			$user->save();
197
+
198
+			WebRequest::setPartialLogin($user);
199
+
200
+			$this->redirectUrl($oauthHelper->getAuthoriseUrl($requestToken->key));
201
+		}
202
+		else {
203
+			// only notify if we're not using the oauth signup.
204
+			$this->getNotificationHelper()->userNew($user);
205
+			WebRequest::setLoggedInUser($user);
206
+			$this->redirect('preferences');
207
+		}
208
+	}
209
+
210
+	protected abstract function getDefaultRole();
211
+
212
+	/**
213
+	 * Entry point for registration complete
214
+	 */
215
+	protected function done()
216
+	{
217
+		$this->setTemplate('registration/alert-registrationcomplete.tpl');
218
+	}
219 219
 }
Please login to merge, or discard this patch.
includes/Router/RequestRouter.php 2 patches
Unused Use Statements   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -21,14 +21,14 @@
 block discarded – undo
21 21
 use Waca\Pages\PageMain;
22 22
 use Waca\Pages\PageOAuth;
23 23
 use Waca\Pages\PagePreferences;
24
-use Waca\Pages\Registration\PageRegisterStandard;
25
-use Waca\Pages\Registration\PageRegisterOption;
26 24
 use Waca\Pages\PageSearch;
27 25
 use Waca\Pages\PageSiteNotice;
28 26
 use Waca\Pages\PageTeam;
29 27
 use Waca\Pages\PageUserManagement;
30 28
 use Waca\Pages\PageViewRequest;
31 29
 use Waca\Pages\PageWelcomeTemplateManagement;
30
+use Waca\Pages\Registration\PageRegisterOption;
31
+use Waca\Pages\Registration\PageRegisterStandard;
32 32
 use Waca\Pages\RequestAction\PageBreakReservation;
33 33
 use Waca\Pages\RequestAction\PageCloseRequest;
34 34
 use Waca\Pages\RequestAction\PageComment;
Please login to merge, or discard this patch.
Indentation   +391 added lines, -391 removed lines patch added patch discarded remove patch
@@ -55,395 +55,395 @@
 block discarded – undo
55 55
  */
56 56
 class RequestRouter implements IRequestRouter
57 57
 {
58
-    /**
59
-     * This is the core routing table for the application. The basic idea is:
60
-     *
61
-     *      array(
62
-     *          "foo" =>
63
-     *              array(
64
-     *                  "class"   => PageFoo::class,
65
-     *                  "actions" => array("bar", "other")
66
-     *              ),
67
-     * );
68
-     *
69
-     * Things to note:
70
-     *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
71
-     *
72
-     *     - If a page is defined and requested, but no action is requested, go to that page's main() method
73
-     *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
74
-     *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
75
-     *       method.
76
-     *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
77
-     *
78
-     *     - Query parameters are ignored.
79
-     *
80
-     * The key point here is request routing with validation that this is allowed, before we start hitting the
81
-     * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
82
-     * before we start calling random methods through the web UI.
83
-     *
84
-     * Examples:
85
-     * /internal.php                => returns instance of PageMain, routed to main()
86
-     * /internal.php?query          => returns instance of PageMain, routed to main()
87
-     * /internal.php/foo            => returns instance of PageFoo, routed to main()
88
-     * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
89
-     * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
90
-     * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
91
-     * /internal.php/foo/baz        => returns instance of Page404, routed to main()
92
-     * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
93
-     * /internal.php/bar            => returns instance of Page404, routed to main()
94
-     * /internal.php/bar?query      => returns instance of Page404, routed to main()
95
-     * /internal.php/bar/baz        => returns instance of Page404, routed to main()
96
-     * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
97
-     *
98
-     * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
99
-     * to change the key, then you'll likely have to update a lot of files.
100
-     *
101
-     * @var array
102
-     */
103
-    private $routeMap = array(
104
-
105
-        //////////////////////////////////////////////////////////////////////////////////////////////////
106
-        // Login and registration
107
-        'logout'                      =>
108
-            array(
109
-                'class'   => PageLogout::class,
110
-                'actions' => array(),
111
-            ),
112
-        'login'                       =>
113
-            array(
114
-                'class'   => PageLogin::class,
115
-                'actions' => array(),
116
-            ),
117
-        'forgotPassword'              =>
118
-            array(
119
-                'class'   => PageForgotPassword::class,
120
-                'actions' => array('reset'),
121
-            ),
122
-        'register'                    =>
123
-            array(
124
-                'class'   => PageRegisterOption::class,
125
-                'actions' => array(),
126
-            ),
127
-        'register/standard'           =>
128
-            array(
129
-                'class'   => PageRegisterStandard::class,
130
-                'actions' => array('done'),
131
-            ),
132
-
133
-        //////////////////////////////////////////////////////////////////////////////////////////////////
134
-        // Discovery
135
-        'search'                      =>
136
-            array(
137
-                'class'   => PageSearch::class,
138
-                'actions' => array(),
139
-            ),
140
-        'logs'                        =>
141
-            array(
142
-                'class'   => PageLog::class,
143
-                'actions' => array(),
144
-            ),
145
-
146
-        //////////////////////////////////////////////////////////////////////////////////////////////////
147
-        // Administration
148
-        'bans'                        =>
149
-            array(
150
-                'class'   => PageBan::class,
151
-                'actions' => array('set', 'remove'),
152
-            ),
153
-        'userManagement'              =>
154
-            array(
155
-                'class'   => PageUserManagement::class,
156
-                'actions' => array(
157
-                    'approve',
158
-                    'decline',
159
-                    'rename',
160
-                    'editUser',
161
-                    'suspend',
162
-                    'editRoles',
163
-                ),
164
-            ),
165
-        'siteNotice'                  =>
166
-            array(
167
-                'class'   => PageSiteNotice::class,
168
-                'actions' => array(),
169
-            ),
170
-        'emailManagement'             =>
171
-            array(
172
-                'class'   => PageEmailManagement::class,
173
-                'actions' => array('create', 'edit', 'view'),
174
-            ),
175
-
176
-        //////////////////////////////////////////////////////////////////////////////////////////////////
177
-        // Personal preferences
178
-        'preferences'                 =>
179
-            array(
180
-                'class'   => PagePreferences::class,
181
-                'actions' => array('changePassword'),
182
-            ),
183
-        'oauth'                       =>
184
-            array(
185
-                'class'   => PageOAuth::class,
186
-                'actions' => array('detach', 'attach'),
187
-            ),
188
-
189
-        //////////////////////////////////////////////////////////////////////////////////////////////////
190
-        // Welcomer configuration
191
-        'welcomeTemplates'            =>
192
-            array(
193
-                'class'   => PageWelcomeTemplateManagement::class,
194
-                'actions' => array('select', 'edit', 'delete', 'add', 'view'),
195
-            ),
196
-
197
-        //////////////////////////////////////////////////////////////////////////////////////////////////
198
-        // Statistics
199
-        'statistics'                  =>
200
-            array(
201
-                'class'   => StatsMain::class,
202
-                'actions' => array(),
203
-            ),
204
-        'statistics/fastCloses'       =>
205
-            array(
206
-                'class'   => StatsFastCloses::class,
207
-                'actions' => array(),
208
-            ),
209
-        'statistics/inactiveUsers'    =>
210
-            array(
211
-                'class'   => StatsInactiveUsers::class,
212
-                'actions' => array(),
213
-            ),
214
-        'statistics/monthlyStats'     =>
215
-            array(
216
-                'class'   => StatsMonthlyStats::class,
217
-                'actions' => array(),
218
-            ),
219
-        'statistics/reservedRequests' =>
220
-            array(
221
-                'class'   => StatsReservedRequests::class,
222
-                'actions' => array(),
223
-            ),
224
-        'statistics/templateStats'    =>
225
-            array(
226
-                'class'   => StatsTemplateStats::class,
227
-                'actions' => array(),
228
-            ),
229
-        'statistics/topCreators'      =>
230
-            array(
231
-                'class'   => StatsTopCreators::class,
232
-                'actions' => array(),
233
-            ),
234
-        'statistics/users'            =>
235
-            array(
236
-                'class'   => StatsUsers::class,
237
-                'actions' => array('detail'),
238
-            ),
239
-
240
-        //////////////////////////////////////////////////////////////////////////////////////////////////
241
-        // Zoom page
242
-        'viewRequest'                 =>
243
-            array(
244
-                'class'   => PageViewRequest::class,
245
-                'actions' => array(),
246
-            ),
247
-        'viewRequest/reserve'         =>
248
-            array(
249
-                'class'   => PageReservation::class,
250
-                'actions' => array(),
251
-            ),
252
-        'viewRequest/breakReserve'    =>
253
-            array(
254
-                'class'   => PageBreakReservation::class,
255
-                'actions' => array(),
256
-            ),
257
-        'viewRequest/defer'           =>
258
-            array(
259
-                'class'   => PageDeferRequest::class,
260
-                'actions' => array(),
261
-            ),
262
-        'viewRequest/comment'         =>
263
-            array(
264
-                'class'   => PageComment::class,
265
-                'actions' => array(),
266
-            ),
267
-        'viewRequest/sendToUser'      =>
268
-            array(
269
-                'class'   => PageSendToUser::class,
270
-                'actions' => array(),
271
-            ),
272
-        'viewRequest/close'           =>
273
-            array(
274
-                'class'   => PageCloseRequest::class,
275
-                'actions' => array(),
276
-            ),
277
-        'viewRequest/drop'            =>
278
-            array(
279
-                'class'   => PageDropRequest::class,
280
-                'actions' => array(),
281
-            ),
282
-        'viewRequest/custom'          =>
283
-            array(
284
-                'class'   => PageCustomClose::class,
285
-                'actions' => array(),
286
-            ),
287
-        'editComment'                 =>
288
-            array(
289
-                'class'   => PageEditComment::class,
290
-                'actions' => array(),
291
-            ),
292
-
293
-        //////////////////////////////////////////////////////////////////////////////////////////////////
294
-        // Misc stuff
295
-        'team'                        =>
296
-            array(
297
-                'class'   => PageTeam::class,
298
-                'actions' => array(),
299
-            ),
300
-        'requestList'                 =>
301
-            array(
302
-                'class'   => PageExpandedRequestList::class,
303
-                'actions' => array(),
304
-            ),
305
-    );
306
-
307
-    /**
308
-     * @return IRoutedTask
309
-     * @throws Exception
310
-     */
311
-    final public function route()
312
-    {
313
-        $pathInfo = WebRequest::pathInfo();
314
-
315
-        list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
316
-
317
-        /** @var IRoutedTask $page */
318
-        $page = new $pageClass();
319
-
320
-        // Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
321
-        // let's use our own.
322
-        if (!($page instanceof IRoutedTask)) {
323
-            throw new Exception('Expected a page, but this is not a page.');
324
-        }
325
-
326
-        // 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
327
-        // inherits PageBase and has been created from the routing map.
328
-        $page->setRoute($action);
329
-
330
-        return $page;
331
-    }
332
-
333
-    /**
334
-     * @param $pathInfo
335
-     *
336
-     * @return array
337
-     */
338
-    protected function getRouteFromPath($pathInfo)
339
-    {
340
-        if (count($pathInfo) === 0) {
341
-            // No pathInfo, so no page to load. Load the main page.
342
-            return $this->getDefaultRoute();
343
-        }
344
-        elseif (count($pathInfo) === 1) {
345
-            // Exactly one path info segment, it's got to be a page.
346
-            $classSegment = $pathInfo[0];
347
-
348
-            return $this->routeSinglePathSegment($classSegment);
349
-        }
350
-
351
-        // OK, we have two or more segments now.
352
-        if (count($pathInfo) > 2) {
353
-            // Let's handle more than two, and collapse it down into two.
354
-            $requestedAction = array_pop($pathInfo);
355
-            $classSegment = implode('/', $pathInfo);
356
-        }
357
-        else {
358
-            // Two path info segments.
359
-            $classSegment = $pathInfo[0];
360
-            $requestedAction = $pathInfo[1];
361
-        }
362
-
363
-        $routeMap = $this->routePathSegments($classSegment, $requestedAction);
364
-
365
-        if ($routeMap[0] === Page404::class) {
366
-            $routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
367
-        }
368
-
369
-        return $routeMap;
370
-    }
371
-
372
-    /**
373
-     * @param $classSegment
374
-     *
375
-     * @return array
376
-     */
377
-    final protected function routeSinglePathSegment($classSegment)
378
-    {
379
-        $routeMap = $this->getRouteMap();
380
-        if (array_key_exists($classSegment, $routeMap)) {
381
-            // Route exists, but we don't have an action in path info, so default to main.
382
-            $pageClass = $routeMap[$classSegment]['class'];
383
-            $action = 'main';
384
-
385
-            return array($pageClass, $action);
386
-        }
387
-        else {
388
-            // Doesn't exist in map. Fall back to 404
389
-            $pageClass = Page404::class;
390
-            $action = "main";
391
-
392
-            return array($pageClass, $action);
393
-        }
394
-    }
395
-
396
-    /**
397
-     * @param $classSegment
398
-     * @param $requestedAction
399
-     *
400
-     * @return array
401
-     */
402
-    final protected function routePathSegments($classSegment, $requestedAction)
403
-    {
404
-        $routeMap = $this->getRouteMap();
405
-        if (array_key_exists($classSegment, $routeMap)) {
406
-            // Route exists, but we don't have an action in path info, so default to main.
407
-
408
-            if (isset($routeMap[$classSegment]['actions'])
409
-                && array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
410
-            ) {
411
-                // Action exists in allowed action list. Allow both the page and the action
412
-                $pageClass = $routeMap[$classSegment]['class'];
413
-                $action = $requestedAction;
414
-
415
-                return array($pageClass, $action);
416
-            }
417
-            else {
418
-                // Valid page, invalid action. 404 our way out.
419
-                $pageClass = Page404::class;
420
-                $action = 'main';
421
-
422
-                return array($pageClass, $action);
423
-            }
424
-        }
425
-        else {
426
-            // Class doesn't exist in map. Fall back to 404
427
-            $pageClass = Page404::class;
428
-            $action = 'main';
429
-
430
-            return array($pageClass, $action);
431
-        }
432
-    }
433
-
434
-    /**
435
-     * @return array
436
-     */
437
-    protected function getRouteMap()
438
-    {
439
-        return $this->routeMap;
440
-    }
441
-
442
-    /**
443
-     * @return callable
444
-     */
445
-    protected function getDefaultRoute()
446
-    {
447
-        return array(PageMain::class, "main");
448
-    }
58
+	/**
59
+	 * This is the core routing table for the application. The basic idea is:
60
+	 *
61
+	 *      array(
62
+	 *          "foo" =>
63
+	 *              array(
64
+	 *                  "class"   => PageFoo::class,
65
+	 *                  "actions" => array("bar", "other")
66
+	 *              ),
67
+	 * );
68
+	 *
69
+	 * Things to note:
70
+	 *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
71
+	 *
72
+	 *     - If a page is defined and requested, but no action is requested, go to that page's main() method
73
+	 *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
74
+	 *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
75
+	 *       method.
76
+	 *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
77
+	 *
78
+	 *     - Query parameters are ignored.
79
+	 *
80
+	 * The key point here is request routing with validation that this is allowed, before we start hitting the
81
+	 * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
82
+	 * before we start calling random methods through the web UI.
83
+	 *
84
+	 * Examples:
85
+	 * /internal.php                => returns instance of PageMain, routed to main()
86
+	 * /internal.php?query          => returns instance of PageMain, routed to main()
87
+	 * /internal.php/foo            => returns instance of PageFoo, routed to main()
88
+	 * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
89
+	 * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
90
+	 * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
91
+	 * /internal.php/foo/baz        => returns instance of Page404, routed to main()
92
+	 * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
93
+	 * /internal.php/bar            => returns instance of Page404, routed to main()
94
+	 * /internal.php/bar?query      => returns instance of Page404, routed to main()
95
+	 * /internal.php/bar/baz        => returns instance of Page404, routed to main()
96
+	 * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
97
+	 *
98
+	 * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
99
+	 * to change the key, then you'll likely have to update a lot of files.
100
+	 *
101
+	 * @var array
102
+	 */
103
+	private $routeMap = array(
104
+
105
+		//////////////////////////////////////////////////////////////////////////////////////////////////
106
+		// Login and registration
107
+		'logout'                      =>
108
+			array(
109
+				'class'   => PageLogout::class,
110
+				'actions' => array(),
111
+			),
112
+		'login'                       =>
113
+			array(
114
+				'class'   => PageLogin::class,
115
+				'actions' => array(),
116
+			),
117
+		'forgotPassword'              =>
118
+			array(
119
+				'class'   => PageForgotPassword::class,
120
+				'actions' => array('reset'),
121
+			),
122
+		'register'                    =>
123
+			array(
124
+				'class'   => PageRegisterOption::class,
125
+				'actions' => array(),
126
+			),
127
+		'register/standard'           =>
128
+			array(
129
+				'class'   => PageRegisterStandard::class,
130
+				'actions' => array('done'),
131
+			),
132
+
133
+		//////////////////////////////////////////////////////////////////////////////////////////////////
134
+		// Discovery
135
+		'search'                      =>
136
+			array(
137
+				'class'   => PageSearch::class,
138
+				'actions' => array(),
139
+			),
140
+		'logs'                        =>
141
+			array(
142
+				'class'   => PageLog::class,
143
+				'actions' => array(),
144
+			),
145
+
146
+		//////////////////////////////////////////////////////////////////////////////////////////////////
147
+		// Administration
148
+		'bans'                        =>
149
+			array(
150
+				'class'   => PageBan::class,
151
+				'actions' => array('set', 'remove'),
152
+			),
153
+		'userManagement'              =>
154
+			array(
155
+				'class'   => PageUserManagement::class,
156
+				'actions' => array(
157
+					'approve',
158
+					'decline',
159
+					'rename',
160
+					'editUser',
161
+					'suspend',
162
+					'editRoles',
163
+				),
164
+			),
165
+		'siteNotice'                  =>
166
+			array(
167
+				'class'   => PageSiteNotice::class,
168
+				'actions' => array(),
169
+			),
170
+		'emailManagement'             =>
171
+			array(
172
+				'class'   => PageEmailManagement::class,
173
+				'actions' => array('create', 'edit', 'view'),
174
+			),
175
+
176
+		//////////////////////////////////////////////////////////////////////////////////////////////////
177
+		// Personal preferences
178
+		'preferences'                 =>
179
+			array(
180
+				'class'   => PagePreferences::class,
181
+				'actions' => array('changePassword'),
182
+			),
183
+		'oauth'                       =>
184
+			array(
185
+				'class'   => PageOAuth::class,
186
+				'actions' => array('detach', 'attach'),
187
+			),
188
+
189
+		//////////////////////////////////////////////////////////////////////////////////////////////////
190
+		// Welcomer configuration
191
+		'welcomeTemplates'            =>
192
+			array(
193
+				'class'   => PageWelcomeTemplateManagement::class,
194
+				'actions' => array('select', 'edit', 'delete', 'add', 'view'),
195
+			),
196
+
197
+		//////////////////////////////////////////////////////////////////////////////////////////////////
198
+		// Statistics
199
+		'statistics'                  =>
200
+			array(
201
+				'class'   => StatsMain::class,
202
+				'actions' => array(),
203
+			),
204
+		'statistics/fastCloses'       =>
205
+			array(
206
+				'class'   => StatsFastCloses::class,
207
+				'actions' => array(),
208
+			),
209
+		'statistics/inactiveUsers'    =>
210
+			array(
211
+				'class'   => StatsInactiveUsers::class,
212
+				'actions' => array(),
213
+			),
214
+		'statistics/monthlyStats'     =>
215
+			array(
216
+				'class'   => StatsMonthlyStats::class,
217
+				'actions' => array(),
218
+			),
219
+		'statistics/reservedRequests' =>
220
+			array(
221
+				'class'   => StatsReservedRequests::class,
222
+				'actions' => array(),
223
+			),
224
+		'statistics/templateStats'    =>
225
+			array(
226
+				'class'   => StatsTemplateStats::class,
227
+				'actions' => array(),
228
+			),
229
+		'statistics/topCreators'      =>
230
+			array(
231
+				'class'   => StatsTopCreators::class,
232
+				'actions' => array(),
233
+			),
234
+		'statistics/users'            =>
235
+			array(
236
+				'class'   => StatsUsers::class,
237
+				'actions' => array('detail'),
238
+			),
239
+
240
+		//////////////////////////////////////////////////////////////////////////////////////////////////
241
+		// Zoom page
242
+		'viewRequest'                 =>
243
+			array(
244
+				'class'   => PageViewRequest::class,
245
+				'actions' => array(),
246
+			),
247
+		'viewRequest/reserve'         =>
248
+			array(
249
+				'class'   => PageReservation::class,
250
+				'actions' => array(),
251
+			),
252
+		'viewRequest/breakReserve'    =>
253
+			array(
254
+				'class'   => PageBreakReservation::class,
255
+				'actions' => array(),
256
+			),
257
+		'viewRequest/defer'           =>
258
+			array(
259
+				'class'   => PageDeferRequest::class,
260
+				'actions' => array(),
261
+			),
262
+		'viewRequest/comment'         =>
263
+			array(
264
+				'class'   => PageComment::class,
265
+				'actions' => array(),
266
+			),
267
+		'viewRequest/sendToUser'      =>
268
+			array(
269
+				'class'   => PageSendToUser::class,
270
+				'actions' => array(),
271
+			),
272
+		'viewRequest/close'           =>
273
+			array(
274
+				'class'   => PageCloseRequest::class,
275
+				'actions' => array(),
276
+			),
277
+		'viewRequest/drop'            =>
278
+			array(
279
+				'class'   => PageDropRequest::class,
280
+				'actions' => array(),
281
+			),
282
+		'viewRequest/custom'          =>
283
+			array(
284
+				'class'   => PageCustomClose::class,
285
+				'actions' => array(),
286
+			),
287
+		'editComment'                 =>
288
+			array(
289
+				'class'   => PageEditComment::class,
290
+				'actions' => array(),
291
+			),
292
+
293
+		//////////////////////////////////////////////////////////////////////////////////////////////////
294
+		// Misc stuff
295
+		'team'                        =>
296
+			array(
297
+				'class'   => PageTeam::class,
298
+				'actions' => array(),
299
+			),
300
+		'requestList'                 =>
301
+			array(
302
+				'class'   => PageExpandedRequestList::class,
303
+				'actions' => array(),
304
+			),
305
+	);
306
+
307
+	/**
308
+	 * @return IRoutedTask
309
+	 * @throws Exception
310
+	 */
311
+	final public function route()
312
+	{
313
+		$pathInfo = WebRequest::pathInfo();
314
+
315
+		list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
316
+
317
+		/** @var IRoutedTask $page */
318
+		$page = new $pageClass();
319
+
320
+		// Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
321
+		// let's use our own.
322
+		if (!($page instanceof IRoutedTask)) {
323
+			throw new Exception('Expected a page, but this is not a page.');
324
+		}
325
+
326
+		// 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
327
+		// inherits PageBase and has been created from the routing map.
328
+		$page->setRoute($action);
329
+
330
+		return $page;
331
+	}
332
+
333
+	/**
334
+	 * @param $pathInfo
335
+	 *
336
+	 * @return array
337
+	 */
338
+	protected function getRouteFromPath($pathInfo)
339
+	{
340
+		if (count($pathInfo) === 0) {
341
+			// No pathInfo, so no page to load. Load the main page.
342
+			return $this->getDefaultRoute();
343
+		}
344
+		elseif (count($pathInfo) === 1) {
345
+			// Exactly one path info segment, it's got to be a page.
346
+			$classSegment = $pathInfo[0];
347
+
348
+			return $this->routeSinglePathSegment($classSegment);
349
+		}
350
+
351
+		// OK, we have two or more segments now.
352
+		if (count($pathInfo) > 2) {
353
+			// Let's handle more than two, and collapse it down into two.
354
+			$requestedAction = array_pop($pathInfo);
355
+			$classSegment = implode('/', $pathInfo);
356
+		}
357
+		else {
358
+			// Two path info segments.
359
+			$classSegment = $pathInfo[0];
360
+			$requestedAction = $pathInfo[1];
361
+		}
362
+
363
+		$routeMap = $this->routePathSegments($classSegment, $requestedAction);
364
+
365
+		if ($routeMap[0] === Page404::class) {
366
+			$routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
367
+		}
368
+
369
+		return $routeMap;
370
+	}
371
+
372
+	/**
373
+	 * @param $classSegment
374
+	 *
375
+	 * @return array
376
+	 */
377
+	final protected function routeSinglePathSegment($classSegment)
378
+	{
379
+		$routeMap = $this->getRouteMap();
380
+		if (array_key_exists($classSegment, $routeMap)) {
381
+			// Route exists, but we don't have an action in path info, so default to main.
382
+			$pageClass = $routeMap[$classSegment]['class'];
383
+			$action = 'main';
384
+
385
+			return array($pageClass, $action);
386
+		}
387
+		else {
388
+			// Doesn't exist in map. Fall back to 404
389
+			$pageClass = Page404::class;
390
+			$action = "main";
391
+
392
+			return array($pageClass, $action);
393
+		}
394
+	}
395
+
396
+	/**
397
+	 * @param $classSegment
398
+	 * @param $requestedAction
399
+	 *
400
+	 * @return array
401
+	 */
402
+	final protected function routePathSegments($classSegment, $requestedAction)
403
+	{
404
+		$routeMap = $this->getRouteMap();
405
+		if (array_key_exists($classSegment, $routeMap)) {
406
+			// Route exists, but we don't have an action in path info, so default to main.
407
+
408
+			if (isset($routeMap[$classSegment]['actions'])
409
+				&& array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
410
+			) {
411
+				// Action exists in allowed action list. Allow both the page and the action
412
+				$pageClass = $routeMap[$classSegment]['class'];
413
+				$action = $requestedAction;
414
+
415
+				return array($pageClass, $action);
416
+			}
417
+			else {
418
+				// Valid page, invalid action. 404 our way out.
419
+				$pageClass = Page404::class;
420
+				$action = 'main';
421
+
422
+				return array($pageClass, $action);
423
+			}
424
+		}
425
+		else {
426
+			// Class doesn't exist in map. Fall back to 404
427
+			$pageClass = Page404::class;
428
+			$action = 'main';
429
+
430
+			return array($pageClass, $action);
431
+		}
432
+	}
433
+
434
+	/**
435
+	 * @return array
436
+	 */
437
+	protected function getRouteMap()
438
+	{
439
+		return $this->routeMap;
440
+	}
441
+
442
+	/**
443
+	 * @return callable
444
+	 */
445
+	protected function getDefaultRoute()
446
+	{
447
+		return array(PageMain::class, "main");
448
+	}
449 449
 }
Please login to merge, or discard this patch.
includes/Security/SecurityManager.php 3 patches
Indentation   +196 added lines, -196 removed lines patch added patch discarded remove patch
@@ -14,200 +14,200 @@
 block discarded – undo
14 14
 
15 15
 final class SecurityManager
16 16
 {
17
-    const ALLOWED = 1;
18
-    const ERROR_NOT_IDENTIFIED = 2;
19
-    const ERROR_DENIED = 3;
20
-    /** @var IdentificationVerifier */
21
-    private $identificationVerifier;
22
-    /**
23
-     * @var RoleConfiguration
24
-     */
25
-    private $roleConfiguration;
26
-
27
-    /**
28
-     * SecurityManager constructor.
29
-     *
30
-     * @param IdentificationVerifier $identificationVerifier
31
-     * @param RoleConfiguration      $roleConfiguration
32
-     */
33
-    public function __construct(
34
-        IdentificationVerifier $identificationVerifier,
35
-        RoleConfiguration $roleConfiguration
36
-    ) {
37
-        $this->identificationVerifier = $identificationVerifier;
38
-        $this->roleConfiguration = $roleConfiguration;
39
-    }
40
-
41
-    /**
42
-     * Tests if a user is allowed to perform an action.
43
-     *
44
-     * This method should form a hard, deterministic security barrier, and only return true if it is absolutely sure
45
-     * that a user should have access to something.
46
-     *
47
-     * @param string $page
48
-     * @param string $route
49
-     * @param User   $user
50
-     *
51
-     * @return int
52
-     *
53
-     * @category Security-Critical
54
-     */
55
-    public function allows($page, $route, User $user)
56
-    {
57
-        $this->getActiveRoles($user, $activeRoles, $inactiveRoles);
58
-
59
-        $availableRights = $this->flattenRoles($activeRoles);
60
-        $testResult = $this->findResult($availableRights, $page, $route);
61
-
62
-        if ($testResult !== null) {
63
-            // We got a firm result here, so just return it.
64
-            return $testResult;
65
-        }
66
-
67
-        // No firm result yet, so continue testing the inactive roles so we can give a better error.
68
-        $inactiveRights = $this->flattenRoles($inactiveRoles);
69
-        $testResult = $this->findResult($inactiveRights, $page, $route);
70
-
71
-        if ($testResult === self::ALLOWED) {
72
-            // The user is allowed to access this, but their role is inactive.
73
-            return self::ERROR_NOT_IDENTIFIED;
74
-        }
75
-
76
-        // Other options from the secondary test are denied and inconclusive, which at this point defaults to denied.
77
-        return self::ERROR_DENIED;
78
-    }
79
-
80
-    /**
81
-     * @param array  $pseudoRole The role (flattened) to check
82
-     * @param string $page       The page class to check
83
-     * @param string $route      The page route to check
84
-     *
85
-     * @return int|null
86
-     */
87
-    private function findResult($pseudoRole, $page, $route)
88
-    {
89
-        if (isset($pseudoRole[$page])) {
90
-            // check for deny on catch-all route
91
-            if (isset($pseudoRole[$page][RoleConfiguration::ALL])) {
92
-                if ($pseudoRole[$page][RoleConfiguration::ALL] === RoleConfiguration::ACCESS_DENY) {
93
-                    return self::ERROR_DENIED;
94
-                }
95
-            }
96
-
97
-            // check normal route
98
-            if (isset($pseudoRole[$page][$route])) {
99
-                if ($pseudoRole[$page][$route] === RoleConfiguration::ACCESS_DENY) {
100
-                    return self::ERROR_DENIED;
101
-                }
102
-
103
-                if ($pseudoRole[$page][$route] === RoleConfiguration::ACCESS_ALLOW) {
104
-                    return self::ALLOWED;
105
-                }
106
-            }
107
-
108
-            // check for allowed on catch-all route
109
-            if (isset($pseudoRole[$page][RoleConfiguration::ALL])) {
110
-                if ($pseudoRole[$page][RoleConfiguration::ALL] === RoleConfiguration::ACCESS_ALLOW) {
111
-                    return self::ALLOWED;
112
-                }
113
-            }
114
-        }
115
-
116
-        // return indeterminate result
117
-        return null;
118
-    }
119
-
120
-    /**
121
-     * Takes an array of roles and flattens the values to a single set.
122
-     *
123
-     * @param array $activeRoles
124
-     *
125
-     * @return array
126
-     */
127
-    private function flattenRoles($activeRoles)
128
-    {
129
-        $result = array();
130
-
131
-        $roleConfig = $this->roleConfiguration->getApplicableRoles($activeRoles);
132
-
133
-        // Iterate over every page in every role
134
-        foreach ($roleConfig as $role) {
135
-            foreach ($role as $page => $pageRights) {
136
-                // Create holder in result for this page
137
-                if (!isset($result[$page])) {
138
-                    $result[$page] = array();
139
-                }
140
-
141
-                foreach ($pageRights as $action => $permission) {
142
-                    // Deny takes precedence, so if it's set, don't change it.
143
-                    if (isset($result[$page][$action])) {
144
-                        if ($result[$page][$action] === RoleConfiguration::ACCESS_DENY) {
145
-                            continue;
146
-                        }
147
-                    }
148
-
149
-                    if ($permission === RoleConfiguration::ACCESS_DEFAULT) {
150
-                        // Configured to do precisely nothing.
151
-                        continue;
152
-                    }
153
-
154
-                    $result[$page][$action] = $permission;
155
-                }
156
-            }
157
-        }
158
-
159
-        return $result;
160
-    }
161
-
162
-    /**
163
-     * @param User  $user
164
-     * @param array $activeRoles
165
-     * @param array $inactiveRoles
166
-     */
167
-    public function getActiveRoles(User $user, &$activeRoles, &$inactiveRoles)
168
-    {
169
-        // Default to the community user here, because the main user is logged out
170
-        $identified = false;
171
-        $userRoles = array('public');
172
-
173
-        // if we're not the community user, get our real rights.
174
-        if (!$user->isCommunityUser()) {
175
-            // Check the user's status - only active users are allowed the effects of roles
176
-
177
-            $userRoles[] = 'loggedIn';
178
-
179
-            if ($user->isActive()) {
180
-                $ur = UserRole::getForUser($user->getId(), $user->getDatabase());
181
-
182
-                // NOTE: public is still in this array.
183
-                foreach ($ur as $r) {
184
-                    $userRoles[] = $r->getRole();
185
-                }
186
-
187
-                $identified = $user->isIdentified($this->identificationVerifier);
188
-            }
189
-        }
190
-
191
-        $activeRoles = array();
192
-        $inactiveRoles = array();
193
-
194
-        /** @var string $v */
195
-        foreach ($userRoles as $v) {
196
-            if ($this->roleConfiguration->roleNeedsIdentification($v)) {
197
-                if ($identified) {
198
-                    $activeRoles[] = $v;
199
-                }
200
-                else {
201
-                    $inactiveRoles[] = $v;
202
-                }
203
-            }
204
-            else {
205
-                $activeRoles[] = $v;
206
-            }
207
-        }
208
-    }
209
-
210
-    public function getRoleConfiguration(){
211
-        return $this->roleConfiguration;
212
-    }
17
+	const ALLOWED = 1;
18
+	const ERROR_NOT_IDENTIFIED = 2;
19
+	const ERROR_DENIED = 3;
20
+	/** @var IdentificationVerifier */
21
+	private $identificationVerifier;
22
+	/**
23
+	 * @var RoleConfiguration
24
+	 */
25
+	private $roleConfiguration;
26
+
27
+	/**
28
+	 * SecurityManager constructor.
29
+	 *
30
+	 * @param IdentificationVerifier $identificationVerifier
31
+	 * @param RoleConfiguration      $roleConfiguration
32
+	 */
33
+	public function __construct(
34
+		IdentificationVerifier $identificationVerifier,
35
+		RoleConfiguration $roleConfiguration
36
+	) {
37
+		$this->identificationVerifier = $identificationVerifier;
38
+		$this->roleConfiguration = $roleConfiguration;
39
+	}
40
+
41
+	/**
42
+	 * Tests if a user is allowed to perform an action.
43
+	 *
44
+	 * This method should form a hard, deterministic security barrier, and only return true if it is absolutely sure
45
+	 * that a user should have access to something.
46
+	 *
47
+	 * @param string $page
48
+	 * @param string $route
49
+	 * @param User   $user
50
+	 *
51
+	 * @return int
52
+	 *
53
+	 * @category Security-Critical
54
+	 */
55
+	public function allows($page, $route, User $user)
56
+	{
57
+		$this->getActiveRoles($user, $activeRoles, $inactiveRoles);
58
+
59
+		$availableRights = $this->flattenRoles($activeRoles);
60
+		$testResult = $this->findResult($availableRights, $page, $route);
61
+
62
+		if ($testResult !== null) {
63
+			// We got a firm result here, so just return it.
64
+			return $testResult;
65
+		}
66
+
67
+		// No firm result yet, so continue testing the inactive roles so we can give a better error.
68
+		$inactiveRights = $this->flattenRoles($inactiveRoles);
69
+		$testResult = $this->findResult($inactiveRights, $page, $route);
70
+
71
+		if ($testResult === self::ALLOWED) {
72
+			// The user is allowed to access this, but their role is inactive.
73
+			return self::ERROR_NOT_IDENTIFIED;
74
+		}
75
+
76
+		// Other options from the secondary test are denied and inconclusive, which at this point defaults to denied.
77
+		return self::ERROR_DENIED;
78
+	}
79
+
80
+	/**
81
+	 * @param array  $pseudoRole The role (flattened) to check
82
+	 * @param string $page       The page class to check
83
+	 * @param string $route      The page route to check
84
+	 *
85
+	 * @return int|null
86
+	 */
87
+	private function findResult($pseudoRole, $page, $route)
88
+	{
89
+		if (isset($pseudoRole[$page])) {
90
+			// check for deny on catch-all route
91
+			if (isset($pseudoRole[$page][RoleConfiguration::ALL])) {
92
+				if ($pseudoRole[$page][RoleConfiguration::ALL] === RoleConfiguration::ACCESS_DENY) {
93
+					return self::ERROR_DENIED;
94
+				}
95
+			}
96
+
97
+			// check normal route
98
+			if (isset($pseudoRole[$page][$route])) {
99
+				if ($pseudoRole[$page][$route] === RoleConfiguration::ACCESS_DENY) {
100
+					return self::ERROR_DENIED;
101
+				}
102
+
103
+				if ($pseudoRole[$page][$route] === RoleConfiguration::ACCESS_ALLOW) {
104
+					return self::ALLOWED;
105
+				}
106
+			}
107
+
108
+			// check for allowed on catch-all route
109
+			if (isset($pseudoRole[$page][RoleConfiguration::ALL])) {
110
+				if ($pseudoRole[$page][RoleConfiguration::ALL] === RoleConfiguration::ACCESS_ALLOW) {
111
+					return self::ALLOWED;
112
+				}
113
+			}
114
+		}
115
+
116
+		// return indeterminate result
117
+		return null;
118
+	}
119
+
120
+	/**
121
+	 * Takes an array of roles and flattens the values to a single set.
122
+	 *
123
+	 * @param array $activeRoles
124
+	 *
125
+	 * @return array
126
+	 */
127
+	private function flattenRoles($activeRoles)
128
+	{
129
+		$result = array();
130
+
131
+		$roleConfig = $this->roleConfiguration->getApplicableRoles($activeRoles);
132
+
133
+		// Iterate over every page in every role
134
+		foreach ($roleConfig as $role) {
135
+			foreach ($role as $page => $pageRights) {
136
+				// Create holder in result for this page
137
+				if (!isset($result[$page])) {
138
+					$result[$page] = array();
139
+				}
140
+
141
+				foreach ($pageRights as $action => $permission) {
142
+					// Deny takes precedence, so if it's set, don't change it.
143
+					if (isset($result[$page][$action])) {
144
+						if ($result[$page][$action] === RoleConfiguration::ACCESS_DENY) {
145
+							continue;
146
+						}
147
+					}
148
+
149
+					if ($permission === RoleConfiguration::ACCESS_DEFAULT) {
150
+						// Configured to do precisely nothing.
151
+						continue;
152
+					}
153
+
154
+					$result[$page][$action] = $permission;
155
+				}
156
+			}
157
+		}
158
+
159
+		return $result;
160
+	}
161
+
162
+	/**
163
+	 * @param User  $user
164
+	 * @param array $activeRoles
165
+	 * @param array $inactiveRoles
166
+	 */
167
+	public function getActiveRoles(User $user, &$activeRoles, &$inactiveRoles)
168
+	{
169
+		// Default to the community user here, because the main user is logged out
170
+		$identified = false;
171
+		$userRoles = array('public');
172
+
173
+		// if we're not the community user, get our real rights.
174
+		if (!$user->isCommunityUser()) {
175
+			// Check the user's status - only active users are allowed the effects of roles
176
+
177
+			$userRoles[] = 'loggedIn';
178
+
179
+			if ($user->isActive()) {
180
+				$ur = UserRole::getForUser($user->getId(), $user->getDatabase());
181
+
182
+				// NOTE: public is still in this array.
183
+				foreach ($ur as $r) {
184
+					$userRoles[] = $r->getRole();
185
+				}
186
+
187
+				$identified = $user->isIdentified($this->identificationVerifier);
188
+			}
189
+		}
190
+
191
+		$activeRoles = array();
192
+		$inactiveRoles = array();
193
+
194
+		/** @var string $v */
195
+		foreach ($userRoles as $v) {
196
+			if ($this->roleConfiguration->roleNeedsIdentification($v)) {
197
+				if ($identified) {
198
+					$activeRoles[] = $v;
199
+				}
200
+				else {
201
+					$inactiveRoles[] = $v;
202
+				}
203
+			}
204
+			else {
205
+				$activeRoles[] = $v;
206
+			}
207
+		}
208
+	}
209
+
210
+	public function getRoleConfiguration(){
211
+		return $this->roleConfiguration;
212
+	}
213 213
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -207,7 +207,7 @@
 block discarded – undo
207 207
         }
208 208
     }
209 209
 
210
-    public function getRoleConfiguration(){
210
+    public function getRoleConfiguration() {
211 211
         return $this->roleConfiguration;
212 212
     }
213 213
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -207,7 +207,8 @@
 block discarded – undo
207 207
         }
208 208
     }
209 209
 
210
-    public function getRoleConfiguration(){
210
+    public function getRoleConfiguration()
211
+    {
211 212
         return $this->roleConfiguration;
212 213
     }
213 214
 }
Please login to merge, or discard this patch.