Test Failed
Push — dependabot/composer/newinterna... ( de8420 )
by
unknown
13:57 queued 08:25
created
smarty-plugins/modifier.date.php 2 patches
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -16,16 +16,16 @@
 block discarded – undo
16 16
  */
17 17
 function smarty_modifier_date($input)
18 18
 {
19
-    if (gettype($input) === 'object'
20
-        && (get_class($input) === DateTime::class || get_class($input) === DateTimeImmutable::class)
21
-    ) {
22
-        /** @var $date DateTime|DateTimeImmutable */
23
-        $date = $input;
24
-        $dateString = $date->format('Y-m-d H:i:s');
19
+	if (gettype($input) === 'object'
20
+		&& (get_class($input) === DateTime::class || get_class($input) === DateTimeImmutable::class)
21
+	) {
22
+		/** @var $date DateTime|DateTimeImmutable */
23
+		$date = $input;
24
+		$dateString = $date->format('Y-m-d H:i:s');
25 25
 
26
-        return $dateString;
27
-    }
28
-    else {
29
-        return $input;
30
-    }
26
+		return $dateString;
27
+	}
28
+	else {
29
+		return $input;
30
+	}
31 31
 }
32 32
\ No newline at end of file
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -24,8 +24,7 @@
 block discarded – undo
24 24
         $dateString = $date->format('Y-m-d H:i:s');
25 25
 
26 26
         return $dateString;
27
-    }
28
-    else {
27
+    } else {
29 28
         return $input;
30 29
     }
31 30
 }
32 31
\ No newline at end of file
Please login to merge, or discard this patch.
includes/ExceptionHandler.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -75,8 +75,7 @@
 block discarded – undo
75 75
             ob_end_clean();
76 76
 
77 77
             $message = str_replace('$2$', $textErrorData, $message);
78
-        }
79
-        else {
78
+        } else {
80 79
             $message = str_replace('$2$', "", $message);
81 80
         }
82 81
 
Please login to merge, or discard this patch.
Indentation   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -13,22 +13,22 @@  discard block
 block discarded – undo
13 13
 
14 14
 class ExceptionHandler
15 15
 {
16
-    /**
17
-     * Global exception handler
18
-     *
19
-     * Smarty would be nice to use, but it COULD BE smarty that throws the errors.
20
-     * Let's build something ourselves, and hope it works.
21
-     *
22
-     * @param $exception
23
-     *
24
-     * @category Security-Critical - has the potential to leak data when exception is thrown.
25
-     */
26
-    public static function exceptionHandler(Throwable $exception)
27
-    {
28
-        /** @global $siteConfiguration SiteConfiguration */
29
-        global $siteConfiguration;
30
-
31
-        $errorDocument = <<<HTML
16
+	/**
17
+	 * Global exception handler
18
+	 *
19
+	 * Smarty would be nice to use, but it COULD BE smarty that throws the errors.
20
+	 * Let's build something ourselves, and hope it works.
21
+	 *
22
+	 * @param $exception
23
+	 *
24
+	 * @category Security-Critical - has the potential to leak data when exception is thrown.
25
+	 */
26
+	public static function exceptionHandler(Throwable $exception)
27
+	{
28
+		/** @global $siteConfiguration SiteConfiguration */
29
+		global $siteConfiguration;
30
+
31
+		$errorDocument = <<<HTML
32 32
 <!DOCTYPE html>
33 33
 <html lang="en"><head>
34 34
 <meta charset="utf-8">
@@ -48,80 +48,80 @@  discard block
 block discarded – undo
48 48
 </div></body></html>
49 49
 HTML;
50 50
 
51
-        $errorData = self::getExceptionData($exception);
52
-        $errorData['server'] = $_SERVER;
53
-        $errorData['get'] = $_GET;
54
-        $errorData['post'] = $_POST;
55
-
56
-        $state = serialize($errorData);
57
-        $errorId = sha1($state);
58
-
59
-        // Save the error for later analysis
60
-        file_put_contents($siteConfiguration->getErrorLog() . '/' . $errorId . '.log', $state);
61
-
62
-        // clear and discard any content that's been saved to the output buffer
63
-        if (ob_get_level() > 0) {
64
-            ob_end_clean();
65
-        }
66
-
67
-        // push error ID into the document.
68
-        $message = str_replace('$1$', $errorId, $errorDocument);
69
-
70
-        if ($siteConfiguration->getDebuggingTraceEnabled()) {
71
-            ob_start();
72
-            var_dump($errorData);
73
-            $textErrorData = ob_get_contents();
74
-            ob_end_clean();
75
-
76
-            $message = str_replace('$2$', $textErrorData, $message);
77
-        }
78
-        else {
79
-            $message = str_replace('$2$', "", $message);
80
-        }
81
-
82
-        // While we *shouldn't* have sent headers by now due to the output buffering, PHPUnit does weird things.
83
-        // This is "only" needed for the tests, but it's a good idea to wrap this anyway.
84
-        if (!headers_sent()) {
85
-            header('HTTP/1.1 500 Internal Server Error');
86
-        }
87
-
88
-        // output the document
89
-        print $message;
90
-    }
91
-
92
-    /**
93
-     * @param int    $errorSeverity The severity level of the exception.
94
-     * @param string $errorMessage  The Exception message to throw.
95
-     * @param string $errorFile     The filename where the exception is thrown.
96
-     * @param int    $errorLine     The line number where the exception is thrown.
97
-     *
98
-     * @throws ErrorException
99
-     */
100
-    public static function errorHandler($errorSeverity, $errorMessage, $errorFile, $errorLine)
101
-    {
102
-        // call into the main exception handler above
103
-        throw new ErrorException($errorMessage, 0, $errorSeverity, $errorFile, $errorLine);
104
-    }
105
-
106
-    /**
107
-     * @param Throwable $exception
108
-     *
109
-     * @return null|array
110
-     */
111
-    public static function getExceptionData($exception)
112
-    {
113
-        if ($exception == null) {
114
-            return null;
115
-        }
116
-
117
-        $array = array(
118
-            'exception' => get_class($exception),
119
-            'message'   => $exception->getMessage(),
120
-            'stack'     => $exception->getTraceAsString(),
121
-        );
122
-
123
-        $array['previous'] = self::getExceptionData($exception->getPrevious());
124
-
125
-        return $array;
126
-    }
51
+		$errorData = self::getExceptionData($exception);
52
+		$errorData['server'] = $_SERVER;
53
+		$errorData['get'] = $_GET;
54
+		$errorData['post'] = $_POST;
55
+
56
+		$state = serialize($errorData);
57
+		$errorId = sha1($state);
58
+
59
+		// Save the error for later analysis
60
+		file_put_contents($siteConfiguration->getErrorLog() . '/' . $errorId . '.log', $state);
61
+
62
+		// clear and discard any content that's been saved to the output buffer
63
+		if (ob_get_level() > 0) {
64
+			ob_end_clean();
65
+		}
66
+
67
+		// push error ID into the document.
68
+		$message = str_replace('$1$', $errorId, $errorDocument);
69
+
70
+		if ($siteConfiguration->getDebuggingTraceEnabled()) {
71
+			ob_start();
72
+			var_dump($errorData);
73
+			$textErrorData = ob_get_contents();
74
+			ob_end_clean();
75
+
76
+			$message = str_replace('$2$', $textErrorData, $message);
77
+		}
78
+		else {
79
+			$message = str_replace('$2$', "", $message);
80
+		}
81
+
82
+		// While we *shouldn't* have sent headers by now due to the output buffering, PHPUnit does weird things.
83
+		// This is "only" needed for the tests, but it's a good idea to wrap this anyway.
84
+		if (!headers_sent()) {
85
+			header('HTTP/1.1 500 Internal Server Error');
86
+		}
87
+
88
+		// output the document
89
+		print $message;
90
+	}
91
+
92
+	/**
93
+	 * @param int    $errorSeverity The severity level of the exception.
94
+	 * @param string $errorMessage  The Exception message to throw.
95
+	 * @param string $errorFile     The filename where the exception is thrown.
96
+	 * @param int    $errorLine     The line number where the exception is thrown.
97
+	 *
98
+	 * @throws ErrorException
99
+	 */
100
+	public static function errorHandler($errorSeverity, $errorMessage, $errorFile, $errorLine)
101
+	{
102
+		// call into the main exception handler above
103
+		throw new ErrorException($errorMessage, 0, $errorSeverity, $errorFile, $errorLine);
104
+	}
105
+
106
+	/**
107
+	 * @param Throwable $exception
108
+	 *
109
+	 * @return null|array
110
+	 */
111
+	public static function getExceptionData($exception)
112
+	{
113
+		if ($exception == null) {
114
+			return null;
115
+		}
116
+
117
+		$array = array(
118
+			'exception' => get_class($exception),
119
+			'message'   => $exception->getMessage(),
120
+			'stack'     => $exception->getTraceAsString(),
121
+		);
122
+
123
+		$array['previous'] = self::getExceptionData($exception->getPrevious());
124
+
125
+		return $array;
126
+	}
127 127
 }
Please login to merge, or discard this patch.
includes/Fragments/RequestData.php 2 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -295,8 +295,7 @@
 block discarded – undo
295 295
                 if (!$proxyIsInPrivateRange) {
296 296
                     $proxyReverseDns = $this->getRdnsProvider()->getReverseDNS($proxyAddress);
297 297
                     $proxyLocation = $this->getLocationProvider()->getIpLocation($proxyAddress);
298
-                }
299
-                else {
298
+                } else {
300 299
                     // this is going to fail, so why bother trying?
301 300
                     $proxyReverseDns = false;
302 301
                     $proxyLocation = false;
Please login to merge, or discard this patch.
Indentation   +312 added lines, -312 removed lines patch added patch discarded remove patch
@@ -24,316 +24,316 @@
 block discarded – undo
24 24
 
25 25
 trait RequestData
26 26
 {
27
-    /**
28
-     * @var array Array of IP address classed as 'private' by RFC1918.
29
-     */
30
-    protected static $rfc1918ips = array(
31
-        "10.0.0.0"    => "10.255.255.255",
32
-        "172.16.0.0"  => "172.31.255.255",
33
-        "192.168.0.0" => "192.168.255.255",
34
-        "169.254.0.0" => "169.254.255.255",
35
-        "127.0.0.0"   => "127.255.255.255",
36
-    );
37
-
38
-    /**
39
-     * Gets a request object
40
-     *
41
-     * @param PdoDatabase $database  The database connection
42
-     * @param int         $requestId The ID of the request to retrieve
43
-     *
44
-     * @return Request
45
-     * @throws ApplicationLogicException
46
-     */
47
-    protected function getRequest(PdoDatabase $database, $requestId)
48
-    {
49
-        if ($requestId === null) {
50
-            throw new ApplicationLogicException("No request specified");
51
-        }
52
-
53
-        $request = Request::getById($requestId, $database);
54
-        if ($request === false || !is_a($request, Request::class)) {
55
-            throw new ApplicationLogicException('Could not load the requested request!');
56
-        }
57
-
58
-        return $request;
59
-    }
60
-
61
-    /**
62
-     * Returns a value stating whether the user is allowed to see private data or not
63
-     *
64
-     * @param Request $request
65
-     * @param User    $currentUser
66
-     *
67
-     * @return bool
68
-     * @category Security-Critical
69
-     */
70
-    protected function isAllowedPrivateData(Request $request, User $currentUser)
71
-    {
72
-        // Test the main security barrier for private data access using SecurityManager
73
-        if ($this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData')) {
74
-            // Tool admins/check-users can always see private data
75
-            return true;
76
-        }
77
-
78
-        // reserving user is allowed to see the data
79
-        if ($currentUser->getId() === $request->getReserved()
80
-            && $request->getReserved() !== null
81
-            && $this->barrierTest('seePrivateDataWhenReserved', $currentUser, 'RequestData')
82
-        ) {
83
-            return true;
84
-        }
85
-
86
-        // user has the reveal hash
87
-        if (WebRequest::getString('hash') === $request->getRevealHash()
88
-            && $this->barrierTest('seePrivateDataWithHash', $currentUser, 'RequestData')
89
-        ) {
90
-            return true;
91
-        }
92
-
93
-        // nope. Not allowed.
94
-        return false;
95
-    }
96
-
97
-    /**
98
-     * Tests the security barrier for a specified action.
99
-     *
100
-     * Don't use within templates
101
-     *
102
-     * @param string      $action
103
-     *
104
-     * @param User        $user
105
-     * @param null|string $pageName
106
-     *
107
-     * @return bool
108
-     * @category Security-Critical
109
-     */
110
-    abstract protected function barrierTest($action, User $user, $pageName = null);
111
-
112
-    /**
113
-     * Gets the name of the route that has been passed from the request router.
114
-     * @return string
115
-     */
116
-    abstract protected function getRouteName();
117
-
118
-    /** @return SecurityManager */
119
-    abstract protected function getSecurityManager();
120
-
121
-    /**
122
-     * Sets the name of the template this page should display.
123
-     *
124
-     * @param string $name
125
-     */
126
-    abstract protected function setTemplate($name);
127
-
128
-    /** @return IXffTrustProvider */
129
-    abstract protected function getXffTrustProvider();
130
-
131
-    /** @return ILocationProvider */
132
-    abstract protected function getLocationProvider();
133
-
134
-    /** @return IRDnsProvider */
135
-    abstract protected function getRdnsProvider();
136
-
137
-    /**
138
-     * Assigns a Smarty variable
139
-     *
140
-     * @param  array|string $name  the template variable name(s)
141
-     * @param  mixed        $value the value to assign
142
-     */
143
-    abstract protected function assign($name, $value);
144
-
145
-    /**
146
-     * @param int         $requestReservationId
147
-     * @param PdoDatabase $database
148
-     * @param User        $currentUser
149
-     */
150
-    protected function setupReservationDetails($requestReservationId, PdoDatabase $database, User $currentUser)
151
-    {
152
-        $requestIsReserved = $requestReservationId !== null;
153
-        $this->assign('requestIsReserved', $requestIsReserved);
154
-        $this->assign('requestIsReservedByMe', false);
155
-
156
-        if ($requestIsReserved) {
157
-            $this->assign('requestReservedByName', User::getById($requestReservationId, $database)->getUsername());
158
-            $this->assign('requestReservedById', $requestReservationId);
159
-
160
-            if ($requestReservationId === $currentUser->getId()) {
161
-                $this->assign('requestIsReservedByMe', true);
162
-            }
163
-        }
164
-
165
-        $this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
166
-    }
167
-
168
-    /**
169
-     * Adds private request data to Smarty. DO NOT USE WITHOUT FIRST CHECKING THAT THE USER IS AUTHORISED!
170
-     *
171
-     * @param Request           $request
172
-     * @param User              $currentUser
173
-     * @param SiteConfiguration $configuration
174
-     *
175
-     * @param PdoDatabase       $database
176
-     */
177
-    protected function setupPrivateData(
178
-        $request,
179
-        User $currentUser,
180
-        SiteConfiguration $configuration,
181
-        PdoDatabase $database
182
-    ) {
183
-        $xffProvider = $this->getXffTrustProvider();
184
-
185
-        $relatedEmailRequests = RequestSearchHelper::get($database)
186
-            ->byEmailAddress($request->getEmail())
187
-            ->withConfirmedEmail()
188
-            ->excludingPurgedData($configuration)
189
-            ->excludingRequest($request->getId())
190
-            ->fetch();
191
-
192
-        $this->assign('requestEmail', $request->getEmail());
193
-        $emailDomain = explode("@", $request->getEmail())[1];
194
-        $this->assign("emailurl", $emailDomain);
195
-        $this->assign('requestRelatedEmailRequestsCount', count($relatedEmailRequests));
196
-        $this->assign('requestRelatedEmailRequests', $relatedEmailRequests);
197
-
198
-        $trustedIp = $xffProvider->getTrustedClientIp($request->getIp(), $request->getForwardedIp());
199
-        $this->assign('requestTrustedIp', $trustedIp);
200
-        $this->assign('requestRealIp', $request->getIp());
201
-        $this->assign('requestForwardedIp', $request->getForwardedIp());
202
-
203
-        $trustedIpLocation = $this->getLocationProvider()->getIpLocation($trustedIp);
204
-        $this->assign('requestTrustedIpLocation', $trustedIpLocation);
205
-
206
-        $this->assign('requestHasForwardedIp', $request->getForwardedIp() !== null);
207
-
208
-        $relatedIpRequests = RequestSearchHelper::get($database)
209
-            ->byIp($trustedIp)
210
-            ->withConfirmedEmail()
211
-            ->excludingPurgedData($configuration)
212
-            ->excludingRequest($request->getId())
213
-            ->fetch();
214
-
215
-        $this->assign('requestRelatedIpRequestsCount', count($relatedIpRequests));
216
-        $this->assign('requestRelatedIpRequests', $relatedIpRequests);
217
-
218
-        $this->setupForwardedIpData($request);
219
-    }
220
-
221
-    /**
222
-     * Adds checkuser request data to Smarty. DO NOT USE WITHOUT FIRST CHECKING THAT THE USER IS AUTHORISED!
223
-     *
224
-     * @param Request $request
225
-     */
226
-    protected function setupCheckUserData(Request $request)
227
-    {
228
-        $this->assign('requestUserAgent', $request->getUserAgent());
229
-    }
230
-
231
-    /**
232
-     * Sets up the basic data for this request, and adds it to Smarty
233
-     *
234
-     * @param Request           $request
235
-     * @param SiteConfiguration $config
236
-     */
237
-    protected function setupBasicData(Request $request, SiteConfiguration $config)
238
-    {
239
-        $this->assign('requestId', $request->getId());
240
-        $this->assign('updateVersion', $request->getUpdateVersion());
241
-        $this->assign('requestName', $request->getName());
242
-        $this->assign('requestDate', $request->getDate());
243
-        $this->assign('requestStatus', $request->getStatus());
244
-
245
-        $isClosed = !array_key_exists($request->getStatus(), $config->getRequestStates())
246
-            && $request->getStatus() !== RequestStatus::HOSPITAL;
247
-        $this->assign('requestIsClosed', $isClosed);
248
-    }
249
-
250
-    /**
251
-     * Sets up the forwarded IP data for this request and adds it to Smarty
252
-     *
253
-     * @param Request $request
254
-     */
255
-    protected function setupForwardedIpData(Request $request)
256
-    {
257
-        if ($request->getForwardedIp() !== null) {
258
-            $requestProxyData = array(); // Initialize array to store data to be output in Smarty template.
259
-            $proxyIndex = 0;
260
-
261
-            // Assuming [client] <=> [proxy1] <=> [proxy2] <=> [proxy3] <=> [us], we will see an XFF header of [client],
262
-            // [proxy1], [proxy2], and our actual IP will be [proxy3]
263
-            $proxies = explode(",", $request->getForwardedIp());
264
-            $proxies[] = $request->getIp();
265
-
266
-            // Origin is the supposed "client" IP.
267
-            $origin = $proxies[0];
268
-            $this->assign("forwardedOrigin", $origin);
269
-
270
-            // We step through the servers in reverse order, from closest to furthest
271
-            $proxies = array_reverse($proxies);
272
-
273
-            // By default, we have trust, because the first in the chain is now REMOTE_ADDR, which is hardest to spoof.
274
-            $trust = true;
275
-
276
-            /**
277
-             * @var int    $index     The zero-based index of the proxy.
278
-             * @var string $proxyData The proxy IP address (although possibly not!)
279
-             */
280
-            foreach ($proxies as $index => $proxyData) {
281
-                $proxyAddress = trim($proxyData);
282
-                $requestProxyData[$proxyIndex]['ip'] = $proxyAddress;
283
-
284
-                // get data on this IP.
285
-                $thisProxyIsTrusted = $this->getXffTrustProvider()->isTrusted($proxyAddress);
286
-
287
-                $proxyIsInPrivateRange = $this->getXffTrustProvider()
288
-                    ->ipInRange(self::$rfc1918ips, $proxyAddress);
289
-
290
-                if (!$proxyIsInPrivateRange) {
291
-                    $proxyReverseDns = $this->getRdnsProvider()->getReverseDNS($proxyAddress);
292
-                    $proxyLocation = $this->getLocationProvider()->getIpLocation($proxyAddress);
293
-                }
294
-                else {
295
-                    // this is going to fail, so why bother trying?
296
-                    $proxyReverseDns = false;
297
-                    $proxyLocation = false;
298
-                }
299
-
300
-                // current trust chain status BEFORE this link
301
-                $preLinkTrust = $trust;
302
-
303
-                // is *this* link trusted? Note, this will be true even if there is an untrusted link before this!
304
-                $requestProxyData[$proxyIndex]['trustedlink'] = $thisProxyIsTrusted;
305
-
306
-                // set the trust status of the chain to this point
307
-                $trust = $trust & $thisProxyIsTrusted;
308
-
309
-                // If this is the origin address, and the chain was trusted before this point, then we can trust
310
-                // the origin.
311
-                if ($preLinkTrust && $proxyAddress == $origin) {
312
-                    // if this is the origin, then we are at the last point in the chain.
313
-                    // @todo: this is probably the cause of some bugs when an IP appears twice - we're missing a check
314
-                    // to see if this is *really* the last in the chain, rather than just the same IP as it.
315
-                    $trust = true;
316
-                }
317
-
318
-                $requestProxyData[$proxyIndex]['trust'] = $trust;
319
-
320
-                $requestProxyData[$proxyIndex]['rdnsfailed'] = $proxyReverseDns === false;
321
-                $requestProxyData[$proxyIndex]['rdns'] = $proxyReverseDns;
322
-                $requestProxyData[$proxyIndex]['routable'] = !$proxyIsInPrivateRange;
323
-
324
-                $requestProxyData[$proxyIndex]['location'] = $proxyLocation;
325
-
326
-                if ($proxyReverseDns === $proxyAddress && $proxyIsInPrivateRange === false) {
327
-                    $requestProxyData[$proxyIndex]['rdns'] = null;
328
-                }
329
-
330
-                $showLinks = (!$trust || $proxyAddress == $origin) && !$proxyIsInPrivateRange;
331
-                $requestProxyData[$proxyIndex]['showlinks'] = $showLinks;
332
-
333
-                $proxyIndex++;
334
-            }
335
-
336
-            $this->assign("requestProxyData", $requestProxyData);
337
-        }
338
-    }
27
+	/**
28
+	 * @var array Array of IP address classed as 'private' by RFC1918.
29
+	 */
30
+	protected static $rfc1918ips = array(
31
+		"10.0.0.0"    => "10.255.255.255",
32
+		"172.16.0.0"  => "172.31.255.255",
33
+		"192.168.0.0" => "192.168.255.255",
34
+		"169.254.0.0" => "169.254.255.255",
35
+		"127.0.0.0"   => "127.255.255.255",
36
+	);
37
+
38
+	/**
39
+	 * Gets a request object
40
+	 *
41
+	 * @param PdoDatabase $database  The database connection
42
+	 * @param int         $requestId The ID of the request to retrieve
43
+	 *
44
+	 * @return Request
45
+	 * @throws ApplicationLogicException
46
+	 */
47
+	protected function getRequest(PdoDatabase $database, $requestId)
48
+	{
49
+		if ($requestId === null) {
50
+			throw new ApplicationLogicException("No request specified");
51
+		}
52
+
53
+		$request = Request::getById($requestId, $database);
54
+		if ($request === false || !is_a($request, Request::class)) {
55
+			throw new ApplicationLogicException('Could not load the requested request!');
56
+		}
57
+
58
+		return $request;
59
+	}
60
+
61
+	/**
62
+	 * Returns a value stating whether the user is allowed to see private data or not
63
+	 *
64
+	 * @param Request $request
65
+	 * @param User    $currentUser
66
+	 *
67
+	 * @return bool
68
+	 * @category Security-Critical
69
+	 */
70
+	protected function isAllowedPrivateData(Request $request, User $currentUser)
71
+	{
72
+		// Test the main security barrier for private data access using SecurityManager
73
+		if ($this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData')) {
74
+			// Tool admins/check-users can always see private data
75
+			return true;
76
+		}
77
+
78
+		// reserving user is allowed to see the data
79
+		if ($currentUser->getId() === $request->getReserved()
80
+			&& $request->getReserved() !== null
81
+			&& $this->barrierTest('seePrivateDataWhenReserved', $currentUser, 'RequestData')
82
+		) {
83
+			return true;
84
+		}
85
+
86
+		// user has the reveal hash
87
+		if (WebRequest::getString('hash') === $request->getRevealHash()
88
+			&& $this->barrierTest('seePrivateDataWithHash', $currentUser, 'RequestData')
89
+		) {
90
+			return true;
91
+		}
92
+
93
+		// nope. Not allowed.
94
+		return false;
95
+	}
96
+
97
+	/**
98
+	 * Tests the security barrier for a specified action.
99
+	 *
100
+	 * Don't use within templates
101
+	 *
102
+	 * @param string      $action
103
+	 *
104
+	 * @param User        $user
105
+	 * @param null|string $pageName
106
+	 *
107
+	 * @return bool
108
+	 * @category Security-Critical
109
+	 */
110
+	abstract protected function barrierTest($action, User $user, $pageName = null);
111
+
112
+	/**
113
+	 * Gets the name of the route that has been passed from the request router.
114
+	 * @return string
115
+	 */
116
+	abstract protected function getRouteName();
117
+
118
+	/** @return SecurityManager */
119
+	abstract protected function getSecurityManager();
120
+
121
+	/**
122
+	 * Sets the name of the template this page should display.
123
+	 *
124
+	 * @param string $name
125
+	 */
126
+	abstract protected function setTemplate($name);
127
+
128
+	/** @return IXffTrustProvider */
129
+	abstract protected function getXffTrustProvider();
130
+
131
+	/** @return ILocationProvider */
132
+	abstract protected function getLocationProvider();
133
+
134
+	/** @return IRDnsProvider */
135
+	abstract protected function getRdnsProvider();
136
+
137
+	/**
138
+	 * Assigns a Smarty variable
139
+	 *
140
+	 * @param  array|string $name  the template variable name(s)
141
+	 * @param  mixed        $value the value to assign
142
+	 */
143
+	abstract protected function assign($name, $value);
144
+
145
+	/**
146
+	 * @param int         $requestReservationId
147
+	 * @param PdoDatabase $database
148
+	 * @param User        $currentUser
149
+	 */
150
+	protected function setupReservationDetails($requestReservationId, PdoDatabase $database, User $currentUser)
151
+	{
152
+		$requestIsReserved = $requestReservationId !== null;
153
+		$this->assign('requestIsReserved', $requestIsReserved);
154
+		$this->assign('requestIsReservedByMe', false);
155
+
156
+		if ($requestIsReserved) {
157
+			$this->assign('requestReservedByName', User::getById($requestReservationId, $database)->getUsername());
158
+			$this->assign('requestReservedById', $requestReservationId);
159
+
160
+			if ($requestReservationId === $currentUser->getId()) {
161
+				$this->assign('requestIsReservedByMe', true);
162
+			}
163
+		}
164
+
165
+		$this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
166
+	}
167
+
168
+	/**
169
+	 * Adds private request data to Smarty. DO NOT USE WITHOUT FIRST CHECKING THAT THE USER IS AUTHORISED!
170
+	 *
171
+	 * @param Request           $request
172
+	 * @param User              $currentUser
173
+	 * @param SiteConfiguration $configuration
174
+	 *
175
+	 * @param PdoDatabase       $database
176
+	 */
177
+	protected function setupPrivateData(
178
+		$request,
179
+		User $currentUser,
180
+		SiteConfiguration $configuration,
181
+		PdoDatabase $database
182
+	) {
183
+		$xffProvider = $this->getXffTrustProvider();
184
+
185
+		$relatedEmailRequests = RequestSearchHelper::get($database)
186
+			->byEmailAddress($request->getEmail())
187
+			->withConfirmedEmail()
188
+			->excludingPurgedData($configuration)
189
+			->excludingRequest($request->getId())
190
+			->fetch();
191
+
192
+		$this->assign('requestEmail', $request->getEmail());
193
+		$emailDomain = explode("@", $request->getEmail())[1];
194
+		$this->assign("emailurl", $emailDomain);
195
+		$this->assign('requestRelatedEmailRequestsCount', count($relatedEmailRequests));
196
+		$this->assign('requestRelatedEmailRequests', $relatedEmailRequests);
197
+
198
+		$trustedIp = $xffProvider->getTrustedClientIp($request->getIp(), $request->getForwardedIp());
199
+		$this->assign('requestTrustedIp', $trustedIp);
200
+		$this->assign('requestRealIp', $request->getIp());
201
+		$this->assign('requestForwardedIp', $request->getForwardedIp());
202
+
203
+		$trustedIpLocation = $this->getLocationProvider()->getIpLocation($trustedIp);
204
+		$this->assign('requestTrustedIpLocation', $trustedIpLocation);
205
+
206
+		$this->assign('requestHasForwardedIp', $request->getForwardedIp() !== null);
207
+
208
+		$relatedIpRequests = RequestSearchHelper::get($database)
209
+			->byIp($trustedIp)
210
+			->withConfirmedEmail()
211
+			->excludingPurgedData($configuration)
212
+			->excludingRequest($request->getId())
213
+			->fetch();
214
+
215
+		$this->assign('requestRelatedIpRequestsCount', count($relatedIpRequests));
216
+		$this->assign('requestRelatedIpRequests', $relatedIpRequests);
217
+
218
+		$this->setupForwardedIpData($request);
219
+	}
220
+
221
+	/**
222
+	 * Adds checkuser request data to Smarty. DO NOT USE WITHOUT FIRST CHECKING THAT THE USER IS AUTHORISED!
223
+	 *
224
+	 * @param Request $request
225
+	 */
226
+	protected function setupCheckUserData(Request $request)
227
+	{
228
+		$this->assign('requestUserAgent', $request->getUserAgent());
229
+	}
230
+
231
+	/**
232
+	 * Sets up the basic data for this request, and adds it to Smarty
233
+	 *
234
+	 * @param Request           $request
235
+	 * @param SiteConfiguration $config
236
+	 */
237
+	protected function setupBasicData(Request $request, SiteConfiguration $config)
238
+	{
239
+		$this->assign('requestId', $request->getId());
240
+		$this->assign('updateVersion', $request->getUpdateVersion());
241
+		$this->assign('requestName', $request->getName());
242
+		$this->assign('requestDate', $request->getDate());
243
+		$this->assign('requestStatus', $request->getStatus());
244
+
245
+		$isClosed = !array_key_exists($request->getStatus(), $config->getRequestStates())
246
+			&& $request->getStatus() !== RequestStatus::HOSPITAL;
247
+		$this->assign('requestIsClosed', $isClosed);
248
+	}
249
+
250
+	/**
251
+	 * Sets up the forwarded IP data for this request and adds it to Smarty
252
+	 *
253
+	 * @param Request $request
254
+	 */
255
+	protected function setupForwardedIpData(Request $request)
256
+	{
257
+		if ($request->getForwardedIp() !== null) {
258
+			$requestProxyData = array(); // Initialize array to store data to be output in Smarty template.
259
+			$proxyIndex = 0;
260
+
261
+			// Assuming [client] <=> [proxy1] <=> [proxy2] <=> [proxy3] <=> [us], we will see an XFF header of [client],
262
+			// [proxy1], [proxy2], and our actual IP will be [proxy3]
263
+			$proxies = explode(",", $request->getForwardedIp());
264
+			$proxies[] = $request->getIp();
265
+
266
+			// Origin is the supposed "client" IP.
267
+			$origin = $proxies[0];
268
+			$this->assign("forwardedOrigin", $origin);
269
+
270
+			// We step through the servers in reverse order, from closest to furthest
271
+			$proxies = array_reverse($proxies);
272
+
273
+			// By default, we have trust, because the first in the chain is now REMOTE_ADDR, which is hardest to spoof.
274
+			$trust = true;
275
+
276
+			/**
277
+			 * @var int    $index     The zero-based index of the proxy.
278
+			 * @var string $proxyData The proxy IP address (although possibly not!)
279
+			 */
280
+			foreach ($proxies as $index => $proxyData) {
281
+				$proxyAddress = trim($proxyData);
282
+				$requestProxyData[$proxyIndex]['ip'] = $proxyAddress;
283
+
284
+				// get data on this IP.
285
+				$thisProxyIsTrusted = $this->getXffTrustProvider()->isTrusted($proxyAddress);
286
+
287
+				$proxyIsInPrivateRange = $this->getXffTrustProvider()
288
+					->ipInRange(self::$rfc1918ips, $proxyAddress);
289
+
290
+				if (!$proxyIsInPrivateRange) {
291
+					$proxyReverseDns = $this->getRdnsProvider()->getReverseDNS($proxyAddress);
292
+					$proxyLocation = $this->getLocationProvider()->getIpLocation($proxyAddress);
293
+				}
294
+				else {
295
+					// this is going to fail, so why bother trying?
296
+					$proxyReverseDns = false;
297
+					$proxyLocation = false;
298
+				}
299
+
300
+				// current trust chain status BEFORE this link
301
+				$preLinkTrust = $trust;
302
+
303
+				// is *this* link trusted? Note, this will be true even if there is an untrusted link before this!
304
+				$requestProxyData[$proxyIndex]['trustedlink'] = $thisProxyIsTrusted;
305
+
306
+				// set the trust status of the chain to this point
307
+				$trust = $trust & $thisProxyIsTrusted;
308
+
309
+				// If this is the origin address, and the chain was trusted before this point, then we can trust
310
+				// the origin.
311
+				if ($preLinkTrust && $proxyAddress == $origin) {
312
+					// if this is the origin, then we are at the last point in the chain.
313
+					// @todo: this is probably the cause of some bugs when an IP appears twice - we're missing a check
314
+					// to see if this is *really* the last in the chain, rather than just the same IP as it.
315
+					$trust = true;
316
+				}
317
+
318
+				$requestProxyData[$proxyIndex]['trust'] = $trust;
319
+
320
+				$requestProxyData[$proxyIndex]['rdnsfailed'] = $proxyReverseDns === false;
321
+				$requestProxyData[$proxyIndex]['rdns'] = $proxyReverseDns;
322
+				$requestProxyData[$proxyIndex]['routable'] = !$proxyIsInPrivateRange;
323
+
324
+				$requestProxyData[$proxyIndex]['location'] = $proxyLocation;
325
+
326
+				if ($proxyReverseDns === $proxyAddress && $proxyIsInPrivateRange === false) {
327
+					$requestProxyData[$proxyIndex]['rdns'] = null;
328
+				}
329
+
330
+				$showLinks = (!$trust || $proxyAddress == $origin) && !$proxyIsInPrivateRange;
331
+				$requestProxyData[$proxyIndex]['showlinks'] = $showLinks;
332
+
333
+				$proxyIndex++;
334
+			}
335
+
336
+			$this->assign("requestProxyData", $requestProxyData);
337
+		}
338
+	}
339 339
 }
Please login to merge, or discard this patch.
includes/Validation/RequestValidationHelper.php 1 patch
Indentation   +284 added lines, -284 removed lines patch added patch discarded remove patch
@@ -22,288 +22,288 @@
 block discarded – undo
22 22
  */
23 23
 class RequestValidationHelper
24 24
 {
25
-    /** @var IBanHelper */
26
-    private $banHelper;
27
-    /** @var Request */
28
-    private $request;
29
-    private $emailConfirmation;
30
-    /** @var PdoDatabase */
31
-    private $database;
32
-    /** @var IAntiSpoofProvider */
33
-    private $antiSpoofProvider;
34
-    /** @var IXffTrustProvider */
35
-    private $xffTrustProvider;
36
-    /** @var HttpHelper */
37
-    private $httpHelper;
38
-    /**
39
-     * @var string
40
-     */
41
-    private $mediawikiApiEndpoint;
42
-    private $titleBlacklistEnabled;
43
-    /**
44
-     * @var TorExitProvider
45
-     */
46
-    private $torExitProvider;
47
-
48
-    /**
49
-     * Summary of __construct
50
-     *
51
-     * @param IBanHelper         $banHelper
52
-     * @param Request            $request
53
-     * @param string             $emailConfirmation
54
-     * @param PdoDatabase        $database
55
-     * @param IAntiSpoofProvider $antiSpoofProvider
56
-     * @param IXffTrustProvider  $xffTrustProvider
57
-     * @param HttpHelper         $httpHelper
58
-     * @param string             $mediawikiApiEndpoint
59
-     * @param boolean            $titleBlacklistEnabled
60
-     * @param TorExitProvider    $torExitProvider
61
-     */
62
-    public function __construct(
63
-        IBanHelper $banHelper,
64
-        Request $request,
65
-        $emailConfirmation,
66
-        PdoDatabase $database,
67
-        IAntiSpoofProvider $antiSpoofProvider,
68
-        IXffTrustProvider $xffTrustProvider,
69
-        HttpHelper $httpHelper,
70
-        $mediawikiApiEndpoint,
71
-        $titleBlacklistEnabled,
72
-        TorExitProvider $torExitProvider
73
-    ) {
74
-        $this->banHelper = $banHelper;
75
-        $this->request = $request;
76
-        $this->emailConfirmation = $emailConfirmation;
77
-        $this->database = $database;
78
-        $this->antiSpoofProvider = $antiSpoofProvider;
79
-        $this->xffTrustProvider = $xffTrustProvider;
80
-        $this->httpHelper = $httpHelper;
81
-        $this->mediawikiApiEndpoint = $mediawikiApiEndpoint;
82
-        $this->titleBlacklistEnabled = $titleBlacklistEnabled;
83
-        $this->torExitProvider = $torExitProvider;
84
-    }
85
-
86
-    /**
87
-     * Summary of validateName
88
-     * @return ValidationError[]
89
-     */
90
-    public function validateName()
91
-    {
92
-        $errorList = array();
93
-
94
-        // ERRORS
95
-        // name is empty
96
-        if (trim($this->request->getName()) == "") {
97
-            $errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_EMPTY);
98
-        }
99
-
100
-        // name is banned
101
-        $ban = $this->banHelper->nameIsBanned($this->request->getName());
102
-        if ($ban != false) {
103
-            $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
104
-        }
105
-
106
-        // username already exists
107
-        if ($this->userExists()) {
108
-            $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS);
109
-        }
110
-
111
-        // username part of SUL account
112
-        if ($this->userSulExists()) {
113
-            // using same error slot as name exists - it's the same sort of error, and we probably only want to show one.
114
-            $errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS_SUL);
115
-        }
116
-
117
-        // username is numbers
118
-        if (preg_match("/^[0-9]+$/", $this->request->getName()) === 1) {
119
-            $errorList[ValidationError::NAME_NUMONLY] = new ValidationError(ValidationError::NAME_NUMONLY);
120
-        }
121
-
122
-        // username can't contain #@/<>[]|{}
123
-        if (preg_match("/[" . preg_quote("#@/<>[]|{}", "/") . "]/", $this->request->getName()) === 1) {
124
-            $errorList[ValidationError::NAME_INVALIDCHAR] = new ValidationError(ValidationError::NAME_INVALIDCHAR);
125
-        }
126
-
127
-        // existing non-closed request for this name
128
-        if ($this->nameRequestExists()) {
129
-            $errorList[ValidationError::OPEN_REQUEST_NAME] = new ValidationError(ValidationError::OPEN_REQUEST_NAME);
130
-        }
131
-
132
-        return $errorList;
133
-    }
134
-
135
-    /**
136
-     * Summary of validateEmail
137
-     * @return ValidationError[]
138
-     */
139
-    public function validateEmail()
140
-    {
141
-        $errorList = array();
142
-
143
-        // ERRORS
144
-
145
-        // Email is banned
146
-        $ban = $this->banHelper->emailIsBanned($this->request->getEmail());
147
-        if ($ban != false) {
148
-            $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
149
-        }
150
-
151
-        // email addresses must match
152
-        if ($this->request->getEmail() != $this->emailConfirmation) {
153
-            $errorList[ValidationError::EMAIL_MISMATCH] = new ValidationError(ValidationError::EMAIL_MISMATCH);
154
-        }
155
-
156
-        // email address must be validly formed
157
-        if (trim($this->request->getEmail()) == "") {
158
-            $errorList[ValidationError::EMAIL_EMPTY] = new ValidationError(ValidationError::EMAIL_EMPTY);
159
-        }
160
-
161
-        // email address must be validly formed
162
-        if (!filter_var($this->request->getEmail(), FILTER_VALIDATE_EMAIL)) {
163
-            if (trim($this->request->getEmail()) != "") {
164
-                $errorList[ValidationError::EMAIL_INVALID] = new ValidationError(ValidationError::EMAIL_INVALID);
165
-            }
166
-        }
167
-
168
-        // email address can't be wikimedia/wikipedia .com/org
169
-        if (preg_match('/.*@.*wiki(m.dia|p.dia)\.(org|com)/i', $this->request->getEmail()) === 1) {
170
-            $errorList[ValidationError::EMAIL_WIKIMEDIA] = new ValidationError(ValidationError::EMAIL_WIKIMEDIA);
171
-        }
172
-
173
-        // WARNINGS
174
-
175
-        return $errorList;
176
-    }
177
-
178
-    /**
179
-     * Summary of validateOther
180
-     * @return ValidationError[]
181
-     */
182
-    public function validateOther()
183
-    {
184
-        $errorList = array();
185
-
186
-        $trustedIp = $this->xffTrustProvider->getTrustedClientIp($this->request->getIp(),
187
-            $this->request->getForwardedIp());
188
-
189
-        // ERRORS
190
-
191
-        // TOR nodes
192
-        if ($this->torExitProvider->isTorExit($trustedIp)) {
193
-            $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED_TOR);
194
-        }
195
-
196
-        // IP banned
197
-        $ban = $this->banHelper->ipIsBanned($trustedIp);
198
-        if ($ban != false) {
199
-            $errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
200
-        }
201
-
202
-        // WARNINGS
203
-
204
-        // Antispoof check
205
-        $this->checkAntiSpoof();
206
-
207
-        // Blacklist check
208
-        $this->checkTitleBlacklist();
209
-
210
-        return $errorList;
211
-    }
212
-
213
-    private function checkAntiSpoof()
214
-    {
215
-        try {
216
-            if (count($this->antiSpoofProvider->getSpoofs($this->request->getName())) > 0) {
217
-                // If there were spoofs an Admin should handle the request.
218
-                $this->request->setStatus("Flagged users");
219
-            }
220
-        }
221
-        catch (Exception $ex) {
222
-            // logme
223
-        }
224
-    }
225
-
226
-    private function checkTitleBlacklist()
227
-    {
228
-        if ($this->titleBlacklistEnabled == 1) {
229
-            $apiResult = $this->httpHelper->get(
230
-                $this->mediawikiApiEndpoint,
231
-                array(
232
-                    'action'       => 'titleblacklist',
233
-                    'tbtitle'      => $this->request->getName(),
234
-                    'tbaction'     => 'new-account',
235
-                    'tbnooverride' => true,
236
-                    'format'       => 'php',
237
-                )
238
-            );
239
-
240
-            $data = unserialize($apiResult);
241
-
242
-            $requestIsOk = $data['titleblacklist']['result'] == "ok";
243
-
244
-            if (!$requestIsOk) {
245
-                $this->request->setStatus("Flagged users");
246
-            }
247
-        }
248
-    }
249
-
250
-    private function userExists()
251
-    {
252
-        $userExists = $this->httpHelper->get(
253
-            $this->mediawikiApiEndpoint,
254
-            array(
255
-                'action'  => 'query',
256
-                'list'    => 'users',
257
-                'ususers' => $this->request->getName(),
258
-                'format'  => 'php',
259
-            )
260
-        );
261
-
262
-        $ue = unserialize($userExists);
263
-        if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) {
264
-            return true;
265
-        }
266
-
267
-        return false;
268
-    }
269
-
270
-    private function userSulExists()
271
-    {
272
-        $requestName = $this->request->getName();
273
-
274
-        $userExists = $this->httpHelper->get(
275
-            $this->mediawikiApiEndpoint,
276
-            array(
277
-                'action'  => 'query',
278
-                'meta'    => 'globaluserinfo',
279
-                'guiuser' => $requestName,
280
-                'format'  => 'php',
281
-            )
282
-        );
283
-
284
-        $ue = unserialize($userExists);
285
-        if (isset ($ue['query']['globaluserinfo']['id'])) {
286
-            return true;
287
-        }
288
-
289
-        return false;
290
-    }
291
-
292
-    /**
293
-     * Checks if a request with this name is currently open
294
-     *
295
-     * @return bool
296
-     */
297
-    private function nameRequestExists()
298
-    {
299
-        $query = "SELECT COUNT(id) FROM request WHERE status != 'Closed' AND name = :name;";
300
-        $statement = $this->database->prepare($query);
301
-        $statement->execute(array(':name' => $this->request->getName()));
302
-
303
-        if (!$statement) {
304
-            return false;
305
-        }
306
-
307
-        return $statement->fetchColumn() > 0;
308
-    }
25
+	/** @var IBanHelper */
26
+	private $banHelper;
27
+	/** @var Request */
28
+	private $request;
29
+	private $emailConfirmation;
30
+	/** @var PdoDatabase */
31
+	private $database;
32
+	/** @var IAntiSpoofProvider */
33
+	private $antiSpoofProvider;
34
+	/** @var IXffTrustProvider */
35
+	private $xffTrustProvider;
36
+	/** @var HttpHelper */
37
+	private $httpHelper;
38
+	/**
39
+	 * @var string
40
+	 */
41
+	private $mediawikiApiEndpoint;
42
+	private $titleBlacklistEnabled;
43
+	/**
44
+	 * @var TorExitProvider
45
+	 */
46
+	private $torExitProvider;
47
+
48
+	/**
49
+	 * Summary of __construct
50
+	 *
51
+	 * @param IBanHelper         $banHelper
52
+	 * @param Request            $request
53
+	 * @param string             $emailConfirmation
54
+	 * @param PdoDatabase        $database
55
+	 * @param IAntiSpoofProvider $antiSpoofProvider
56
+	 * @param IXffTrustProvider  $xffTrustProvider
57
+	 * @param HttpHelper         $httpHelper
58
+	 * @param string             $mediawikiApiEndpoint
59
+	 * @param boolean            $titleBlacklistEnabled
60
+	 * @param TorExitProvider    $torExitProvider
61
+	 */
62
+	public function __construct(
63
+		IBanHelper $banHelper,
64
+		Request $request,
65
+		$emailConfirmation,
66
+		PdoDatabase $database,
67
+		IAntiSpoofProvider $antiSpoofProvider,
68
+		IXffTrustProvider $xffTrustProvider,
69
+		HttpHelper $httpHelper,
70
+		$mediawikiApiEndpoint,
71
+		$titleBlacklistEnabled,
72
+		TorExitProvider $torExitProvider
73
+	) {
74
+		$this->banHelper = $banHelper;
75
+		$this->request = $request;
76
+		$this->emailConfirmation = $emailConfirmation;
77
+		$this->database = $database;
78
+		$this->antiSpoofProvider = $antiSpoofProvider;
79
+		$this->xffTrustProvider = $xffTrustProvider;
80
+		$this->httpHelper = $httpHelper;
81
+		$this->mediawikiApiEndpoint = $mediawikiApiEndpoint;
82
+		$this->titleBlacklistEnabled = $titleBlacklistEnabled;
83
+		$this->torExitProvider = $torExitProvider;
84
+	}
85
+
86
+	/**
87
+	 * Summary of validateName
88
+	 * @return ValidationError[]
89
+	 */
90
+	public function validateName()
91
+	{
92
+		$errorList = array();
93
+
94
+		// ERRORS
95
+		// name is empty
96
+		if (trim($this->request->getName()) == "") {
97
+			$errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_EMPTY);
98
+		}
99
+
100
+		// name is banned
101
+		$ban = $this->banHelper->nameIsBanned($this->request->getName());
102
+		if ($ban != false) {
103
+			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
104
+		}
105
+
106
+		// username already exists
107
+		if ($this->userExists()) {
108
+			$errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS);
109
+		}
110
+
111
+		// username part of SUL account
112
+		if ($this->userSulExists()) {
113
+			// using same error slot as name exists - it's the same sort of error, and we probably only want to show one.
114
+			$errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS_SUL);
115
+		}
116
+
117
+		// username is numbers
118
+		if (preg_match("/^[0-9]+$/", $this->request->getName()) === 1) {
119
+			$errorList[ValidationError::NAME_NUMONLY] = new ValidationError(ValidationError::NAME_NUMONLY);
120
+		}
121
+
122
+		// username can't contain #@/<>[]|{}
123
+		if (preg_match("/[" . preg_quote("#@/<>[]|{}", "/") . "]/", $this->request->getName()) === 1) {
124
+			$errorList[ValidationError::NAME_INVALIDCHAR] = new ValidationError(ValidationError::NAME_INVALIDCHAR);
125
+		}
126
+
127
+		// existing non-closed request for this name
128
+		if ($this->nameRequestExists()) {
129
+			$errorList[ValidationError::OPEN_REQUEST_NAME] = new ValidationError(ValidationError::OPEN_REQUEST_NAME);
130
+		}
131
+
132
+		return $errorList;
133
+	}
134
+
135
+	/**
136
+	 * Summary of validateEmail
137
+	 * @return ValidationError[]
138
+	 */
139
+	public function validateEmail()
140
+	{
141
+		$errorList = array();
142
+
143
+		// ERRORS
144
+
145
+		// Email is banned
146
+		$ban = $this->banHelper->emailIsBanned($this->request->getEmail());
147
+		if ($ban != false) {
148
+			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
149
+		}
150
+
151
+		// email addresses must match
152
+		if ($this->request->getEmail() != $this->emailConfirmation) {
153
+			$errorList[ValidationError::EMAIL_MISMATCH] = new ValidationError(ValidationError::EMAIL_MISMATCH);
154
+		}
155
+
156
+		// email address must be validly formed
157
+		if (trim($this->request->getEmail()) == "") {
158
+			$errorList[ValidationError::EMAIL_EMPTY] = new ValidationError(ValidationError::EMAIL_EMPTY);
159
+		}
160
+
161
+		// email address must be validly formed
162
+		if (!filter_var($this->request->getEmail(), FILTER_VALIDATE_EMAIL)) {
163
+			if (trim($this->request->getEmail()) != "") {
164
+				$errorList[ValidationError::EMAIL_INVALID] = new ValidationError(ValidationError::EMAIL_INVALID);
165
+			}
166
+		}
167
+
168
+		// email address can't be wikimedia/wikipedia .com/org
169
+		if (preg_match('/.*@.*wiki(m.dia|p.dia)\.(org|com)/i', $this->request->getEmail()) === 1) {
170
+			$errorList[ValidationError::EMAIL_WIKIMEDIA] = new ValidationError(ValidationError::EMAIL_WIKIMEDIA);
171
+		}
172
+
173
+		// WARNINGS
174
+
175
+		return $errorList;
176
+	}
177
+
178
+	/**
179
+	 * Summary of validateOther
180
+	 * @return ValidationError[]
181
+	 */
182
+	public function validateOther()
183
+	{
184
+		$errorList = array();
185
+
186
+		$trustedIp = $this->xffTrustProvider->getTrustedClientIp($this->request->getIp(),
187
+			$this->request->getForwardedIp());
188
+
189
+		// ERRORS
190
+
191
+		// TOR nodes
192
+		if ($this->torExitProvider->isTorExit($trustedIp)) {
193
+			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED_TOR);
194
+		}
195
+
196
+		// IP banned
197
+		$ban = $this->banHelper->ipIsBanned($trustedIp);
198
+		if ($ban != false) {
199
+			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
200
+		}
201
+
202
+		// WARNINGS
203
+
204
+		// Antispoof check
205
+		$this->checkAntiSpoof();
206
+
207
+		// Blacklist check
208
+		$this->checkTitleBlacklist();
209
+
210
+		return $errorList;
211
+	}
212
+
213
+	private function checkAntiSpoof()
214
+	{
215
+		try {
216
+			if (count($this->antiSpoofProvider->getSpoofs($this->request->getName())) > 0) {
217
+				// If there were spoofs an Admin should handle the request.
218
+				$this->request->setStatus("Flagged users");
219
+			}
220
+		}
221
+		catch (Exception $ex) {
222
+			// logme
223
+		}
224
+	}
225
+
226
+	private function checkTitleBlacklist()
227
+	{
228
+		if ($this->titleBlacklistEnabled == 1) {
229
+			$apiResult = $this->httpHelper->get(
230
+				$this->mediawikiApiEndpoint,
231
+				array(
232
+					'action'       => 'titleblacklist',
233
+					'tbtitle'      => $this->request->getName(),
234
+					'tbaction'     => 'new-account',
235
+					'tbnooverride' => true,
236
+					'format'       => 'php',
237
+				)
238
+			);
239
+
240
+			$data = unserialize($apiResult);
241
+
242
+			$requestIsOk = $data['titleblacklist']['result'] == "ok";
243
+
244
+			if (!$requestIsOk) {
245
+				$this->request->setStatus("Flagged users");
246
+			}
247
+		}
248
+	}
249
+
250
+	private function userExists()
251
+	{
252
+		$userExists = $this->httpHelper->get(
253
+			$this->mediawikiApiEndpoint,
254
+			array(
255
+				'action'  => 'query',
256
+				'list'    => 'users',
257
+				'ususers' => $this->request->getName(),
258
+				'format'  => 'php',
259
+			)
260
+		);
261
+
262
+		$ue = unserialize($userExists);
263
+		if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) {
264
+			return true;
265
+		}
266
+
267
+		return false;
268
+	}
269
+
270
+	private function userSulExists()
271
+	{
272
+		$requestName = $this->request->getName();
273
+
274
+		$userExists = $this->httpHelper->get(
275
+			$this->mediawikiApiEndpoint,
276
+			array(
277
+				'action'  => 'query',
278
+				'meta'    => 'globaluserinfo',
279
+				'guiuser' => $requestName,
280
+				'format'  => 'php',
281
+			)
282
+		);
283
+
284
+		$ue = unserialize($userExists);
285
+		if (isset ($ue['query']['globaluserinfo']['id'])) {
286
+			return true;
287
+		}
288
+
289
+		return false;
290
+	}
291
+
292
+	/**
293
+	 * Checks if a request with this name is currently open
294
+	 *
295
+	 * @return bool
296
+	 */
297
+	private function nameRequestExists()
298
+	{
299
+		$query = "SELECT COUNT(id) FROM request WHERE status != 'Closed' AND name = :name;";
300
+		$statement = $this->database->prepare($query);
301
+		$statement->execute(array(':name' => $this->request->getName()));
302
+
303
+		if (!$statement) {
304
+			return false;
305
+		}
306
+
307
+		return $statement->fetchColumn() > 0;
308
+	}
309 309
 }
Please login to merge, or discard this patch.
includes/IrcColourCode.php 1 patch
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -10,27 +10,27 @@
 block discarded – undo
10 10
 
11 11
 class IrcColourCode
12 12
 {
13
-    const BOLD = "\x02";
14
-    const ITALIC = "\x09";
15
-    const STRIKE = "\x13";
16
-    const UNDERLINE = "\x15";
17
-    const UNDERLINE2 = "\x1f";
18
-    const REVERSE = "\x16";
19
-    const RESET = "\x0f";
20
-    const WHITE = "\x0300";
21
-    const BLACK = "\x0301";
22
-    const DARK_BLUE = "\x0302";
23
-    const DARK_GREEN = "\x0303";
24
-    const RED = "\x0304";
25
-    const DARK_RED = "\x0305";
26
-    const DARK_VIOLET = "\x0306";
27
-    const ORANGE = "\x0307";
28
-    const YELLOW = "\x0308";
29
-    const LIGHT_GREEN = "\x0309";
30
-    const CYAN = "\x0310";
31
-    const LIGHT_CYAN = "\x0311";
32
-    const BLUE = "\x0312";
33
-    const VIOLET = "\x0313";
34
-    const DARK_GREY = "\x0314";
35
-    const LIGHT_GREY = "\x0315";
13
+	const BOLD = "\x02";
14
+	const ITALIC = "\x09";
15
+	const STRIKE = "\x13";
16
+	const UNDERLINE = "\x15";
17
+	const UNDERLINE2 = "\x1f";
18
+	const REVERSE = "\x16";
19
+	const RESET = "\x0f";
20
+	const WHITE = "\x0300";
21
+	const BLACK = "\x0301";
22
+	const DARK_BLUE = "\x0302";
23
+	const DARK_GREEN = "\x0303";
24
+	const RED = "\x0304";
25
+	const DARK_RED = "\x0305";
26
+	const DARK_VIOLET = "\x0306";
27
+	const ORANGE = "\x0307";
28
+	const YELLOW = "\x0308";
29
+	const LIGHT_GREEN = "\x0309";
30
+	const CYAN = "\x0310";
31
+	const LIGHT_CYAN = "\x0311";
32
+	const BLUE = "\x0312";
33
+	const VIOLET = "\x0313";
34
+	const DARK_GREY = "\x0314";
35
+	const LIGHT_GREY = "\x0315";
36 36
 }
Please login to merge, or discard this patch.
includes/Session.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -17,25 +17,25 @@
 block discarded – undo
17 17
  */
18 18
 class Session
19 19
 {
20
-    public static function start()
21
-    {
22
-        ini_set('session.cookie_httponly', 1);
20
+	public static function start()
21
+	{
22
+		ini_set('session.cookie_httponly', 1);
23 23
 
24
-        if (WebRequest::isHttps()) {
25
-            ini_set('session.cookie_secure', 1);
26
-        }
24
+		if (WebRequest::isHttps()) {
25
+			ini_set('session.cookie_secure', 1);
26
+		}
27 27
 
28
-        session_start();
29
-    }
28
+		session_start();
29
+	}
30 30
 
31
-    public static function destroy()
32
-    {
33
-        session_destroy();
34
-    }
31
+	public static function destroy()
32
+	{
33
+		session_destroy();
34
+	}
35 35
 
36
-    public static function restart()
37
-    {
38
-        self::destroy();
39
-        self::start();
40
-    }
36
+	public static function restart()
37
+	{
38
+		self::destroy();
39
+		self::start();
40
+	}
41 41
 }
Please login to merge, or discard this patch.
includes/Helpers/DebugHelper.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -13,53 +13,53 @@
 block discarded – undo
13 13
  */
14 14
 class DebugHelper
15 15
 {
16
-    /**
17
-     * Internal mockable method wrapper for debug_backtrace.
18
-     *
19
-     * As mocking out debug_backtrace uses debug_backtrace internally, we need this in order to not cause a recursive
20
-     * cascade until the runtime explodes.
21
-     *
22
-     * Instead, we mock this method, which allows debug_backtrace to still be called correctly.
23
-     *
24
-     * @return array
25
-     */
26
-    public function get_debug_backtrace()
27
-    {
28
-        return debug_backtrace();
29
-    }
16
+	/**
17
+	 * Internal mockable method wrapper for debug_backtrace.
18
+	 *
19
+	 * As mocking out debug_backtrace uses debug_backtrace internally, we need this in order to not cause a recursive
20
+	 * cascade until the runtime explodes.
21
+	 *
22
+	 * Instead, we mock this method, which allows debug_backtrace to still be called correctly.
23
+	 *
24
+	 * @return array
25
+	 */
26
+	public function get_debug_backtrace()
27
+	{
28
+		return debug_backtrace();
29
+	}
30 30
 
31
-    /**
32
-     * Returns a string representation of the current backtrace for display.
33
-     *
34
-     * Note that this explicitly excludes the top two frames, which will be methods from this class.
35
-     *
36
-     * @return string
37
-     */
38
-    public function getBacktrace()
39
-    {
40
-        $backtrace = $this->get_debug_backtrace();
31
+	/**
32
+	 * Returns a string representation of the current backtrace for display.
33
+	 *
34
+	 * Note that this explicitly excludes the top two frames, which will be methods from this class.
35
+	 *
36
+	 * @return string
37
+	 */
38
+	public function getBacktrace()
39
+	{
40
+		$backtrace = $this->get_debug_backtrace();
41 41
 
42
-        $output = "";
42
+		$output = "";
43 43
 
44
-        $count = 0;
45
-        foreach ($backtrace as $line) {
46
-            if ($count <= 1) {
47
-                $count++;
48
-                continue;
49
-            }
44
+		$count = 0;
45
+		foreach ($backtrace as $line) {
46
+			if ($count <= 1) {
47
+				$count++;
48
+				continue;
49
+			}
50 50
 
51
-            $output .= "#{$count}: ";
51
+			$output .= "#{$count}: ";
52 52
 
53
-            if (isset($line['type']) && $line['type'] != "") {
54
-                $output .= $line['class'] . $line['type'];
55
-            }
53
+			if (isset($line['type']) && $line['type'] != "") {
54
+				$output .= $line['class'] . $line['type'];
55
+			}
56 56
 
57
-            $output .= $line['function'] . "(...)";
58
-            $output .= " [{$line['file']}#{$line['line']}\r\n";
57
+			$output .= $line['function'] . "(...)";
58
+			$output .= " [{$line['file']}#{$line['line']}\r\n";
59 59
 
60
-            $count++;
61
-        }
60
+			$count++;
61
+		}
62 62
 
63
-        return $output;
64
-    }
63
+		return $output;
64
+	}
65 65
 }
Please login to merge, or discard this patch.
includes/Helpers/FakeBlacklistHelper.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -12,16 +12,16 @@
 block discarded – undo
12 12
 
13 13
 class FakeBlacklistHelper implements IBlacklistHelper
14 14
 {
15
-    /**
16
-     * Returns a value indicating whether the provided username is blacklisted by the on-wiki title blacklist
17
-     *
18
-     * @param string $username
19
-     *
20
-     * @return bool
21
-     */
22
-    public function isBlacklisted($username)
23
-    {
24
-        // Short-circuit
25
-        return false;
26
-    }
15
+	/**
16
+	 * Returns a value indicating whether the provided username is blacklisted by the on-wiki title blacklist
17
+	 *
18
+	 * @param string $username
19
+	 *
20
+	 * @return bool
21
+	 */
22
+	public function isBlacklisted($username)
23
+	{
24
+		// Short-circuit
25
+		return false;
26
+	}
27 27
 }
28 28
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Helpers/BanHelper.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -14,49 +14,49 @@
 block discarded – undo
14 14
 
15 15
 class BanHelper implements IBanHelper
16 16
 {
17
-    /**
18
-     * @var PdoDatabase
19
-     */
20
-    private $database;
17
+	/**
18
+	 * @var PdoDatabase
19
+	 */
20
+	private $database;
21 21
 
22
-    public function __construct(PdoDatabase $database)
23
-    {
24
-        $this->database = $database;
25
-    }
22
+	public function __construct(PdoDatabase $database)
23
+	{
24
+		$this->database = $database;
25
+	}
26 26
 
27
-    /**
28
-     * Summary of nameIsBanned
29
-     *
30
-     * @param string $name The name to test if is banned.
31
-     *
32
-     * @return Ban
33
-     */
34
-    public function nameIsBanned($name)
35
-    {
36
-        return Ban::getBanByTarget($name, "Name", $this->database);
37
-    }
27
+	/**
28
+	 * Summary of nameIsBanned
29
+	 *
30
+	 * @param string $name The name to test if is banned.
31
+	 *
32
+	 * @return Ban
33
+	 */
34
+	public function nameIsBanned($name)
35
+	{
36
+		return Ban::getBanByTarget($name, "Name", $this->database);
37
+	}
38 38
 
39
-    /**
40
-     * Summary of emailIsBanned
41
-     *
42
-     * @param string $email
43
-     *
44
-     * @return Ban
45
-     */
46
-    public function emailIsBanned($email)
47
-    {
48
-        return Ban::getBanByTarget($email, "EMail", $this->database);
49
-    }
39
+	/**
40
+	 * Summary of emailIsBanned
41
+	 *
42
+	 * @param string $email
43
+	 *
44
+	 * @return Ban
45
+	 */
46
+	public function emailIsBanned($email)
47
+	{
48
+		return Ban::getBanByTarget($email, "EMail", $this->database);
49
+	}
50 50
 
51
-    /**
52
-     * Summary of ipIsBanned
53
-     *
54
-     * @param string $ip
55
-     *
56
-     * @return Ban
57
-     */
58
-    public function ipIsBanned($ip)
59
-    {
60
-        return Ban::getBanByTarget($ip, "IP", $this->database);
61
-    }
51
+	/**
52
+	 * Summary of ipIsBanned
53
+	 *
54
+	 * @param string $ip
55
+	 *
56
+	 * @return Ban
57
+	 */
58
+	public function ipIsBanned($ip)
59
+	{
60
+		return Ban::getBanByTarget($ip, "IP", $this->database);
61
+	}
62 62
 }
Please login to merge, or discard this patch.