@@ -24,316 +24,316 @@ |
||
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 | } |
@@ -25,288 +25,288 @@ |
||
25 | 25 | |
26 | 26 | class PageViewRequest extends InternalPageBase |
27 | 27 | { |
28 | - use RequestData; |
|
29 | - const STATUS_SYMBOL_OPEN = '☐'; |
|
30 | - const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
31 | - const STATUS_SYMBOL_REJECTED = '☒'; |
|
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 = '☐'; |
|
30 | + const STATUS_SYMBOL_ACCEPTED = '☑'; |
|
31 | + const STATUS_SYMBOL_REJECTED = '☒'; |
|
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 | } |
@@ -19,120 +19,120 @@ |
||
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 | } |
@@ -22,208 +22,208 @@ |
||
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 | } |
@@ -20,65 +20,65 @@ discard block |
||
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 |
||
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 | } |
@@ -20,190 +20,190 @@ |
||
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 | } |
@@ -19,137 +19,137 @@ |
||
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 | } |
@@ -20,136 +20,136 @@ |
||
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 | } |
@@ -8,17 +8,17 @@ |
||
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 | } |