Completed
Pull Request — newinternal (#547)
by Simon
05:45
created
includes/Fragments/RequestData.php 1 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/Pages/PageViewRequest.php 1 patch
Indentation   +284 added lines, -284 removed lines patch added patch discarded remove patch
@@ -25,288 +25,288 @@
 block discarded – undo
25 25
 
26 26
 class PageViewRequest extends InternalPageBase
27 27
 {
28
-    use RequestData;
29
-    const STATUS_SYMBOL_OPEN = '&#x2610';
30
-    const STATUS_SYMBOL_ACCEPTED = '&#x2611';
31
-    const STATUS_SYMBOL_REJECTED = '&#x2612';
32
-
33
-    /**
34
-     * Main function for this page, when no specific actions are called.
35
-     * @throws ApplicationLogicException
36
-     */
37
-    protected function main()
38
-    {
39
-        // set up csrf protection
40
-        $this->assignCSRFToken();
41
-
42
-        // get some useful objects
43
-        $database = $this->getDatabase();
44
-        $request = $this->getRequest($database, WebRequest::getInt('id'));
45
-        $config = $this->getSiteConfiguration();
46
-        $currentUser = User::getCurrent($database);
47
-
48
-        // Test we should be able to look at this request
49
-        if ($config->getEmailConfirmationEnabled()) {
50
-            if ($request->getEmailConfirm() !== 'Confirmed') {
51
-                // Not allowed to look at this yet.
52
-                throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
53
-            }
54
-        }
55
-
56
-        $this->setupBasicData($request, $config);
57
-
58
-        $this->setupUsernameData($request);
59
-
60
-        $this->setupTitle($request);
61
-
62
-        $this->setupReservationDetails($request->getReserved(), $database, $currentUser);
63
-        $this->setupGeneralData($database);
64
-
65
-        $this->assign('requestDataCleared', false);
66
-        if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
67
-            $this->assign('requestDataCleared', true);
68
-        }
69
-
70
-        $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
71
-
72
-        $this->setupCreationTypes($currentUser);
73
-
74
-        $this->setupLogData($request, $database);
75
-
76
-        $this->addJs("/api.php?action=templates&targetVariable=templateconfirms");
77
-
78
-        $this->assign('showRevealLink', false);
79
-        if ($request->getReserved() === $currentUser->getId() ||
80
-            $this->barrierTest('alwaysSeeHash', $currentUser, 'RequestData')
81
-        ) {
82
-            $this->assign('showRevealLink', true);
83
-            $this->assign('revealHash', $request->getRevealHash());
84
-        }
85
-
86
-        if ($allowedPrivateData) {
87
-            $this->setTemplate('view-request/main-with-data.tpl');
88
-            $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
89
-
90
-            $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
91
-            $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
92
-
93
-            if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
94
-                $this->setTemplate('view-request/main-with-checkuser-data.tpl');
95
-                $this->setupCheckUserData($request);
96
-            }
97
-        }
98
-        else {
99
-            $this->setTemplate('view-request/main.tpl');
100
-        }
101
-    }
102
-
103
-    /**
104
-     * @param Request $request
105
-     */
106
-    protected function setupTitle(Request $request)
107
-    {
108
-        $statusSymbol = self::STATUS_SYMBOL_OPEN;
109
-        if ($request->getStatus() === 'Closed') {
110
-            if ($request->getWasCreated()) {
111
-                $statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
112
-            }
113
-            else {
114
-                $statusSymbol = self::STATUS_SYMBOL_REJECTED;
115
-            }
116
-        }
117
-
118
-        $this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
119
-    }
120
-
121
-    /**
122
-     * Sets up data unrelated to the request, such as the email template information
123
-     *
124
-     * @param PdoDatabase $database
125
-     */
126
-    protected function setupGeneralData(PdoDatabase $database)
127
-    {
128
-        $config = $this->getSiteConfiguration();
129
-
130
-        $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
131
-
132
-        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
133
-
134
-        $this->assign('requestStates', $config->getRequestStates());
135
-
136
-        /** @var EmailTemplate $createdTemplate */
137
-        $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
138
-
139
-        $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
140
-        $this->assign('createdId', $createdTemplate->getId());
141
-        $this->assign('createdName', $createdTemplate->getName());
142
-
143
-        $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
144
-        $this->assign("createReasons", $createReasons);
145
-        $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
146
-        $this->assign("declineReasons", $declineReasons);
147
-
148
-        $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
149
-        $this->assign("allCreateReasons", $allCreateReasons);
150
-        $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
151
-        $this->assign("allDeclineReasons", $allDeclineReasons);
152
-        $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
153
-        $this->assign("allOtherReasons", $allOtherReasons);
154
-    }
155
-
156
-    private function setupLogData(Request $request, PdoDatabase $database)
157
-    {
158
-        $currentUser = User::getCurrent($database);
159
-
160
-        $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
161
-        $requestLogs = array();
162
-
163
-        if (trim($request->getComment()) !== "") {
164
-            $requestLogs[] = array(
165
-                'type'     => 'comment',
166
-                'security' => 'user',
167
-                'userid'   => null,
168
-                'user'     => $request->getName(),
169
-                'entry'    => null,
170
-                'time'     => $request->getDate(),
171
-                'canedit'  => false,
172
-                'id'       => $request->getId(),
173
-                'comment'  => $request->getComment(),
174
-            );
175
-        }
176
-
177
-        /** @var User[] $nameCache */
178
-        $nameCache = array();
179
-
180
-        $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
181
-
182
-        /** @var Log|Comment $entry */
183
-        foreach ($logs as $entry) {
184
-            // both log and comment have a 'user' field
185
-            if (!array_key_exists($entry->getUser(), $nameCache)) {
186
-                $entryUser = User::getById($entry->getUser(), $database);
187
-                $nameCache[$entry->getUser()] = $entryUser;
188
-            }
189
-
190
-            if ($entry instanceof Comment) {
191
-                $requestLogs[] = array(
192
-                    'type'     => 'comment',
193
-                    'security' => $entry->getVisibility(),
194
-                    'user'     => $nameCache[$entry->getUser()]->getUsername(),
195
-                    'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
196
-                    'entry'    => null,
197
-                    'time'     => $entry->getTime(),
198
-                    'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
199
-                    'id'       => $entry->getId(),
200
-                    'comment'  => $entry->getComment(),
201
-                );
202
-            }
203
-
204
-            if ($entry instanceof Log) {
205
-                $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
206
-                $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
207
-
208
-                $entryComment = $entry->getComment();
209
-
210
-                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
211
-                    $data = unserialize($entry->getComment());
212
-                    /** @var JobQueue $job */
213
-                    $job = JobQueue::getById($data['job'], $database);
214
-                    $requestLogs[] = array(
215
-                        'type'     => 'joblog',
216
-                        'security' => 'user',
217
-                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
218
-                        'user'     => $entryUser->getUsername(),
219
-                        'entry'    => LogHelper::getLogDescription($entry),
220
-                        'time'     => $entry->getTimestamp(),
221
-                        'canedit'  => false,
222
-                        'id'       => $entry->getId(),
223
-                        'jobId'    => $job->getId(),
224
-                        'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
225
-                    );
226
-                } else {
227
-                    $requestLogs[] = array(
228
-                        'type'     => 'log',
229
-                        'security' => 'user',
230
-                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
231
-                        'user'     => $entryUser->getUsername(),
232
-                        'entry'    => LogHelper::getLogDescription($entry),
233
-                        'time'     => $entry->getTimestamp(),
234
-                        'canedit'  => false,
235
-                        'id'       => $entry->getId(),
236
-                        'comment'  => $entryComment,
237
-                    );
238
-                }
239
-            }
240
-        }
241
-
242
-        $this->addJs("/api.php?action=users&targetVariable=typeaheaddata");
243
-
244
-        $this->assign("requestLogs", $requestLogs);
245
-    }
246
-
247
-    /**
248
-     * @param Request $request
249
-     */
250
-    protected function setupUsernameData(Request $request)
251
-    {
252
-        $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
253
-
254
-        $this->assign('requestIsBlacklisted', $blacklistData !== false);
255
-        $this->assign('requestBlacklist', $blacklistData);
256
-
257
-        try {
258
-            $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
259
-        }
260
-        catch (Exception $ex) {
261
-            $spoofs = $ex->getMessage();
262
-        }
263
-
264
-        $this->assign("spoofs", $spoofs);
265
-    }
266
-
267
-    private function setupCreationTypes(User $user)
268
-    {
269
-        $this->assign('allowWelcomeSkip', false);
270
-        $this->assign('forceWelcomeSkip', false);
271
-
272
-        $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
273
-
274
-        if ($user->getWelcomeTemplate() != 0) {
275
-            $this->assign('allowWelcomeSkip', true);
276
-
277
-            if (!$oauth->canWelcome()) {
278
-                $this->assign('forceWelcomeSkip', true);
279
-            }
280
-        }
281
-
282
-        // test credentials
283
-        $canManualCreate = $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation');
284
-        $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation');
285
-        $canBotCreate = $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation');
286
-
287
-        $this->assign('canManualCreate', $canManualCreate);
288
-        $this->assign('canOauthCreate', $canOauthCreate);
289
-        $this->assign('canBotCreate', $canBotCreate);
290
-
291
-        // show/hide the type radio buttons
292
-        $creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1;
293
-
294
-        if (!$this->barrierTest($user->getCreationMode(), $user, 'RequestCreation')) {
295
-            // user is not allowed to use their default. Force a choice.
296
-            $creationHasChoice = true;
297
-        }
298
-
299
-        $this->assign('creationHasChoice', $creationHasChoice);
300
-
301
-        // determine problems in creation types
302
-        $this->assign('botProblem', false);
303
-        if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) {
304
-            $this->assign('botProblem', true);
305
-        }
306
-
307
-        $this->assign('oauthProblem', false);
308
-        if ($canOauthCreate && !$oauth->canCreateAccount()) {
309
-            $this->assign('oauthProblem', true);
310
-        }
311
-    }
28
+	use RequestData;
29
+	const STATUS_SYMBOL_OPEN = '&#x2610';
30
+	const STATUS_SYMBOL_ACCEPTED = '&#x2611';
31
+	const STATUS_SYMBOL_REJECTED = '&#x2612';
32
+
33
+	/**
34
+	 * Main function for this page, when no specific actions are called.
35
+	 * @throws ApplicationLogicException
36
+	 */
37
+	protected function main()
38
+	{
39
+		// set up csrf protection
40
+		$this->assignCSRFToken();
41
+
42
+		// get some useful objects
43
+		$database = $this->getDatabase();
44
+		$request = $this->getRequest($database, WebRequest::getInt('id'));
45
+		$config = $this->getSiteConfiguration();
46
+		$currentUser = User::getCurrent($database);
47
+
48
+		// Test we should be able to look at this request
49
+		if ($config->getEmailConfirmationEnabled()) {
50
+			if ($request->getEmailConfirm() !== 'Confirmed') {
51
+				// Not allowed to look at this yet.
52
+				throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
53
+			}
54
+		}
55
+
56
+		$this->setupBasicData($request, $config);
57
+
58
+		$this->setupUsernameData($request);
59
+
60
+		$this->setupTitle($request);
61
+
62
+		$this->setupReservationDetails($request->getReserved(), $database, $currentUser);
63
+		$this->setupGeneralData($database);
64
+
65
+		$this->assign('requestDataCleared', false);
66
+		if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
67
+			$this->assign('requestDataCleared', true);
68
+		}
69
+
70
+		$allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
71
+
72
+		$this->setupCreationTypes($currentUser);
73
+
74
+		$this->setupLogData($request, $database);
75
+
76
+		$this->addJs("/api.php?action=templates&targetVariable=templateconfirms");
77
+
78
+		$this->assign('showRevealLink', false);
79
+		if ($request->getReserved() === $currentUser->getId() ||
80
+			$this->barrierTest('alwaysSeeHash', $currentUser, 'RequestData')
81
+		) {
82
+			$this->assign('showRevealLink', true);
83
+			$this->assign('revealHash', $request->getRevealHash());
84
+		}
85
+
86
+		if ($allowedPrivateData) {
87
+			$this->setTemplate('view-request/main-with-data.tpl');
88
+			$this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
89
+
90
+			$this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
91
+			$this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
92
+
93
+			if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
94
+				$this->setTemplate('view-request/main-with-checkuser-data.tpl');
95
+				$this->setupCheckUserData($request);
96
+			}
97
+		}
98
+		else {
99
+			$this->setTemplate('view-request/main.tpl');
100
+		}
101
+	}
102
+
103
+	/**
104
+	 * @param Request $request
105
+	 */
106
+	protected function setupTitle(Request $request)
107
+	{
108
+		$statusSymbol = self::STATUS_SYMBOL_OPEN;
109
+		if ($request->getStatus() === 'Closed') {
110
+			if ($request->getWasCreated()) {
111
+				$statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
112
+			}
113
+			else {
114
+				$statusSymbol = self::STATUS_SYMBOL_REJECTED;
115
+			}
116
+		}
117
+
118
+		$this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
119
+	}
120
+
121
+	/**
122
+	 * Sets up data unrelated to the request, such as the email template information
123
+	 *
124
+	 * @param PdoDatabase $database
125
+	 */
126
+	protected function setupGeneralData(PdoDatabase $database)
127
+	{
128
+		$config = $this->getSiteConfiguration();
129
+
130
+		$this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
131
+
132
+		$this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
133
+
134
+		$this->assign('requestStates', $config->getRequestStates());
135
+
136
+		/** @var EmailTemplate $createdTemplate */
137
+		$createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
138
+
139
+		$this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
140
+		$this->assign('createdId', $createdTemplate->getId());
141
+		$this->assign('createdName', $createdTemplate->getName());
142
+
143
+		$createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
144
+		$this->assign("createReasons", $createReasons);
145
+		$declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
146
+		$this->assign("declineReasons", $declineReasons);
147
+
148
+		$allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
149
+		$this->assign("allCreateReasons", $allCreateReasons);
150
+		$allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
151
+		$this->assign("allDeclineReasons", $allDeclineReasons);
152
+		$allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
153
+		$this->assign("allOtherReasons", $allOtherReasons);
154
+	}
155
+
156
+	private function setupLogData(Request $request, PdoDatabase $database)
157
+	{
158
+		$currentUser = User::getCurrent($database);
159
+
160
+		$logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
161
+		$requestLogs = array();
162
+
163
+		if (trim($request->getComment()) !== "") {
164
+			$requestLogs[] = array(
165
+				'type'     => 'comment',
166
+				'security' => 'user',
167
+				'userid'   => null,
168
+				'user'     => $request->getName(),
169
+				'entry'    => null,
170
+				'time'     => $request->getDate(),
171
+				'canedit'  => false,
172
+				'id'       => $request->getId(),
173
+				'comment'  => $request->getComment(),
174
+			);
175
+		}
176
+
177
+		/** @var User[] $nameCache */
178
+		$nameCache = array();
179
+
180
+		$editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
181
+
182
+		/** @var Log|Comment $entry */
183
+		foreach ($logs as $entry) {
184
+			// both log and comment have a 'user' field
185
+			if (!array_key_exists($entry->getUser(), $nameCache)) {
186
+				$entryUser = User::getById($entry->getUser(), $database);
187
+				$nameCache[$entry->getUser()] = $entryUser;
188
+			}
189
+
190
+			if ($entry instanceof Comment) {
191
+				$requestLogs[] = array(
192
+					'type'     => 'comment',
193
+					'security' => $entry->getVisibility(),
194
+					'user'     => $nameCache[$entry->getUser()]->getUsername(),
195
+					'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
196
+					'entry'    => null,
197
+					'time'     => $entry->getTime(),
198
+					'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
199
+					'id'       => $entry->getId(),
200
+					'comment'  => $entry->getComment(),
201
+				);
202
+			}
203
+
204
+			if ($entry instanceof Log) {
205
+				$invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
206
+				$entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
207
+
208
+				$entryComment = $entry->getComment();
209
+
210
+				if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
211
+					$data = unserialize($entry->getComment());
212
+					/** @var JobQueue $job */
213
+					$job = JobQueue::getById($data['job'], $database);
214
+					$requestLogs[] = array(
215
+						'type'     => 'joblog',
216
+						'security' => 'user',
217
+						'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
218
+						'user'     => $entryUser->getUsername(),
219
+						'entry'    => LogHelper::getLogDescription($entry),
220
+						'time'     => $entry->getTimestamp(),
221
+						'canedit'  => false,
222
+						'id'       => $entry->getId(),
223
+						'jobId'    => $job->getId(),
224
+						'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
225
+					);
226
+				} else {
227
+					$requestLogs[] = array(
228
+						'type'     => 'log',
229
+						'security' => 'user',
230
+						'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
231
+						'user'     => $entryUser->getUsername(),
232
+						'entry'    => LogHelper::getLogDescription($entry),
233
+						'time'     => $entry->getTimestamp(),
234
+						'canedit'  => false,
235
+						'id'       => $entry->getId(),
236
+						'comment'  => $entryComment,
237
+					);
238
+				}
239
+			}
240
+		}
241
+
242
+		$this->addJs("/api.php?action=users&targetVariable=typeaheaddata");
243
+
244
+		$this->assign("requestLogs", $requestLogs);
245
+	}
246
+
247
+	/**
248
+	 * @param Request $request
249
+	 */
250
+	protected function setupUsernameData(Request $request)
251
+	{
252
+		$blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
253
+
254
+		$this->assign('requestIsBlacklisted', $blacklistData !== false);
255
+		$this->assign('requestBlacklist', $blacklistData);
256
+
257
+		try {
258
+			$spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
259
+		}
260
+		catch (Exception $ex) {
261
+			$spoofs = $ex->getMessage();
262
+		}
263
+
264
+		$this->assign("spoofs", $spoofs);
265
+	}
266
+
267
+	private function setupCreationTypes(User $user)
268
+	{
269
+		$this->assign('allowWelcomeSkip', false);
270
+		$this->assign('forceWelcomeSkip', false);
271
+
272
+		$oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
273
+
274
+		if ($user->getWelcomeTemplate() != 0) {
275
+			$this->assign('allowWelcomeSkip', true);
276
+
277
+			if (!$oauth->canWelcome()) {
278
+				$this->assign('forceWelcomeSkip', true);
279
+			}
280
+		}
281
+
282
+		// test credentials
283
+		$canManualCreate = $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation');
284
+		$canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation');
285
+		$canBotCreate = $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation');
286
+
287
+		$this->assign('canManualCreate', $canManualCreate);
288
+		$this->assign('canOauthCreate', $canOauthCreate);
289
+		$this->assign('canBotCreate', $canBotCreate);
290
+
291
+		// show/hide the type radio buttons
292
+		$creationHasChoice = count(array_filter([$canManualCreate, $canOauthCreate, $canBotCreate])) > 1;
293
+
294
+		if (!$this->barrierTest($user->getCreationMode(), $user, 'RequestCreation')) {
295
+			// user is not allowed to use their default. Force a choice.
296
+			$creationHasChoice = true;
297
+		}
298
+
299
+		$this->assign('creationHasChoice', $creationHasChoice);
300
+
301
+		// determine problems in creation types
302
+		$this->assign('botProblem', false);
303
+		if ($canBotCreate && $this->getSiteConfiguration()->getCreationBotPassword() === null) {
304
+			$this->assign('botProblem', true);
305
+		}
306
+
307
+		$this->assign('oauthProblem', false);
308
+		if ($canOauthCreate && !$oauth->canCreateAccount()) {
309
+			$this->assign('oauthProblem', true);
310
+		}
311
+	}
312 312
 }
Please login to merge, or discard this patch.
includes/Pages/PageExpandedRequestList.php 1 patch
Indentation   +111 added lines, -111 removed lines patch added patch discarded remove patch
@@ -19,120 +19,120 @@
 block discarded – undo
19 19
 
20 20
 class PageExpandedRequestList extends InternalPageBase
21 21
 {
22
-    /**
23
-     * Main function for this page, when no specific actions are called.
24
-     * @return void
25
-     * @todo This is very similar to the PageMain code, we could probably generalise this somehow
26
-     */
27
-    protected function main()
28
-    {
29
-        $config = $this->getSiteConfiguration();
30
-
31
-        $requestedStatus = WebRequest::getString('status');
32
-        $requestStates = $config->getRequestStates();
33
-
34
-        if ($requestedStatus !== null && isset($requestStates[$requestedStatus])) {
22
+	/**
23
+	 * Main function for this page, when no specific actions are called.
24
+	 * @return void
25
+	 * @todo This is very similar to the PageMain code, we could probably generalise this somehow
26
+	 */
27
+	protected function main()
28
+	{
29
+		$config = $this->getSiteConfiguration();
30
+
31
+		$requestedStatus = WebRequest::getString('status');
32
+		$requestStates = $config->getRequestStates();
33
+
34
+		if ($requestedStatus !== null && isset($requestStates[$requestedStatus])) {
35 35
 
36
-            $this->assignCSRFToken();
37
-
38
-            $database = $this->getDatabase();
39
-
40
-            $help = $requestStates[$requestedStatus]['queuehelp'];
41
-            $this->assign('queuehelp', $help);
42
-
43
-            if ($config->getEmailConfirmationEnabled()) {
44
-                $query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
45
-                $totalQuery = "SELECT COUNT(id) FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
46
-            }
47
-            else {
48
-                $query = "SELECT * FROM request WHERE status = :type;";
49
-                $totalQuery = "SELECT COUNT(id) FROM request WHERE status = :type;";
50
-            }
51
-
52
-            $statement = $database->prepare($query);
53
-
54
-            $totalRequestsStatement = $database->prepare($totalQuery);
55
-
56
-            $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
57
-
58
-            $type = $requestedStatus;
59
-
60
-            $statement->bindValue(":type", $type);
61
-            $statement->execute();
62
-
63
-            $requests = $statement->fetchAll(PDO::FETCH_CLASS, Request::class);
64
-
65
-            /** @var Request $req */
66
-            foreach ($requests as $req) {
67
-                $req->setDatabase($database);
68
-            }
69
-
70
-            $this->assign('requests', $requests);
71
-            $this->assign('header', $type);
72
-
73
-            $totalRequestsStatement->bindValue(':type', $type);
74
-            $totalRequestsStatement->execute();
75
-            $totalRequests = $totalRequestsStatement->fetchColumn();
76
-            $totalRequestsStatement->closeCursor();
77
-            $this->assign('totalRequests', $totalRequests);
78
-
79
-
80
-            $this->setHtmlTitle('{$header|escape}{if $totalRequests > 0} [{$totalRequests|escape}]{/if}');
81
-
82
-            $userIds = array_map(
83
-                function(Request $entry) {
84
-                    return $entry->getReserved();
85
-                },
86
-                $requests
87
-            );
88
-
89
-            $userList = UserSearchHelper::get($this->getDatabase())->inIds($userIds)->fetchMap('username');
90
-            $this->assign('userList', $userList);
91
-
92
-            $requestTrustedIp = [];
93
-            $relatedEmailRequests = [];
94
-            $relatedIpRequests = [];
95
-            foreach ($requests as $request) {
96
-                $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
97
-                    $request->getIp(),
98
-                    $request->getForwardedIp()
99
-                );
100
-
101
-                RequestSearchHelper::get($database)
102
-                    ->byIp($trustedIp)
103
-                    ->withConfirmedEmail()
104
-                    ->excludingPurgedData($this->getSiteConfiguration())
105
-                    ->excludingRequest($request->getId())
106
-                    ->getRecordCount($ipCount);
107
-
108
-                RequestSearchHelper::get($database)
109
-                    ->byEmailAddress($request->getEmail())
110
-                    ->withConfirmedEmail()
111
-                    ->excludingPurgedData($this->getSiteConfiguration())
112
-                    ->excludingRequest($request->getId())
113
-                    ->getRecordCount($emailCount);
114
-
115
-                $requestTrustedIp[$request->getId()] = $trustedIp;
116
-                $relatedEmailRequests[$request->getId()] = $emailCount;
117
-                $relatedIpRequests[$request->getId()] = $ipCount;
118
-            }
119
-            $this->assign('requestTrustedIp', $requestTrustedIp);
120
-            $this->assign('relatedEmailRequests', $relatedEmailRequests);
121
-            $this->assign('relatedIpRequests', $relatedIpRequests);
122
-
123
-            $this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
36
+			$this->assignCSRFToken();
37
+
38
+			$database = $this->getDatabase();
39
+
40
+			$help = $requestStates[$requestedStatus]['queuehelp'];
41
+			$this->assign('queuehelp', $help);
42
+
43
+			if ($config->getEmailConfirmationEnabled()) {
44
+				$query = "SELECT * FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
45
+				$totalQuery = "SELECT COUNT(id) FROM request WHERE status = :type AND emailconfirm = 'Confirmed';";
46
+			}
47
+			else {
48
+				$query = "SELECT * FROM request WHERE status = :type;";
49
+				$totalQuery = "SELECT COUNT(id) FROM request WHERE status = :type;";
50
+			}
51
+
52
+			$statement = $database->prepare($query);
53
+
54
+			$totalRequestsStatement = $database->prepare($totalQuery);
55
+
56
+			$this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
57
+
58
+			$type = $requestedStatus;
59
+
60
+			$statement->bindValue(":type", $type);
61
+			$statement->execute();
62
+
63
+			$requests = $statement->fetchAll(PDO::FETCH_CLASS, Request::class);
64
+
65
+			/** @var Request $req */
66
+			foreach ($requests as $req) {
67
+				$req->setDatabase($database);
68
+			}
69
+
70
+			$this->assign('requests', $requests);
71
+			$this->assign('header', $type);
72
+
73
+			$totalRequestsStatement->bindValue(':type', $type);
74
+			$totalRequestsStatement->execute();
75
+			$totalRequests = $totalRequestsStatement->fetchColumn();
76
+			$totalRequestsStatement->closeCursor();
77
+			$this->assign('totalRequests', $totalRequests);
78
+
79
+
80
+			$this->setHtmlTitle('{$header|escape}{if $totalRequests > 0} [{$totalRequests|escape}]{/if}');
81
+
82
+			$userIds = array_map(
83
+				function(Request $entry) {
84
+					return $entry->getReserved();
85
+				},
86
+				$requests
87
+			);
88
+
89
+			$userList = UserSearchHelper::get($this->getDatabase())->inIds($userIds)->fetchMap('username');
90
+			$this->assign('userList', $userList);
91
+
92
+			$requestTrustedIp = [];
93
+			$relatedEmailRequests = [];
94
+			$relatedIpRequests = [];
95
+			foreach ($requests as $request) {
96
+				$trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
97
+					$request->getIp(),
98
+					$request->getForwardedIp()
99
+				);
100
+
101
+				RequestSearchHelper::get($database)
102
+					->byIp($trustedIp)
103
+					->withConfirmedEmail()
104
+					->excludingPurgedData($this->getSiteConfiguration())
105
+					->excludingRequest($request->getId())
106
+					->getRecordCount($ipCount);
107
+
108
+				RequestSearchHelper::get($database)
109
+					->byEmailAddress($request->getEmail())
110
+					->withConfirmedEmail()
111
+					->excludingPurgedData($this->getSiteConfiguration())
112
+					->excludingRequest($request->getId())
113
+					->getRecordCount($emailCount);
114
+
115
+				$requestTrustedIp[$request->getId()] = $trustedIp;
116
+				$relatedEmailRequests[$request->getId()] = $emailCount;
117
+				$relatedIpRequests[$request->getId()] = $ipCount;
118
+			}
119
+			$this->assign('requestTrustedIp', $requestTrustedIp);
120
+			$this->assign('relatedEmailRequests', $relatedEmailRequests);
121
+			$this->assign('relatedIpRequests', $relatedIpRequests);
122
+
123
+			$this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
124 124
 
125
-            $currentUser = User::getCurrent($database);
126
-            $this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
127
-            $this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
125
+			$currentUser = User::getCurrent($database);
126
+			$this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
127
+			$this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
128 128
 
129
-            $this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
130
-            $this->assign('xff', $this->getXffTrustProvider());
129
+			$this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
130
+			$this->assign('xff', $this->getXffTrustProvider());
131 131
 
132
-            $this->assign('dataClearEmail', $this->getSiteConfiguration()->getDataClearEmail());
133
-            $this->assign('dataClearIp', $this->getSiteConfiguration()->getDataClearIp());
132
+			$this->assign('dataClearEmail', $this->getSiteConfiguration()->getDataClearEmail());
133
+			$this->assign('dataClearIp', $this->getSiteConfiguration()->getDataClearIp());
134 134
 
135
-            $this->setTemplate('mainpage/expandedrequestlist.tpl');
136
-        }
137
-    }
135
+			$this->setTemplate('mainpage/expandedrequestlist.tpl');
136
+		}
137
+	}
138 138
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageForgotPassword.php 1 patch
Indentation   +204 added lines, -204 removed lines patch added patch discarded remove patch
@@ -22,208 +22,208 @@
 block discarded – undo
22 22
 
23 23
 class PageForgotPassword extends InternalPageBase
24 24
 {
25
-    /**
26
-     * Main function for this page, when no specific actions are called.
27
-     *
28
-     * This is the forgotten password reset form
29
-     * @category Security-Critical
30
-     */
31
-    protected function main()
32
-    {
33
-        if (WebRequest::wasPosted()) {
34
-            $this->validateCSRFToken();
35
-            $username = WebRequest::postString('username');
36
-            $email = WebRequest::postEmail('email');
37
-            $database = $this->getDatabase();
38
-
39
-            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
-                throw new ApplicationLogicException("Both username and email address must be specified!");
41
-            }
42
-
43
-            $user = User::getByUsername($username, $database);
44
-            $this->sendResetMail($user, $email);
45
-
46
-            SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
-
48
-            $this->redirect('login');
49
-        }
50
-        else {
51
-            $this->assignCSRFToken();
52
-            $this->setTemplate('forgot-password/forgotpw.tpl');
53
-        }
54
-    }
55
-
56
-    /**
57
-     * Sends a reset email if the user is authenticated
58
-     *
59
-     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
-     *                            check anyway within this method and silently skip if we don't have a user.
61
-     * @param string       $email The provided email address
62
-     */
63
-    private function sendResetMail($user, $email)
64
-    {
65
-        // If the user isn't found, or the email address is wrong, skip sending the details silently.
66
-        if (!$user instanceof User) {
67
-            return;
68
-        }
69
-
70
-        if (strtolower($user->getEmail()) === strtolower($email)) {
71
-            $clientIp = $this->getXffTrustProvider()
72
-                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
-
74
-            $this->cleanExistingTokens($user);
75
-
76
-            $hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
-
78
-            $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
-
80
-            $cred = new Credential();
81
-            $cred->setDatabase($this->getDatabase());
82
-            $cred->setFactor(-1);
83
-            $cred->setUserId($user->getId());
84
-            $cred->setType('reset');
85
-            $cred->setData($encryptionHelper->encryptData($hash));
86
-            $cred->setVersion(0);
87
-            $cred->setDisabled(0);
88
-            $cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
-            $cred->setPriority(9);
90
-            $cred->save();
91
-
92
-            $this->assign("user", $user);
93
-            $this->assign("hash", $hash);
94
-            $this->assign("remoteAddress", $clientIp);
95
-
96
-            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
-
98
-            $this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
-        }
100
-    }
101
-
102
-    /**
103
-     * Entry point for the reset action
104
-     *
105
-     * This is the reset password part of the form.
106
-     * @category Security-Critical
107
-     */
108
-    protected function reset()
109
-    {
110
-        $si = WebRequest::getString('si');
111
-        $id = WebRequest::getString('id');
112
-
113
-        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
-            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
-        }
116
-
117
-        $database = $this->getDatabase();
118
-        $user = $this->getResettingUser($id, $database, $si);
119
-
120
-        // Dual mode
121
-        if (WebRequest::wasPosted()) {
122
-            $this->validateCSRFToken();
123
-            try {
124
-                $this->doReset($user);
125
-                $this->cleanExistingTokens($user);
126
-            }
127
-            catch (ApplicationLogicException $ex) {
128
-                SessionAlert::error($ex->getMessage());
129
-                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
-
131
-                return;
132
-            }
133
-        }
134
-        else {
135
-            $this->assignCSRFToken();
136
-            $this->assign('user', $user);
137
-            $this->setTemplate('forgot-password/forgotpwreset.tpl');
138
-        }
139
-    }
140
-
141
-    /**
142
-     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
143
-     *
144
-     * @param integer     $id       The ID of the user to retrieve
145
-     * @param PdoDatabase $database The database object to use
146
-     * @param string      $si       The reset hash provided
147
-     *
148
-     * @return User
149
-     * @throws ApplicationLogicException
150
-     */
151
-    private function getResettingUser($id, $database, $si)
152
-    {
153
-        $user = User::getById($id, $database);
154
-
155
-        if ($user === false ||  $user->isCommunityUser()) {
156
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
157
-        }
158
-
159
-        $statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
160
-        $statement->execute([':user' => $user->getId()]);
161
-
162
-        /** @var Credential $credential */
163
-        $credential = $statement->fetchObject(Credential::class);
164
-
165
-        $statement->closeCursor();
166
-
167
-        if ($credential === false) {
168
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
169
-        }
170
-
171
-        $credential->setDatabase($database);
172
-
173
-        $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
174
-        if ($encryptionHelper->decryptData($credential->getData()) != $si) {
175
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
176
-        }
177
-
178
-        if ($credential->getTimeout() < new DateTimeImmutable()) {
179
-            $credential->delete();
180
-            throw new ApplicationLogicException("Password reset token expired. Please try again.");
181
-        }
182
-
183
-        return $user;
184
-    }
185
-
186
-    /**
187
-     * Performs the setting of the new password
188
-     *
189
-     * @param User $user The user to set the password for
190
-     *
191
-     * @throws ApplicationLogicException
192
-     */
193
-    private function doReset(User $user)
194
-    {
195
-        $pw = WebRequest::postString('pw');
196
-        $pw2 = WebRequest::postString('pw2');
197
-
198
-        if ($pw !== $pw2) {
199
-            throw new ApplicationLogicException('Passwords do not match!');
200
-        }
201
-
202
-        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
203
-        $passwordCredentialProvider->setCredential($user, 1, $pw);
204
-
205
-        SessionAlert::success('You may now log in!');
206
-        $this->redirect('login');
207
-    }
208
-
209
-    protected function isProtectedPage()
210
-    {
211
-        return false;
212
-    }
213
-
214
-    /**
215
-     * @param $user
216
-     */
217
-    private function cleanExistingTokens($user): void
218
-    {
219
-        // clean out existing reset tokens
220
-        $statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
221
-        $statement->execute([':user' => $user->getId()]);
222
-        $existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
223
-
224
-        foreach ($existing as $c) {
225
-            $c->setDatabase($this->getDatabase());
226
-            $c->delete();
227
-        }
228
-    }
25
+	/**
26
+	 * Main function for this page, when no specific actions are called.
27
+	 *
28
+	 * This is the forgotten password reset form
29
+	 * @category Security-Critical
30
+	 */
31
+	protected function main()
32
+	{
33
+		if (WebRequest::wasPosted()) {
34
+			$this->validateCSRFToken();
35
+			$username = WebRequest::postString('username');
36
+			$email = WebRequest::postEmail('email');
37
+			$database = $this->getDatabase();
38
+
39
+			if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
+				throw new ApplicationLogicException("Both username and email address must be specified!");
41
+			}
42
+
43
+			$user = User::getByUsername($username, $database);
44
+			$this->sendResetMail($user, $email);
45
+
46
+			SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
+
48
+			$this->redirect('login');
49
+		}
50
+		else {
51
+			$this->assignCSRFToken();
52
+			$this->setTemplate('forgot-password/forgotpw.tpl');
53
+		}
54
+	}
55
+
56
+	/**
57
+	 * Sends a reset email if the user is authenticated
58
+	 *
59
+	 * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
+	 *                            check anyway within this method and silently skip if we don't have a user.
61
+	 * @param string       $email The provided email address
62
+	 */
63
+	private function sendResetMail($user, $email)
64
+	{
65
+		// If the user isn't found, or the email address is wrong, skip sending the details silently.
66
+		if (!$user instanceof User) {
67
+			return;
68
+		}
69
+
70
+		if (strtolower($user->getEmail()) === strtolower($email)) {
71
+			$clientIp = $this->getXffTrustProvider()
72
+				->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
+
74
+			$this->cleanExistingTokens($user);
75
+
76
+			$hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
+
78
+			$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
+
80
+			$cred = new Credential();
81
+			$cred->setDatabase($this->getDatabase());
82
+			$cred->setFactor(-1);
83
+			$cred->setUserId($user->getId());
84
+			$cred->setType('reset');
85
+			$cred->setData($encryptionHelper->encryptData($hash));
86
+			$cred->setVersion(0);
87
+			$cred->setDisabled(0);
88
+			$cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
+			$cred->setPriority(9);
90
+			$cred->save();
91
+
92
+			$this->assign("user", $user);
93
+			$this->assign("hash", $hash);
94
+			$this->assign("remoteAddress", $clientIp);
95
+
96
+			$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
+
98
+			$this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
+		}
100
+	}
101
+
102
+	/**
103
+	 * Entry point for the reset action
104
+	 *
105
+	 * This is the reset password part of the form.
106
+	 * @category Security-Critical
107
+	 */
108
+	protected function reset()
109
+	{
110
+		$si = WebRequest::getString('si');
111
+		$id = WebRequest::getString('id');
112
+
113
+		if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
+			throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
+		}
116
+
117
+		$database = $this->getDatabase();
118
+		$user = $this->getResettingUser($id, $database, $si);
119
+
120
+		// Dual mode
121
+		if (WebRequest::wasPosted()) {
122
+			$this->validateCSRFToken();
123
+			try {
124
+				$this->doReset($user);
125
+				$this->cleanExistingTokens($user);
126
+			}
127
+			catch (ApplicationLogicException $ex) {
128
+				SessionAlert::error($ex->getMessage());
129
+				$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
+
131
+				return;
132
+			}
133
+		}
134
+		else {
135
+			$this->assignCSRFToken();
136
+			$this->assign('user', $user);
137
+			$this->setTemplate('forgot-password/forgotpwreset.tpl');
138
+		}
139
+	}
140
+
141
+	/**
142
+	 * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
143
+	 *
144
+	 * @param integer     $id       The ID of the user to retrieve
145
+	 * @param PdoDatabase $database The database object to use
146
+	 * @param string      $si       The reset hash provided
147
+	 *
148
+	 * @return User
149
+	 * @throws ApplicationLogicException
150
+	 */
151
+	private function getResettingUser($id, $database, $si)
152
+	{
153
+		$user = User::getById($id, $database);
154
+
155
+		if ($user === false ||  $user->isCommunityUser()) {
156
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
157
+		}
158
+
159
+		$statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
160
+		$statement->execute([':user' => $user->getId()]);
161
+
162
+		/** @var Credential $credential */
163
+		$credential = $statement->fetchObject(Credential::class);
164
+
165
+		$statement->closeCursor();
166
+
167
+		if ($credential === false) {
168
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
169
+		}
170
+
171
+		$credential->setDatabase($database);
172
+
173
+		$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
174
+		if ($encryptionHelper->decryptData($credential->getData()) != $si) {
175
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
176
+		}
177
+
178
+		if ($credential->getTimeout() < new DateTimeImmutable()) {
179
+			$credential->delete();
180
+			throw new ApplicationLogicException("Password reset token expired. Please try again.");
181
+		}
182
+
183
+		return $user;
184
+	}
185
+
186
+	/**
187
+	 * Performs the setting of the new password
188
+	 *
189
+	 * @param User $user The user to set the password for
190
+	 *
191
+	 * @throws ApplicationLogicException
192
+	 */
193
+	private function doReset(User $user)
194
+	{
195
+		$pw = WebRequest::postString('pw');
196
+		$pw2 = WebRequest::postString('pw2');
197
+
198
+		if ($pw !== $pw2) {
199
+			throw new ApplicationLogicException('Passwords do not match!');
200
+		}
201
+
202
+		$passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
203
+		$passwordCredentialProvider->setCredential($user, 1, $pw);
204
+
205
+		SessionAlert::success('You may now log in!');
206
+		$this->redirect('login');
207
+	}
208
+
209
+	protected function isProtectedPage()
210
+	{
211
+		return false;
212
+	}
213
+
214
+	/**
215
+	 * @param $user
216
+	 */
217
+	private function cleanExistingTokens($user): void
218
+	{
219
+		// clean out existing reset tokens
220
+		$statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
221
+		$statement->execute([':user' => $user->getId()]);
222
+		$existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
223
+
224
+		foreach ($existing as $c) {
225
+			$c->setDatabase($this->getDatabase());
226
+			$c->delete();
227
+		}
228
+	}
229 229
 }
Please login to merge, or discard this patch.
includes/Pages/PageMain.php 1 patch
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -20,65 +20,65 @@  discard block
 block discarded – undo
20 20
 
21 21
 class PageMain extends InternalPageBase
22 22
 {
23
-    /**
24
-     * Main function for this page, when no actions are called.
25
-     */
26
-    protected function main()
27
-    {
28
-        $this->assignCSRFToken();
29
-
30
-        $config = $this->getSiteConfiguration();
31
-        $database = $this->getDatabase();
32
-        $currentUser = User::getCurrent($database);
33
-
34
-        // general template configuration
35
-        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
36
-        $this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
37
-
38
-        // Get map of possible usernames
39
-        $userList = UserSearchHelper::get($database)->withReservedRequest();
40
-        $this->assign('userList', $userList);
41
-
42
-        $seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class);
43
-        $this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
44
-        $this->assign('xff', $this->getXffTrustProvider());
45
-
46
-        $this->assign('dataClearEmail', $config->getDataClearEmail());
47
-        $this->assign('dataClearIp', $config->getDataClearIp());
48
-
49
-        // Fetch request data
50
-        $requestSectionData = array();
51
-        if ($seeAllRequests) {
52
-            $this->setupStatusSections($database, $config, $requestSectionData);
53
-            $this->setupHospitalQueue($database, $config, $requestSectionData);
54
-            $this->setupJobQueue($database, $config, $requestSectionData);
55
-        }
56
-        $this->setupLastFiveClosedData($database, $seeAllRequests);
57
-
58
-        // Assign data to template
59
-        $this->assign('requestSectionData', $requestSectionData);
60
-
61
-        // Extra rights
62
-        $this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
63
-        $this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
64
-
65
-        $this->setTemplate('mainpage/mainpage.tpl');
66
-    }
67
-
68
-    /**
69
-     * @param PdoDatabase $database
70
-     * @param bool        $seeAllRequests
71
-     *
72
-     * @internal param User $currentUser
73
-     */
74
-    private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests)
75
-    {
76
-        $this->assign('showLastFive', $seeAllRequests);
77
-        if (!$seeAllRequests) {
78
-            return;
79
-        }
80
-
81
-        $query = <<<SQL
23
+	/**
24
+	 * Main function for this page, when no actions are called.
25
+	 */
26
+	protected function main()
27
+	{
28
+		$this->assignCSRFToken();
29
+
30
+		$config = $this->getSiteConfiguration();
31
+		$database = $this->getDatabase();
32
+		$currentUser = User::getCurrent($database);
33
+
34
+		// general template configuration
35
+		$this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
36
+		$this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
37
+
38
+		// Get map of possible usernames
39
+		$userList = UserSearchHelper::get($database)->withReservedRequest();
40
+		$this->assign('userList', $userList);
41
+
42
+		$seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class);
43
+		$this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
44
+		$this->assign('xff', $this->getXffTrustProvider());
45
+
46
+		$this->assign('dataClearEmail', $config->getDataClearEmail());
47
+		$this->assign('dataClearIp', $config->getDataClearIp());
48
+
49
+		// Fetch request data
50
+		$requestSectionData = array();
51
+		if ($seeAllRequests) {
52
+			$this->setupStatusSections($database, $config, $requestSectionData);
53
+			$this->setupHospitalQueue($database, $config, $requestSectionData);
54
+			$this->setupJobQueue($database, $config, $requestSectionData);
55
+		}
56
+		$this->setupLastFiveClosedData($database, $seeAllRequests);
57
+
58
+		// Assign data to template
59
+		$this->assign('requestSectionData', $requestSectionData);
60
+
61
+		// Extra rights
62
+		$this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
63
+		$this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
64
+
65
+		$this->setTemplate('mainpage/mainpage.tpl');
66
+	}
67
+
68
+	/**
69
+	 * @param PdoDatabase $database
70
+	 * @param bool        $seeAllRequests
71
+	 *
72
+	 * @internal param User $currentUser
73
+	 */
74
+	private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests)
75
+	{
76
+		$this->assign('showLastFive', $seeAllRequests);
77
+		if (!$seeAllRequests) {
78
+			return;
79
+		}
80
+
81
+		$query = <<<SQL
82 82
 		SELECT request.id, request.name, request.updateversion
83 83
 		FROM request /* PageMain::main() */
84 84
 		JOIN log ON log.objectid = request.id AND log.objecttype = 'Request'
@@ -87,140 +87,140 @@  discard block
 block discarded – undo
87 87
 		LIMIT 5;
88 88
 SQL;
89 89
 
90
-        $statement = $database->prepare($query);
91
-        $statement->execute();
92
-
93
-        $last5result = $statement->fetchAll(PDO::FETCH_ASSOC);
94
-
95
-        $this->assign('lastFive', $last5result);
96
-    }
97
-
98
-    /**
99
-     * @param PdoDatabase       $database
100
-     * @param SiteConfiguration $config
101
-     * @param                   $requestSectionData
102
-     */
103
-    private function setupHospitalQueue(
104
-        PdoDatabase $database,
105
-        SiteConfiguration $config,
106
-        &$requestSectionData
107
-    ) {
108
-        $search = RequestSearchHelper::get($database)
109
-            ->limit($config->getMiserModeLimit())
110
-            ->excludingStatus('Closed')
111
-            ->isHospitalised();
112
-
113
-        if ($config->getEmailConfirmationEnabled()) {
114
-            $search->withConfirmedEmail();
115
-        }
116
-
117
-        $results = $search->getRecordCount($requestCount)->fetch();
118
-
119
-        if($requestCount > 0) {
120
-            $requestSectionData['Hospital - Requests failed auto-creation'] = array(
121
-                'requests' => $results,
122
-                'total'    => $requestCount,
123
-                'api'      => 'hospital',
124
-                'type'     => 'hospital',
125
-                'special'  => 'Job Queue',
126
-                'help'     => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.'
127
-            );
128
-        }
129
-    }
130
-
131
-    /**
132
-     * @param PdoDatabase       $database
133
-     * @param SiteConfiguration $config
134
-     * @param                   $requestSectionData
135
-     */
136
-    private function setupJobQueue(
137
-        PdoDatabase $database,
138
-        SiteConfiguration $config,
139
-        &$requestSectionData
140
-    ) {
141
-        $search = RequestSearchHelper::get($database)
142
-            ->limit($config->getMiserModeLimit())
143
-            ->byStatus(RequestStatus::JOBQUEUE);
144
-
145
-        if ($config->getEmailConfirmationEnabled()) {
146
-            $search->withConfirmedEmail();
147
-        }
148
-
149
-        $results = $search->getRecordCount($requestCount)->fetch();
150
-
151
-        if($requestCount > 0) {
152
-            $requestSectionData['Requests queued in the Job Queue'] = array(
153
-                'requests' => $results,
154
-                'total'    => $requestCount,
155
-                'api'      => 'JobQueue',
156
-                'type'     => 'JobQueue',
157
-                'special'  => 'Job Queue',
158
-                'help'     => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.'
159
-            );
160
-        }
161
-    }
162
-
163
-    /**
164
-     * @param PdoDatabase       $database
165
-     * @param SiteConfiguration $config
166
-     * @param                   $requestSectionData
167
-     */
168
-    private function setupStatusSections(
169
-        PdoDatabase $database,
170
-        SiteConfiguration $config,
171
-        &$requestSectionData
172
-    ) {
173
-        $search = RequestSearchHelper::get($database)->limit($config->getMiserModeLimit())->notHospitalised();
174
-
175
-        if ($config->getEmailConfirmationEnabled()) {
176
-            $search->withConfirmedEmail();
177
-        }
178
-
179
-        $allRequestStates = $config->getRequestStates();
180
-        $requestsByStatus = $search->fetchByStatus(array_keys($allRequestStates));
181
-
182
-        foreach ($allRequestStates as $requestState => $requestStateConfig) {
183
-
184
-            $requestTrustedIp = [];
185
-            $relatedEmailRequests = [];
186
-            $relatedIpRequests = [];
187
-            foreach ($requestsByStatus[$requestState]['data'] as $request) {
188
-                $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
189
-                    $request->getIp(),
190
-                    $request->getForwardedIp()
191
-                );
192
-
193
-                RequestSearchHelper::get($database)
194
-                    ->byIp($trustedIp)
195
-                    ->withConfirmedEmail()
196
-                    ->excludingPurgedData($config)
197
-                    ->excludingRequest($request->getId())
198
-                    ->getRecordCount($ipCount);
199
-
200
-                RequestSearchHelper::get($database)
201
-                    ->byEmailAddress($request->getEmail())
202
-                    ->withConfirmedEmail()
203
-                    ->excludingPurgedData($config)
204
-                    ->excludingRequest($request->getId())
205
-                    ->getRecordCount($emailCount);
206
-
207
-                $requestTrustedIp[$request->getId()] = $trustedIp;
208
-                $relatedEmailRequests[$request->getId()] = $emailCount;
209
-                $relatedIpRequests[$request->getId()] = $ipCount;
210
-            }
211
-
212
-
213
-            $requestSectionData[$requestStateConfig['header']] = array(
214
-                'requests' => $requestsByStatus[$requestState]['data'],
215
-                'total'    => $requestsByStatus[$requestState]['count'],
216
-                'api'      => $requestStateConfig['api'],
217
-                'type'     => $requestState,
218
-                'special'  => null,
219
-                'help'     => $requestStateConfig['queuehelp'],
220
-                'requestTrustedIp' => $requestTrustedIp,
221
-                'relatedEmailRequests' => $relatedEmailRequests,
222
-                'relatedIpRequests' => $relatedIpRequests
223
-            );
224
-        }
225
-    }
90
+		$statement = $database->prepare($query);
91
+		$statement->execute();
92
+
93
+		$last5result = $statement->fetchAll(PDO::FETCH_ASSOC);
94
+
95
+		$this->assign('lastFive', $last5result);
96
+	}
97
+
98
+	/**
99
+	 * @param PdoDatabase       $database
100
+	 * @param SiteConfiguration $config
101
+	 * @param                   $requestSectionData
102
+	 */
103
+	private function setupHospitalQueue(
104
+		PdoDatabase $database,
105
+		SiteConfiguration $config,
106
+		&$requestSectionData
107
+	) {
108
+		$search = RequestSearchHelper::get($database)
109
+			->limit($config->getMiserModeLimit())
110
+			->excludingStatus('Closed')
111
+			->isHospitalised();
112
+
113
+		if ($config->getEmailConfirmationEnabled()) {
114
+			$search->withConfirmedEmail();
115
+		}
116
+
117
+		$results = $search->getRecordCount($requestCount)->fetch();
118
+
119
+		if($requestCount > 0) {
120
+			$requestSectionData['Hospital - Requests failed auto-creation'] = array(
121
+				'requests' => $results,
122
+				'total'    => $requestCount,
123
+				'api'      => 'hospital',
124
+				'type'     => 'hospital',
125
+				'special'  => 'Job Queue',
126
+				'help'     => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.'
127
+			);
128
+		}
129
+	}
130
+
131
+	/**
132
+	 * @param PdoDatabase       $database
133
+	 * @param SiteConfiguration $config
134
+	 * @param                   $requestSectionData
135
+	 */
136
+	private function setupJobQueue(
137
+		PdoDatabase $database,
138
+		SiteConfiguration $config,
139
+		&$requestSectionData
140
+	) {
141
+		$search = RequestSearchHelper::get($database)
142
+			->limit($config->getMiserModeLimit())
143
+			->byStatus(RequestStatus::JOBQUEUE);
144
+
145
+		if ($config->getEmailConfirmationEnabled()) {
146
+			$search->withConfirmedEmail();
147
+		}
148
+
149
+		$results = $search->getRecordCount($requestCount)->fetch();
150
+
151
+		if($requestCount > 0) {
152
+			$requestSectionData['Requests queued in the Job Queue'] = array(
153
+				'requests' => $results,
154
+				'total'    => $requestCount,
155
+				'api'      => 'JobQueue',
156
+				'type'     => 'JobQueue',
157
+				'special'  => 'Job Queue',
158
+				'help'     => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.'
159
+			);
160
+		}
161
+	}
162
+
163
+	/**
164
+	 * @param PdoDatabase       $database
165
+	 * @param SiteConfiguration $config
166
+	 * @param                   $requestSectionData
167
+	 */
168
+	private function setupStatusSections(
169
+		PdoDatabase $database,
170
+		SiteConfiguration $config,
171
+		&$requestSectionData
172
+	) {
173
+		$search = RequestSearchHelper::get($database)->limit($config->getMiserModeLimit())->notHospitalised();
174
+
175
+		if ($config->getEmailConfirmationEnabled()) {
176
+			$search->withConfirmedEmail();
177
+		}
178
+
179
+		$allRequestStates = $config->getRequestStates();
180
+		$requestsByStatus = $search->fetchByStatus(array_keys($allRequestStates));
181
+
182
+		foreach ($allRequestStates as $requestState => $requestStateConfig) {
183
+
184
+			$requestTrustedIp = [];
185
+			$relatedEmailRequests = [];
186
+			$relatedIpRequests = [];
187
+			foreach ($requestsByStatus[$requestState]['data'] as $request) {
188
+				$trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
189
+					$request->getIp(),
190
+					$request->getForwardedIp()
191
+				);
192
+
193
+				RequestSearchHelper::get($database)
194
+					->byIp($trustedIp)
195
+					->withConfirmedEmail()
196
+					->excludingPurgedData($config)
197
+					->excludingRequest($request->getId())
198
+					->getRecordCount($ipCount);
199
+
200
+				RequestSearchHelper::get($database)
201
+					->byEmailAddress($request->getEmail())
202
+					->withConfirmedEmail()
203
+					->excludingPurgedData($config)
204
+					->excludingRequest($request->getId())
205
+					->getRecordCount($emailCount);
206
+
207
+				$requestTrustedIp[$request->getId()] = $trustedIp;
208
+				$relatedEmailRequests[$request->getId()] = $emailCount;
209
+				$relatedIpRequests[$request->getId()] = $ipCount;
210
+			}
211
+
212
+
213
+			$requestSectionData[$requestStateConfig['header']] = array(
214
+				'requests' => $requestsByStatus[$requestState]['data'],
215
+				'total'    => $requestsByStatus[$requestState]['count'],
216
+				'api'      => $requestStateConfig['api'],
217
+				'type'     => $requestState,
218
+				'special'  => null,
219
+				'help'     => $requestStateConfig['queuehelp'],
220
+				'requestTrustedIp' => $requestTrustedIp,
221
+				'relatedEmailRequests' => $relatedEmailRequests,
222
+				'relatedIpRequests' => $relatedIpRequests
223
+			);
224
+		}
225
+	}
226 226
 }
Please login to merge, or discard this patch.
includes/Pages/PageSearch.php 1 patch
Indentation   +186 added lines, -186 removed lines patch added patch discarded remove patch
@@ -20,190 +20,190 @@
 block discarded – undo
20 20
 
21 21
 class PageSearch extends InternalPageBase
22 22
 {
23
-    /**
24
-     * Main function for this page, when no specific actions are called.
25
-     */
26
-    protected function main()
27
-    {
28
-        $this->setHtmlTitle('Search');
29
-
30
-        // Dual-mode page
31
-        if (WebRequest::wasPosted()) {
32
-            $searchType = WebRequest::postString('type');
33
-            $searchTerm = WebRequest::postString('term');
34
-
35
-            $validationError = "";
36
-            if (!$this->validateSearchParameters($searchType, $searchTerm, $validationError)) {
37
-                SessionAlert::error($validationError, "Search error");
38
-                $this->redirect("search");
39
-
40
-                return;
41
-            }
42
-
43
-            $results = array();
44
-
45
-            switch ($searchType) {
46
-                case 'name':
47
-                    $results = $this->getNameSearchResults($searchTerm);
48
-                    break;
49
-                case 'email':
50
-                    $results = $this->getEmailSearchResults($searchTerm);
51
-                    break;
52
-                case 'ip':
53
-                    $results = $this->getIpSearchResults($searchTerm);
54
-                    break;
55
-            }
56
-
57
-            // deal with results
58
-            $this->assign('requests', $results);
59
-            $this->assign('term', $searchTerm);
60
-            $this->assign('target', $searchType);
61
-
62
-            $userIds = array_map(
63
-                function(Request $entry) {
64
-                    return $entry->getReserved();
65
-                },
66
-                $results);
67
-            $userList = UserSearchHelper::get($this->getDatabase())->inIds($userIds)->fetchMap('username');
68
-            $this->assign('userList', $userList);
69
-
70
-            $requestTrustedIp = [];
71
-            $relatedEmailRequests = [];
72
-            $relatedIpRequests = [];
73
-            foreach ($results as $request) {
74
-                $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
75
-                    $request->getIp(),
76
-                    $request->getForwardedIp()
77
-                );
78
-
79
-                RequestSearchHelper::get($this->getDatabase())
80
-                    ->byIp($trustedIp)
81
-                    ->withConfirmedEmail()
82
-                    ->excludingPurgedData($this->getSiteConfiguration())
83
-                    ->excludingRequest($request->getId())
84
-                    ->getRecordCount($ipCount);
85
-
86
-                RequestSearchHelper::get($this->getDatabase())
87
-                    ->byEmailAddress($request->getEmail())
88
-                    ->withConfirmedEmail()
89
-                    ->excludingPurgedData($this->getSiteConfiguration())
90
-                    ->excludingRequest($request->getId())
91
-                    ->getRecordCount($emailCount);
92
-
93
-                $requestTrustedIp[$request->getId()] = $trustedIp;
94
-                $relatedEmailRequests[$request->getId()] = $emailCount;
95
-                $relatedIpRequests[$request->getId()] = $ipCount;
96
-            }
97
-            $this->assign('requestTrustedIp', $requestTrustedIp);
98
-            $this->assign('relatedEmailRequests', $relatedEmailRequests);
99
-            $this->assign('relatedIpRequests', $relatedIpRequests);
100
-
101
-            $currentUser = User::getCurrent($this->getDatabase());
102
-            $this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
103
-            $this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
104
-
105
-            $this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
106
-            $this->assign('xff', $this->getXffTrustProvider());
107
-
108
-            $this->assign('dataClearEmail', $this->getSiteConfiguration()->getDataClearEmail());
109
-            $this->assign('dataClearIp', $this->getSiteConfiguration()->getDataClearIp());
110
-
111
-            $this->assignCSRFToken();
112
-            $this->setTemplate('search/searchResult.tpl');
113
-        }
114
-        else {
115
-            $this->assignCSRFToken();
116
-            $this->setTemplate('search/searchForm.tpl');
117
-        }
118
-    }
119
-
120
-    /**
121
-     * Gets search results by name
122
-     *
123
-     * @param string $searchTerm
124
-     *
125
-     * @returns Request[]
126
-     */
127
-    private function getNameSearchResults($searchTerm)
128
-    {
129
-        $padded = '%' . $searchTerm . '%';
130
-
131
-        /** @var Request[] $requests */
132
-        $requests = RequestSearchHelper::get($this->getDatabase())
133
-            ->byName($padded)
134
-            ->fetch();
135
-
136
-        return $requests;
137
-    }
138
-
139
-    /**
140
-     * Gets search results by email
141
-     *
142
-     * @param string $searchTerm
143
-     *
144
-     * @return Request[]
145
-     * @throws ApplicationLogicException
146
-     */
147
-    private function getEmailSearchResults($searchTerm)
148
-    {
149
-        if ($searchTerm === "@") {
150
-            throw new ApplicationLogicException('The search term "@" is not valid for email address searches!');
151
-        }
152
-
153
-        $padded = '%' . $searchTerm . '%';
154
-
155
-        /** @var Request[] $requests */
156
-        $requests = RequestSearchHelper::get($this->getDatabase())
157
-            ->byEmailAddress($padded)
158
-            ->excludingPurgedData($this->getSiteConfiguration())
159
-            ->fetch();
160
-
161
-        return $requests;
162
-    }
163
-
164
-    /**
165
-     * Gets search results by IP address or XFF IP address
166
-     *
167
-     * @param string $searchTerm
168
-     *
169
-     * @returns Request[]
170
-     */
171
-    private function getIpSearchResults($searchTerm)
172
-    {
173
-        /** @var Request[] $requests */
174
-        $requests = RequestSearchHelper::get($this->getDatabase())
175
-            ->byIp($searchTerm)
176
-            ->excludingPurgedData($this->getSiteConfiguration())
177
-            ->fetch();
178
-
179
-        return $requests;
180
-    }
181
-
182
-    /**
183
-     * @param string $searchType
184
-     * @param string $searchTerm
185
-     *
186
-     * @param string $errorMessage
187
-     *
188
-     * @return bool true if parameters are valid
189
-     * @throws ApplicationLogicException
190
-     */
191
-    protected function validateSearchParameters($searchType, $searchTerm, &$errorMessage)
192
-    {
193
-        if (!in_array($searchType, array('name', 'email', 'ip'))) {
194
-            $errorMessage = 'Unknown search type';
195
-
196
-            return false;
197
-        }
198
-
199
-        if ($searchTerm === '%' || $searchTerm === '' || $searchTerm === null) {
200
-            $errorMessage = 'No search term specified entered';
201
-
202
-            return false;
203
-        }
204
-
205
-        $errorMessage = "";
206
-
207
-        return true;
208
-    }
23
+	/**
24
+	 * Main function for this page, when no specific actions are called.
25
+	 */
26
+	protected function main()
27
+	{
28
+		$this->setHtmlTitle('Search');
29
+
30
+		// Dual-mode page
31
+		if (WebRequest::wasPosted()) {
32
+			$searchType = WebRequest::postString('type');
33
+			$searchTerm = WebRequest::postString('term');
34
+
35
+			$validationError = "";
36
+			if (!$this->validateSearchParameters($searchType, $searchTerm, $validationError)) {
37
+				SessionAlert::error($validationError, "Search error");
38
+				$this->redirect("search");
39
+
40
+				return;
41
+			}
42
+
43
+			$results = array();
44
+
45
+			switch ($searchType) {
46
+				case 'name':
47
+					$results = $this->getNameSearchResults($searchTerm);
48
+					break;
49
+				case 'email':
50
+					$results = $this->getEmailSearchResults($searchTerm);
51
+					break;
52
+				case 'ip':
53
+					$results = $this->getIpSearchResults($searchTerm);
54
+					break;
55
+			}
56
+
57
+			// deal with results
58
+			$this->assign('requests', $results);
59
+			$this->assign('term', $searchTerm);
60
+			$this->assign('target', $searchType);
61
+
62
+			$userIds = array_map(
63
+				function(Request $entry) {
64
+					return $entry->getReserved();
65
+				},
66
+				$results);
67
+			$userList = UserSearchHelper::get($this->getDatabase())->inIds($userIds)->fetchMap('username');
68
+			$this->assign('userList', $userList);
69
+
70
+			$requestTrustedIp = [];
71
+			$relatedEmailRequests = [];
72
+			$relatedIpRequests = [];
73
+			foreach ($results as $request) {
74
+				$trustedIp = $this->getXffTrustProvider()->getTrustedClientIp(
75
+					$request->getIp(),
76
+					$request->getForwardedIp()
77
+				);
78
+
79
+				RequestSearchHelper::get($this->getDatabase())
80
+					->byIp($trustedIp)
81
+					->withConfirmedEmail()
82
+					->excludingPurgedData($this->getSiteConfiguration())
83
+					->excludingRequest($request->getId())
84
+					->getRecordCount($ipCount);
85
+
86
+				RequestSearchHelper::get($this->getDatabase())
87
+					->byEmailAddress($request->getEmail())
88
+					->withConfirmedEmail()
89
+					->excludingPurgedData($this->getSiteConfiguration())
90
+					->excludingRequest($request->getId())
91
+					->getRecordCount($emailCount);
92
+
93
+				$requestTrustedIp[$request->getId()] = $trustedIp;
94
+				$relatedEmailRequests[$request->getId()] = $emailCount;
95
+				$relatedIpRequests[$request->getId()] = $ipCount;
96
+			}
97
+			$this->assign('requestTrustedIp', $requestTrustedIp);
98
+			$this->assign('relatedEmailRequests', $relatedEmailRequests);
99
+			$this->assign('relatedIpRequests', $relatedIpRequests);
100
+
101
+			$currentUser = User::getCurrent($this->getDatabase());
102
+			$this->assign('canBan', $this->barrierTest('set', $currentUser, PageBan::class));
103
+			$this->assign('canBreakReservation', $this->barrierTest('force', $currentUser, PageBreakReservation::class));
104
+
105
+			$this->assign('showPrivateData', $this->barrierTest('alwaysSeePrivateData', $currentUser, 'RequestData'));
106
+			$this->assign('xff', $this->getXffTrustProvider());
107
+
108
+			$this->assign('dataClearEmail', $this->getSiteConfiguration()->getDataClearEmail());
109
+			$this->assign('dataClearIp', $this->getSiteConfiguration()->getDataClearIp());
110
+
111
+			$this->assignCSRFToken();
112
+			$this->setTemplate('search/searchResult.tpl');
113
+		}
114
+		else {
115
+			$this->assignCSRFToken();
116
+			$this->setTemplate('search/searchForm.tpl');
117
+		}
118
+	}
119
+
120
+	/**
121
+	 * Gets search results by name
122
+	 *
123
+	 * @param string $searchTerm
124
+	 *
125
+	 * @returns Request[]
126
+	 */
127
+	private function getNameSearchResults($searchTerm)
128
+	{
129
+		$padded = '%' . $searchTerm . '%';
130
+
131
+		/** @var Request[] $requests */
132
+		$requests = RequestSearchHelper::get($this->getDatabase())
133
+			->byName($padded)
134
+			->fetch();
135
+
136
+		return $requests;
137
+	}
138
+
139
+	/**
140
+	 * Gets search results by email
141
+	 *
142
+	 * @param string $searchTerm
143
+	 *
144
+	 * @return Request[]
145
+	 * @throws ApplicationLogicException
146
+	 */
147
+	private function getEmailSearchResults($searchTerm)
148
+	{
149
+		if ($searchTerm === "@") {
150
+			throw new ApplicationLogicException('The search term "@" is not valid for email address searches!');
151
+		}
152
+
153
+		$padded = '%' . $searchTerm . '%';
154
+
155
+		/** @var Request[] $requests */
156
+		$requests = RequestSearchHelper::get($this->getDatabase())
157
+			->byEmailAddress($padded)
158
+			->excludingPurgedData($this->getSiteConfiguration())
159
+			->fetch();
160
+
161
+		return $requests;
162
+	}
163
+
164
+	/**
165
+	 * Gets search results by IP address or XFF IP address
166
+	 *
167
+	 * @param string $searchTerm
168
+	 *
169
+	 * @returns Request[]
170
+	 */
171
+	private function getIpSearchResults($searchTerm)
172
+	{
173
+		/** @var Request[] $requests */
174
+		$requests = RequestSearchHelper::get($this->getDatabase())
175
+			->byIp($searchTerm)
176
+			->excludingPurgedData($this->getSiteConfiguration())
177
+			->fetch();
178
+
179
+		return $requests;
180
+	}
181
+
182
+	/**
183
+	 * @param string $searchType
184
+	 * @param string $searchTerm
185
+	 *
186
+	 * @param string $errorMessage
187
+	 *
188
+	 * @return bool true if parameters are valid
189
+	 * @throws ApplicationLogicException
190
+	 */
191
+	protected function validateSearchParameters($searchType, $searchTerm, &$errorMessage)
192
+	{
193
+		if (!in_array($searchType, array('name', 'email', 'ip'))) {
194
+			$errorMessage = 'Unknown search type';
195
+
196
+			return false;
197
+		}
198
+
199
+		if ($searchTerm === '%' || $searchTerm === '' || $searchTerm === null) {
200
+			$errorMessage = 'No search term specified entered';
201
+
202
+			return false;
203
+		}
204
+
205
+		$errorMessage = "";
206
+
207
+		return true;
208
+	}
209 209
 }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/TotpCredentialProvider.php 1 patch
Indentation   +130 added lines, -130 removed lines patch added patch discarded remove patch
@@ -19,137 +19,137 @@
 block discarded – undo
19 19
 
20 20
 class TotpCredentialProvider extends CredentialProviderBase
21 21
 {
22
-    /** @var EncryptionHelper */
23
-    private $encryptionHelper;
24
-
25
-    /**
26
-     * TotpCredentialProvider constructor.
27
-     *
28
-     * @param PdoDatabase       $database
29
-     * @param SiteConfiguration $configuration
30
-     */
31
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
-    {
33
-        parent::__construct($database, $configuration, 'totp');
34
-        $this->encryptionHelper = new EncryptionHelper($configuration);
35
-    }
36
-
37
-    /**
38
-     * Validates a user-provided credential
39
-     *
40
-     * @param User   $user The user to test the authentication against
41
-     * @param string $data The raw credential data to be validated
42
-     *
43
-     * @return bool
44
-     * @throws ApplicationLogicException
45
-     */
46
-    public function authenticate(User $user, $data)
47
-    {
48
-        if (is_array($data)) {
49
-            return false;
50
-        }
51
-
52
-        $storedData = $this->getCredentialData($user->getId());
53
-
54
-        if ($storedData === null) {
55
-            throw new ApplicationLogicException('Credential data not found');
56
-        }
57
-
58
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
-
61
-        return $totp->verify($data, null, 2);
62
-    }
63
-
64
-    public function verifyEnable(User $user, $data)
65
-    {
66
-        $storedData = $this->getCredentialData($user->getId(), true);
67
-
68
-        if ($storedData === null) {
69
-            throw new ApplicationLogicException('Credential data not found');
70
-        }
71
-
72
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
-
75
-        $result = $totp->verify($data, null, 2);
76
-
77
-        if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
-            $storedData->setDisabled(0);
79
-            $storedData->setPriority(5);
80
-            $storedData->setTimeout(null);
81
-            $storedData->save();
82
-        }
83
-
84
-        return $result;
85
-    }
86
-
87
-    /**
88
-     * @param User   $user   The user the credential belongs to
89
-     * @param int    $factor The factor this credential provides
90
-     * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
-     */
92
-    public function setCredential(User $user, $factor, $data)
93
-    {
94
-        $issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
-        $totp = TOTP::create();
96
-        $totp->setLabel($user->getUsername());
97
-        $totp->setIssuer($issuer);
98
-
99
-        $storedData = $this->getCredentialData($user->getId(), null);
100
-
101
-        if ($storedData !== null) {
102
-            $storedData->delete();
103
-        }
104
-
105
-        $storedData = $this->createNewCredential($user);
106
-
107
-        $storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
108
-        $storedData->setFactor($factor);
109
-        $storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
110
-        $storedData->setDisabled(1);
111
-        $storedData->setVersion(1);
112
-
113
-        $storedData->save();
114
-    }
115
-
116
-    public function getProvisioningUrl(User $user)
117
-    {
118
-        $storedData = $this->getCredentialData($user->getId(), true);
119
-
120
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
121
-            $storedData->delete();
122
-            $storedData = null;
123
-        }
124
-
125
-        if ($storedData === null) {
126
-            throw new ApplicationLogicException('Credential data not found');
127
-        }
128
-
129
-        return $this->encryptionHelper->decryptData($storedData->getData());
130
-    }
131
-
132
-    public function isPartiallyEnrolled(User $user)
133
-    {
134
-        $storedData = $this->getCredentialData($user->getId(), true);
135
-
136
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
137
-            $storedData->delete();
138
-
139
-            return false;
140
-        }
141
-
142
-        if ($storedData === null) {
143
-            return false;
144
-        }
22
+	/** @var EncryptionHelper */
23
+	private $encryptionHelper;
24
+
25
+	/**
26
+	 * TotpCredentialProvider constructor.
27
+	 *
28
+	 * @param PdoDatabase       $database
29
+	 * @param SiteConfiguration $configuration
30
+	 */
31
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
+	{
33
+		parent::__construct($database, $configuration, 'totp');
34
+		$this->encryptionHelper = new EncryptionHelper($configuration);
35
+	}
36
+
37
+	/**
38
+	 * Validates a user-provided credential
39
+	 *
40
+	 * @param User   $user The user to test the authentication against
41
+	 * @param string $data The raw credential data to be validated
42
+	 *
43
+	 * @return bool
44
+	 * @throws ApplicationLogicException
45
+	 */
46
+	public function authenticate(User $user, $data)
47
+	{
48
+		if (is_array($data)) {
49
+			return false;
50
+		}
51
+
52
+		$storedData = $this->getCredentialData($user->getId());
53
+
54
+		if ($storedData === null) {
55
+			throw new ApplicationLogicException('Credential data not found');
56
+		}
57
+
58
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
+
61
+		return $totp->verify($data, null, 2);
62
+	}
63
+
64
+	public function verifyEnable(User $user, $data)
65
+	{
66
+		$storedData = $this->getCredentialData($user->getId(), true);
67
+
68
+		if ($storedData === null) {
69
+			throw new ApplicationLogicException('Credential data not found');
70
+		}
71
+
72
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
+
75
+		$result = $totp->verify($data, null, 2);
76
+
77
+		if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
+			$storedData->setDisabled(0);
79
+			$storedData->setPriority(5);
80
+			$storedData->setTimeout(null);
81
+			$storedData->save();
82
+		}
83
+
84
+		return $result;
85
+	}
86
+
87
+	/**
88
+	 * @param User   $user   The user the credential belongs to
89
+	 * @param int    $factor The factor this credential provides
90
+	 * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
+	 */
92
+	public function setCredential(User $user, $factor, $data)
93
+	{
94
+		$issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
+		$totp = TOTP::create();
96
+		$totp->setLabel($user->getUsername());
97
+		$totp->setIssuer($issuer);
98
+
99
+		$storedData = $this->getCredentialData($user->getId(), null);
100
+
101
+		if ($storedData !== null) {
102
+			$storedData->delete();
103
+		}
104
+
105
+		$storedData = $this->createNewCredential($user);
106
+
107
+		$storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
108
+		$storedData->setFactor($factor);
109
+		$storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
110
+		$storedData->setDisabled(1);
111
+		$storedData->setVersion(1);
112
+
113
+		$storedData->save();
114
+	}
115
+
116
+	public function getProvisioningUrl(User $user)
117
+	{
118
+		$storedData = $this->getCredentialData($user->getId(), true);
119
+
120
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
121
+			$storedData->delete();
122
+			$storedData = null;
123
+		}
124
+
125
+		if ($storedData === null) {
126
+			throw new ApplicationLogicException('Credential data not found');
127
+		}
128
+
129
+		return $this->encryptionHelper->decryptData($storedData->getData());
130
+	}
131
+
132
+	public function isPartiallyEnrolled(User $user)
133
+	{
134
+		$storedData = $this->getCredentialData($user->getId(), true);
135
+
136
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
137
+			$storedData->delete();
138
+
139
+			return false;
140
+		}
141
+
142
+		if ($storedData === null) {
143
+			return false;
144
+		}
145 145
 
146
-        return true;
147
-    }
146
+		return true;
147
+	}
148 148
 
149
-    public function getSecret(User $user)
150
-    {
151
-        $totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
149
+	public function getSecret(User $user)
150
+	{
151
+		$totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
152 152
 
153
-        return $totp->getSecret();
154
-    }
153
+		return $totp->getSecret();
154
+	}
155 155
 }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/ScratchTokenCredentialProvider.php 1 patch
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -20,136 +20,136 @@
 block discarded – undo
20 20
 
21 21
 class ScratchTokenCredentialProvider extends CredentialProviderBase
22 22
 {
23
-    /** @var EncryptionHelper */
24
-    private $encryptionHelper;
25
-    /** @var array the tokens generated in the last generation round. */
26
-    private $generatedTokens;
27
-
28
-    /**
29
-     * ScratchTokenCredentialProvider constructor.
30
-     *
31
-     * @param PdoDatabase       $database
32
-     * @param SiteConfiguration $configuration
33
-     */
34
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
35
-    {
36
-        parent::__construct($database, $configuration, 'scratch');
37
-        $this->encryptionHelper = new EncryptionHelper($configuration);
38
-    }
39
-
40
-    /**
41
-     * Validates a user-provided credential
42
-     *
43
-     * @param User   $user The user to test the authentication against
44
-     * @param string $data The raw credential data to be validated
45
-     *
46
-     * @return bool
47
-     * @throws ApplicationLogicException|OptimisticLockFailedException
48
-     */
49
-    public function authenticate(User $user, $data)
50
-    {
51
-        if (is_array($data)) {
52
-            return false;
53
-        }
54
-
55
-        $storedData = $this->getCredentialData($user->getId());
56
-
57
-        if ($storedData === null) {
58
-            throw new ApplicationLogicException('Credential data not found');
59
-        }
60
-
61
-        $scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
62
-
63
-        $usedToken = null;
64
-        foreach ($scratchTokens as $scratchToken) {
65
-            if (password_verify($data, $scratchToken)){
66
-                $usedToken = $scratchToken;
67
-                SessionAlert::quick("Hey, it looks like you used a scratch token to log in. Would you like to change your multi-factor authentication configuration?", 'alert-warning');
68
-                WebRequest::setPostLoginRedirect($this->getConfiguration()->getBaseUrl() . "/internal.php/multiFactor");
69
-                break;
70
-            }
71
-        }
72
-
73
-        if($usedToken === null) {
74
-            return false;
75
-        }
76
-
77
-        $scratchTokens = array_diff($scratchTokens, [$usedToken]);
78
-
79
-        $storedData->setData($this->encryptionHelper->encryptData(serialize($scratchTokens)));
80
-        $storedData->save();
81
-
82
-        return true;
83
-    }
84
-
85
-    /**
86
-     * @param User   $user   The user the credential belongs to
87
-     * @param int    $factor The factor this credential provides
88
-     * @param string $data   Unused.
89
-     *
90
-     * @throws OptimisticLockFailedException
91
-     */
92
-    public function setCredential(User $user, $factor, $data)
93
-    {
94
-        $plaintextScratch = array();
95
-        $storedScratch = array();
96
-        for ($i = 0; $i < 5; $i++) {
97
-            $token = Base32::encodeUpper(openssl_random_pseudo_bytes(10));
98
-            $plaintextScratch[] = $token;
99
-
100
-            $storedScratch[] = password_hash(
101
-                $token,
102
-                PasswordCredentialProvider::PASSWORD_ALGO,
103
-                array('cost' => PasswordCredentialProvider::PASSWORD_COST)
104
-            );
105
-        }
106
-
107
-        $storedData = $this->getCredentialData($user->getId(), null);
108
-
109
-        if ($storedData !== null) {
110
-            $storedData->delete();
111
-        }
112
-
113
-        $storedData = $this->createNewCredential($user);
114
-
115
-        $storedData->setData($this->encryptionHelper->encryptData(serialize($storedScratch)));
116
-        $storedData->setFactor($factor);
117
-        $storedData->setVersion(1);
118
-        $storedData->setPriority(9);
119
-
120
-        $storedData->save();
121
-        $this->generatedTokens = $plaintextScratch;
122
-    }
123
-
124
-    /**
125
-     * Gets the count of remaining valid tokens
126
-     *
127
-     * @param int $userId
128
-     *
129
-     * @return int
130
-     */
131
-    public function getRemaining($userId)
132
-    {
133
-        $storedData = $this->getCredentialData($userId);
134
-
135
-        if ($storedData === null) {
136
-            return 0;
137
-        }
138
-
139
-        $scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
140
-
141
-        return count($scratchTokens);
142
-    }
143
-
144
-    /**
145
-     * @return array
146
-     */
147
-    public function getTokens()
148
-    {
149
-        if ($this->generatedTokens != null) {
150
-            return $this->generatedTokens;
151
-        }
152
-
153
-        return array();
154
-    }
23
+	/** @var EncryptionHelper */
24
+	private $encryptionHelper;
25
+	/** @var array the tokens generated in the last generation round. */
26
+	private $generatedTokens;
27
+
28
+	/**
29
+	 * ScratchTokenCredentialProvider constructor.
30
+	 *
31
+	 * @param PdoDatabase       $database
32
+	 * @param SiteConfiguration $configuration
33
+	 */
34
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
35
+	{
36
+		parent::__construct($database, $configuration, 'scratch');
37
+		$this->encryptionHelper = new EncryptionHelper($configuration);
38
+	}
39
+
40
+	/**
41
+	 * Validates a user-provided credential
42
+	 *
43
+	 * @param User   $user The user to test the authentication against
44
+	 * @param string $data The raw credential data to be validated
45
+	 *
46
+	 * @return bool
47
+	 * @throws ApplicationLogicException|OptimisticLockFailedException
48
+	 */
49
+	public function authenticate(User $user, $data)
50
+	{
51
+		if (is_array($data)) {
52
+			return false;
53
+		}
54
+
55
+		$storedData = $this->getCredentialData($user->getId());
56
+
57
+		if ($storedData === null) {
58
+			throw new ApplicationLogicException('Credential data not found');
59
+		}
60
+
61
+		$scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
62
+
63
+		$usedToken = null;
64
+		foreach ($scratchTokens as $scratchToken) {
65
+			if (password_verify($data, $scratchToken)){
66
+				$usedToken = $scratchToken;
67
+				SessionAlert::quick("Hey, it looks like you used a scratch token to log in. Would you like to change your multi-factor authentication configuration?", 'alert-warning');
68
+				WebRequest::setPostLoginRedirect($this->getConfiguration()->getBaseUrl() . "/internal.php/multiFactor");
69
+				break;
70
+			}
71
+		}
72
+
73
+		if($usedToken === null) {
74
+			return false;
75
+		}
76
+
77
+		$scratchTokens = array_diff($scratchTokens, [$usedToken]);
78
+
79
+		$storedData->setData($this->encryptionHelper->encryptData(serialize($scratchTokens)));
80
+		$storedData->save();
81
+
82
+		return true;
83
+	}
84
+
85
+	/**
86
+	 * @param User   $user   The user the credential belongs to
87
+	 * @param int    $factor The factor this credential provides
88
+	 * @param string $data   Unused.
89
+	 *
90
+	 * @throws OptimisticLockFailedException
91
+	 */
92
+	public function setCredential(User $user, $factor, $data)
93
+	{
94
+		$plaintextScratch = array();
95
+		$storedScratch = array();
96
+		for ($i = 0; $i < 5; $i++) {
97
+			$token = Base32::encodeUpper(openssl_random_pseudo_bytes(10));
98
+			$plaintextScratch[] = $token;
99
+
100
+			$storedScratch[] = password_hash(
101
+				$token,
102
+				PasswordCredentialProvider::PASSWORD_ALGO,
103
+				array('cost' => PasswordCredentialProvider::PASSWORD_COST)
104
+			);
105
+		}
106
+
107
+		$storedData = $this->getCredentialData($user->getId(), null);
108
+
109
+		if ($storedData !== null) {
110
+			$storedData->delete();
111
+		}
112
+
113
+		$storedData = $this->createNewCredential($user);
114
+
115
+		$storedData->setData($this->encryptionHelper->encryptData(serialize($storedScratch)));
116
+		$storedData->setFactor($factor);
117
+		$storedData->setVersion(1);
118
+		$storedData->setPriority(9);
119
+
120
+		$storedData->save();
121
+		$this->generatedTokens = $plaintextScratch;
122
+	}
123
+
124
+	/**
125
+	 * Gets the count of remaining valid tokens
126
+	 *
127
+	 * @param int $userId
128
+	 *
129
+	 * @return int
130
+	 */
131
+	public function getRemaining($userId)
132
+	{
133
+		$storedData = $this->getCredentialData($userId);
134
+
135
+		if ($storedData === null) {
136
+			return 0;
137
+		}
138
+
139
+		$scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
140
+
141
+		return count($scratchTokens);
142
+	}
143
+
144
+	/**
145
+	 * @return array
146
+	 */
147
+	public function getTokens()
148
+	{
149
+		if ($this->generatedTokens != null) {
150
+			return $this->generatedTokens;
151
+		}
152
+
153
+		return array();
154
+	}
155 155
 }
Please login to merge, or discard this patch.
smarty-plugins/modifier.iphex.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -8,17 +8,17 @@
 block discarded – undo
8 8
 
9 9
 function smarty_modifier_iphex($input)
10 10
 {
11
-    $output = $input;
11
+	$output = $input;
12 12
 
13
-    if(filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false){
14
-        $octets = explode('.', $input);
15
-        $output = '';
16
-        foreach ($octets as $octet){
17
-            $output .= str_pad(dechex($octet), 2, '0', STR_PAD_LEFT);
18
-        }
13
+	if(filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false){
14
+		$octets = explode('.', $input);
15
+		$output = '';
16
+		foreach ($octets as $octet){
17
+			$output .= str_pad(dechex($octet), 2, '0', STR_PAD_LEFT);
18
+		}
19 19
 
20
-        $output = str_pad($output, 32, '0', STR_PAD_LEFT);
21
-    }
20
+		$output = str_pad($output, 32, '0', STR_PAD_LEFT);
21
+	}
22 22
 
23
-    return $output;
23
+	return $output;
24 24
 }
Please login to merge, or discard this patch.