@@ -10,276 +10,276 @@ |
||
10 | 10 | */ |
11 | 11 | class ElggCrypto { |
12 | 12 | |
13 | - /** |
|
14 | - * Character set for temp passwords (no risk of embedded profanity/glyphs that look similar) |
|
15 | - */ |
|
16 | - const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789'; |
|
13 | + /** |
|
14 | + * Character set for temp passwords (no risk of embedded profanity/glyphs that look similar) |
|
15 | + */ |
|
16 | + const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789'; |
|
17 | 17 | |
18 | - /** |
|
19 | - * Character set for hexadecimal |
|
20 | - */ |
|
21 | - const CHARS_HEX = '0123456789abcdef'; |
|
18 | + /** |
|
19 | + * Character set for hexadecimal |
|
20 | + */ |
|
21 | + const CHARS_HEX = '0123456789abcdef'; |
|
22 | 22 | |
23 | - /** |
|
24 | - * Generate a string of highly randomized bytes (over the full 8-bit range). |
|
25 | - * |
|
26 | - * @param int $length Number of bytes needed |
|
27 | - * @return string Random bytes |
|
28 | - * |
|
29 | - * @author George Argyros <[email protected]> |
|
30 | - * @copyright 2012, George Argyros. All rights reserved. |
|
31 | - * @license Modified BSD |
|
32 | - * @link https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP/blob/master/srand.php Original |
|
33 | - * |
|
34 | - * Redistribution and use in source and binary forms, with or without |
|
35 | - * modification, are permitted provided that the following conditions are met: |
|
36 | - * * Redistributions of source code must retain the above copyright |
|
37 | - * notice, this list of conditions and the following disclaimer. |
|
38 | - * * Redistributions in binary form must reproduce the above copyright |
|
39 | - * notice, this list of conditions and the following disclaimer in the |
|
40 | - * documentation and/or other materials provided with the distribution. |
|
41 | - * * Neither the name of the <organization> nor the |
|
42 | - * names of its contributors may be used to endorse or promote products |
|
43 | - * derived from this software without specific prior written permission. |
|
44 | - * |
|
45 | - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
46 | - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
47 | - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
48 | - * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY |
|
49 | - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
50 | - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
51 | - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
52 | - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
53 | - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
54 | - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
55 | - */ |
|
56 | - public function getRandomBytes($length) { |
|
57 | - if (is_callable('random_bytes')) { |
|
58 | - try { |
|
59 | - return random_bytes($length); |
|
60 | - } catch (\Exception $e) { |
|
61 | - } |
|
62 | - } |
|
23 | + /** |
|
24 | + * Generate a string of highly randomized bytes (over the full 8-bit range). |
|
25 | + * |
|
26 | + * @param int $length Number of bytes needed |
|
27 | + * @return string Random bytes |
|
28 | + * |
|
29 | + * @author George Argyros <[email protected]> |
|
30 | + * @copyright 2012, George Argyros. All rights reserved. |
|
31 | + * @license Modified BSD |
|
32 | + * @link https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP/blob/master/srand.php Original |
|
33 | + * |
|
34 | + * Redistribution and use in source and binary forms, with or without |
|
35 | + * modification, are permitted provided that the following conditions are met: |
|
36 | + * * Redistributions of source code must retain the above copyright |
|
37 | + * notice, this list of conditions and the following disclaimer. |
|
38 | + * * Redistributions in binary form must reproduce the above copyright |
|
39 | + * notice, this list of conditions and the following disclaimer in the |
|
40 | + * documentation and/or other materials provided with the distribution. |
|
41 | + * * Neither the name of the <organization> nor the |
|
42 | + * names of its contributors may be used to endorse or promote products |
|
43 | + * derived from this software without specific prior written permission. |
|
44 | + * |
|
45 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
46 | + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
47 | + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
48 | + * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY |
|
49 | + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
50 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
51 | + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
52 | + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
53 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
54 | + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
55 | + */ |
|
56 | + public function getRandomBytes($length) { |
|
57 | + if (is_callable('random_bytes')) { |
|
58 | + try { |
|
59 | + return random_bytes($length); |
|
60 | + } catch (\Exception $e) { |
|
61 | + } |
|
62 | + } |
|
63 | 63 | |
64 | - $SSLstr = '4'; // http://xkcd.com/221/ |
|
64 | + $SSLstr = '4'; // http://xkcd.com/221/ |
|
65 | 65 | |
66 | - /** |
|
67 | - * Our primary choice for a cryptographic strong randomness function is |
|
68 | - * openssl_random_pseudo_bytes. |
|
69 | - */ |
|
70 | - if (function_exists('openssl_random_pseudo_bytes') && substr(PHP_OS, 0, 3) !== 'WIN') { |
|
71 | - $SSLstr = openssl_random_pseudo_bytes($length, $strong); |
|
72 | - if ($strong) { |
|
73 | - return $SSLstr; |
|
74 | - } |
|
75 | - } |
|
66 | + /** |
|
67 | + * Our primary choice for a cryptographic strong randomness function is |
|
68 | + * openssl_random_pseudo_bytes. |
|
69 | + */ |
|
70 | + if (function_exists('openssl_random_pseudo_bytes') && substr(PHP_OS, 0, 3) !== 'WIN') { |
|
71 | + $SSLstr = openssl_random_pseudo_bytes($length, $strong); |
|
72 | + if ($strong) { |
|
73 | + return $SSLstr; |
|
74 | + } |
|
75 | + } |
|
76 | 76 | |
77 | - /** |
|
78 | - * If mcrypt extension is available then we use it to gather entropy from |
|
79 | - * the operating system's PRNG. This is better than reading /dev/urandom |
|
80 | - * directly since it avoids reading larger blocks of data than needed. |
|
81 | - */ |
|
82 | - if (function_exists('mcrypt_create_iv') && substr(PHP_OS, 0, 3) !== 'WIN') { |
|
83 | - $str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); |
|
84 | - if ($str !== false) { |
|
85 | - return $str; |
|
86 | - } |
|
87 | - } |
|
77 | + /** |
|
78 | + * If mcrypt extension is available then we use it to gather entropy from |
|
79 | + * the operating system's PRNG. This is better than reading /dev/urandom |
|
80 | + * directly since it avoids reading larger blocks of data than needed. |
|
81 | + */ |
|
82 | + if (function_exists('mcrypt_create_iv') && substr(PHP_OS, 0, 3) !== 'WIN') { |
|
83 | + $str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); |
|
84 | + if ($str !== false) { |
|
85 | + return $str; |
|
86 | + } |
|
87 | + } |
|
88 | 88 | |
89 | - /** |
|
90 | - * No build-in crypto randomness function found. We collect any entropy |
|
91 | - * available in the PHP core PRNGs along with some filesystem info and memory |
|
92 | - * stats. To make this data cryptographically strong we add data either from |
|
93 | - * /dev/urandom or if its unavailable, we gather entropy by measuring the |
|
94 | - * time needed to compute a number of SHA-1 hashes. |
|
95 | - */ |
|
96 | - $str = ''; |
|
97 | - $bits_per_round = 2; // bits of entropy collected in each clock drift round |
|
98 | - $msec_per_round = 400; // expected running time of each round in microseconds |
|
99 | - $hash_len = 20; // SHA-1 Hash length |
|
100 | - $total = $length; // total bytes of entropy to collect |
|
89 | + /** |
|
90 | + * No build-in crypto randomness function found. We collect any entropy |
|
91 | + * available in the PHP core PRNGs along with some filesystem info and memory |
|
92 | + * stats. To make this data cryptographically strong we add data either from |
|
93 | + * /dev/urandom or if its unavailable, we gather entropy by measuring the |
|
94 | + * time needed to compute a number of SHA-1 hashes. |
|
95 | + */ |
|
96 | + $str = ''; |
|
97 | + $bits_per_round = 2; // bits of entropy collected in each clock drift round |
|
98 | + $msec_per_round = 400; // expected running time of each round in microseconds |
|
99 | + $hash_len = 20; // SHA-1 Hash length |
|
100 | + $total = $length; // total bytes of entropy to collect |
|
101 | 101 | |
102 | - $handle = @fopen('/dev/urandom', 'rb'); |
|
103 | - if ($handle && function_exists('stream_set_read_buffer')) { |
|
104 | - @stream_set_read_buffer($handle, 0); |
|
105 | - } |
|
102 | + $handle = @fopen('/dev/urandom', 'rb'); |
|
103 | + if ($handle && function_exists('stream_set_read_buffer')) { |
|
104 | + @stream_set_read_buffer($handle, 0); |
|
105 | + } |
|
106 | 106 | |
107 | - do { |
|
108 | - $bytes = ($total > $hash_len) ? $hash_len : $total; |
|
109 | - $total -= $bytes; |
|
107 | + do { |
|
108 | + $bytes = ($total > $hash_len) ? $hash_len : $total; |
|
109 | + $total -= $bytes; |
|
110 | 110 | |
111 | - //collect any entropy available from the PHP system and filesystem |
|
112 | - $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; |
|
113 | - $entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); |
|
114 | - $entropy .= memory_get_usage() . getmypid(); |
|
115 | - $entropy .= serialize($_ENV) . serialize($_SERVER); |
|
116 | - if (function_exists('posix_times')) { |
|
117 | - $entropy .= serialize(posix_times()); |
|
118 | - } |
|
119 | - if (function_exists('zend_thread_id')) { |
|
120 | - $entropy .= zend_thread_id(); |
|
121 | - } |
|
111 | + //collect any entropy available from the PHP system and filesystem |
|
112 | + $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; |
|
113 | + $entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); |
|
114 | + $entropy .= memory_get_usage() . getmypid(); |
|
115 | + $entropy .= serialize($_ENV) . serialize($_SERVER); |
|
116 | + if (function_exists('posix_times')) { |
|
117 | + $entropy .= serialize(posix_times()); |
|
118 | + } |
|
119 | + if (function_exists('zend_thread_id')) { |
|
120 | + $entropy .= zend_thread_id(); |
|
121 | + } |
|
122 | 122 | |
123 | - if ($handle) { |
|
124 | - $entropy .= @fread($handle, $bytes); |
|
125 | - } else { |
|
126 | - // In the future we should consider outright refusing to generate bytes without an |
|
127 | - // official random source, as many consider hacks like this irresponsible. |
|
123 | + if ($handle) { |
|
124 | + $entropy .= @fread($handle, $bytes); |
|
125 | + } else { |
|
126 | + // In the future we should consider outright refusing to generate bytes without an |
|
127 | + // official random source, as many consider hacks like this irresponsible. |
|
128 | 128 | |
129 | - // Measure the time that the operations will take on average |
|
130 | - for ($i = 0; $i < 3; $i++) { |
|
131 | - $c1 = microtime(true); |
|
132 | - $var = sha1(mt_rand()); |
|
133 | - for ($j = 0; $j < 50; $j++) { |
|
134 | - $var = sha1($var); |
|
135 | - } |
|
136 | - $c2 = microtime(true); |
|
137 | - $entropy .= $c1 . $c2; |
|
138 | - } |
|
129 | + // Measure the time that the operations will take on average |
|
130 | + for ($i = 0; $i < 3; $i++) { |
|
131 | + $c1 = microtime(true); |
|
132 | + $var = sha1(mt_rand()); |
|
133 | + for ($j = 0; $j < 50; $j++) { |
|
134 | + $var = sha1($var); |
|
135 | + } |
|
136 | + $c2 = microtime(true); |
|
137 | + $entropy .= $c1 . $c2; |
|
138 | + } |
|
139 | 139 | |
140 | - // Based on the above measurement determine the total rounds |
|
141 | - // in order to bound the total running time. |
|
142 | - if ($c2 - $c1 == 0) { |
|
143 | - // This occurs on some Windows systems. On a late 2013 MacBook Pro, 2.6 GHz Intel Core i7 |
|
144 | - // this averaged 400, so we're just going with that. With all the other entropy gathered |
|
145 | - // this should be sufficient. |
|
146 | - $rounds = 400; |
|
147 | - } else { |
|
148 | - $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); |
|
149 | - } |
|
140 | + // Based on the above measurement determine the total rounds |
|
141 | + // in order to bound the total running time. |
|
142 | + if ($c2 - $c1 == 0) { |
|
143 | + // This occurs on some Windows systems. On a late 2013 MacBook Pro, 2.6 GHz Intel Core i7 |
|
144 | + // this averaged 400, so we're just going with that. With all the other entropy gathered |
|
145 | + // this should be sufficient. |
|
146 | + $rounds = 400; |
|
147 | + } else { |
|
148 | + $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); |
|
149 | + } |
|
150 | 150 | |
151 | - // Take the additional measurements. On average we can expect |
|
152 | - // at least $bits_per_round bits of entropy from each measurement. |
|
153 | - $iter = $bytes * (int) (ceil(8 / $bits_per_round)); |
|
151 | + // Take the additional measurements. On average we can expect |
|
152 | + // at least $bits_per_round bits of entropy from each measurement. |
|
153 | + $iter = $bytes * (int) (ceil(8 / $bits_per_round)); |
|
154 | 154 | |
155 | - for ($i = 0; $i < $iter; $i++) { |
|
156 | - $c1 = microtime(); |
|
157 | - $var = sha1(mt_rand()); |
|
158 | - for ($j = 0; $j < $rounds; $j++) { |
|
159 | - $var = sha1($var); |
|
160 | - } |
|
161 | - $c2 = microtime(); |
|
162 | - $entropy .= $c1 . $c2; |
|
163 | - } |
|
164 | - } |
|
155 | + for ($i = 0; $i < $iter; $i++) { |
|
156 | + $c1 = microtime(); |
|
157 | + $var = sha1(mt_rand()); |
|
158 | + for ($j = 0; $j < $rounds; $j++) { |
|
159 | + $var = sha1($var); |
|
160 | + } |
|
161 | + $c2 = microtime(); |
|
162 | + $entropy .= $c1 . $c2; |
|
163 | + } |
|
164 | + } |
|
165 | 165 | |
166 | - // We assume sha1 is a deterministic extractor for the $entropy variable. |
|
167 | - $str .= sha1($entropy, true); |
|
168 | - } while ($length > strlen($str)); |
|
166 | + // We assume sha1 is a deterministic extractor for the $entropy variable. |
|
167 | + $str .= sha1($entropy, true); |
|
168 | + } while ($length > strlen($str)); |
|
169 | 169 | |
170 | - if ($handle) { |
|
171 | - @fclose($handle); |
|
172 | - } |
|
170 | + if ($handle) { |
|
171 | + @fclose($handle); |
|
172 | + } |
|
173 | 173 | |
174 | - return substr($str, 0, $length); |
|
175 | - } |
|
174 | + return substr($str, 0, $length); |
|
175 | + } |
|
176 | 176 | |
177 | - /** |
|
178 | - * Generate a random string of specified length. |
|
179 | - * |
|
180 | - * Uses supplied character list for generating the new string. |
|
181 | - * If no character list provided - uses Base64 URL character set. |
|
182 | - * |
|
183 | - * @param int $length Desired length of the string |
|
184 | - * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL |
|
185 | - * charset will be used. |
|
186 | - * |
|
187 | - * @return string The random string |
|
188 | - * |
|
189 | - * @throws InvalidArgumentException |
|
190 | - * |
|
191 | - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) |
|
192 | - * @license http://framework.zend.com/license/new-bsd New BSD License |
|
193 | - * |
|
194 | - * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 |
|
195 | - */ |
|
196 | - public function getRandomString($length, $chars = null) { |
|
197 | - if ($length < 1) { |
|
198 | - throw new \InvalidArgumentException('Length should be >= 1'); |
|
199 | - } |
|
177 | + /** |
|
178 | + * Generate a random string of specified length. |
|
179 | + * |
|
180 | + * Uses supplied character list for generating the new string. |
|
181 | + * If no character list provided - uses Base64 URL character set. |
|
182 | + * |
|
183 | + * @param int $length Desired length of the string |
|
184 | + * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL |
|
185 | + * charset will be used. |
|
186 | + * |
|
187 | + * @return string The random string |
|
188 | + * |
|
189 | + * @throws InvalidArgumentException |
|
190 | + * |
|
191 | + * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) |
|
192 | + * @license http://framework.zend.com/license/new-bsd New BSD License |
|
193 | + * |
|
194 | + * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 |
|
195 | + */ |
|
196 | + public function getRandomString($length, $chars = null) { |
|
197 | + if ($length < 1) { |
|
198 | + throw new \InvalidArgumentException('Length should be >= 1'); |
|
199 | + } |
|
200 | 200 | |
201 | - if (empty($chars)) { |
|
202 | - $numBytes = ceil($length * 0.75); |
|
203 | - $bytes = $this->getRandomBytes($numBytes); |
|
204 | - $string = substr(rtrim(base64_encode($bytes), '='), 0, $length); |
|
201 | + if (empty($chars)) { |
|
202 | + $numBytes = ceil($length * 0.75); |
|
203 | + $bytes = $this->getRandomBytes($numBytes); |
|
204 | + $string = substr(rtrim(base64_encode($bytes), '='), 0, $length); |
|
205 | 205 | |
206 | - // Base64 URL |
|
207 | - return strtr($string, '+/', '-_'); |
|
208 | - } |
|
206 | + // Base64 URL |
|
207 | + return strtr($string, '+/', '-_'); |
|
208 | + } |
|
209 | 209 | |
210 | - if ($chars == self::CHARS_HEX) { |
|
211 | - // hex is easy |
|
212 | - $bytes = $this->getRandomBytes(ceil($length / 2)); |
|
213 | - return substr(bin2hex($bytes), 0, $length); |
|
214 | - } |
|
210 | + if ($chars == self::CHARS_HEX) { |
|
211 | + // hex is easy |
|
212 | + $bytes = $this->getRandomBytes(ceil($length / 2)); |
|
213 | + return substr(bin2hex($bytes), 0, $length); |
|
214 | + } |
|
215 | 215 | |
216 | - $listLen = strlen($chars); |
|
216 | + $listLen = strlen($chars); |
|
217 | 217 | |
218 | - if ($listLen == 1) { |
|
219 | - return str_repeat($chars, $length); |
|
220 | - } |
|
218 | + if ($listLen == 1) { |
|
219 | + return str_repeat($chars, $length); |
|
220 | + } |
|
221 | 221 | |
222 | - $bytes = $this->getRandomBytes($length); |
|
223 | - $pos = 0; |
|
224 | - $result = ''; |
|
225 | - for ($i = 0; $i < $length; $i++) { |
|
226 | - $pos = ($pos + ord($bytes[$i])) % $listLen; |
|
227 | - $result .= $chars[$pos]; |
|
228 | - } |
|
222 | + $bytes = $this->getRandomBytes($length); |
|
223 | + $pos = 0; |
|
224 | + $result = ''; |
|
225 | + for ($i = 0; $i < $length; $i++) { |
|
226 | + $pos = ($pos + ord($bytes[$i])) % $listLen; |
|
227 | + $result .= $chars[$pos]; |
|
228 | + } |
|
229 | 229 | |
230 | - return $result; |
|
231 | - } |
|
230 | + return $result; |
|
231 | + } |
|
232 | 232 | |
233 | - /** |
|
234 | - * Are two strings equal (compared in constant time)? |
|
235 | - * |
|
236 | - * @param string $str1 First string to compare |
|
237 | - * @param string $str2 Second string to compare |
|
238 | - * |
|
239 | - * @return bool |
|
240 | - * |
|
241 | - * Based on password_verify in PasswordCompat |
|
242 | - * @author Anthony Ferrara <[email protected]> |
|
243 | - * @license http://www.opensource.org/licenses/mit-license.html MIT License |
|
244 | - * @copyright 2012 The Authors |
|
245 | - */ |
|
246 | - public function areEqual($str1, $str2) { |
|
247 | - $len1 = $this->strlen($str1); |
|
248 | - $len2 = $this->strlen($str2); |
|
249 | - if ($len1 !== $len2) { |
|
250 | - return false; |
|
251 | - } |
|
233 | + /** |
|
234 | + * Are two strings equal (compared in constant time)? |
|
235 | + * |
|
236 | + * @param string $str1 First string to compare |
|
237 | + * @param string $str2 Second string to compare |
|
238 | + * |
|
239 | + * @return bool |
|
240 | + * |
|
241 | + * Based on password_verify in PasswordCompat |
|
242 | + * @author Anthony Ferrara <[email protected]> |
|
243 | + * @license http://www.opensource.org/licenses/mit-license.html MIT License |
|
244 | + * @copyright 2012 The Authors |
|
245 | + */ |
|
246 | + public function areEqual($str1, $str2) { |
|
247 | + $len1 = $this->strlen($str1); |
|
248 | + $len2 = $this->strlen($str2); |
|
249 | + if ($len1 !== $len2) { |
|
250 | + return false; |
|
251 | + } |
|
252 | 252 | |
253 | - $status = 0; |
|
254 | - for ($i = 0; $i < $len1; $i++) { |
|
255 | - $status |= (ord($str1[$i]) ^ ord($str2[$i])); |
|
256 | - } |
|
253 | + $status = 0; |
|
254 | + for ($i = 0; $i < $len1; $i++) { |
|
255 | + $status |= (ord($str1[$i]) ^ ord($str2[$i])); |
|
256 | + } |
|
257 | 257 | |
258 | - return $status === 0; |
|
259 | - } |
|
258 | + return $status === 0; |
|
259 | + } |
|
260 | 260 | |
261 | - /** |
|
262 | - * Count the number of bytes in a string |
|
263 | - * |
|
264 | - * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension. |
|
265 | - * In this case, strlen() will count the number of *characters* based on the internal encoding. A |
|
266 | - * sequence of bytes might be regarded as a single multibyte character. |
|
267 | - * |
|
268 | - * Use elgg_strlen() to count UTF-characters instead of bytes. |
|
269 | - * |
|
270 | - * @param string $binary_string The input string |
|
271 | - * |
|
272 | - * @return int The number of bytes |
|
273 | - * |
|
274 | - * From PasswordCompat\binary\_strlen |
|
275 | - * @author Anthony Ferrara <[email protected]> |
|
276 | - * @license http://www.opensource.org/licenses/mit-license.html MIT License |
|
277 | - * @copyright 2012 The Authors |
|
278 | - */ |
|
279 | - protected function strlen($binary_string) { |
|
280 | - if (function_exists('mb_strlen')) { |
|
281 | - return mb_strlen($binary_string, '8bit'); |
|
282 | - } |
|
283 | - return strlen($binary_string); |
|
284 | - } |
|
261 | + /** |
|
262 | + * Count the number of bytes in a string |
|
263 | + * |
|
264 | + * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension. |
|
265 | + * In this case, strlen() will count the number of *characters* based on the internal encoding. A |
|
266 | + * sequence of bytes might be regarded as a single multibyte character. |
|
267 | + * |
|
268 | + * Use elgg_strlen() to count UTF-characters instead of bytes. |
|
269 | + * |
|
270 | + * @param string $binary_string The input string |
|
271 | + * |
|
272 | + * @return int The number of bytes |
|
273 | + * |
|
274 | + * From PasswordCompat\binary\_strlen |
|
275 | + * @author Anthony Ferrara <[email protected]> |
|
276 | + * @license http://www.opensource.org/licenses/mit-license.html MIT License |
|
277 | + * @copyright 2012 The Authors |
|
278 | + */ |
|
279 | + protected function strlen($binary_string) { |
|
280 | + if (function_exists('mb_strlen')) { |
|
281 | + return mb_strlen($binary_string, '8bit'); |
|
282 | + } |
|
283 | + return strlen($binary_string); |
|
284 | + } |
|
285 | 285 | } |
@@ -11,139 +11,139 @@ |
||
11 | 11 | */ |
12 | 12 | class File { |
13 | 13 | |
14 | - const INLINE = 'inline'; |
|
15 | - const ATTACHMENT = 'attachment'; |
|
16 | - |
|
17 | - /** |
|
18 | - * @var \ElggFile |
|
19 | - */ |
|
20 | - private $file; |
|
21 | - |
|
22 | - /** |
|
23 | - * @var int |
|
24 | - */ |
|
25 | - private $expires; |
|
26 | - |
|
27 | - /** |
|
28 | - * @var string |
|
29 | - */ |
|
30 | - private $disposition; |
|
31 | - |
|
32 | - /** |
|
33 | - * @var bool |
|
34 | - */ |
|
35 | - private $use_cookie = true; |
|
36 | - |
|
37 | - /** |
|
38 | - * Set file object |
|
39 | - * |
|
40 | - * @param \ElggFile $file File object |
|
41 | - * @return void |
|
42 | - */ |
|
43 | - public function setFile(\ElggFile $file) { |
|
44 | - $this->file = $file; |
|
45 | - } |
|
46 | - |
|
47 | - /** |
|
48 | - * Returns file object |
|
49 | - * @return \ElggFile|null |
|
50 | - */ |
|
51 | - public function getFile() { |
|
52 | - return $this->file; |
|
53 | - } |
|
54 | - |
|
55 | - /** |
|
56 | - * Sets URL expiration |
|
57 | - * |
|
58 | - * @param int $expires String suitable for strtotime() |
|
59 | - * @return void |
|
60 | - */ |
|
61 | - public function setExpires($expires = '+2 hours') { |
|
62 | - $this->expires = strtotime($expires); |
|
63 | - } |
|
64 | - |
|
65 | - /** |
|
66 | - * Sets content disposition |
|
67 | - * |
|
68 | - * @param string $disposition Content disposition ('inline' or 'attachment') |
|
69 | - * @return void |
|
70 | - */ |
|
71 | - public function setDisposition($disposition = self::ATTACHMENT) { |
|
72 | - if (!in_array($disposition, [self::ATTACHMENT, self::INLINE])) { |
|
73 | - throw new \InvalidArgumentException("Disposition $disposition is not supported in " . __CLASS__); |
|
74 | - } |
|
75 | - $this->disposition = $disposition; |
|
76 | - } |
|
77 | - |
|
78 | - /** |
|
79 | - * Bind URL to current user session |
|
80 | - * |
|
81 | - * @param bool $use_cookie Use cookie |
|
82 | - * @return void |
|
83 | - */ |
|
84 | - public function bindSession($use_cookie = true) { |
|
85 | - $this->use_cookie = $use_cookie; |
|
86 | - } |
|
87 | - |
|
88 | - /** |
|
89 | - * Returns publicly accessible URL |
|
90 | - * @return string|false |
|
91 | - */ |
|
92 | - public function getURL() { |
|
93 | - |
|
94 | - if (!$this->file instanceof \ElggFile || !$this->file->exists()) { |
|
95 | - elgg_log("Unable to resolve resource URL for a file that does not exist on filestore"); |
|
96 | - return false; |
|
97 | - } |
|
98 | - |
|
99 | - $relative_path = ''; |
|
100 | - $root_prefix = _elgg_services()->config->getDataPath(); |
|
101 | - $path = $this->file->getFilenameOnFilestore(); |
|
102 | - if (substr($path, 0, strlen($root_prefix)) == $root_prefix) { |
|
103 | - $relative_path = substr($path, strlen($root_prefix)); |
|
104 | - } |
|
105 | - |
|
106 | - if (!$relative_path) { |
|
107 | - elgg_log("Unable to resolve relative path of the file on the filestore"); |
|
108 | - return false; |
|
109 | - } |
|
110 | - |
|
111 | - if (preg_match('~[^a-zA-Z0-9_\./ ]~', $relative_path)) { |
|
112 | - // Filenames may contain special characters that result in malformatted URLs |
|
113 | - // and/or HMAC mismatches. We want to avoid that by encoding the path. |
|
114 | - $relative_path = ':' . Base64Url::encode($relative_path); |
|
115 | - } |
|
116 | - |
|
117 | - $data = [ |
|
118 | - 'expires' => isset($this->expires) ? $this->expires : 0, |
|
119 | - 'last_updated' => filemtime($this->file->getFilenameOnFilestore()), |
|
120 | - 'disposition' => $this->disposition == self::INLINE ? 'i' : 'a', |
|
121 | - 'path' => $relative_path, |
|
122 | - ]; |
|
123 | - |
|
124 | - if ($this->use_cookie) { |
|
125 | - $data['cookie'] = _elgg_services()->session->getId(); |
|
126 | - if (empty($data['cookie'])) { |
|
127 | - return false; |
|
128 | - } |
|
129 | - $data['use_cookie'] = 1; |
|
130 | - } else { |
|
131 | - $data['use_cookie'] = 0; |
|
132 | - } |
|
133 | - |
|
134 | - ksort($data); |
|
135 | - $mac = _elgg_services()->hmac->getHmac($data)->getToken(); |
|
136 | - |
|
137 | - $url_segments = [ |
|
138 | - 'serve-file', |
|
139 | - "e{$data['expires']}", |
|
140 | - "l{$data['last_updated']}", |
|
141 | - "d{$data['disposition']}", |
|
142 | - "c{$data['use_cookie']}", |
|
143 | - $mac, |
|
144 | - $relative_path, |
|
145 | - ]; |
|
146 | - |
|
147 | - return elgg_normalize_url(implode('/', $url_segments)); |
|
148 | - } |
|
14 | + const INLINE = 'inline'; |
|
15 | + const ATTACHMENT = 'attachment'; |
|
16 | + |
|
17 | + /** |
|
18 | + * @var \ElggFile |
|
19 | + */ |
|
20 | + private $file; |
|
21 | + |
|
22 | + /** |
|
23 | + * @var int |
|
24 | + */ |
|
25 | + private $expires; |
|
26 | + |
|
27 | + /** |
|
28 | + * @var string |
|
29 | + */ |
|
30 | + private $disposition; |
|
31 | + |
|
32 | + /** |
|
33 | + * @var bool |
|
34 | + */ |
|
35 | + private $use_cookie = true; |
|
36 | + |
|
37 | + /** |
|
38 | + * Set file object |
|
39 | + * |
|
40 | + * @param \ElggFile $file File object |
|
41 | + * @return void |
|
42 | + */ |
|
43 | + public function setFile(\ElggFile $file) { |
|
44 | + $this->file = $file; |
|
45 | + } |
|
46 | + |
|
47 | + /** |
|
48 | + * Returns file object |
|
49 | + * @return \ElggFile|null |
|
50 | + */ |
|
51 | + public function getFile() { |
|
52 | + return $this->file; |
|
53 | + } |
|
54 | + |
|
55 | + /** |
|
56 | + * Sets URL expiration |
|
57 | + * |
|
58 | + * @param int $expires String suitable for strtotime() |
|
59 | + * @return void |
|
60 | + */ |
|
61 | + public function setExpires($expires = '+2 hours') { |
|
62 | + $this->expires = strtotime($expires); |
|
63 | + } |
|
64 | + |
|
65 | + /** |
|
66 | + * Sets content disposition |
|
67 | + * |
|
68 | + * @param string $disposition Content disposition ('inline' or 'attachment') |
|
69 | + * @return void |
|
70 | + */ |
|
71 | + public function setDisposition($disposition = self::ATTACHMENT) { |
|
72 | + if (!in_array($disposition, [self::ATTACHMENT, self::INLINE])) { |
|
73 | + throw new \InvalidArgumentException("Disposition $disposition is not supported in " . __CLASS__); |
|
74 | + } |
|
75 | + $this->disposition = $disposition; |
|
76 | + } |
|
77 | + |
|
78 | + /** |
|
79 | + * Bind URL to current user session |
|
80 | + * |
|
81 | + * @param bool $use_cookie Use cookie |
|
82 | + * @return void |
|
83 | + */ |
|
84 | + public function bindSession($use_cookie = true) { |
|
85 | + $this->use_cookie = $use_cookie; |
|
86 | + } |
|
87 | + |
|
88 | + /** |
|
89 | + * Returns publicly accessible URL |
|
90 | + * @return string|false |
|
91 | + */ |
|
92 | + public function getURL() { |
|
93 | + |
|
94 | + if (!$this->file instanceof \ElggFile || !$this->file->exists()) { |
|
95 | + elgg_log("Unable to resolve resource URL for a file that does not exist on filestore"); |
|
96 | + return false; |
|
97 | + } |
|
98 | + |
|
99 | + $relative_path = ''; |
|
100 | + $root_prefix = _elgg_services()->config->getDataPath(); |
|
101 | + $path = $this->file->getFilenameOnFilestore(); |
|
102 | + if (substr($path, 0, strlen($root_prefix)) == $root_prefix) { |
|
103 | + $relative_path = substr($path, strlen($root_prefix)); |
|
104 | + } |
|
105 | + |
|
106 | + if (!$relative_path) { |
|
107 | + elgg_log("Unable to resolve relative path of the file on the filestore"); |
|
108 | + return false; |
|
109 | + } |
|
110 | + |
|
111 | + if (preg_match('~[^a-zA-Z0-9_\./ ]~', $relative_path)) { |
|
112 | + // Filenames may contain special characters that result in malformatted URLs |
|
113 | + // and/or HMAC mismatches. We want to avoid that by encoding the path. |
|
114 | + $relative_path = ':' . Base64Url::encode($relative_path); |
|
115 | + } |
|
116 | + |
|
117 | + $data = [ |
|
118 | + 'expires' => isset($this->expires) ? $this->expires : 0, |
|
119 | + 'last_updated' => filemtime($this->file->getFilenameOnFilestore()), |
|
120 | + 'disposition' => $this->disposition == self::INLINE ? 'i' : 'a', |
|
121 | + 'path' => $relative_path, |
|
122 | + ]; |
|
123 | + |
|
124 | + if ($this->use_cookie) { |
|
125 | + $data['cookie'] = _elgg_services()->session->getId(); |
|
126 | + if (empty($data['cookie'])) { |
|
127 | + return false; |
|
128 | + } |
|
129 | + $data['use_cookie'] = 1; |
|
130 | + } else { |
|
131 | + $data['use_cookie'] = 0; |
|
132 | + } |
|
133 | + |
|
134 | + ksort($data); |
|
135 | + $mac = _elgg_services()->hmac->getHmac($data)->getToken(); |
|
136 | + |
|
137 | + $url_segments = [ |
|
138 | + 'serve-file', |
|
139 | + "e{$data['expires']}", |
|
140 | + "l{$data['last_updated']}", |
|
141 | + "d{$data['disposition']}", |
|
142 | + "c{$data['use_cookie']}", |
|
143 | + $mac, |
|
144 | + $relative_path, |
|
145 | + ]; |
|
146 | + |
|
147 | + return elgg_normalize_url(implode('/', $url_segments)); |
|
148 | + } |
|
149 | 149 | } |
@@ -18,482 +18,482 @@ |
||
18 | 18 | */ |
19 | 19 | class ActionsService { |
20 | 20 | |
21 | - use \Elgg\TimeUsing; |
|
21 | + use \Elgg\TimeUsing; |
|
22 | 22 | |
23 | - /** |
|
24 | - * @var Config |
|
25 | - */ |
|
26 | - private $config; |
|
27 | - |
|
28 | - /** |
|
29 | - * @var ElggSession |
|
30 | - */ |
|
31 | - private $session; |
|
32 | - |
|
33 | - /** |
|
34 | - * @var ElggCrypto |
|
35 | - */ |
|
36 | - private $crypto; |
|
37 | - |
|
38 | - /** |
|
39 | - * Registered actions storage |
|
40 | - * |
|
41 | - * Each element has keys: |
|
42 | - * "file" => filename |
|
43 | - * "access" => access level |
|
44 | - * |
|
45 | - * @var array |
|
46 | - */ |
|
47 | - private $actions = []; |
|
48 | - |
|
49 | - /** |
|
50 | - * The current action being processed |
|
51 | - * @var string |
|
52 | - */ |
|
53 | - private $currentAction = null; |
|
54 | - |
|
55 | - /** |
|
56 | - * @var string[] |
|
57 | - */ |
|
58 | - private static $access_levels = ['public', 'logged_in', 'admin']; |
|
59 | - |
|
60 | - /** |
|
61 | - * Constructor |
|
62 | - * |
|
63 | - * @param Config $config Config |
|
64 | - * @param ElggSession $session Session |
|
65 | - * @param ElggCrypto $crypto Crypto service |
|
66 | - */ |
|
67 | - public function __construct(Config $config, ElggSession $session, ElggCrypto $crypto) { |
|
68 | - $this->config = $config; |
|
69 | - $this->session = $session; |
|
70 | - $this->crypto = $crypto; |
|
71 | - } |
|
72 | - |
|
73 | - /** |
|
74 | - * Executes an action |
|
75 | - * If called from action() redirect will be issued by the response factory |
|
76 | - * If called as /action page handler response will be handled by \Elgg\Router |
|
77 | - * |
|
78 | - * @param string $action Action name |
|
79 | - * @param string $forwarder URL to forward to after completion |
|
80 | - * @return ResponseBuilder|null |
|
81 | - * @see action |
|
82 | - * @access private |
|
83 | - */ |
|
84 | - public function execute($action, $forwarder = "") { |
|
85 | - $action = rtrim($action, '/'); |
|
86 | - $this->currentAction = $action; |
|
23 | + /** |
|
24 | + * @var Config |
|
25 | + */ |
|
26 | + private $config; |
|
27 | + |
|
28 | + /** |
|
29 | + * @var ElggSession |
|
30 | + */ |
|
31 | + private $session; |
|
32 | + |
|
33 | + /** |
|
34 | + * @var ElggCrypto |
|
35 | + */ |
|
36 | + private $crypto; |
|
37 | + |
|
38 | + /** |
|
39 | + * Registered actions storage |
|
40 | + * |
|
41 | + * Each element has keys: |
|
42 | + * "file" => filename |
|
43 | + * "access" => access level |
|
44 | + * |
|
45 | + * @var array |
|
46 | + */ |
|
47 | + private $actions = []; |
|
48 | + |
|
49 | + /** |
|
50 | + * The current action being processed |
|
51 | + * @var string |
|
52 | + */ |
|
53 | + private $currentAction = null; |
|
54 | + |
|
55 | + /** |
|
56 | + * @var string[] |
|
57 | + */ |
|
58 | + private static $access_levels = ['public', 'logged_in', 'admin']; |
|
59 | + |
|
60 | + /** |
|
61 | + * Constructor |
|
62 | + * |
|
63 | + * @param Config $config Config |
|
64 | + * @param ElggSession $session Session |
|
65 | + * @param ElggCrypto $crypto Crypto service |
|
66 | + */ |
|
67 | + public function __construct(Config $config, ElggSession $session, ElggCrypto $crypto) { |
|
68 | + $this->config = $config; |
|
69 | + $this->session = $session; |
|
70 | + $this->crypto = $crypto; |
|
71 | + } |
|
72 | + |
|
73 | + /** |
|
74 | + * Executes an action |
|
75 | + * If called from action() redirect will be issued by the response factory |
|
76 | + * If called as /action page handler response will be handled by \Elgg\Router |
|
77 | + * |
|
78 | + * @param string $action Action name |
|
79 | + * @param string $forwarder URL to forward to after completion |
|
80 | + * @return ResponseBuilder|null |
|
81 | + * @see action |
|
82 | + * @access private |
|
83 | + */ |
|
84 | + public function execute($action, $forwarder = "") { |
|
85 | + $action = rtrim($action, '/'); |
|
86 | + $this->currentAction = $action; |
|
87 | 87 | |
88 | - // @todo REMOVE THESE ONCE #1509 IS IN PLACE. |
|
89 | - // Allow users to disable plugins without a token in order to |
|
90 | - // remove plugins that are incompatible. |
|
91 | - // Login and logout are for convenience. |
|
92 | - // file/download (see #2010) |
|
93 | - $exceptions = [ |
|
94 | - 'admin/plugins/disable', |
|
95 | - 'logout', |
|
96 | - 'file/download', |
|
97 | - ]; |
|
88 | + // @todo REMOVE THESE ONCE #1509 IS IN PLACE. |
|
89 | + // Allow users to disable plugins without a token in order to |
|
90 | + // remove plugins that are incompatible. |
|
91 | + // Login and logout are for convenience. |
|
92 | + // file/download (see #2010) |
|
93 | + $exceptions = [ |
|
94 | + 'admin/plugins/disable', |
|
95 | + 'logout', |
|
96 | + 'file/download', |
|
97 | + ]; |
|
98 | 98 | |
99 | - if (!in_array($action, $exceptions)) { |
|
100 | - // All actions require a token. |
|
101 | - $pass = $this->gatekeeper($action); |
|
102 | - if (!$pass) { |
|
103 | - return; |
|
104 | - } |
|
105 | - } |
|
99 | + if (!in_array($action, $exceptions)) { |
|
100 | + // All actions require a token. |
|
101 | + $pass = $this->gatekeeper($action); |
|
102 | + if (!$pass) { |
|
103 | + return; |
|
104 | + } |
|
105 | + } |
|
106 | 106 | |
107 | - $forwarder = str_replace($this->config->getSiteUrl(), "", $forwarder); |
|
108 | - $forwarder = str_replace("http://", "", $forwarder); |
|
109 | - $forwarder = str_replace("@", "", $forwarder); |
|
110 | - if (substr($forwarder, 0, 1) == "/") { |
|
111 | - $forwarder = substr($forwarder, 1); |
|
112 | - } |
|
113 | - |
|
114 | - $ob_started = false; |
|
115 | - |
|
116 | - /** |
|
117 | - * Prepare action response |
|
118 | - * |
|
119 | - * @param string $error_key Error message key |
|
120 | - * @param int $status_code HTTP status code |
|
121 | - * @return ResponseBuilder |
|
122 | - */ |
|
123 | - $forward = function ($error_key = '', $status_code = ELGG_HTTP_OK) use ($action, $forwarder, &$ob_started) { |
|
124 | - if ($error_key) { |
|
125 | - if ($ob_started) { |
|
126 | - ob_end_clean(); |
|
127 | - } |
|
128 | - $msg = _elgg_services()->translator->translate($error_key, [$action]); |
|
129 | - _elgg_services()->systemMessages->addErrorMessage($msg); |
|
130 | - $response = new \Elgg\Http\ErrorResponse($msg, $status_code); |
|
131 | - } else { |
|
132 | - $content = ob_get_clean(); |
|
133 | - $response = new \Elgg\Http\OkResponse($content, $status_code); |
|
134 | - } |
|
107 | + $forwarder = str_replace($this->config->getSiteUrl(), "", $forwarder); |
|
108 | + $forwarder = str_replace("http://", "", $forwarder); |
|
109 | + $forwarder = str_replace("@", "", $forwarder); |
|
110 | + if (substr($forwarder, 0, 1) == "/") { |
|
111 | + $forwarder = substr($forwarder, 1); |
|
112 | + } |
|
113 | + |
|
114 | + $ob_started = false; |
|
115 | + |
|
116 | + /** |
|
117 | + * Prepare action response |
|
118 | + * |
|
119 | + * @param string $error_key Error message key |
|
120 | + * @param int $status_code HTTP status code |
|
121 | + * @return ResponseBuilder |
|
122 | + */ |
|
123 | + $forward = function ($error_key = '', $status_code = ELGG_HTTP_OK) use ($action, $forwarder, &$ob_started) { |
|
124 | + if ($error_key) { |
|
125 | + if ($ob_started) { |
|
126 | + ob_end_clean(); |
|
127 | + } |
|
128 | + $msg = _elgg_services()->translator->translate($error_key, [$action]); |
|
129 | + _elgg_services()->systemMessages->addErrorMessage($msg); |
|
130 | + $response = new \Elgg\Http\ErrorResponse($msg, $status_code); |
|
131 | + } else { |
|
132 | + $content = ob_get_clean(); |
|
133 | + $response = new \Elgg\Http\OkResponse($content, $status_code); |
|
134 | + } |
|
135 | 135 | |
136 | - $forwarder = empty($forwarder) ? REFERER : $forwarder; |
|
137 | - $response->setForwardURL($forwarder); |
|
138 | - return $response; |
|
139 | - }; |
|
140 | - |
|
141 | - if (!isset($this->actions[$action])) { |
|
142 | - return $forward('actionundefined', ELGG_HTTP_NOT_IMPLEMENTED); |
|
143 | - } |
|
144 | - |
|
145 | - $user = $this->session->getLoggedInUser(); |
|
146 | - |
|
147 | - // access checks |
|
148 | - switch ($this->actions[$action]['access']) { |
|
149 | - case 'public': |
|
150 | - break; |
|
151 | - case 'logged_in': |
|
152 | - if (!$user) { |
|
153 | - return $forward('actionloggedout', ELGG_HTTP_FORBIDDEN); |
|
154 | - } |
|
155 | - break; |
|
156 | - default: |
|
157 | - // admin or misspelling |
|
158 | - if (!$user || !$user->isAdmin()) { |
|
159 | - return $forward('actionunauthorized', ELGG_HTTP_FORBIDDEN); |
|
160 | - } |
|
161 | - } |
|
162 | - |
|
163 | - ob_start(); |
|
136 | + $forwarder = empty($forwarder) ? REFERER : $forwarder; |
|
137 | + $response->setForwardURL($forwarder); |
|
138 | + return $response; |
|
139 | + }; |
|
140 | + |
|
141 | + if (!isset($this->actions[$action])) { |
|
142 | + return $forward('actionundefined', ELGG_HTTP_NOT_IMPLEMENTED); |
|
143 | + } |
|
144 | + |
|
145 | + $user = $this->session->getLoggedInUser(); |
|
146 | + |
|
147 | + // access checks |
|
148 | + switch ($this->actions[$action]['access']) { |
|
149 | + case 'public': |
|
150 | + break; |
|
151 | + case 'logged_in': |
|
152 | + if (!$user) { |
|
153 | + return $forward('actionloggedout', ELGG_HTTP_FORBIDDEN); |
|
154 | + } |
|
155 | + break; |
|
156 | + default: |
|
157 | + // admin or misspelling |
|
158 | + if (!$user || !$user->isAdmin()) { |
|
159 | + return $forward('actionunauthorized', ELGG_HTTP_FORBIDDEN); |
|
160 | + } |
|
161 | + } |
|
162 | + |
|
163 | + ob_start(); |
|
164 | 164 | |
165 | - // To quietly cancel the file, return a falsey value in the "action" hook. |
|
166 | - if (!_elgg_services()->hooks->trigger('action', $action, null, true)) { |
|
167 | - return $forward('', ELGG_HTTP_OK); |
|
168 | - } |
|
169 | - |
|
170 | - $file = $this->actions[$action]['file']; |
|
171 | - |
|
172 | - if (!is_file($file) || !is_readable($file)) { |
|
173 | - return $forward('actionnotfound', ELGG_HTTP_NOT_IMPLEMENTED); |
|
174 | - } |
|
175 | - |
|
176 | - // set the maximum execution time for actions |
|
177 | - $action_timeout = $this->config->get('action_time_limit'); |
|
178 | - if (isset($action_timeout)) { |
|
179 | - set_time_limit($action_timeout); |
|
180 | - } |
|
181 | - |
|
182 | - $result = Includer::includeFile($file); |
|
183 | - if ($result instanceof ResponseBuilder) { |
|
184 | - ob_end_clean(); |
|
185 | - return $result; |
|
186 | - } |
|
187 | - |
|
188 | - return $forward('', ELGG_HTTP_OK); |
|
189 | - } |
|
165 | + // To quietly cancel the file, return a falsey value in the "action" hook. |
|
166 | + if (!_elgg_services()->hooks->trigger('action', $action, null, true)) { |
|
167 | + return $forward('', ELGG_HTTP_OK); |
|
168 | + } |
|
169 | + |
|
170 | + $file = $this->actions[$action]['file']; |
|
171 | + |
|
172 | + if (!is_file($file) || !is_readable($file)) { |
|
173 | + return $forward('actionnotfound', ELGG_HTTP_NOT_IMPLEMENTED); |
|
174 | + } |
|
175 | + |
|
176 | + // set the maximum execution time for actions |
|
177 | + $action_timeout = $this->config->get('action_time_limit'); |
|
178 | + if (isset($action_timeout)) { |
|
179 | + set_time_limit($action_timeout); |
|
180 | + } |
|
181 | + |
|
182 | + $result = Includer::includeFile($file); |
|
183 | + if ($result instanceof ResponseBuilder) { |
|
184 | + ob_end_clean(); |
|
185 | + return $result; |
|
186 | + } |
|
187 | + |
|
188 | + return $forward('', ELGG_HTTP_OK); |
|
189 | + } |
|
190 | 190 | |
191 | - /** |
|
192 | - * @see elgg_register_action |
|
193 | - * @access private |
|
194 | - */ |
|
195 | - public function register($action, $filename = "", $access = 'logged_in') { |
|
196 | - // plugins are encouraged to call actions with a trailing / to prevent 301 |
|
197 | - // redirects but we store the actions without it |
|
198 | - $action = rtrim($action, '/'); |
|
191 | + /** |
|
192 | + * @see elgg_register_action |
|
193 | + * @access private |
|
194 | + */ |
|
195 | + public function register($action, $filename = "", $access = 'logged_in') { |
|
196 | + // plugins are encouraged to call actions with a trailing / to prevent 301 |
|
197 | + // redirects but we store the actions without it |
|
198 | + $action = rtrim($action, '/'); |
|
199 | 199 | |
200 | - if (empty($filename)) { |
|
201 | - $path = __DIR__ . '/../../../actions'; |
|
202 | - $filename = realpath("$path/$action.php"); |
|
203 | - } |
|
204 | - |
|
205 | - if (!in_array($access, self::$access_levels)) { |
|
206 | - _elgg_services()->logger->error("Unrecognized value '$access' for \$access in " . __METHOD__); |
|
207 | - $access = 'admin'; |
|
208 | - } |
|
200 | + if (empty($filename)) { |
|
201 | + $path = __DIR__ . '/../../../actions'; |
|
202 | + $filename = realpath("$path/$action.php"); |
|
203 | + } |
|
204 | + |
|
205 | + if (!in_array($access, self::$access_levels)) { |
|
206 | + _elgg_services()->logger->error("Unrecognized value '$access' for \$access in " . __METHOD__); |
|
207 | + $access = 'admin'; |
|
208 | + } |
|
209 | 209 | |
210 | - $this->actions[$action] = [ |
|
211 | - 'file' => $filename, |
|
212 | - 'access' => $access, |
|
213 | - ]; |
|
214 | - return true; |
|
215 | - } |
|
210 | + $this->actions[$action] = [ |
|
211 | + 'file' => $filename, |
|
212 | + 'access' => $access, |
|
213 | + ]; |
|
214 | + return true; |
|
215 | + } |
|
216 | 216 | |
217 | - /** |
|
218 | - * @see elgg_unregister_action |
|
219 | - * @access private |
|
220 | - */ |
|
221 | - public function unregister($action) { |
|
222 | - if (isset($this->actions[$action])) { |
|
223 | - unset($this->actions[$action]); |
|
224 | - return true; |
|
225 | - } else { |
|
226 | - return false; |
|
227 | - } |
|
228 | - } |
|
229 | - |
|
230 | - /** |
|
231 | - * @see validate_action_token |
|
232 | - * @access private |
|
233 | - */ |
|
234 | - public function validateActionToken($visible_errors = true, $token = null, $ts = null) { |
|
235 | - if (!$token) { |
|
236 | - $token = get_input('__elgg_token'); |
|
237 | - } |
|
217 | + /** |
|
218 | + * @see elgg_unregister_action |
|
219 | + * @access private |
|
220 | + */ |
|
221 | + public function unregister($action) { |
|
222 | + if (isset($this->actions[$action])) { |
|
223 | + unset($this->actions[$action]); |
|
224 | + return true; |
|
225 | + } else { |
|
226 | + return false; |
|
227 | + } |
|
228 | + } |
|
229 | + |
|
230 | + /** |
|
231 | + * @see validate_action_token |
|
232 | + * @access private |
|
233 | + */ |
|
234 | + public function validateActionToken($visible_errors = true, $token = null, $ts = null) { |
|
235 | + if (!$token) { |
|
236 | + $token = get_input('__elgg_token'); |
|
237 | + } |
|
238 | 238 | |
239 | - if (!$ts) { |
|
240 | - $ts = get_input('__elgg_ts'); |
|
241 | - } |
|
242 | - |
|
243 | - $session_id = $this->session->getId(); |
|
244 | - |
|
245 | - if (($token) && ($ts) && ($session_id)) { |
|
246 | - if ($this->validateTokenOwnership($token, $ts)) { |
|
247 | - if ($this->validateTokenTimestamp($ts)) { |
|
248 | - // We have already got this far, so unless anything |
|
249 | - // else says something to the contrary we assume we're ok |
|
250 | - $returnval = _elgg_services()->hooks->trigger('action_gatekeeper:permissions:check', 'all', [ |
|
251 | - 'token' => $token, |
|
252 | - 'time' => $ts |
|
253 | - ], true); |
|
254 | - |
|
255 | - if ($returnval) { |
|
256 | - return true; |
|
257 | - } else if ($visible_errors) { |
|
258 | - register_error(_elgg_services()->translator->translate('actiongatekeeper:pluginprevents')); |
|
259 | - } |
|
260 | - } else if ($visible_errors) { |
|
261 | - // this is necessary because of #5133 |
|
262 | - if (elgg_is_xhr()) { |
|
263 | - register_error(_elgg_services()->translator->translate( |
|
264 | - 'js:security:token_refresh_failed', |
|
265 | - [$this->config->getSiteUrl()] |
|
266 | - )); |
|
267 | - } else { |
|
268 | - register_error(_elgg_services()->translator->translate('actiongatekeeper:timeerror')); |
|
269 | - } |
|
270 | - } |
|
271 | - } else if ($visible_errors) { |
|
272 | - // this is necessary because of #5133 |
|
273 | - if (elgg_is_xhr()) { |
|
274 | - register_error(_elgg_services()->translator->translate('js:security:token_refresh_failed', [$this->config->getSiteUrl()])); |
|
275 | - } else { |
|
276 | - register_error(_elgg_services()->translator->translate('actiongatekeeper:tokeninvalid')); |
|
277 | - } |
|
278 | - } |
|
279 | - } else { |
|
280 | - $req = _elgg_services()->request; |
|
281 | - $length = $req->server->get('CONTENT_LENGTH'); |
|
282 | - $post_count = count($req->request); |
|
283 | - if ($length && $post_count < 1) { |
|
284 | - // The size of $_POST or uploaded file has exceed the size limit |
|
285 | - $error_msg = _elgg_services()->hooks->trigger('action_gatekeeper:upload_exceeded_msg', 'all', [ |
|
286 | - 'post_size' => $length, |
|
287 | - 'visible_errors' => $visible_errors, |
|
288 | - ], _elgg_services()->translator->translate('actiongatekeeper:uploadexceeded')); |
|
289 | - } else { |
|
290 | - $error_msg = _elgg_services()->translator->translate('actiongatekeeper:missingfields'); |
|
291 | - } |
|
292 | - if ($visible_errors) { |
|
293 | - register_error($error_msg); |
|
294 | - } |
|
295 | - } |
|
296 | - |
|
297 | - return false; |
|
298 | - } |
|
299 | - |
|
300 | - /** |
|
301 | - * Is the token timestamp within acceptable range? |
|
302 | - * |
|
303 | - * @param int $ts timestamp from the CSRF token |
|
304 | - * |
|
305 | - * @return bool |
|
306 | - */ |
|
307 | - protected function validateTokenTimestamp($ts) { |
|
308 | - $timeout = $this->getActionTokenTimeout(); |
|
309 | - $now = $this->getCurrentTime()->getTimestamp(); |
|
310 | - return ($timeout == 0 || ($ts > $now - $timeout) && ($ts < $now + $timeout)); |
|
311 | - } |
|
312 | - |
|
313 | - /** |
|
314 | - * @see ActionsService::validateActionToken |
|
315 | - * @access private |
|
316 | - * @since 1.9.0 |
|
317 | - * @return int number of seconds that action token is valid |
|
318 | - */ |
|
319 | - public function getActionTokenTimeout() { |
|
320 | - if (($timeout = $this->config->get('action_token_timeout')) === null) { |
|
321 | - // default to 2 hours |
|
322 | - $timeout = 2; |
|
323 | - } |
|
324 | - $hour = 60 * 60; |
|
325 | - return (int) ((float) $timeout * $hour); |
|
326 | - } |
|
327 | - |
|
328 | - /** |
|
329 | - * @return bool |
|
330 | - * @see action_gatekeeper |
|
331 | - * @access private |
|
332 | - */ |
|
333 | - public function gatekeeper($action) { |
|
334 | - if ($action === 'login') { |
|
335 | - if ($this->validateActionToken(false)) { |
|
336 | - return true; |
|
337 | - } |
|
338 | - |
|
339 | - $token = get_input('__elgg_token'); |
|
340 | - $ts = (int) get_input('__elgg_ts'); |
|
341 | - if ($token && $this->validateTokenTimestamp($ts)) { |
|
342 | - // The tokens are present and the time looks valid: this is probably a mismatch due to the |
|
343 | - // login form being on a different domain. |
|
344 | - register_error(_elgg_services()->translator->translate('actiongatekeeper:crosssitelogin')); |
|
345 | - _elgg_services()->responseFactory->redirect('login', 'csrf'); |
|
346 | - return false; |
|
347 | - } |
|
348 | - } |
|
239 | + if (!$ts) { |
|
240 | + $ts = get_input('__elgg_ts'); |
|
241 | + } |
|
242 | + |
|
243 | + $session_id = $this->session->getId(); |
|
244 | + |
|
245 | + if (($token) && ($ts) && ($session_id)) { |
|
246 | + if ($this->validateTokenOwnership($token, $ts)) { |
|
247 | + if ($this->validateTokenTimestamp($ts)) { |
|
248 | + // We have already got this far, so unless anything |
|
249 | + // else says something to the contrary we assume we're ok |
|
250 | + $returnval = _elgg_services()->hooks->trigger('action_gatekeeper:permissions:check', 'all', [ |
|
251 | + 'token' => $token, |
|
252 | + 'time' => $ts |
|
253 | + ], true); |
|
254 | + |
|
255 | + if ($returnval) { |
|
256 | + return true; |
|
257 | + } else if ($visible_errors) { |
|
258 | + register_error(_elgg_services()->translator->translate('actiongatekeeper:pluginprevents')); |
|
259 | + } |
|
260 | + } else if ($visible_errors) { |
|
261 | + // this is necessary because of #5133 |
|
262 | + if (elgg_is_xhr()) { |
|
263 | + register_error(_elgg_services()->translator->translate( |
|
264 | + 'js:security:token_refresh_failed', |
|
265 | + [$this->config->getSiteUrl()] |
|
266 | + )); |
|
267 | + } else { |
|
268 | + register_error(_elgg_services()->translator->translate('actiongatekeeper:timeerror')); |
|
269 | + } |
|
270 | + } |
|
271 | + } else if ($visible_errors) { |
|
272 | + // this is necessary because of #5133 |
|
273 | + if (elgg_is_xhr()) { |
|
274 | + register_error(_elgg_services()->translator->translate('js:security:token_refresh_failed', [$this->config->getSiteUrl()])); |
|
275 | + } else { |
|
276 | + register_error(_elgg_services()->translator->translate('actiongatekeeper:tokeninvalid')); |
|
277 | + } |
|
278 | + } |
|
279 | + } else { |
|
280 | + $req = _elgg_services()->request; |
|
281 | + $length = $req->server->get('CONTENT_LENGTH'); |
|
282 | + $post_count = count($req->request); |
|
283 | + if ($length && $post_count < 1) { |
|
284 | + // The size of $_POST or uploaded file has exceed the size limit |
|
285 | + $error_msg = _elgg_services()->hooks->trigger('action_gatekeeper:upload_exceeded_msg', 'all', [ |
|
286 | + 'post_size' => $length, |
|
287 | + 'visible_errors' => $visible_errors, |
|
288 | + ], _elgg_services()->translator->translate('actiongatekeeper:uploadexceeded')); |
|
289 | + } else { |
|
290 | + $error_msg = _elgg_services()->translator->translate('actiongatekeeper:missingfields'); |
|
291 | + } |
|
292 | + if ($visible_errors) { |
|
293 | + register_error($error_msg); |
|
294 | + } |
|
295 | + } |
|
296 | + |
|
297 | + return false; |
|
298 | + } |
|
299 | + |
|
300 | + /** |
|
301 | + * Is the token timestamp within acceptable range? |
|
302 | + * |
|
303 | + * @param int $ts timestamp from the CSRF token |
|
304 | + * |
|
305 | + * @return bool |
|
306 | + */ |
|
307 | + protected function validateTokenTimestamp($ts) { |
|
308 | + $timeout = $this->getActionTokenTimeout(); |
|
309 | + $now = $this->getCurrentTime()->getTimestamp(); |
|
310 | + return ($timeout == 0 || ($ts > $now - $timeout) && ($ts < $now + $timeout)); |
|
311 | + } |
|
312 | + |
|
313 | + /** |
|
314 | + * @see ActionsService::validateActionToken |
|
315 | + * @access private |
|
316 | + * @since 1.9.0 |
|
317 | + * @return int number of seconds that action token is valid |
|
318 | + */ |
|
319 | + public function getActionTokenTimeout() { |
|
320 | + if (($timeout = $this->config->get('action_token_timeout')) === null) { |
|
321 | + // default to 2 hours |
|
322 | + $timeout = 2; |
|
323 | + } |
|
324 | + $hour = 60 * 60; |
|
325 | + return (int) ((float) $timeout * $hour); |
|
326 | + } |
|
327 | + |
|
328 | + /** |
|
329 | + * @return bool |
|
330 | + * @see action_gatekeeper |
|
331 | + * @access private |
|
332 | + */ |
|
333 | + public function gatekeeper($action) { |
|
334 | + if ($action === 'login') { |
|
335 | + if ($this->validateActionToken(false)) { |
|
336 | + return true; |
|
337 | + } |
|
338 | + |
|
339 | + $token = get_input('__elgg_token'); |
|
340 | + $ts = (int) get_input('__elgg_ts'); |
|
341 | + if ($token && $this->validateTokenTimestamp($ts)) { |
|
342 | + // The tokens are present and the time looks valid: this is probably a mismatch due to the |
|
343 | + // login form being on a different domain. |
|
344 | + register_error(_elgg_services()->translator->translate('actiongatekeeper:crosssitelogin')); |
|
345 | + _elgg_services()->responseFactory->redirect('login', 'csrf'); |
|
346 | + return false; |
|
347 | + } |
|
348 | + } |
|
349 | 349 | |
350 | - if ($this->validateActionToken()) { |
|
351 | - return true; |
|
352 | - } |
|
350 | + if ($this->validateActionToken()) { |
|
351 | + return true; |
|
352 | + } |
|
353 | 353 | |
354 | - _elgg_services()->responseFactory->redirect(REFERER, 'csrf'); |
|
355 | - return false; |
|
356 | - } |
|
357 | - |
|
358 | - /** |
|
359 | - * Was the given token generated for the session defined by session_token? |
|
360 | - * |
|
361 | - * @param string $token CSRF token |
|
362 | - * @param int $timestamp Unix time |
|
363 | - * @param string $session_token Session-specific token |
|
364 | - * |
|
365 | - * @return bool |
|
366 | - * @access private |
|
367 | - */ |
|
368 | - public function validateTokenOwnership($token, $timestamp, $session_token = '') { |
|
369 | - $required_token = $this->generateActionToken($timestamp, $session_token); |
|
370 | - |
|
371 | - return _elgg_services()->crypto->areEqual($token, $required_token); |
|
372 | - } |
|
354 | + _elgg_services()->responseFactory->redirect(REFERER, 'csrf'); |
|
355 | + return false; |
|
356 | + } |
|
357 | + |
|
358 | + /** |
|
359 | + * Was the given token generated for the session defined by session_token? |
|
360 | + * |
|
361 | + * @param string $token CSRF token |
|
362 | + * @param int $timestamp Unix time |
|
363 | + * @param string $session_token Session-specific token |
|
364 | + * |
|
365 | + * @return bool |
|
366 | + * @access private |
|
367 | + */ |
|
368 | + public function validateTokenOwnership($token, $timestamp, $session_token = '') { |
|
369 | + $required_token = $this->generateActionToken($timestamp, $session_token); |
|
370 | + |
|
371 | + return _elgg_services()->crypto->areEqual($token, $required_token); |
|
372 | + } |
|
373 | 373 | |
374 | - /** |
|
375 | - * Generate a token from a session token (specifying the user), the timestamp, and the site key. |
|
376 | - * |
|
377 | - * @see generate_action_token |
|
378 | - * |
|
379 | - * @param int $timestamp Unix timestamp |
|
380 | - * @param string $session_token Session-specific token |
|
381 | - * |
|
382 | - * @return string |
|
383 | - * @access private |
|
384 | - */ |
|
385 | - public function generateActionToken($timestamp, $session_token = '') { |
|
386 | - if (!$session_token) { |
|
387 | - $session_token = elgg_get_session()->get('__elgg_session'); |
|
388 | - if (!$session_token) { |
|
389 | - return false; |
|
390 | - } |
|
391 | - } |
|
392 | - |
|
393 | - return _elgg_services()->hmac->getHmac([(int) $timestamp, $session_token], 'md5') |
|
394 | - ->getToken(); |
|
395 | - } |
|
374 | + /** |
|
375 | + * Generate a token from a session token (specifying the user), the timestamp, and the site key. |
|
376 | + * |
|
377 | + * @see generate_action_token |
|
378 | + * |
|
379 | + * @param int $timestamp Unix timestamp |
|
380 | + * @param string $session_token Session-specific token |
|
381 | + * |
|
382 | + * @return string |
|
383 | + * @access private |
|
384 | + */ |
|
385 | + public function generateActionToken($timestamp, $session_token = '') { |
|
386 | + if (!$session_token) { |
|
387 | + $session_token = elgg_get_session()->get('__elgg_session'); |
|
388 | + if (!$session_token) { |
|
389 | + return false; |
|
390 | + } |
|
391 | + } |
|
392 | + |
|
393 | + return _elgg_services()->hmac->getHmac([(int) $timestamp, $session_token], 'md5') |
|
394 | + ->getToken(); |
|
395 | + } |
|
396 | 396 | |
397 | - /** |
|
398 | - * @see elgg_action_exists |
|
399 | - * @access private |
|
400 | - */ |
|
401 | - public function exists($action) { |
|
402 | - return (isset($this->actions[$action]) && file_exists($this->actions[$action]['file'])); |
|
403 | - } |
|
397 | + /** |
|
398 | + * @see elgg_action_exists |
|
399 | + * @access private |
|
400 | + */ |
|
401 | + public function exists($action) { |
|
402 | + return (isset($this->actions[$action]) && file_exists($this->actions[$action]['file'])); |
|
403 | + } |
|
404 | 404 | |
405 | - /** |
|
406 | - * @see ajax_forward_hook |
|
407 | - * @access private |
|
408 | - * @deprecated 2.3 |
|
409 | - */ |
|
410 | - public function ajaxForwardHook($hook, $reason, $forward_url, $params) { |
|
411 | - if (!elgg_is_xhr()) { |
|
412 | - return; |
|
413 | - } |
|
414 | - |
|
415 | - // grab any data echo'd in the action |
|
416 | - $output = ob_get_clean(); |
|
417 | - |
|
418 | - if ($reason == 'walled_garden' || $reason == 'csrf') { |
|
419 | - $reason = '403'; |
|
420 | - } |
|
421 | - |
|
422 | - $status_code = (int) $reason; |
|
423 | - if ($status_code < 100 || ($status_code > 299 && $status_code < 400) || $status_code > 599) { |
|
424 | - // We only want to preserve OK and error codes |
|
425 | - // Redirect responses should be converted to OK responses as this is an XHR request |
|
426 | - $status_code = ELGG_HTTP_OK; |
|
427 | - } |
|
428 | - |
|
429 | - $response = elgg_ok_response($output, '', $forward_url, $status_code); |
|
430 | - |
|
431 | - $headers = $response->getHeaders(); |
|
432 | - $headers['Content-Type'] = 'application/json; charset=UTF-8'; |
|
433 | - $response->setHeaders($headers); |
|
434 | - |
|
435 | - _elgg_services()->responseFactory->respond($response); |
|
436 | - exit; |
|
437 | - } |
|
405 | + /** |
|
406 | + * @see ajax_forward_hook |
|
407 | + * @access private |
|
408 | + * @deprecated 2.3 |
|
409 | + */ |
|
410 | + public function ajaxForwardHook($hook, $reason, $forward_url, $params) { |
|
411 | + if (!elgg_is_xhr()) { |
|
412 | + return; |
|
413 | + } |
|
414 | + |
|
415 | + // grab any data echo'd in the action |
|
416 | + $output = ob_get_clean(); |
|
417 | + |
|
418 | + if ($reason == 'walled_garden' || $reason == 'csrf') { |
|
419 | + $reason = '403'; |
|
420 | + } |
|
421 | + |
|
422 | + $status_code = (int) $reason; |
|
423 | + if ($status_code < 100 || ($status_code > 299 && $status_code < 400) || $status_code > 599) { |
|
424 | + // We only want to preserve OK and error codes |
|
425 | + // Redirect responses should be converted to OK responses as this is an XHR request |
|
426 | + $status_code = ELGG_HTTP_OK; |
|
427 | + } |
|
428 | + |
|
429 | + $response = elgg_ok_response($output, '', $forward_url, $status_code); |
|
430 | + |
|
431 | + $headers = $response->getHeaders(); |
|
432 | + $headers['Content-Type'] = 'application/json; charset=UTF-8'; |
|
433 | + $response->setHeaders($headers); |
|
434 | + |
|
435 | + _elgg_services()->responseFactory->respond($response); |
|
436 | + exit; |
|
437 | + } |
|
438 | 438 | |
439 | - /** |
|
440 | - * @see ajax_action_hook |
|
441 | - * @access private |
|
442 | - * @deprecated 2.3 |
|
443 | - */ |
|
444 | - public function ajaxActionHook() { |
|
445 | - if (elgg_is_xhr()) { |
|
446 | - ob_start(); |
|
447 | - } |
|
448 | - } |
|
449 | - |
|
450 | - /** |
|
451 | - * Get all actions |
|
452 | - * |
|
453 | - * @return array |
|
454 | - */ |
|
455 | - public function getAllActions() { |
|
456 | - return $this->actions; |
|
457 | - } |
|
458 | - |
|
459 | - /** |
|
460 | - * Send an updated CSRF token, provided the page's current tokens were not fake. |
|
461 | - * |
|
462 | - * @return ResponseBuilder |
|
463 | - * @access private |
|
464 | - */ |
|
465 | - public function handleTokenRefreshRequest() { |
|
466 | - if (!elgg_is_xhr()) { |
|
467 | - return false; |
|
468 | - } |
|
469 | - |
|
470 | - // the page's session_token might have expired (not matching __elgg_session in the session), but |
|
471 | - // we still allow it to be given to validate the tokens in the page. |
|
472 | - $session_token = get_input('session_token', null, false); |
|
473 | - $pairs = (array) get_input('pairs', [], false); |
|
474 | - $valid_tokens = (object) []; |
|
475 | - foreach ($pairs as $pair) { |
|
476 | - list($ts, $token) = explode(',', $pair, 2); |
|
477 | - if ($this->validateTokenOwnership($token, $ts, $session_token)) { |
|
478 | - $valid_tokens->{$token} = true; |
|
479 | - } |
|
480 | - } |
|
481 | - |
|
482 | - $ts = $this->getCurrentTime()->getTimestamp(); |
|
483 | - $token = $this->generateActionToken($ts); |
|
484 | - $data = [ |
|
485 | - 'token' => [ |
|
486 | - '__elgg_ts' => $ts, |
|
487 | - '__elgg_token' => $token, |
|
488 | - 'logged_in' => $this->session->isLoggedIn(), |
|
489 | - ], |
|
490 | - 'valid_tokens' => $valid_tokens, |
|
491 | - 'session_token' => $this->session->get('__elgg_session'), |
|
492 | - 'user_guid' => $this->session->getLoggedInUserGuid(), |
|
493 | - ]; |
|
494 | - |
|
495 | - elgg_set_http_header("Content-Type: application/json;charset=utf-8"); |
|
496 | - return elgg_ok_response($data); |
|
497 | - } |
|
439 | + /** |
|
440 | + * @see ajax_action_hook |
|
441 | + * @access private |
|
442 | + * @deprecated 2.3 |
|
443 | + */ |
|
444 | + public function ajaxActionHook() { |
|
445 | + if (elgg_is_xhr()) { |
|
446 | + ob_start(); |
|
447 | + } |
|
448 | + } |
|
449 | + |
|
450 | + /** |
|
451 | + * Get all actions |
|
452 | + * |
|
453 | + * @return array |
|
454 | + */ |
|
455 | + public function getAllActions() { |
|
456 | + return $this->actions; |
|
457 | + } |
|
458 | + |
|
459 | + /** |
|
460 | + * Send an updated CSRF token, provided the page's current tokens were not fake. |
|
461 | + * |
|
462 | + * @return ResponseBuilder |
|
463 | + * @access private |
|
464 | + */ |
|
465 | + public function handleTokenRefreshRequest() { |
|
466 | + if (!elgg_is_xhr()) { |
|
467 | + return false; |
|
468 | + } |
|
469 | + |
|
470 | + // the page's session_token might have expired (not matching __elgg_session in the session), but |
|
471 | + // we still allow it to be given to validate the tokens in the page. |
|
472 | + $session_token = get_input('session_token', null, false); |
|
473 | + $pairs = (array) get_input('pairs', [], false); |
|
474 | + $valid_tokens = (object) []; |
|
475 | + foreach ($pairs as $pair) { |
|
476 | + list($ts, $token) = explode(',', $pair, 2); |
|
477 | + if ($this->validateTokenOwnership($token, $ts, $session_token)) { |
|
478 | + $valid_tokens->{$token} = true; |
|
479 | + } |
|
480 | + } |
|
481 | + |
|
482 | + $ts = $this->getCurrentTime()->getTimestamp(); |
|
483 | + $token = $this->generateActionToken($ts); |
|
484 | + $data = [ |
|
485 | + 'token' => [ |
|
486 | + '__elgg_ts' => $ts, |
|
487 | + '__elgg_token' => $token, |
|
488 | + 'logged_in' => $this->session->isLoggedIn(), |
|
489 | + ], |
|
490 | + 'valid_tokens' => $valid_tokens, |
|
491 | + 'session_token' => $this->session->get('__elgg_session'), |
|
492 | + 'user_guid' => $this->session->getLoggedInUserGuid(), |
|
493 | + ]; |
|
494 | + |
|
495 | + elgg_set_http_header("Content-Type: application/json;charset=utf-8"); |
|
496 | + return elgg_ok_response($data); |
|
497 | + } |
|
498 | 498 | } |
499 | 499 |
@@ -21,518 +21,518 @@ discard block |
||
21 | 21 | */ |
22 | 22 | class UsersTable { |
23 | 23 | |
24 | - use \Elgg\TimeUsing; |
|
25 | - |
|
26 | - /** |
|
27 | - * @var Conf |
|
28 | - */ |
|
29 | - protected $config; |
|
30 | - |
|
31 | - /** |
|
32 | - * @var Database |
|
33 | - */ |
|
34 | - protected $db; |
|
35 | - |
|
36 | - /** |
|
37 | - * @var EntityTable |
|
38 | - */ |
|
39 | - protected $entities; |
|
40 | - |
|
41 | - /** |
|
42 | - * @var EntityCache |
|
43 | - */ |
|
44 | - protected $entity_cache; |
|
45 | - |
|
46 | - /** |
|
47 | - * @var EventsService |
|
48 | - */ |
|
49 | - protected $events; |
|
50 | - |
|
51 | - /** |
|
52 | - * @var string |
|
53 | - */ |
|
54 | - protected $table; |
|
55 | - |
|
56 | - /** |
|
57 | - * Constructor |
|
58 | - * |
|
59 | - * @param Conf $config Config |
|
60 | - * @param Database $db Database |
|
61 | - * @param EntityTable $entities Entity table |
|
62 | - * @param EntityCache $cache Entity cache |
|
63 | - * @param EventsService $events Event service |
|
64 | - */ |
|
65 | - public function __construct( |
|
66 | - Conf $config, Database $db, EntityTable $entities, EntityCache $cache, EventsService $events |
|
67 | - ) { |
|
68 | - $this->config = $config; |
|
69 | - $this->db = $db; |
|
70 | - $this->table = $this->db->prefix . "users_entity"; |
|
71 | - $this->entities = $entities; |
|
72 | - $this->entity_cache = $cache; |
|
73 | - $this->events = $events; |
|
74 | - } |
|
75 | - |
|
76 | - /** |
|
77 | - * Return the user specific details of a user by a row. |
|
78 | - * |
|
79 | - * @param int $guid The \ElggUser guid |
|
80 | - * |
|
81 | - * @return mixed |
|
82 | - * @access private |
|
83 | - */ |
|
84 | - public function getRow($guid) { |
|
85 | - $sql = " |
|
24 | + use \Elgg\TimeUsing; |
|
25 | + |
|
26 | + /** |
|
27 | + * @var Conf |
|
28 | + */ |
|
29 | + protected $config; |
|
30 | + |
|
31 | + /** |
|
32 | + * @var Database |
|
33 | + */ |
|
34 | + protected $db; |
|
35 | + |
|
36 | + /** |
|
37 | + * @var EntityTable |
|
38 | + */ |
|
39 | + protected $entities; |
|
40 | + |
|
41 | + /** |
|
42 | + * @var EntityCache |
|
43 | + */ |
|
44 | + protected $entity_cache; |
|
45 | + |
|
46 | + /** |
|
47 | + * @var EventsService |
|
48 | + */ |
|
49 | + protected $events; |
|
50 | + |
|
51 | + /** |
|
52 | + * @var string |
|
53 | + */ |
|
54 | + protected $table; |
|
55 | + |
|
56 | + /** |
|
57 | + * Constructor |
|
58 | + * |
|
59 | + * @param Conf $config Config |
|
60 | + * @param Database $db Database |
|
61 | + * @param EntityTable $entities Entity table |
|
62 | + * @param EntityCache $cache Entity cache |
|
63 | + * @param EventsService $events Event service |
|
64 | + */ |
|
65 | + public function __construct( |
|
66 | + Conf $config, Database $db, EntityTable $entities, EntityCache $cache, EventsService $events |
|
67 | + ) { |
|
68 | + $this->config = $config; |
|
69 | + $this->db = $db; |
|
70 | + $this->table = $this->db->prefix . "users_entity"; |
|
71 | + $this->entities = $entities; |
|
72 | + $this->entity_cache = $cache; |
|
73 | + $this->events = $events; |
|
74 | + } |
|
75 | + |
|
76 | + /** |
|
77 | + * Return the user specific details of a user by a row. |
|
78 | + * |
|
79 | + * @param int $guid The \ElggUser guid |
|
80 | + * |
|
81 | + * @return mixed |
|
82 | + * @access private |
|
83 | + */ |
|
84 | + public function getRow($guid) { |
|
85 | + $sql = " |
|
86 | 86 | SELECT * FROM {$this->table} |
87 | 87 | WHERE guid = :guid |
88 | 88 | "; |
89 | - $params = [ |
|
90 | - ':guid' => $guid, |
|
91 | - ]; |
|
92 | - return $this->db->getDataRow($sql, null, $params); |
|
93 | - } |
|
94 | - |
|
95 | - /** |
|
96 | - * Disables all of a user's entities |
|
97 | - * |
|
98 | - * @param int $owner_guid The owner GUID |
|
99 | - * @return bool Depending on success |
|
100 | - * @deprecated 2.3 |
|
101 | - */ |
|
102 | - public function disableEntities($owner_guid) { |
|
103 | - return $this->entities->disableEntities($owner_guid); |
|
104 | - } |
|
105 | - |
|
106 | - /** |
|
107 | - * Ban a user (calls events, stores the reason) |
|
108 | - * |
|
109 | - * @param int $user_guid The user guid |
|
110 | - * @param string $reason A reason |
|
111 | - * @return bool |
|
112 | - */ |
|
113 | - public function ban($user_guid, $reason = "") { |
|
114 | - |
|
115 | - $user = get_entity($user_guid); |
|
116 | - |
|
117 | - if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
118 | - return false; |
|
119 | - } |
|
120 | - |
|
121 | - if (!$this->events->trigger('ban', 'user', $user)) { |
|
122 | - return false; |
|
123 | - } |
|
124 | - |
|
125 | - $user->ban_reason = $reason; |
|
126 | - |
|
127 | - _elgg_invalidate_cache_for_entity($user_guid); |
|
128 | - _elgg_invalidate_memcache_for_entity($user_guid); |
|
129 | - |
|
130 | - if ($this->markBanned($user_guid, true)) { |
|
131 | - return true; |
|
132 | - } |
|
133 | - |
|
134 | - return false; |
|
135 | - } |
|
136 | - |
|
137 | - /** |
|
138 | - * Mark a user entity banned or unbanned. |
|
139 | - * |
|
140 | - * @note Use ban() or unban() |
|
141 | - * |
|
142 | - * @param int $guid User GUID |
|
143 | - * @param bool $banned Mark the user banned? |
|
144 | - * @return int Num rows affected |
|
145 | - */ |
|
146 | - public function markBanned($guid, $banned) { |
|
147 | - |
|
148 | - $query = " |
|
89 | + $params = [ |
|
90 | + ':guid' => $guid, |
|
91 | + ]; |
|
92 | + return $this->db->getDataRow($sql, null, $params); |
|
93 | + } |
|
94 | + |
|
95 | + /** |
|
96 | + * Disables all of a user's entities |
|
97 | + * |
|
98 | + * @param int $owner_guid The owner GUID |
|
99 | + * @return bool Depending on success |
|
100 | + * @deprecated 2.3 |
|
101 | + */ |
|
102 | + public function disableEntities($owner_guid) { |
|
103 | + return $this->entities->disableEntities($owner_guid); |
|
104 | + } |
|
105 | + |
|
106 | + /** |
|
107 | + * Ban a user (calls events, stores the reason) |
|
108 | + * |
|
109 | + * @param int $user_guid The user guid |
|
110 | + * @param string $reason A reason |
|
111 | + * @return bool |
|
112 | + */ |
|
113 | + public function ban($user_guid, $reason = "") { |
|
114 | + |
|
115 | + $user = get_entity($user_guid); |
|
116 | + |
|
117 | + if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
118 | + return false; |
|
119 | + } |
|
120 | + |
|
121 | + if (!$this->events->trigger('ban', 'user', $user)) { |
|
122 | + return false; |
|
123 | + } |
|
124 | + |
|
125 | + $user->ban_reason = $reason; |
|
126 | + |
|
127 | + _elgg_invalidate_cache_for_entity($user_guid); |
|
128 | + _elgg_invalidate_memcache_for_entity($user_guid); |
|
129 | + |
|
130 | + if ($this->markBanned($user_guid, true)) { |
|
131 | + return true; |
|
132 | + } |
|
133 | + |
|
134 | + return false; |
|
135 | + } |
|
136 | + |
|
137 | + /** |
|
138 | + * Mark a user entity banned or unbanned. |
|
139 | + * |
|
140 | + * @note Use ban() or unban() |
|
141 | + * |
|
142 | + * @param int $guid User GUID |
|
143 | + * @param bool $banned Mark the user banned? |
|
144 | + * @return int Num rows affected |
|
145 | + */ |
|
146 | + public function markBanned($guid, $banned) { |
|
147 | + |
|
148 | + $query = " |
|
149 | 149 | UPDATE {$this->table} |
150 | 150 | SET banned = :banned |
151 | 151 | WHERE guid = :guid |
152 | 152 | "; |
153 | 153 | |
154 | - $params = [ |
|
155 | - ':banned' => $banned ? 'yes' : 'no', |
|
156 | - ':guid' => (int) $guid, |
|
157 | - ]; |
|
154 | + $params = [ |
|
155 | + ':banned' => $banned ? 'yes' : 'no', |
|
156 | + ':guid' => (int) $guid, |
|
157 | + ]; |
|
158 | 158 | |
159 | - return $this->db->updateData($query, true, $params); |
|
160 | - } |
|
159 | + return $this->db->updateData($query, true, $params); |
|
160 | + } |
|
161 | 161 | |
162 | - /** |
|
163 | - * Unban a user (calls events, removes the reason) |
|
164 | - * |
|
165 | - * @param int $user_guid Unban a user |
|
166 | - * @return bool |
|
167 | - */ |
|
168 | - public function unban($user_guid) { |
|
162 | + /** |
|
163 | + * Unban a user (calls events, removes the reason) |
|
164 | + * |
|
165 | + * @param int $user_guid Unban a user |
|
166 | + * @return bool |
|
167 | + */ |
|
168 | + public function unban($user_guid) { |
|
169 | 169 | |
170 | - $user = get_entity($user_guid); |
|
170 | + $user = get_entity($user_guid); |
|
171 | 171 | |
172 | - if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
173 | - return false; |
|
174 | - } |
|
172 | + if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
173 | + return false; |
|
174 | + } |
|
175 | 175 | |
176 | - if (!$this->events->trigger('unban', 'user', $user)) { |
|
177 | - return false; |
|
178 | - } |
|
176 | + if (!$this->events->trigger('unban', 'user', $user)) { |
|
177 | + return false; |
|
178 | + } |
|
179 | 179 | |
180 | - $user->deleteMetadata('ban_reason'); |
|
180 | + $user->deleteMetadata('ban_reason'); |
|
181 | 181 | |
182 | - _elgg_invalidate_cache_for_entity($user_guid); |
|
183 | - _elgg_invalidate_memcache_for_entity($user_guid); |
|
182 | + _elgg_invalidate_cache_for_entity($user_guid); |
|
183 | + _elgg_invalidate_memcache_for_entity($user_guid); |
|
184 | 184 | |
185 | - return $this->markBanned($user_guid, false); |
|
186 | - } |
|
185 | + return $this->markBanned($user_guid, false); |
|
186 | + } |
|
187 | 187 | |
188 | - /** |
|
189 | - * Makes user $guid an admin. |
|
190 | - * |
|
191 | - * @param int $user_guid User guid |
|
192 | - * @return bool |
|
193 | - */ |
|
194 | - public function makeAdmin($user_guid) { |
|
195 | - $user = get_entity($user_guid); |
|
188 | + /** |
|
189 | + * Makes user $guid an admin. |
|
190 | + * |
|
191 | + * @param int $user_guid User guid |
|
192 | + * @return bool |
|
193 | + */ |
|
194 | + public function makeAdmin($user_guid) { |
|
195 | + $user = get_entity($user_guid); |
|
196 | 196 | |
197 | - if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
198 | - return false; |
|
199 | - } |
|
197 | + if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
198 | + return false; |
|
199 | + } |
|
200 | 200 | |
201 | - if (!$this->events->trigger('make_admin', 'user', $user)) { |
|
202 | - return false; |
|
203 | - } |
|
201 | + if (!$this->events->trigger('make_admin', 'user', $user)) { |
|
202 | + return false; |
|
203 | + } |
|
204 | 204 | |
205 | - $query = " |
|
205 | + $query = " |
|
206 | 206 | UPDATE {$this->table} |
207 | 207 | SET admin = 'yes' |
208 | 208 | WHERE guid = :guid |
209 | 209 | "; |
210 | 210 | |
211 | - $params = [ |
|
212 | - ':guid' => (int) $user_guid, |
|
213 | - ]; |
|
211 | + $params = [ |
|
212 | + ':guid' => (int) $user_guid, |
|
213 | + ]; |
|
214 | 214 | |
215 | - _elgg_invalidate_cache_for_entity($user_guid); |
|
216 | - _elgg_invalidate_memcache_for_entity($user_guid); |
|
215 | + _elgg_invalidate_cache_for_entity($user_guid); |
|
216 | + _elgg_invalidate_memcache_for_entity($user_guid); |
|
217 | 217 | |
218 | - if ($this->db->updateData($query, true, $params)) { |
|
219 | - return true; |
|
220 | - } |
|
218 | + if ($this->db->updateData($query, true, $params)) { |
|
219 | + return true; |
|
220 | + } |
|
221 | 221 | |
222 | - return false; |
|
223 | - } |
|
222 | + return false; |
|
223 | + } |
|
224 | 224 | |
225 | - /** |
|
226 | - * Removes user $guid's admin flag. |
|
227 | - * |
|
228 | - * @param int $user_guid User GUID |
|
229 | - * @return bool |
|
230 | - */ |
|
231 | - public function removeAdmin($user_guid) { |
|
225 | + /** |
|
226 | + * Removes user $guid's admin flag. |
|
227 | + * |
|
228 | + * @param int $user_guid User GUID |
|
229 | + * @return bool |
|
230 | + */ |
|
231 | + public function removeAdmin($user_guid) { |
|
232 | 232 | |
233 | - $user = get_entity($user_guid); |
|
233 | + $user = get_entity($user_guid); |
|
234 | 234 | |
235 | - if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
236 | - return false; |
|
237 | - } |
|
235 | + if (!$user instanceof ElggUser || !$user->canEdit()) { |
|
236 | + return false; |
|
237 | + } |
|
238 | 238 | |
239 | - if (!$this->events->trigger('remove_admin', 'user', $user)) { |
|
240 | - return false; |
|
241 | - } |
|
239 | + if (!$this->events->trigger('remove_admin', 'user', $user)) { |
|
240 | + return false; |
|
241 | + } |
|
242 | 242 | |
243 | - $query = " |
|
243 | + $query = " |
|
244 | 244 | UPDATE {$this->table} |
245 | 245 | SET admin = 'no' |
246 | 246 | WHERE guid = :guid |
247 | 247 | "; |
248 | 248 | |
249 | - $params = [ |
|
250 | - ':guid' => (int) $user_guid, |
|
251 | - ]; |
|
252 | - |
|
253 | - _elgg_invalidate_cache_for_entity($user_guid); |
|
254 | - _elgg_invalidate_memcache_for_entity($user_guid); |
|
255 | - |
|
256 | - if ($this->db->updateData($query, true, $params)) { |
|
257 | - return true; |
|
258 | - } |
|
259 | - |
|
260 | - return false; |
|
261 | - } |
|
262 | - |
|
263 | - /** |
|
264 | - * Get user by username |
|
265 | - * |
|
266 | - * @param string $username The user's username |
|
267 | - * |
|
268 | - * @return ElggUser|false Depending on success |
|
269 | - */ |
|
270 | - public function getByUsername($username) { |
|
271 | - |
|
272 | - // Fixes #6052. Username is frequently sniffed from the path info, which, |
|
273 | - // unlike $_GET, is not URL decoded. If the username was not URL encoded, |
|
274 | - // this is harmless. |
|
275 | - $username = rawurldecode($username); |
|
276 | - |
|
277 | - if (!$username) { |
|
278 | - return false; |
|
279 | - } |
|
280 | - |
|
281 | - $entity = $this->entity_cache->getByUsername($username); |
|
282 | - if ($entity) { |
|
283 | - return $entity; |
|
284 | - } |
|
285 | - |
|
286 | - $users = $this->entities->getEntitiesFromAttributes([ |
|
287 | - 'types' => 'user', |
|
288 | - 'attribute_name_value_pairs' => [ |
|
289 | - 'name' => 'username', |
|
290 | - 'value' => $username, |
|
291 | - ], |
|
292 | - 'limit' => 1, |
|
293 | - ]); |
|
294 | - return $users ? $users[0] : false; |
|
295 | - } |
|
296 | - |
|
297 | - /** |
|
298 | - * Get an array of users from an email address |
|
299 | - * |
|
300 | - * @param string $email Email address |
|
301 | - * @return array |
|
302 | - */ |
|
303 | - public function getByEmail($email) { |
|
304 | - if (!$email) { |
|
305 | - return []; |
|
306 | - } |
|
307 | - |
|
308 | - $users = $this->entities->getEntitiesFromAttributes([ |
|
309 | - 'types' => 'user', |
|
310 | - 'attribute_name_value_pairs' => [ |
|
311 | - 'name' => 'email', |
|
312 | - 'value' => $email, |
|
313 | - ], |
|
314 | - 'limit' => 1, |
|
315 | - ]); |
|
316 | - |
|
317 | - return $users ? : []; |
|
318 | - } |
|
319 | - |
|
320 | - /** |
|
321 | - * Return users (or the number of them) who have been active within a recent period. |
|
322 | - * |
|
323 | - * @param array $options Array of options with keys: |
|
324 | - * |
|
325 | - * seconds (int) => Length of period (default 600 = 10min) |
|
326 | - * limit (int) => Limit (default 10) |
|
327 | - * offset (int) => Offset (default 0) |
|
328 | - * count (bool) => Return a count instead of users? (default false) |
|
329 | - * |
|
330 | - * @return \ElggUser[]|int |
|
331 | - */ |
|
332 | - public function findActive(array $options = []) { |
|
249 | + $params = [ |
|
250 | + ':guid' => (int) $user_guid, |
|
251 | + ]; |
|
252 | + |
|
253 | + _elgg_invalidate_cache_for_entity($user_guid); |
|
254 | + _elgg_invalidate_memcache_for_entity($user_guid); |
|
255 | + |
|
256 | + if ($this->db->updateData($query, true, $params)) { |
|
257 | + return true; |
|
258 | + } |
|
259 | + |
|
260 | + return false; |
|
261 | + } |
|
262 | + |
|
263 | + /** |
|
264 | + * Get user by username |
|
265 | + * |
|
266 | + * @param string $username The user's username |
|
267 | + * |
|
268 | + * @return ElggUser|false Depending on success |
|
269 | + */ |
|
270 | + public function getByUsername($username) { |
|
271 | + |
|
272 | + // Fixes #6052. Username is frequently sniffed from the path info, which, |
|
273 | + // unlike $_GET, is not URL decoded. If the username was not URL encoded, |
|
274 | + // this is harmless. |
|
275 | + $username = rawurldecode($username); |
|
276 | + |
|
277 | + if (!$username) { |
|
278 | + return false; |
|
279 | + } |
|
280 | + |
|
281 | + $entity = $this->entity_cache->getByUsername($username); |
|
282 | + if ($entity) { |
|
283 | + return $entity; |
|
284 | + } |
|
285 | + |
|
286 | + $users = $this->entities->getEntitiesFromAttributes([ |
|
287 | + 'types' => 'user', |
|
288 | + 'attribute_name_value_pairs' => [ |
|
289 | + 'name' => 'username', |
|
290 | + 'value' => $username, |
|
291 | + ], |
|
292 | + 'limit' => 1, |
|
293 | + ]); |
|
294 | + return $users ? $users[0] : false; |
|
295 | + } |
|
296 | + |
|
297 | + /** |
|
298 | + * Get an array of users from an email address |
|
299 | + * |
|
300 | + * @param string $email Email address |
|
301 | + * @return array |
|
302 | + */ |
|
303 | + public function getByEmail($email) { |
|
304 | + if (!$email) { |
|
305 | + return []; |
|
306 | + } |
|
307 | + |
|
308 | + $users = $this->entities->getEntitiesFromAttributes([ |
|
309 | + 'types' => 'user', |
|
310 | + 'attribute_name_value_pairs' => [ |
|
311 | + 'name' => 'email', |
|
312 | + 'value' => $email, |
|
313 | + ], |
|
314 | + 'limit' => 1, |
|
315 | + ]); |
|
316 | + |
|
317 | + return $users ? : []; |
|
318 | + } |
|
319 | + |
|
320 | + /** |
|
321 | + * Return users (or the number of them) who have been active within a recent period. |
|
322 | + * |
|
323 | + * @param array $options Array of options with keys: |
|
324 | + * |
|
325 | + * seconds (int) => Length of period (default 600 = 10min) |
|
326 | + * limit (int) => Limit (default 10) |
|
327 | + * offset (int) => Offset (default 0) |
|
328 | + * count (bool) => Return a count instead of users? (default false) |
|
329 | + * |
|
330 | + * @return \ElggUser[]|int |
|
331 | + */ |
|
332 | + public function findActive(array $options = []) { |
|
333 | 333 | |
334 | - $options = array_merge([ |
|
335 | - 'seconds' => 600, |
|
336 | - 'limit' => $this->config->get('default_limit'), |
|
337 | - ], $options); |
|
338 | - |
|
339 | - // cast options we're sending to hook |
|
340 | - foreach (['seconds', 'limit', 'offset'] as $key) { |
|
341 | - $options[$key] = (int) $options[$key]; |
|
342 | - } |
|
343 | - $options['count'] = (bool) $options['count']; |
|
344 | - |
|
345 | - // allow plugins to override |
|
346 | - $params = [ |
|
347 | - 'seconds' => $options['seconds'], |
|
348 | - 'limit' => $options['limit'], |
|
349 | - 'offset' => $options['offset'], |
|
350 | - 'count' => $options['count'], |
|
351 | - 'options' => $options, |
|
352 | - ]; |
|
353 | - $data = _elgg_services()->hooks->trigger('find_active_users', 'system', $params, null); |
|
354 | - // check null because the handler could legitimately return falsey values. |
|
355 | - if ($data !== null) { |
|
356 | - return $data; |
|
357 | - } |
|
358 | - |
|
359 | - $dbprefix = $this->config->get('dbprefix'); |
|
360 | - $time = $this->getCurrentTime()->getTimestamp() - $options['seconds']; |
|
361 | - return elgg_get_entities([ |
|
362 | - 'type' => 'user', |
|
363 | - 'limit' => $options['limit'], |
|
364 | - 'offset' => $options['offset'], |
|
365 | - 'count' => $options['count'], |
|
366 | - 'joins' => ["join {$dbprefix}users_entity u on e.guid = u.guid"], |
|
367 | - 'wheres' => ["u.last_action >= {$time}"], |
|
368 | - 'order_by' => "u.last_action desc", |
|
369 | - ]); |
|
370 | - } |
|
371 | - |
|
372 | - /** |
|
373 | - * Registers a user, returning false if the username already exists |
|
374 | - * |
|
375 | - * @param string $username The username of the new user |
|
376 | - * @param string $password The password |
|
377 | - * @param string $name The user's display name |
|
378 | - * @param string $email The user's email address |
|
379 | - * @param bool $allow_multiple_emails Allow the same email address to be |
|
380 | - * registered multiple times? |
|
381 | - * |
|
382 | - * @return int|false The new user's GUID; false on failure |
|
383 | - * @throws RegistrationException |
|
384 | - */ |
|
385 | - public function register($username, $password, $name, $email, $allow_multiple_emails = false) { |
|
386 | - |
|
387 | - // no need to trim password |
|
388 | - $username = trim($username); |
|
389 | - $name = trim(strip_tags($name)); |
|
390 | - $email = trim($email); |
|
391 | - |
|
392 | - // A little sanity checking |
|
393 | - if (empty($username) || empty($password) || empty($name) || empty($email)) { |
|
394 | - return false; |
|
395 | - } |
|
396 | - |
|
397 | - // Make sure a user with conflicting details hasn't registered and been disabled |
|
398 | - $access_status = access_get_show_hidden_status(); |
|
399 | - access_show_hidden_entities(true); |
|
400 | - |
|
401 | - if (!validate_email_address($email)) { |
|
402 | - throw new RegistrationException(_elgg_services()->translator->translate('registration:emailnotvalid')); |
|
403 | - } |
|
404 | - |
|
405 | - if (!validate_password($password)) { |
|
406 | - throw new RegistrationException(_elgg_services()->translator->translate('registration:passwordnotvalid')); |
|
407 | - } |
|
408 | - |
|
409 | - if (!validate_username($username)) { |
|
410 | - throw new RegistrationException(_elgg_services()->translator->translate('registration:usernamenotvalid')); |
|
411 | - } |
|
412 | - |
|
413 | - if ($user = get_user_by_username($username)) { |
|
414 | - throw new RegistrationException(_elgg_services()->translator->translate('registration:userexists')); |
|
415 | - } |
|
416 | - |
|
417 | - if ((!$allow_multiple_emails) && (get_user_by_email($email))) { |
|
418 | - throw new RegistrationException(_elgg_services()->translator->translate('registration:dupeemail')); |
|
419 | - } |
|
420 | - |
|
421 | - access_show_hidden_entities($access_status); |
|
422 | - |
|
423 | - // Create user |
|
424 | - $user = new ElggUser(); |
|
425 | - $user->username = $username; |
|
426 | - $user->email = $email; |
|
427 | - $user->name = $name; |
|
428 | - $user->access_id = ACCESS_PUBLIC; |
|
429 | - $user->setPassword($password); |
|
430 | - $user->owner_guid = 0; // Users aren't owned by anyone, even if they are admin created. |
|
431 | - $user->container_guid = 0; // Users aren't contained by anyone, even if they are admin created. |
|
432 | - $user->language = _elgg_services()->translator->getCurrentLanguage(); |
|
433 | - if ($user->save() === false) { |
|
434 | - return false; |
|
435 | - } |
|
436 | - |
|
437 | - // Turn on email notifications by default |
|
438 | - $user->setNotificationSetting('email', true); |
|
334 | + $options = array_merge([ |
|
335 | + 'seconds' => 600, |
|
336 | + 'limit' => $this->config->get('default_limit'), |
|
337 | + ], $options); |
|
338 | + |
|
339 | + // cast options we're sending to hook |
|
340 | + foreach (['seconds', 'limit', 'offset'] as $key) { |
|
341 | + $options[$key] = (int) $options[$key]; |
|
342 | + } |
|
343 | + $options['count'] = (bool) $options['count']; |
|
344 | + |
|
345 | + // allow plugins to override |
|
346 | + $params = [ |
|
347 | + 'seconds' => $options['seconds'], |
|
348 | + 'limit' => $options['limit'], |
|
349 | + 'offset' => $options['offset'], |
|
350 | + 'count' => $options['count'], |
|
351 | + 'options' => $options, |
|
352 | + ]; |
|
353 | + $data = _elgg_services()->hooks->trigger('find_active_users', 'system', $params, null); |
|
354 | + // check null because the handler could legitimately return falsey values. |
|
355 | + if ($data !== null) { |
|
356 | + return $data; |
|
357 | + } |
|
358 | + |
|
359 | + $dbprefix = $this->config->get('dbprefix'); |
|
360 | + $time = $this->getCurrentTime()->getTimestamp() - $options['seconds']; |
|
361 | + return elgg_get_entities([ |
|
362 | + 'type' => 'user', |
|
363 | + 'limit' => $options['limit'], |
|
364 | + 'offset' => $options['offset'], |
|
365 | + 'count' => $options['count'], |
|
366 | + 'joins' => ["join {$dbprefix}users_entity u on e.guid = u.guid"], |
|
367 | + 'wheres' => ["u.last_action >= {$time}"], |
|
368 | + 'order_by' => "u.last_action desc", |
|
369 | + ]); |
|
370 | + } |
|
371 | + |
|
372 | + /** |
|
373 | + * Registers a user, returning false if the username already exists |
|
374 | + * |
|
375 | + * @param string $username The username of the new user |
|
376 | + * @param string $password The password |
|
377 | + * @param string $name The user's display name |
|
378 | + * @param string $email The user's email address |
|
379 | + * @param bool $allow_multiple_emails Allow the same email address to be |
|
380 | + * registered multiple times? |
|
381 | + * |
|
382 | + * @return int|false The new user's GUID; false on failure |
|
383 | + * @throws RegistrationException |
|
384 | + */ |
|
385 | + public function register($username, $password, $name, $email, $allow_multiple_emails = false) { |
|
386 | + |
|
387 | + // no need to trim password |
|
388 | + $username = trim($username); |
|
389 | + $name = trim(strip_tags($name)); |
|
390 | + $email = trim($email); |
|
391 | + |
|
392 | + // A little sanity checking |
|
393 | + if (empty($username) || empty($password) || empty($name) || empty($email)) { |
|
394 | + return false; |
|
395 | + } |
|
396 | + |
|
397 | + // Make sure a user with conflicting details hasn't registered and been disabled |
|
398 | + $access_status = access_get_show_hidden_status(); |
|
399 | + access_show_hidden_entities(true); |
|
400 | + |
|
401 | + if (!validate_email_address($email)) { |
|
402 | + throw new RegistrationException(_elgg_services()->translator->translate('registration:emailnotvalid')); |
|
403 | + } |
|
404 | + |
|
405 | + if (!validate_password($password)) { |
|
406 | + throw new RegistrationException(_elgg_services()->translator->translate('registration:passwordnotvalid')); |
|
407 | + } |
|
408 | + |
|
409 | + if (!validate_username($username)) { |
|
410 | + throw new RegistrationException(_elgg_services()->translator->translate('registration:usernamenotvalid')); |
|
411 | + } |
|
412 | + |
|
413 | + if ($user = get_user_by_username($username)) { |
|
414 | + throw new RegistrationException(_elgg_services()->translator->translate('registration:userexists')); |
|
415 | + } |
|
416 | + |
|
417 | + if ((!$allow_multiple_emails) && (get_user_by_email($email))) { |
|
418 | + throw new RegistrationException(_elgg_services()->translator->translate('registration:dupeemail')); |
|
419 | + } |
|
420 | + |
|
421 | + access_show_hidden_entities($access_status); |
|
422 | + |
|
423 | + // Create user |
|
424 | + $user = new ElggUser(); |
|
425 | + $user->username = $username; |
|
426 | + $user->email = $email; |
|
427 | + $user->name = $name; |
|
428 | + $user->access_id = ACCESS_PUBLIC; |
|
429 | + $user->setPassword($password); |
|
430 | + $user->owner_guid = 0; // Users aren't owned by anyone, even if they are admin created. |
|
431 | + $user->container_guid = 0; // Users aren't contained by anyone, even if they are admin created. |
|
432 | + $user->language = _elgg_services()->translator->getCurrentLanguage(); |
|
433 | + if ($user->save() === false) { |
|
434 | + return false; |
|
435 | + } |
|
436 | + |
|
437 | + // Turn on email notifications by default |
|
438 | + $user->setNotificationSetting('email', true); |
|
439 | 439 | |
440 | - return $user->getGUID(); |
|
441 | - } |
|
442 | - |
|
443 | - /** |
|
444 | - * Generates a unique invite code for a user |
|
445 | - * |
|
446 | - * @param string $username The username of the user sending the invitation |
|
447 | - * |
|
448 | - * @return string Invite code |
|
449 | - * @see validateInviteCode |
|
450 | - */ |
|
451 | - public function generateInviteCode($username) { |
|
452 | - $time = $this->getCurrentTime()->getTimestamp(); |
|
453 | - return "$time." . _elgg_services()->hmac->getHmac([(int) $time, $username])->getToken(); |
|
454 | - } |
|
455 | - |
|
456 | - /** |
|
457 | - * Validate a user's invite code |
|
458 | - * |
|
459 | - * @param string $username The username |
|
460 | - * @param string $code The invite code |
|
461 | - * |
|
462 | - * @return bool |
|
463 | - * @see generateInviteCode |
|
464 | - */ |
|
465 | - public function validateInviteCode($username, $code) { |
|
466 | - // validate the format of the token created by ->generateInviteCode() |
|
467 | - if (!preg_match('~^(\d+)\.([a-zA-Z0-9\-_]+)$~', $code, $m)) { |
|
468 | - return false; |
|
469 | - } |
|
470 | - $time = $m[1]; |
|
471 | - $mac = $m[2]; |
|
472 | - |
|
473 | - return _elgg_services()->hmac->getHmac([(int) $time, $username])->matchesToken($mac); |
|
474 | - } |
|
475 | - |
|
476 | - /** |
|
477 | - * Set the validation status for a user. |
|
478 | - * |
|
479 | - * @param int $user_guid The user's GUID |
|
480 | - * @param bool $status Validated (true) or unvalidated (false) |
|
481 | - * @param string $method Optional method to say how a user was validated |
|
482 | - * @return bool |
|
483 | - */ |
|
484 | - public function setValidationStatus($user_guid, $status, $method = '') { |
|
485 | - $user = get_user($user_guid); |
|
486 | - if (!$user) { |
|
487 | - return false; |
|
488 | - } |
|
489 | - |
|
490 | - $result1 = create_metadata($user->guid, 'validated', (int) $status); |
|
491 | - $result2 = create_metadata($user->guid, 'validated_method', $method); |
|
492 | - if ($result1 && $result2) { |
|
493 | - if ((bool) $status) { |
|
494 | - elgg_trigger_after_event('validate', 'user', $user); |
|
495 | - } else { |
|
496 | - elgg_trigger_after_event('invalidate', 'user', $user); |
|
497 | - } |
|
498 | - return true; |
|
499 | - } else { |
|
500 | - return false; |
|
501 | - } |
|
502 | - } |
|
503 | - |
|
504 | - /** |
|
505 | - * Gets the validation status of a user. |
|
506 | - * |
|
507 | - * @param int $user_guid The user's GUID |
|
508 | - * @return bool|null Null means status was not set for this user. |
|
509 | - */ |
|
510 | - public function getValidationStatus($user_guid) { |
|
511 | - $user = get_entity($user_guid); |
|
512 | - if (!$user || !isset($user->validated)) { |
|
513 | - return null; |
|
514 | - } |
|
515 | - return (bool) $user->validated; |
|
516 | - } |
|
517 | - |
|
518 | - /** |
|
519 | - * Sets the last action time of the given user to right now. |
|
520 | - * |
|
521 | - * @see _elgg_session_boot The session boot calls this at the beginning of every request |
|
522 | - * |
|
523 | - * @param ElggUser $user User entity |
|
524 | - * @return void |
|
525 | - */ |
|
526 | - public function setLastAction(ElggUser $user) { |
|
527 | - |
|
528 | - $time = $this->getCurrentTime()->getTimestamp(); |
|
529 | - |
|
530 | - if ($user->last_action == $time) { |
|
531 | - // no change required |
|
532 | - return; |
|
533 | - } |
|
534 | - |
|
535 | - $query = " |
|
440 | + return $user->getGUID(); |
|
441 | + } |
|
442 | + |
|
443 | + /** |
|
444 | + * Generates a unique invite code for a user |
|
445 | + * |
|
446 | + * @param string $username The username of the user sending the invitation |
|
447 | + * |
|
448 | + * @return string Invite code |
|
449 | + * @see validateInviteCode |
|
450 | + */ |
|
451 | + public function generateInviteCode($username) { |
|
452 | + $time = $this->getCurrentTime()->getTimestamp(); |
|
453 | + return "$time." . _elgg_services()->hmac->getHmac([(int) $time, $username])->getToken(); |
|
454 | + } |
|
455 | + |
|
456 | + /** |
|
457 | + * Validate a user's invite code |
|
458 | + * |
|
459 | + * @param string $username The username |
|
460 | + * @param string $code The invite code |
|
461 | + * |
|
462 | + * @return bool |
|
463 | + * @see generateInviteCode |
|
464 | + */ |
|
465 | + public function validateInviteCode($username, $code) { |
|
466 | + // validate the format of the token created by ->generateInviteCode() |
|
467 | + if (!preg_match('~^(\d+)\.([a-zA-Z0-9\-_]+)$~', $code, $m)) { |
|
468 | + return false; |
|
469 | + } |
|
470 | + $time = $m[1]; |
|
471 | + $mac = $m[2]; |
|
472 | + |
|
473 | + return _elgg_services()->hmac->getHmac([(int) $time, $username])->matchesToken($mac); |
|
474 | + } |
|
475 | + |
|
476 | + /** |
|
477 | + * Set the validation status for a user. |
|
478 | + * |
|
479 | + * @param int $user_guid The user's GUID |
|
480 | + * @param bool $status Validated (true) or unvalidated (false) |
|
481 | + * @param string $method Optional method to say how a user was validated |
|
482 | + * @return bool |
|
483 | + */ |
|
484 | + public function setValidationStatus($user_guid, $status, $method = '') { |
|
485 | + $user = get_user($user_guid); |
|
486 | + if (!$user) { |
|
487 | + return false; |
|
488 | + } |
|
489 | + |
|
490 | + $result1 = create_metadata($user->guid, 'validated', (int) $status); |
|
491 | + $result2 = create_metadata($user->guid, 'validated_method', $method); |
|
492 | + if ($result1 && $result2) { |
|
493 | + if ((bool) $status) { |
|
494 | + elgg_trigger_after_event('validate', 'user', $user); |
|
495 | + } else { |
|
496 | + elgg_trigger_after_event('invalidate', 'user', $user); |
|
497 | + } |
|
498 | + return true; |
|
499 | + } else { |
|
500 | + return false; |
|
501 | + } |
|
502 | + } |
|
503 | + |
|
504 | + /** |
|
505 | + * Gets the validation status of a user. |
|
506 | + * |
|
507 | + * @param int $user_guid The user's GUID |
|
508 | + * @return bool|null Null means status was not set for this user. |
|
509 | + */ |
|
510 | + public function getValidationStatus($user_guid) { |
|
511 | + $user = get_entity($user_guid); |
|
512 | + if (!$user || !isset($user->validated)) { |
|
513 | + return null; |
|
514 | + } |
|
515 | + return (bool) $user->validated; |
|
516 | + } |
|
517 | + |
|
518 | + /** |
|
519 | + * Sets the last action time of the given user to right now. |
|
520 | + * |
|
521 | + * @see _elgg_session_boot The session boot calls this at the beginning of every request |
|
522 | + * |
|
523 | + * @param ElggUser $user User entity |
|
524 | + * @return void |
|
525 | + */ |
|
526 | + public function setLastAction(ElggUser $user) { |
|
527 | + |
|
528 | + $time = $this->getCurrentTime()->getTimestamp(); |
|
529 | + |
|
530 | + if ($user->last_action == $time) { |
|
531 | + // no change required |
|
532 | + return; |
|
533 | + } |
|
534 | + |
|
535 | + $query = " |
|
536 | 536 | UPDATE {$this->table} |
537 | 537 | SET |
538 | 538 | prev_last_action = last_action, |
@@ -540,43 +540,43 @@ discard block |
||
540 | 540 | WHERE guid = :guid |
541 | 541 | "; |
542 | 542 | |
543 | - $params = [ |
|
544 | - ':last_action' => $time, |
|
545 | - ':guid' => (int) $user->guid, |
|
546 | - ]; |
|
543 | + $params = [ |
|
544 | + ':last_action' => $time, |
|
545 | + ':guid' => (int) $user->guid, |
|
546 | + ]; |
|
547 | 547 | |
548 | - $user->prev_last_action = $user->last_action; |
|
549 | - $user->last_action = $time; |
|
548 | + $user->prev_last_action = $user->last_action; |
|
549 | + $user->last_action = $time; |
|
550 | 550 | |
551 | - execute_delayed_write_query($query, null, $params); |
|
551 | + execute_delayed_write_query($query, null, $params); |
|
552 | 552 | |
553 | - $this->entity_cache->set($user); |
|
553 | + $this->entity_cache->set($user); |
|
554 | 554 | |
555 | - // If we save the user to memcache during this request, then we'll end up with the |
|
556 | - // old (incorrect) attributes cached (notice the above query is delayed). So it's |
|
557 | - // simplest to just resave the user after all plugin code runs. |
|
558 | - register_shutdown_function(function () use ($user, $time) { |
|
559 | - $this->entities->updateLastAction($user, $time); // keep entity table in sync |
|
560 | - $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache'), $time); |
|
561 | - }); |
|
562 | - } |
|
555 | + // If we save the user to memcache during this request, then we'll end up with the |
|
556 | + // old (incorrect) attributes cached (notice the above query is delayed). So it's |
|
557 | + // simplest to just resave the user after all plugin code runs. |
|
558 | + register_shutdown_function(function () use ($user, $time) { |
|
559 | + $this->entities->updateLastAction($user, $time); // keep entity table in sync |
|
560 | + $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache'), $time); |
|
561 | + }); |
|
562 | + } |
|
563 | 563 | |
564 | - /** |
|
565 | - * Sets the last logon time of the given user to right now. |
|
566 | - * |
|
567 | - * @param ElggUser $user User entity |
|
568 | - * @return void |
|
569 | - */ |
|
570 | - public function setLastLogin(ElggUser $user) { |
|
564 | + /** |
|
565 | + * Sets the last logon time of the given user to right now. |
|
566 | + * |
|
567 | + * @param ElggUser $user User entity |
|
568 | + * @return void |
|
569 | + */ |
|
570 | + public function setLastLogin(ElggUser $user) { |
|
571 | 571 | |
572 | - $time = $this->getCurrentTime()->getTimestamp(); |
|
572 | + $time = $this->getCurrentTime()->getTimestamp(); |
|
573 | 573 | |
574 | - if ($user->last_login == $time) { |
|
575 | - // no change required |
|
576 | - return; |
|
577 | - } |
|
574 | + if ($user->last_login == $time) { |
|
575 | + // no change required |
|
576 | + return; |
|
577 | + } |
|
578 | 578 | |
579 | - $query = " |
|
579 | + $query = " |
|
580 | 580 | UPDATE {$this->table} |
581 | 581 | SET |
582 | 582 | prev_last_login = last_login, |
@@ -584,23 +584,23 @@ discard block |
||
584 | 584 | WHERE guid = :guid |
585 | 585 | "; |
586 | 586 | |
587 | - $params = [ |
|
588 | - ':last_login' => $time, |
|
589 | - ':guid' => (int) $user->guid, |
|
590 | - ]; |
|
587 | + $params = [ |
|
588 | + ':last_login' => $time, |
|
589 | + ':guid' => (int) $user->guid, |
|
590 | + ]; |
|
591 | 591 | |
592 | - $user->prev_last_login = $user->last_login; |
|
593 | - $user->last_login = $time; |
|
592 | + $user->prev_last_login = $user->last_login; |
|
593 | + $user->last_login = $time; |
|
594 | 594 | |
595 | - execute_delayed_write_query($query, null, $params); |
|
595 | + execute_delayed_write_query($query, null, $params); |
|
596 | 596 | |
597 | - $this->entity_cache->set($user); |
|
597 | + $this->entity_cache->set($user); |
|
598 | 598 | |
599 | - // If we save the user to memcache during this request, then we'll end up with the |
|
600 | - // old (incorrect) attributes cached. Hence we want to invalidate as late as possible. |
|
601 | - // the user object gets saved |
|
602 | - register_shutdown_function(function () use ($user) { |
|
603 | - $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
604 | - }); |
|
605 | - } |
|
599 | + // If we save the user to memcache during this request, then we'll end up with the |
|
600 | + // old (incorrect) attributes cached. Hence we want to invalidate as late as possible. |
|
601 | + // the user object gets saved |
|
602 | + register_shutdown_function(function () use ($user) { |
|
603 | + $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
|
604 | + }); |
|
605 | + } |
|
606 | 606 | } |
@@ -67,7 +67,7 @@ discard block |
||
67 | 67 | ) { |
68 | 68 | $this->config = $config; |
69 | 69 | $this->db = $db; |
70 | - $this->table = $this->db->prefix . "users_entity"; |
|
70 | + $this->table = $this->db->prefix."users_entity"; |
|
71 | 71 | $this->entities = $entities; |
72 | 72 | $this->entity_cache = $cache; |
73 | 73 | $this->events = $events; |
@@ -314,7 +314,7 @@ discard block |
||
314 | 314 | 'limit' => 1, |
315 | 315 | ]); |
316 | 316 | |
317 | - return $users ? : []; |
|
317 | + return $users ?: []; |
|
318 | 318 | } |
319 | 319 | |
320 | 320 | /** |
@@ -450,7 +450,7 @@ discard block |
||
450 | 450 | */ |
451 | 451 | public function generateInviteCode($username) { |
452 | 452 | $time = $this->getCurrentTime()->getTimestamp(); |
453 | - return "$time." . _elgg_services()->hmac->getHmac([(int) $time, $username])->getToken(); |
|
453 | + return "$time."._elgg_services()->hmac->getHmac([(int) $time, $username])->getToken(); |
|
454 | 454 | } |
455 | 455 | |
456 | 456 | /** |
@@ -555,7 +555,7 @@ discard block |
||
555 | 555 | // If we save the user to memcache during this request, then we'll end up with the |
556 | 556 | // old (incorrect) attributes cached (notice the above query is delayed). So it's |
557 | 557 | // simplest to just resave the user after all plugin code runs. |
558 | - register_shutdown_function(function () use ($user, $time) { |
|
558 | + register_shutdown_function(function() use ($user, $time) { |
|
559 | 559 | $this->entities->updateLastAction($user, $time); // keep entity table in sync |
560 | 560 | $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache'), $time); |
561 | 561 | }); |
@@ -599,7 +599,7 @@ discard block |
||
599 | 599 | // If we save the user to memcache during this request, then we'll end up with the |
600 | 600 | // old (incorrect) attributes cached. Hence we want to invalidate as late as possible. |
601 | 601 | // the user object gets saved |
602 | - register_shutdown_function(function () use ($user) { |
|
602 | + register_shutdown_function(function() use ($user) { |
|
603 | 603 | $user->storeInPersistedCache(_elgg_get_memcache('new_entity_cache')); |
604 | 604 | }); |
605 | 605 | } |
@@ -19,7 +19,7 @@ discard block |
||
19 | 19 | * @access private |
20 | 20 | */ |
21 | 21 | function _elgg_action_handler(array $segments) { |
22 | - return _elgg_services()->actions->execute(implode('/', $segments)); |
|
22 | + return _elgg_services()->actions->execute(implode('/', $segments)); |
|
23 | 23 | } |
24 | 24 | |
25 | 25 | /** |
@@ -51,12 +51,12 @@ discard block |
||
51 | 51 | * @access private |
52 | 52 | */ |
53 | 53 | function action($action, $forwarder = "") { |
54 | - $response = _elgg_services()->actions->execute($action, $forwarder); |
|
55 | - if ($response instanceof ResponseBuilder) { |
|
56 | - // in case forward() wasn't called in the action |
|
57 | - _elgg_services()->responseFactory->respond($response); |
|
58 | - } |
|
59 | - _elgg_services()->responseFactory->redirect(REFERRER, 'csrf'); |
|
54 | + $response = _elgg_services()->actions->execute($action, $forwarder); |
|
55 | + if ($response instanceof ResponseBuilder) { |
|
56 | + // in case forward() wasn't called in the action |
|
57 | + _elgg_services()->responseFactory->respond($response); |
|
58 | + } |
|
59 | + _elgg_services()->responseFactory->redirect(REFERRER, 'csrf'); |
|
60 | 60 | } |
61 | 61 | |
62 | 62 | /** |
@@ -94,7 +94,7 @@ discard block |
||
94 | 94 | * @return bool |
95 | 95 | */ |
96 | 96 | function elgg_register_action($action, $filename = "", $access = 'logged_in') { |
97 | - return _elgg_services()->actions->register($action, $filename, $access); |
|
97 | + return _elgg_services()->actions->register($action, $filename, $access); |
|
98 | 98 | } |
99 | 99 | |
100 | 100 | /** |
@@ -105,7 +105,7 @@ discard block |
||
105 | 105 | * @since 1.8.1 |
106 | 106 | */ |
107 | 107 | function elgg_unregister_action($action) { |
108 | - return _elgg_services()->actions->unregister($action); |
|
108 | + return _elgg_services()->actions->unregister($action); |
|
109 | 109 | } |
110 | 110 | |
111 | 111 | /** |
@@ -116,7 +116,7 @@ discard block |
||
116 | 116 | * @since 1.11 |
117 | 117 | */ |
118 | 118 | function elgg_build_hmac($data) { |
119 | - return _elgg_services()->hmac->getHmac($data); |
|
119 | + return _elgg_services()->hmac->getHmac($data); |
|
120 | 120 | } |
121 | 121 | |
122 | 122 | /** |
@@ -136,7 +136,7 @@ discard block |
||
136 | 136 | * @access private |
137 | 137 | */ |
138 | 138 | function validate_action_token($visible_errors = true, $token = null, $ts = null) { |
139 | - return _elgg_services()->actions->validateActionToken($visible_errors, $token, $ts); |
|
139 | + return _elgg_services()->actions->validateActionToken($visible_errors, $token, $ts); |
|
140 | 140 | } |
141 | 141 | |
142 | 142 | /** |
@@ -154,7 +154,7 @@ discard block |
||
154 | 154 | * @access private |
155 | 155 | */ |
156 | 156 | function action_gatekeeper($action) { |
157 | - return _elgg_services()->actions->gatekeeper($action); |
|
157 | + return _elgg_services()->actions->gatekeeper($action); |
|
158 | 158 | } |
159 | 159 | |
160 | 160 | /** |
@@ -175,7 +175,7 @@ discard block |
||
175 | 175 | * @return string|false |
176 | 176 | */ |
177 | 177 | function generate_action_token($timestamp) { |
178 | - return _elgg_services()->actions->generateActionToken($timestamp); |
|
178 | + return _elgg_services()->actions->generateActionToken($timestamp); |
|
179 | 179 | } |
180 | 180 | |
181 | 181 | /** |
@@ -190,7 +190,7 @@ discard block |
||
190 | 190 | * @todo Move to better file. |
191 | 191 | */ |
192 | 192 | function init_site_secret() { |
193 | - return _elgg_services()->siteSecret->init(); |
|
193 | + return _elgg_services()->siteSecret->init(); |
|
194 | 194 | } |
195 | 195 | |
196 | 196 | /** |
@@ -203,7 +203,7 @@ discard block |
||
203 | 203 | * @todo Move to better file. |
204 | 204 | */ |
205 | 205 | function get_site_secret() { |
206 | - return _elgg_services()->siteSecret->get(); |
|
206 | + return _elgg_services()->siteSecret->get(); |
|
207 | 207 | } |
208 | 208 | |
209 | 209 | /** |
@@ -213,7 +213,7 @@ discard block |
||
213 | 213 | * @access private |
214 | 214 | */ |
215 | 215 | function _elgg_get_site_secret_strength() { |
216 | - return _elgg_services()->siteSecret->getStrength(); |
|
216 | + return _elgg_services()->siteSecret->getStrength(); |
|
217 | 217 | } |
218 | 218 | |
219 | 219 | /** |
@@ -225,7 +225,7 @@ discard block |
||
225 | 225 | * @since 1.8.0 |
226 | 226 | */ |
227 | 227 | function elgg_action_exists($action) { |
228 | - return _elgg_services()->actions->exists($action); |
|
228 | + return _elgg_services()->actions->exists($action); |
|
229 | 229 | } |
230 | 230 | |
231 | 231 | /** |
@@ -235,7 +235,7 @@ discard block |
||
235 | 235 | * @since 1.8.0 |
236 | 236 | */ |
237 | 237 | function elgg_is_xhr() { |
238 | - return _elgg_services()->request->isXmlHttpRequest(); |
|
238 | + return _elgg_services()->request->isXmlHttpRequest(); |
|
239 | 239 | } |
240 | 240 | |
241 | 241 | /** |
@@ -266,8 +266,8 @@ discard block |
||
266 | 266 | * @deprecated 2.3 |
267 | 267 | */ |
268 | 268 | function ajax_forward_hook($hook, $type, $reason, $params) { |
269 | - elgg_deprecated_notice(__FUNCTION__ . ' is deprecated and is no longer used as a plugin hook handler', '2.3'); |
|
270 | - _elgg_services()->actions->ajaxForwardHook($hook, $type, $reason, $params); |
|
269 | + elgg_deprecated_notice(__FUNCTION__ . ' is deprecated and is no longer used as a plugin hook handler', '2.3'); |
|
270 | + _elgg_services()->actions->ajaxForwardHook($hook, $type, $reason, $params); |
|
271 | 271 | } |
272 | 272 | |
273 | 273 | /** |
@@ -277,8 +277,8 @@ discard block |
||
277 | 277 | * @deprecated 2.3 |
278 | 278 | */ |
279 | 279 | function ajax_action_hook() { |
280 | - elgg_deprecated_notice(__FUNCTION__ . ' is deprecated and is no longer used as a plugin hook handler', '2.3'); |
|
281 | - _elgg_services()->actions->ajaxActionHook(); |
|
280 | + elgg_deprecated_notice(__FUNCTION__ . ' is deprecated and is no longer used as a plugin hook handler', '2.3'); |
|
281 | + _elgg_services()->actions->ajaxActionHook(); |
|
282 | 282 | } |
283 | 283 | |
284 | 284 | /** |
@@ -288,7 +288,7 @@ discard block |
||
288 | 288 | * @access private |
289 | 289 | */ |
290 | 290 | function _elgg_csrf_token_refresh() { |
291 | - return _elgg_services()->actions->handleTokenRefreshRequest(); |
|
291 | + return _elgg_services()->actions->handleTokenRefreshRequest(); |
|
292 | 292 | } |
293 | 293 | |
294 | 294 | /** |
@@ -296,12 +296,12 @@ discard block |
||
296 | 296 | * @access private |
297 | 297 | */ |
298 | 298 | function actions_init() { |
299 | - elgg_register_page_handler('action', '_elgg_action_handler'); |
|
300 | - elgg_register_page_handler('refresh_token', '_elgg_csrf_token_refresh'); |
|
299 | + elgg_register_page_handler('action', '_elgg_action_handler'); |
|
300 | + elgg_register_page_handler('refresh_token', '_elgg_csrf_token_refresh'); |
|
301 | 301 | |
302 | - elgg_register_simplecache_view('languages/en.js'); |
|
302 | + elgg_register_simplecache_view('languages/en.js'); |
|
303 | 303 | } |
304 | 304 | |
305 | 305 | return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { |
306 | - $events->registerHandler('init', 'system', 'actions_init'); |
|
306 | + $events->registerHandler('init', 'system', 'actions_init'); |
|
307 | 307 | }; |
@@ -90,383 +90,383 @@ |
||
90 | 90 | */ |
91 | 91 | class ServiceProvider extends \Elgg\Di\DiContainer { |
92 | 92 | |
93 | - /** |
|
94 | - * Constructor |
|
95 | - * |
|
96 | - * @param \Elgg\Config $config Elgg Config service |
|
97 | - */ |
|
98 | - public function __construct(\Elgg\Config $config) { |
|
99 | - |
|
100 | - $this->setFactory('autoloadManager', function(ServiceProvider $c) { |
|
101 | - $manager = new \Elgg\AutoloadManager($c->classLoader); |
|
102 | - if (!$c->config->get('AutoloaderManager_skip_storage')) { |
|
103 | - $manager->setStorage($c->fileCache); |
|
104 | - $manager->loadCache(); |
|
105 | - } |
|
106 | - return $manager; |
|
107 | - }); |
|
108 | - |
|
109 | - $this->setFactory('accessCache', function(ServiceProvider $c) { |
|
110 | - return new \ElggStaticVariableCache('access'); |
|
111 | - }); |
|
112 | - |
|
113 | - $this->setFactory('accessCollections', function(ServiceProvider $c) { |
|
114 | - return new \Elgg\Database\AccessCollections( |
|
115 | - $c->config, $c->db, $c->entityTable, $c->accessCache, $c->hooks, $c->session, $c->translator); |
|
116 | - }); |
|
117 | - |
|
118 | - $this->setFactory('actions', function(ServiceProvider $c) { |
|
119 | - return new \Elgg\ActionsService($c->config, $c->session, $c->crypto); |
|
120 | - }); |
|
121 | - |
|
122 | - $this->setClassName('adminNotices', \Elgg\Database\AdminNotices::class); |
|
123 | - |
|
124 | - $this->setFactory('ajax', function(ServiceProvider $c) { |
|
125 | - return new \Elgg\Ajax\Service($c->hooks, $c->systemMessages, $c->input, $c->amdConfig); |
|
126 | - }); |
|
127 | - |
|
128 | - $this->setFactory('amdConfig', function(ServiceProvider $c) { |
|
129 | - $obj = new \Elgg\Amd\Config($c->hooks); |
|
130 | - $obj->setBaseUrl($c->simpleCache->getRoot()); |
|
131 | - return $obj; |
|
132 | - }); |
|
133 | - |
|
134 | - $this->setFactory('annotations', function(ServiceProvider $c) { |
|
135 | - return new \Elgg\Database\Annotations($c->db, $c->session, $c->events); |
|
136 | - }); |
|
137 | - |
|
138 | - $this->setClassName('autoP', \ElggAutoP::class); |
|
139 | - |
|
140 | - $this->setFactory('boot', function(ServiceProvider $c) { |
|
141 | - $boot = new \Elgg\BootService(); |
|
142 | - if ($c->config->getVolatile('enable_profiling')) { |
|
143 | - $boot->setTimer($c->timer); |
|
144 | - } |
|
145 | - return $boot; |
|
146 | - }); |
|
147 | - |
|
148 | - $this->setFactory('batchUpgrader', function(ServiceProvider $c) { |
|
149 | - return new \Elgg\BatchUpgrader($c->config); |
|
150 | - }); |
|
151 | - |
|
152 | - $this->setFactory('classLoader', function(ServiceProvider $c) { |
|
153 | - $loader = new \Elgg\ClassLoader(new \Elgg\ClassMap()); |
|
154 | - $loader->register(); |
|
155 | - return $loader; |
|
156 | - }); |
|
157 | - |
|
158 | - $this->setValue('config', $config); |
|
159 | - |
|
160 | - $this->setFactory('configTable', function(ServiceProvider $c) { |
|
161 | - return new \Elgg\Database\ConfigTable($c->db, $c->boot, $c->logger); |
|
162 | - }); |
|
163 | - |
|
164 | - $this->setFactory('context', function(ServiceProvider $c) { |
|
165 | - $context = new \Elgg\Context(); |
|
166 | - $context->initialize($c->request); |
|
167 | - return $context; |
|
168 | - }); |
|
169 | - |
|
170 | - $this->setClassName('crypto', \ElggCrypto::class); |
|
171 | - |
|
172 | - $this->setFactory('db', function(ServiceProvider $c) { |
|
173 | - // gonna need dbprefix from settings |
|
174 | - $c->config->loadSettingsFile(); |
|
175 | - $db_config = new \Elgg\Database\Config($c->config->getStorageObject()); |
|
176 | - |
|
177 | - // we inject the logger in _elgg_engine_boot() |
|
178 | - $db = new \Elgg\Database($db_config); |
|
179 | - |
|
180 | - if ($c->config->getVolatile('profiling_sql')) { |
|
181 | - $db->setTimer($c->timer); |
|
182 | - } |
|
183 | - |
|
184 | - return $db; |
|
185 | - }); |
|
186 | - |
|
187 | - $this->setFactory('deprecation', function(ServiceProvider $c) { |
|
188 | - return new \Elgg\DeprecationService($c->logger); |
|
189 | - }); |
|
190 | - |
|
191 | - $this->setFactory('entityCache', function(ServiceProvider $c) { |
|
192 | - return new \Elgg\Cache\EntityCache($c->session, $c->metadataCache); |
|
193 | - }); |
|
194 | - |
|
195 | - $this->setFactory('entityPreloader', function(ServiceProvider $c) { |
|
196 | - return new \Elgg\EntityPreloader($c->entityCache, $c->entityTable); |
|
197 | - }); |
|
198 | - |
|
199 | - $this->setFactory('entityTable', function(ServiceProvider $c) { |
|
200 | - return new \Elgg\Database\EntityTable( |
|
201 | - $c->config, |
|
202 | - $c->db, |
|
203 | - $c->entityCache, |
|
204 | - $c->metadataCache, |
|
205 | - $c->subtypeTable, |
|
206 | - $c->events, |
|
207 | - $c->session, |
|
208 | - $c->translator, |
|
209 | - $c->logger |
|
210 | - ); |
|
211 | - }); |
|
212 | - |
|
213 | - $this->setFactory('events', function (ServiceProvider $c) { |
|
214 | - $events = new \Elgg\EventsService(); |
|
215 | - if ($c->config->getVolatile('enable_profiling')) { |
|
216 | - $events->setTimer($c->timer); |
|
217 | - } |
|
218 | - return $events; |
|
219 | - }); |
|
220 | - |
|
221 | - $this->setFactory('externalFiles', function(ServiceProvider $c) { |
|
222 | - return new \Elgg\Assets\ExternalFiles($c->config->getStorageObject()); |
|
223 | - }); |
|
224 | - |
|
225 | - $this->setFactory('fileCache', function(ServiceProvider $c) { |
|
226 | - return new \ElggFileCache($c->config->getCachePath() . 'system_cache/'); |
|
227 | - }); |
|
228 | - |
|
229 | - $this->setFactory('filestore', function(ServiceProvider $c) { |
|
230 | - return new \ElggDiskFilestore($c->config->getDataPath()); |
|
231 | - }); |
|
232 | - |
|
233 | - $this->setFactory('forms', function(ServiceProvider $c) { |
|
234 | - return new \Elgg\FormsService($c->views, $c->logger); |
|
235 | - }); |
|
236 | - |
|
237 | - $this->setClassName('handlers', \Elgg\HandlersService::class); |
|
238 | - |
|
239 | - $this->setFactory('hmac', function(ServiceProvider $c) { |
|
240 | - return new \Elgg\Security\HmacFactory($c->siteSecret, $c->crypto); |
|
241 | - }); |
|
242 | - |
|
243 | - $this->setClassName('hooks', \Elgg\PluginHooksService::class); |
|
244 | - |
|
245 | - $this->setFactory('iconService', function(ServiceProvider $c) { |
|
246 | - return new \Elgg\EntityIconService($c->config, $c->hooks, $c->request, $c->logger, $c->entityTable); |
|
247 | - }); |
|
248 | - |
|
249 | - $this->setClassName('input', \Elgg\Http\Input::class); |
|
250 | - |
|
251 | - $this->setFactory('imageService', function(ServiceProvider $c) { |
|
252 | - $imagine = new \Imagine\Gd\Imagine(); |
|
253 | - return new \Elgg\ImageService($imagine, $c->config); |
|
254 | - }); |
|
255 | - |
|
256 | - $this->setFactory('logger', function (ServiceProvider $c) { |
|
257 | - return new \Elgg\Logger($c->hooks, $c->config, $c->context); |
|
258 | - }); |
|
259 | - |
|
260 | - // TODO(evan): Support configurable transports... |
|
261 | - $this->setClassName('mailer', 'Zend\Mail\Transport\Sendmail'); |
|
262 | - |
|
263 | - $this->setFactory('menus', function(ServiceProvider $c) { |
|
264 | - return new \Elgg\Menu\Service($c->hooks, $c->config); |
|
265 | - }); |
|
266 | - |
|
267 | - $this->setFactory('metadataCache', function (ServiceProvider $c) { |
|
268 | - return new \Elgg\Cache\MetadataCache($c->session); |
|
269 | - }); |
|
270 | - |
|
271 | - $this->setFactory('memcacheStashPool', function(ServiceProvider $c) { |
|
272 | - if (!$c->config->getVolatile('memcache')) { |
|
273 | - return null; |
|
274 | - } |
|
275 | - |
|
276 | - $servers = $c->config->getVolatile('memcache_servers'); |
|
277 | - if (!$servers) { |
|
278 | - return null; |
|
279 | - } |
|
280 | - $driver = new \Stash\Driver\Memcache([ |
|
281 | - 'servers' => $servers, |
|
282 | - ]); |
|
283 | - return new \Stash\Pool($driver); |
|
284 | - }); |
|
285 | - |
|
286 | - $this->setFactory('metadataTable', function(ServiceProvider $c) { |
|
287 | - // TODO(ewinslow): Use Pool instead of MetadataCache for caching |
|
288 | - return new \Elgg\Database\MetadataTable( |
|
289 | - $c->metadataCache, $c->db, $c->entityTable, $c->events, $c->session); |
|
290 | - }); |
|
291 | - |
|
292 | - $this->setFactory('mutex', function(ServiceProvider $c) { |
|
293 | - return new \Elgg\Database\Mutex( |
|
294 | - $c->db, |
|
295 | - $c->logger |
|
296 | - ); |
|
297 | - }); |
|
298 | - |
|
299 | - $this->setFactory('notifications', function(ServiceProvider $c) { |
|
300 | - // @todo move queue in service provider |
|
301 | - $queue_name = \Elgg\Notifications\NotificationsService::QUEUE_NAME; |
|
302 | - $queue = new \Elgg\Queue\DatabaseQueue($queue_name, $c->db); |
|
303 | - $sub = new \Elgg\Notifications\SubscriptionsService($c->db); |
|
304 | - return new \Elgg\Notifications\NotificationsService($sub, $queue, $c->hooks, $c->session, $c->translator, $c->entityTable, $c->logger); |
|
305 | - }); |
|
306 | - |
|
307 | - $this->setClassName('nullCache', \Elgg\Cache\NullCache::class); |
|
308 | - |
|
309 | - $this->setFactory('persistentLogin', function(ServiceProvider $c) { |
|
310 | - $global_cookies_config = $c->config->getCookieConfig(); |
|
311 | - $cookie_config = $global_cookies_config['remember_me']; |
|
312 | - $cookie_name = $cookie_config['name']; |
|
313 | - $cookie_token = $c->request->cookies->get($cookie_name, ''); |
|
314 | - return new \Elgg\PersistentLoginService( |
|
315 | - $c->db, $c->session, $c->crypto, $cookie_config, $cookie_token); |
|
316 | - }); |
|
317 | - |
|
318 | - $this->setClassName('passwords', \Elgg\PasswordService::class); |
|
319 | - |
|
320 | - $this->setFactory('plugins', function(ServiceProvider $c) { |
|
321 | - $pool = new Pool\InMemory(); |
|
322 | - $plugins = new \Elgg\Database\Plugins($pool, $c->pluginSettingsCache); |
|
323 | - if ($c->config->getVolatile('enable_profiling')) { |
|
324 | - $plugins->setTimer($c->timer); |
|
325 | - } |
|
326 | - return $plugins; |
|
327 | - }); |
|
328 | - |
|
329 | - $this->setClassName('pluginSettingsCache', \Elgg\Cache\PluginSettingsCache::class); |
|
330 | - |
|
331 | - $this->setFactory('privateSettings', function(ServiceProvider $c) { |
|
332 | - return new \Elgg\Database\PrivateSettingsTable($c->db, $c->entityTable, $c->pluginSettingsCache); |
|
333 | - }); |
|
334 | - |
|
335 | - $this->setFactory('publicDb', function(ServiceProvider $c) { |
|
336 | - return new \Elgg\Application\Database($c->db); |
|
337 | - }); |
|
338 | - |
|
339 | - $this->setFactory('queryCounter', function(ServiceProvider $c) { |
|
340 | - return new \Elgg\Database\QueryCounter($c->db); |
|
341 | - }, false); |
|
342 | - |
|
343 | - $this->setFactory('relationshipsTable', function(ServiceProvider $c) { |
|
344 | - return new \Elgg\Database\RelationshipsTable($c->db, $c->entityTable, $c->metadataTable, $c->events); |
|
345 | - }); |
|
346 | - |
|
347 | - $this->setFactory('request', [\Elgg\Http\Request::class, 'createFromGlobals']); |
|
348 | - |
|
349 | - $this->setFactory('responseFactory', function(ServiceProvider $c) { |
|
350 | - if (PHP_SAPI === 'cli') { |
|
351 | - $transport = new \Elgg\Http\OutputBufferTransport(); |
|
352 | - } else { |
|
353 | - $transport = new \Elgg\Http\HttpProtocolTransport(); |
|
354 | - } |
|
355 | - return new \Elgg\Http\ResponseFactory($c->request, $c->hooks, $c->ajax, $transport); |
|
356 | - }); |
|
357 | - |
|
358 | - $this->setFactory('router', function(ServiceProvider $c) { |
|
359 | - // TODO(evan): Init routes from plugins or cache |
|
360 | - $router = new \Elgg\Router($c->hooks); |
|
361 | - if ($c->config->getVolatile('enable_profiling')) { |
|
362 | - $router->setTimer($c->timer); |
|
363 | - } |
|
364 | - return $router; |
|
365 | - }); |
|
366 | - |
|
367 | - $this->setFactory('serveFileHandler', function(ServiceProvider $c) { |
|
368 | - return new \Elgg\Application\ServeFileHandler($c->hmac, $c->config); |
|
369 | - }); |
|
370 | - |
|
371 | - $this->setFactory('session', function(ServiceProvider $c) { |
|
372 | - $params = $c->config->getCookieConfig()['session']; |
|
373 | - $options = [ |
|
374 | - // session.cache_limiter is unfortunately set to "" by the NativeSessionStorage |
|
375 | - // constructor, so we must capture and inject it directly. |
|
376 | - 'cache_limiter' => session_cache_limiter(), |
|
377 | - |
|
378 | - 'name' => $params['name'], |
|
379 | - 'cookie_path' => $params['path'], |
|
380 | - 'cookie_domain' => $params['domain'], |
|
381 | - 'cookie_secure' => $params['secure'], |
|
382 | - 'cookie_httponly' => $params['httponly'], |
|
383 | - 'cookie_lifetime' => $params['lifetime'], |
|
384 | - ]; |
|
385 | - |
|
386 | - $handler = new \Elgg\Http\DatabaseSessionHandler($c->db); |
|
387 | - $storage = new NativeSessionStorage($options, $handler); |
|
388 | - $session = new SymfonySession($storage); |
|
389 | - return new \ElggSession($session); |
|
390 | - }); |
|
391 | - |
|
392 | - $this->setClassName('urlSigner', \Elgg\Security\UrlSigner::class); |
|
393 | - |
|
394 | - $this->setFactory('simpleCache', function(ServiceProvider $c) { |
|
395 | - return new \Elgg\Cache\SimpleCache($c->config, $c->views); |
|
396 | - }); |
|
397 | - |
|
398 | - $this->setFactory('siteSecret', function(ServiceProvider $c) { |
|
399 | - $c->config->setConfigTable($c->configTable); |
|
400 | - return new \Elgg\Database\SiteSecret($c->config); |
|
401 | - }); |
|
402 | - |
|
403 | - $this->setClassName('stickyForms', \Elgg\Forms\StickyForms::class); |
|
404 | - |
|
405 | - $this->setFactory('subtypeTable', function(ServiceProvider $c) { |
|
406 | - return new \Elgg\Database\SubtypeTable($c->db); |
|
407 | - }); |
|
408 | - |
|
409 | - $this->setFactory('systemCache', function (ServiceProvider $c) { |
|
410 | - $cache = new \Elgg\Cache\SystemCache($c->fileCache, $c->config); |
|
411 | - if ($c->config->getVolatile('enable_profiling')) { |
|
412 | - $cache->setTimer($c->timer); |
|
413 | - } |
|
414 | - return $cache; |
|
415 | - }); |
|
416 | - |
|
417 | - $this->setFactory('systemMessages', function(ServiceProvider $c) { |
|
418 | - return new \Elgg\SystemMessagesService($c->session); |
|
419 | - }); |
|
420 | - |
|
421 | - $this->setClassName('table_columns', \Elgg\Views\TableColumn\ColumnFactory::class); |
|
422 | - |
|
423 | - $this->setClassName('timer', \Elgg\Timer::class); |
|
424 | - |
|
425 | - $this->setFactory('translator', function(ServiceProvider $c) { |
|
426 | - return new \Elgg\I18n\Translator($c->config); |
|
427 | - }); |
|
428 | - |
|
429 | - $this->setFactory('uploads', function(ServiceProvider $c) { |
|
430 | - return new \Elgg\UploadService($c->request); |
|
431 | - }); |
|
432 | - |
|
433 | - $this->setFactory('upgrades', function(ServiceProvider $c) { |
|
434 | - return new \Elgg\UpgradeService( |
|
435 | - $c->translator, |
|
436 | - $c->events, |
|
437 | - $c->hooks, |
|
438 | - $c->config, |
|
439 | - $c->logger, |
|
440 | - $c->mutex |
|
441 | - ); |
|
442 | - }); |
|
443 | - |
|
444 | - $this->setFactory('userCapabilities', function(ServiceProvider $c) { |
|
445 | - return new \Elgg\UserCapabilities($c->hooks, $c->entityTable, $c->session); |
|
446 | - }); |
|
447 | - |
|
448 | - $this->setFactory('usersTable', function(ServiceProvider $c) { |
|
449 | - return new \Elgg\Database\UsersTable( |
|
450 | - $c->config, |
|
451 | - $c->db, |
|
452 | - $c->entityTable, |
|
453 | - $c->entityCache, |
|
454 | - $c->events |
|
455 | - ); |
|
456 | - }); |
|
457 | - |
|
458 | - $this->setFactory('upgradeLocator', function(ServiceProvider $c) { |
|
459 | - return new \Elgg\Upgrade\Locator( |
|
460 | - $c->plugins, |
|
461 | - $c->logger, |
|
462 | - $c->privateSettings |
|
463 | - ); |
|
464 | - }); |
|
465 | - |
|
466 | - $this->setFactory('views', function(ServiceProvider $c) { |
|
467 | - return new \Elgg\ViewsService($c->hooks, $c->logger); |
|
468 | - }); |
|
469 | - |
|
470 | - $this->setClassName('widgets', \Elgg\WidgetsService::class); |
|
471 | - } |
|
93 | + /** |
|
94 | + * Constructor |
|
95 | + * |
|
96 | + * @param \Elgg\Config $config Elgg Config service |
|
97 | + */ |
|
98 | + public function __construct(\Elgg\Config $config) { |
|
99 | + |
|
100 | + $this->setFactory('autoloadManager', function(ServiceProvider $c) { |
|
101 | + $manager = new \Elgg\AutoloadManager($c->classLoader); |
|
102 | + if (!$c->config->get('AutoloaderManager_skip_storage')) { |
|
103 | + $manager->setStorage($c->fileCache); |
|
104 | + $manager->loadCache(); |
|
105 | + } |
|
106 | + return $manager; |
|
107 | + }); |
|
108 | + |
|
109 | + $this->setFactory('accessCache', function(ServiceProvider $c) { |
|
110 | + return new \ElggStaticVariableCache('access'); |
|
111 | + }); |
|
112 | + |
|
113 | + $this->setFactory('accessCollections', function(ServiceProvider $c) { |
|
114 | + return new \Elgg\Database\AccessCollections( |
|
115 | + $c->config, $c->db, $c->entityTable, $c->accessCache, $c->hooks, $c->session, $c->translator); |
|
116 | + }); |
|
117 | + |
|
118 | + $this->setFactory('actions', function(ServiceProvider $c) { |
|
119 | + return new \Elgg\ActionsService($c->config, $c->session, $c->crypto); |
|
120 | + }); |
|
121 | + |
|
122 | + $this->setClassName('adminNotices', \Elgg\Database\AdminNotices::class); |
|
123 | + |
|
124 | + $this->setFactory('ajax', function(ServiceProvider $c) { |
|
125 | + return new \Elgg\Ajax\Service($c->hooks, $c->systemMessages, $c->input, $c->amdConfig); |
|
126 | + }); |
|
127 | + |
|
128 | + $this->setFactory('amdConfig', function(ServiceProvider $c) { |
|
129 | + $obj = new \Elgg\Amd\Config($c->hooks); |
|
130 | + $obj->setBaseUrl($c->simpleCache->getRoot()); |
|
131 | + return $obj; |
|
132 | + }); |
|
133 | + |
|
134 | + $this->setFactory('annotations', function(ServiceProvider $c) { |
|
135 | + return new \Elgg\Database\Annotations($c->db, $c->session, $c->events); |
|
136 | + }); |
|
137 | + |
|
138 | + $this->setClassName('autoP', \ElggAutoP::class); |
|
139 | + |
|
140 | + $this->setFactory('boot', function(ServiceProvider $c) { |
|
141 | + $boot = new \Elgg\BootService(); |
|
142 | + if ($c->config->getVolatile('enable_profiling')) { |
|
143 | + $boot->setTimer($c->timer); |
|
144 | + } |
|
145 | + return $boot; |
|
146 | + }); |
|
147 | + |
|
148 | + $this->setFactory('batchUpgrader', function(ServiceProvider $c) { |
|
149 | + return new \Elgg\BatchUpgrader($c->config); |
|
150 | + }); |
|
151 | + |
|
152 | + $this->setFactory('classLoader', function(ServiceProvider $c) { |
|
153 | + $loader = new \Elgg\ClassLoader(new \Elgg\ClassMap()); |
|
154 | + $loader->register(); |
|
155 | + return $loader; |
|
156 | + }); |
|
157 | + |
|
158 | + $this->setValue('config', $config); |
|
159 | + |
|
160 | + $this->setFactory('configTable', function(ServiceProvider $c) { |
|
161 | + return new \Elgg\Database\ConfigTable($c->db, $c->boot, $c->logger); |
|
162 | + }); |
|
163 | + |
|
164 | + $this->setFactory('context', function(ServiceProvider $c) { |
|
165 | + $context = new \Elgg\Context(); |
|
166 | + $context->initialize($c->request); |
|
167 | + return $context; |
|
168 | + }); |
|
169 | + |
|
170 | + $this->setClassName('crypto', \ElggCrypto::class); |
|
171 | + |
|
172 | + $this->setFactory('db', function(ServiceProvider $c) { |
|
173 | + // gonna need dbprefix from settings |
|
174 | + $c->config->loadSettingsFile(); |
|
175 | + $db_config = new \Elgg\Database\Config($c->config->getStorageObject()); |
|
176 | + |
|
177 | + // we inject the logger in _elgg_engine_boot() |
|
178 | + $db = new \Elgg\Database($db_config); |
|
179 | + |
|
180 | + if ($c->config->getVolatile('profiling_sql')) { |
|
181 | + $db->setTimer($c->timer); |
|
182 | + } |
|
183 | + |
|
184 | + return $db; |
|
185 | + }); |
|
186 | + |
|
187 | + $this->setFactory('deprecation', function(ServiceProvider $c) { |
|
188 | + return new \Elgg\DeprecationService($c->logger); |
|
189 | + }); |
|
190 | + |
|
191 | + $this->setFactory('entityCache', function(ServiceProvider $c) { |
|
192 | + return new \Elgg\Cache\EntityCache($c->session, $c->metadataCache); |
|
193 | + }); |
|
194 | + |
|
195 | + $this->setFactory('entityPreloader', function(ServiceProvider $c) { |
|
196 | + return new \Elgg\EntityPreloader($c->entityCache, $c->entityTable); |
|
197 | + }); |
|
198 | + |
|
199 | + $this->setFactory('entityTable', function(ServiceProvider $c) { |
|
200 | + return new \Elgg\Database\EntityTable( |
|
201 | + $c->config, |
|
202 | + $c->db, |
|
203 | + $c->entityCache, |
|
204 | + $c->metadataCache, |
|
205 | + $c->subtypeTable, |
|
206 | + $c->events, |
|
207 | + $c->session, |
|
208 | + $c->translator, |
|
209 | + $c->logger |
|
210 | + ); |
|
211 | + }); |
|
212 | + |
|
213 | + $this->setFactory('events', function (ServiceProvider $c) { |
|
214 | + $events = new \Elgg\EventsService(); |
|
215 | + if ($c->config->getVolatile('enable_profiling')) { |
|
216 | + $events->setTimer($c->timer); |
|
217 | + } |
|
218 | + return $events; |
|
219 | + }); |
|
220 | + |
|
221 | + $this->setFactory('externalFiles', function(ServiceProvider $c) { |
|
222 | + return new \Elgg\Assets\ExternalFiles($c->config->getStorageObject()); |
|
223 | + }); |
|
224 | + |
|
225 | + $this->setFactory('fileCache', function(ServiceProvider $c) { |
|
226 | + return new \ElggFileCache($c->config->getCachePath() . 'system_cache/'); |
|
227 | + }); |
|
228 | + |
|
229 | + $this->setFactory('filestore', function(ServiceProvider $c) { |
|
230 | + return new \ElggDiskFilestore($c->config->getDataPath()); |
|
231 | + }); |
|
232 | + |
|
233 | + $this->setFactory('forms', function(ServiceProvider $c) { |
|
234 | + return new \Elgg\FormsService($c->views, $c->logger); |
|
235 | + }); |
|
236 | + |
|
237 | + $this->setClassName('handlers', \Elgg\HandlersService::class); |
|
238 | + |
|
239 | + $this->setFactory('hmac', function(ServiceProvider $c) { |
|
240 | + return new \Elgg\Security\HmacFactory($c->siteSecret, $c->crypto); |
|
241 | + }); |
|
242 | + |
|
243 | + $this->setClassName('hooks', \Elgg\PluginHooksService::class); |
|
244 | + |
|
245 | + $this->setFactory('iconService', function(ServiceProvider $c) { |
|
246 | + return new \Elgg\EntityIconService($c->config, $c->hooks, $c->request, $c->logger, $c->entityTable); |
|
247 | + }); |
|
248 | + |
|
249 | + $this->setClassName('input', \Elgg\Http\Input::class); |
|
250 | + |
|
251 | + $this->setFactory('imageService', function(ServiceProvider $c) { |
|
252 | + $imagine = new \Imagine\Gd\Imagine(); |
|
253 | + return new \Elgg\ImageService($imagine, $c->config); |
|
254 | + }); |
|
255 | + |
|
256 | + $this->setFactory('logger', function (ServiceProvider $c) { |
|
257 | + return new \Elgg\Logger($c->hooks, $c->config, $c->context); |
|
258 | + }); |
|
259 | + |
|
260 | + // TODO(evan): Support configurable transports... |
|
261 | + $this->setClassName('mailer', 'Zend\Mail\Transport\Sendmail'); |
|
262 | + |
|
263 | + $this->setFactory('menus', function(ServiceProvider $c) { |
|
264 | + return new \Elgg\Menu\Service($c->hooks, $c->config); |
|
265 | + }); |
|
266 | + |
|
267 | + $this->setFactory('metadataCache', function (ServiceProvider $c) { |
|
268 | + return new \Elgg\Cache\MetadataCache($c->session); |
|
269 | + }); |
|
270 | + |
|
271 | + $this->setFactory('memcacheStashPool', function(ServiceProvider $c) { |
|
272 | + if (!$c->config->getVolatile('memcache')) { |
|
273 | + return null; |
|
274 | + } |
|
275 | + |
|
276 | + $servers = $c->config->getVolatile('memcache_servers'); |
|
277 | + if (!$servers) { |
|
278 | + return null; |
|
279 | + } |
|
280 | + $driver = new \Stash\Driver\Memcache([ |
|
281 | + 'servers' => $servers, |
|
282 | + ]); |
|
283 | + return new \Stash\Pool($driver); |
|
284 | + }); |
|
285 | + |
|
286 | + $this->setFactory('metadataTable', function(ServiceProvider $c) { |
|
287 | + // TODO(ewinslow): Use Pool instead of MetadataCache for caching |
|
288 | + return new \Elgg\Database\MetadataTable( |
|
289 | + $c->metadataCache, $c->db, $c->entityTable, $c->events, $c->session); |
|
290 | + }); |
|
291 | + |
|
292 | + $this->setFactory('mutex', function(ServiceProvider $c) { |
|
293 | + return new \Elgg\Database\Mutex( |
|
294 | + $c->db, |
|
295 | + $c->logger |
|
296 | + ); |
|
297 | + }); |
|
298 | + |
|
299 | + $this->setFactory('notifications', function(ServiceProvider $c) { |
|
300 | + // @todo move queue in service provider |
|
301 | + $queue_name = \Elgg\Notifications\NotificationsService::QUEUE_NAME; |
|
302 | + $queue = new \Elgg\Queue\DatabaseQueue($queue_name, $c->db); |
|
303 | + $sub = new \Elgg\Notifications\SubscriptionsService($c->db); |
|
304 | + return new \Elgg\Notifications\NotificationsService($sub, $queue, $c->hooks, $c->session, $c->translator, $c->entityTable, $c->logger); |
|
305 | + }); |
|
306 | + |
|
307 | + $this->setClassName('nullCache', \Elgg\Cache\NullCache::class); |
|
308 | + |
|
309 | + $this->setFactory('persistentLogin', function(ServiceProvider $c) { |
|
310 | + $global_cookies_config = $c->config->getCookieConfig(); |
|
311 | + $cookie_config = $global_cookies_config['remember_me']; |
|
312 | + $cookie_name = $cookie_config['name']; |
|
313 | + $cookie_token = $c->request->cookies->get($cookie_name, ''); |
|
314 | + return new \Elgg\PersistentLoginService( |
|
315 | + $c->db, $c->session, $c->crypto, $cookie_config, $cookie_token); |
|
316 | + }); |
|
317 | + |
|
318 | + $this->setClassName('passwords', \Elgg\PasswordService::class); |
|
319 | + |
|
320 | + $this->setFactory('plugins', function(ServiceProvider $c) { |
|
321 | + $pool = new Pool\InMemory(); |
|
322 | + $plugins = new \Elgg\Database\Plugins($pool, $c->pluginSettingsCache); |
|
323 | + if ($c->config->getVolatile('enable_profiling')) { |
|
324 | + $plugins->setTimer($c->timer); |
|
325 | + } |
|
326 | + return $plugins; |
|
327 | + }); |
|
328 | + |
|
329 | + $this->setClassName('pluginSettingsCache', \Elgg\Cache\PluginSettingsCache::class); |
|
330 | + |
|
331 | + $this->setFactory('privateSettings', function(ServiceProvider $c) { |
|
332 | + return new \Elgg\Database\PrivateSettingsTable($c->db, $c->entityTable, $c->pluginSettingsCache); |
|
333 | + }); |
|
334 | + |
|
335 | + $this->setFactory('publicDb', function(ServiceProvider $c) { |
|
336 | + return new \Elgg\Application\Database($c->db); |
|
337 | + }); |
|
338 | + |
|
339 | + $this->setFactory('queryCounter', function(ServiceProvider $c) { |
|
340 | + return new \Elgg\Database\QueryCounter($c->db); |
|
341 | + }, false); |
|
342 | + |
|
343 | + $this->setFactory('relationshipsTable', function(ServiceProvider $c) { |
|
344 | + return new \Elgg\Database\RelationshipsTable($c->db, $c->entityTable, $c->metadataTable, $c->events); |
|
345 | + }); |
|
346 | + |
|
347 | + $this->setFactory('request', [\Elgg\Http\Request::class, 'createFromGlobals']); |
|
348 | + |
|
349 | + $this->setFactory('responseFactory', function(ServiceProvider $c) { |
|
350 | + if (PHP_SAPI === 'cli') { |
|
351 | + $transport = new \Elgg\Http\OutputBufferTransport(); |
|
352 | + } else { |
|
353 | + $transport = new \Elgg\Http\HttpProtocolTransport(); |
|
354 | + } |
|
355 | + return new \Elgg\Http\ResponseFactory($c->request, $c->hooks, $c->ajax, $transport); |
|
356 | + }); |
|
357 | + |
|
358 | + $this->setFactory('router', function(ServiceProvider $c) { |
|
359 | + // TODO(evan): Init routes from plugins or cache |
|
360 | + $router = new \Elgg\Router($c->hooks); |
|
361 | + if ($c->config->getVolatile('enable_profiling')) { |
|
362 | + $router->setTimer($c->timer); |
|
363 | + } |
|
364 | + return $router; |
|
365 | + }); |
|
366 | + |
|
367 | + $this->setFactory('serveFileHandler', function(ServiceProvider $c) { |
|
368 | + return new \Elgg\Application\ServeFileHandler($c->hmac, $c->config); |
|
369 | + }); |
|
370 | + |
|
371 | + $this->setFactory('session', function(ServiceProvider $c) { |
|
372 | + $params = $c->config->getCookieConfig()['session']; |
|
373 | + $options = [ |
|
374 | + // session.cache_limiter is unfortunately set to "" by the NativeSessionStorage |
|
375 | + // constructor, so we must capture and inject it directly. |
|
376 | + 'cache_limiter' => session_cache_limiter(), |
|
377 | + |
|
378 | + 'name' => $params['name'], |
|
379 | + 'cookie_path' => $params['path'], |
|
380 | + 'cookie_domain' => $params['domain'], |
|
381 | + 'cookie_secure' => $params['secure'], |
|
382 | + 'cookie_httponly' => $params['httponly'], |
|
383 | + 'cookie_lifetime' => $params['lifetime'], |
|
384 | + ]; |
|
385 | + |
|
386 | + $handler = new \Elgg\Http\DatabaseSessionHandler($c->db); |
|
387 | + $storage = new NativeSessionStorage($options, $handler); |
|
388 | + $session = new SymfonySession($storage); |
|
389 | + return new \ElggSession($session); |
|
390 | + }); |
|
391 | + |
|
392 | + $this->setClassName('urlSigner', \Elgg\Security\UrlSigner::class); |
|
393 | + |
|
394 | + $this->setFactory('simpleCache', function(ServiceProvider $c) { |
|
395 | + return new \Elgg\Cache\SimpleCache($c->config, $c->views); |
|
396 | + }); |
|
397 | + |
|
398 | + $this->setFactory('siteSecret', function(ServiceProvider $c) { |
|
399 | + $c->config->setConfigTable($c->configTable); |
|
400 | + return new \Elgg\Database\SiteSecret($c->config); |
|
401 | + }); |
|
402 | + |
|
403 | + $this->setClassName('stickyForms', \Elgg\Forms\StickyForms::class); |
|
404 | + |
|
405 | + $this->setFactory('subtypeTable', function(ServiceProvider $c) { |
|
406 | + return new \Elgg\Database\SubtypeTable($c->db); |
|
407 | + }); |
|
408 | + |
|
409 | + $this->setFactory('systemCache', function (ServiceProvider $c) { |
|
410 | + $cache = new \Elgg\Cache\SystemCache($c->fileCache, $c->config); |
|
411 | + if ($c->config->getVolatile('enable_profiling')) { |
|
412 | + $cache->setTimer($c->timer); |
|
413 | + } |
|
414 | + return $cache; |
|
415 | + }); |
|
416 | + |
|
417 | + $this->setFactory('systemMessages', function(ServiceProvider $c) { |
|
418 | + return new \Elgg\SystemMessagesService($c->session); |
|
419 | + }); |
|
420 | + |
|
421 | + $this->setClassName('table_columns', \Elgg\Views\TableColumn\ColumnFactory::class); |
|
422 | + |
|
423 | + $this->setClassName('timer', \Elgg\Timer::class); |
|
424 | + |
|
425 | + $this->setFactory('translator', function(ServiceProvider $c) { |
|
426 | + return new \Elgg\I18n\Translator($c->config); |
|
427 | + }); |
|
428 | + |
|
429 | + $this->setFactory('uploads', function(ServiceProvider $c) { |
|
430 | + return new \Elgg\UploadService($c->request); |
|
431 | + }); |
|
432 | + |
|
433 | + $this->setFactory('upgrades', function(ServiceProvider $c) { |
|
434 | + return new \Elgg\UpgradeService( |
|
435 | + $c->translator, |
|
436 | + $c->events, |
|
437 | + $c->hooks, |
|
438 | + $c->config, |
|
439 | + $c->logger, |
|
440 | + $c->mutex |
|
441 | + ); |
|
442 | + }); |
|
443 | + |
|
444 | + $this->setFactory('userCapabilities', function(ServiceProvider $c) { |
|
445 | + return new \Elgg\UserCapabilities($c->hooks, $c->entityTable, $c->session); |
|
446 | + }); |
|
447 | + |
|
448 | + $this->setFactory('usersTable', function(ServiceProvider $c) { |
|
449 | + return new \Elgg\Database\UsersTable( |
|
450 | + $c->config, |
|
451 | + $c->db, |
|
452 | + $c->entityTable, |
|
453 | + $c->entityCache, |
|
454 | + $c->events |
|
455 | + ); |
|
456 | + }); |
|
457 | + |
|
458 | + $this->setFactory('upgradeLocator', function(ServiceProvider $c) { |
|
459 | + return new \Elgg\Upgrade\Locator( |
|
460 | + $c->plugins, |
|
461 | + $c->logger, |
|
462 | + $c->privateSettings |
|
463 | + ); |
|
464 | + }); |
|
465 | + |
|
466 | + $this->setFactory('views', function(ServiceProvider $c) { |
|
467 | + return new \Elgg\ViewsService($c->hooks, $c->logger); |
|
468 | + }); |
|
469 | + |
|
470 | + $this->setClassName('widgets', \Elgg\WidgetsService::class); |
|
471 | + } |
|
472 | 472 | } |
@@ -9,40 +9,40 @@ |
||
9 | 9 | */ |
10 | 10 | class HmacFactory { |
11 | 11 | |
12 | - /** |
|
13 | - * @var SiteSecret |
|
14 | - */ |
|
15 | - private $site_secret; |
|
12 | + /** |
|
13 | + * @var SiteSecret |
|
14 | + */ |
|
15 | + private $site_secret; |
|
16 | 16 | |
17 | - /** |
|
18 | - * @var ElggCrypto |
|
19 | - */ |
|
20 | - private $crypto; |
|
17 | + /** |
|
18 | + * @var ElggCrypto |
|
19 | + */ |
|
20 | + private $crypto; |
|
21 | 21 | |
22 | - /** |
|
23 | - * Constructor |
|
24 | - * |
|
25 | - * @param SiteSecret $secret Site secret |
|
26 | - * @param ElggCrypto $crypto Elgg crypto service |
|
27 | - */ |
|
28 | - public function __construct(SiteSecret $secret, ElggCrypto $crypto) { |
|
29 | - $this->site_secret = $secret; |
|
30 | - $this->crypto = $crypto; |
|
31 | - } |
|
22 | + /** |
|
23 | + * Constructor |
|
24 | + * |
|
25 | + * @param SiteSecret $secret Site secret |
|
26 | + * @param ElggCrypto $crypto Elgg crypto service |
|
27 | + */ |
|
28 | + public function __construct(SiteSecret $secret, ElggCrypto $crypto) { |
|
29 | + $this->site_secret = $secret; |
|
30 | + $this->crypto = $crypto; |
|
31 | + } |
|
32 | 32 | |
33 | - /** |
|
34 | - * Get an HMAC token builder/validator object |
|
35 | - * |
|
36 | - * @param mixed $data HMAC data or serializable data |
|
37 | - * @param string $algo Hash algorithm |
|
38 | - * @param string $key Optional key (default uses site secret) |
|
39 | - * |
|
40 | - * @return Hmac |
|
41 | - */ |
|
42 | - public function getHmac($data, $algo = 'sha256', $key = '') { |
|
43 | - if (!$key) { |
|
44 | - $key = $this->site_secret->get(true); |
|
45 | - } |
|
46 | - return new Hmac($key, [$this->crypto, 'areEqual'], $data, $algo); |
|
47 | - } |
|
33 | + /** |
|
34 | + * Get an HMAC token builder/validator object |
|
35 | + * |
|
36 | + * @param mixed $data HMAC data or serializable data |
|
37 | + * @param string $algo Hash algorithm |
|
38 | + * @param string $key Optional key (default uses site secret) |
|
39 | + * |
|
40 | + * @return Hmac |
|
41 | + */ |
|
42 | + public function getHmac($data, $algo = 'sha256', $key = '') { |
|
43 | + if (!$key) { |
|
44 | + $key = $this->site_secret->get(true); |
|
45 | + } |
|
46 | + return new Hmac($key, [$this->crypto, 'areEqual'], $data, $algo); |
|
47 | + } |
|
48 | 48 | } |
@@ -21,134 +21,134 @@ |
||
21 | 21 | */ |
22 | 22 | class ServeFileHandler { |
23 | 23 | |
24 | - /** |
|
25 | - * @var HmacFactory |
|
26 | - */ |
|
27 | - private $hmac; |
|
28 | - |
|
29 | - /** |
|
30 | - * @var Config |
|
31 | - */ |
|
32 | - private $config; |
|
33 | - |
|
34 | - /** |
|
35 | - * Constructor |
|
36 | - * |
|
37 | - * @param HmacFactory $hmac HMAC service |
|
38 | - * @param Config $config Config service |
|
39 | - */ |
|
40 | - public function __construct(HmacFactory $hmac, Config $config) { |
|
41 | - $this->hmac = $hmac; |
|
42 | - $this->config = $config; |
|
43 | - } |
|
44 | - |
|
45 | - /** |
|
46 | - * Handle a request for a file |
|
47 | - * |
|
48 | - * @param Request $request HTTP request |
|
49 | - * @return Response |
|
50 | - */ |
|
51 | - public function getResponse(Request $request) { |
|
52 | - |
|
53 | - $response = new Response(); |
|
54 | - $response->prepare($request); |
|
55 | - |
|
56 | - $path = implode('/', $request->getUrlSegments(true)); |
|
57 | - if (!preg_match('~serve-file/e(\d+)/l(\d+)/d([ia])/c([01])/([a-zA-Z0-9\-_]+)/(.*)$~', $path, $m)) { |
|
58 | - return $response->setStatusCode(400)->setContent('Malformatted request URL'); |
|
59 | - } |
|
60 | - |
|
61 | - list(, $expires, $last_updated, $disposition, $use_cookie, $mac, $path_from_dataroot) = $m; |
|
62 | - |
|
63 | - if ($expires && $expires < time()) { |
|
64 | - return $response->setStatusCode(403)->setContent('URL has expired'); |
|
65 | - } |
|
66 | - |
|
67 | - $hmac_data = [ |
|
68 | - 'expires' => (int) $expires, |
|
69 | - 'last_updated' => (int) $last_updated, |
|
70 | - 'disposition' => $disposition, |
|
71 | - 'path' => $path_from_dataroot, |
|
72 | - 'use_cookie' => (int) $use_cookie, |
|
73 | - ]; |
|
74 | - if ((bool) $use_cookie) { |
|
75 | - $hmac_data['cookie'] = $this->getCookieValue($request); |
|
76 | - } |
|
77 | - ksort($hmac_data); |
|
78 | - |
|
79 | - $hmac = $this->hmac->getHmac($hmac_data); |
|
80 | - if (!$hmac->matchesToken($mac)) { |
|
81 | - return $response->setStatusCode(403)->setContent('HMAC mistmatch'); |
|
82 | - } |
|
83 | - |
|
84 | - // Path may have been encoded to avoid problems with special chars in URLs |
|
85 | - if (0 === strpos($path_from_dataroot, ':')) { |
|
86 | - $path_from_dataroot = Base64Url::decode(substr($path_from_dataroot, 1)); |
|
87 | - } |
|
88 | - |
|
89 | - $dataroot = $this->config->getDataPath(); |
|
90 | - $filenameonfilestore = "{$dataroot}{$path_from_dataroot}"; |
|
91 | - |
|
92 | - if (!is_readable($filenameonfilestore)) { |
|
93 | - return $response->setStatusCode(404)->setContent('File not found'); |
|
94 | - } |
|
95 | - |
|
96 | - $actual_last_updated = filemtime($filenameonfilestore); |
|
97 | - if ($actual_last_updated != $last_updated) { |
|
98 | - return $response->setStatusCode(403)->setContent('URL has expired'); |
|
99 | - } |
|
100 | - |
|
101 | - $if_none_match = $request->headers->get('if_none_match'); |
|
102 | - if (!empty($if_none_match)) { |
|
103 | - // strip mod_deflate suffixes |
|
104 | - $request->headers->set('if_none_match', str_replace('-gzip', '', $if_none_match)); |
|
105 | - } |
|
106 | - |
|
107 | - $etag = '"' . $actual_last_updated . '"'; |
|
108 | - $response->setPublic()->setEtag($etag); |
|
109 | - if ($response->isNotModified($request)) { |
|
110 | - return $response; |
|
111 | - } |
|
112 | - |
|
113 | - $public = $use_cookie ? false : true; |
|
114 | - $content_disposition = $disposition == 'i' ? 'inline' : 'attachment'; |
|
115 | - |
|
116 | - $headers = [ |
|
117 | - 'Content-Type' => (new MimeTypeDetector())->getType($filenameonfilestore), |
|
118 | - ]; |
|
119 | - $response = new BinaryFileResponse($filenameonfilestore, 200, $headers, $public, $content_disposition); |
|
24 | + /** |
|
25 | + * @var HmacFactory |
|
26 | + */ |
|
27 | + private $hmac; |
|
28 | + |
|
29 | + /** |
|
30 | + * @var Config |
|
31 | + */ |
|
32 | + private $config; |
|
33 | + |
|
34 | + /** |
|
35 | + * Constructor |
|
36 | + * |
|
37 | + * @param HmacFactory $hmac HMAC service |
|
38 | + * @param Config $config Config service |
|
39 | + */ |
|
40 | + public function __construct(HmacFactory $hmac, Config $config) { |
|
41 | + $this->hmac = $hmac; |
|
42 | + $this->config = $config; |
|
43 | + } |
|
44 | + |
|
45 | + /** |
|
46 | + * Handle a request for a file |
|
47 | + * |
|
48 | + * @param Request $request HTTP request |
|
49 | + * @return Response |
|
50 | + */ |
|
51 | + public function getResponse(Request $request) { |
|
52 | + |
|
53 | + $response = new Response(); |
|
54 | + $response->prepare($request); |
|
55 | + |
|
56 | + $path = implode('/', $request->getUrlSegments(true)); |
|
57 | + if (!preg_match('~serve-file/e(\d+)/l(\d+)/d([ia])/c([01])/([a-zA-Z0-9\-_]+)/(.*)$~', $path, $m)) { |
|
58 | + return $response->setStatusCode(400)->setContent('Malformatted request URL'); |
|
59 | + } |
|
60 | + |
|
61 | + list(, $expires, $last_updated, $disposition, $use_cookie, $mac, $path_from_dataroot) = $m; |
|
62 | + |
|
63 | + if ($expires && $expires < time()) { |
|
64 | + return $response->setStatusCode(403)->setContent('URL has expired'); |
|
65 | + } |
|
66 | + |
|
67 | + $hmac_data = [ |
|
68 | + 'expires' => (int) $expires, |
|
69 | + 'last_updated' => (int) $last_updated, |
|
70 | + 'disposition' => $disposition, |
|
71 | + 'path' => $path_from_dataroot, |
|
72 | + 'use_cookie' => (int) $use_cookie, |
|
73 | + ]; |
|
74 | + if ((bool) $use_cookie) { |
|
75 | + $hmac_data['cookie'] = $this->getCookieValue($request); |
|
76 | + } |
|
77 | + ksort($hmac_data); |
|
78 | + |
|
79 | + $hmac = $this->hmac->getHmac($hmac_data); |
|
80 | + if (!$hmac->matchesToken($mac)) { |
|
81 | + return $response->setStatusCode(403)->setContent('HMAC mistmatch'); |
|
82 | + } |
|
83 | + |
|
84 | + // Path may have been encoded to avoid problems with special chars in URLs |
|
85 | + if (0 === strpos($path_from_dataroot, ':')) { |
|
86 | + $path_from_dataroot = Base64Url::decode(substr($path_from_dataroot, 1)); |
|
87 | + } |
|
88 | + |
|
89 | + $dataroot = $this->config->getDataPath(); |
|
90 | + $filenameonfilestore = "{$dataroot}{$path_from_dataroot}"; |
|
91 | + |
|
92 | + if (!is_readable($filenameonfilestore)) { |
|
93 | + return $response->setStatusCode(404)->setContent('File not found'); |
|
94 | + } |
|
95 | + |
|
96 | + $actual_last_updated = filemtime($filenameonfilestore); |
|
97 | + if ($actual_last_updated != $last_updated) { |
|
98 | + return $response->setStatusCode(403)->setContent('URL has expired'); |
|
99 | + } |
|
100 | + |
|
101 | + $if_none_match = $request->headers->get('if_none_match'); |
|
102 | + if (!empty($if_none_match)) { |
|
103 | + // strip mod_deflate suffixes |
|
104 | + $request->headers->set('if_none_match', str_replace('-gzip', '', $if_none_match)); |
|
105 | + } |
|
106 | + |
|
107 | + $etag = '"' . $actual_last_updated . '"'; |
|
108 | + $response->setPublic()->setEtag($etag); |
|
109 | + if ($response->isNotModified($request)) { |
|
110 | + return $response; |
|
111 | + } |
|
112 | + |
|
113 | + $public = $use_cookie ? false : true; |
|
114 | + $content_disposition = $disposition == 'i' ? 'inline' : 'attachment'; |
|
115 | + |
|
116 | + $headers = [ |
|
117 | + 'Content-Type' => (new MimeTypeDetector())->getType($filenameonfilestore), |
|
118 | + ]; |
|
119 | + $response = new BinaryFileResponse($filenameonfilestore, 200, $headers, $public, $content_disposition); |
|
120 | 120 | |
121 | - $sendfile_type = $this->config->getVolatile('X-Sendfile-Type'); |
|
122 | - if ($sendfile_type) { |
|
123 | - $request->headers->set('X-Sendfile-Type', $sendfile_type); |
|
121 | + $sendfile_type = $this->config->getVolatile('X-Sendfile-Type'); |
|
122 | + if ($sendfile_type) { |
|
123 | + $request->headers->set('X-Sendfile-Type', $sendfile_type); |
|
124 | 124 | |
125 | - $mapping = (string) $this->config->getVolatile('X-Accel-Mapping'); |
|
126 | - $request->headers->set('X-Accel-Mapping', $mapping); |
|
125 | + $mapping = (string) $this->config->getVolatile('X-Accel-Mapping'); |
|
126 | + $request->headers->set('X-Accel-Mapping', $mapping); |
|
127 | 127 | |
128 | - $response->trustXSendfileTypeHeader(); |
|
129 | - } |
|
128 | + $response->trustXSendfileTypeHeader(); |
|
129 | + } |
|
130 | 130 | |
131 | - $response->prepare($request); |
|
132 | - |
|
133 | - if (empty($expires)) { |
|
134 | - $expires = strtotime('+1 year'); |
|
135 | - } |
|
136 | - $expires_dt = (new DateTime())->setTimestamp($expires); |
|
137 | - $response->setExpires($expires_dt); |
|
138 | - |
|
139 | - $response->setEtag($etag); |
|
140 | - return $response; |
|
141 | - } |
|
142 | - |
|
143 | - /** |
|
144 | - * Get the session ID from the cookie |
|
145 | - * |
|
146 | - * @param Request $request Elgg request |
|
147 | - * @return string |
|
148 | - */ |
|
149 | - private function getCookieValue(Request $request) { |
|
150 | - $config = $this->config->getCookieConfig(); |
|
151 | - $session_name = $config['session']['name']; |
|
152 | - return $request->cookies->get($session_name, ''); |
|
153 | - } |
|
131 | + $response->prepare($request); |
|
132 | + |
|
133 | + if (empty($expires)) { |
|
134 | + $expires = strtotime('+1 year'); |
|
135 | + } |
|
136 | + $expires_dt = (new DateTime())->setTimestamp($expires); |
|
137 | + $response->setExpires($expires_dt); |
|
138 | + |
|
139 | + $response->setEtag($etag); |
|
140 | + return $response; |
|
141 | + } |
|
142 | + |
|
143 | + /** |
|
144 | + * Get the session ID from the cookie |
|
145 | + * |
|
146 | + * @param Request $request Elgg request |
|
147 | + * @return string |
|
148 | + */ |
|
149 | + private function getCookieValue(Request $request) { |
|
150 | + $config = $this->config->getCookieConfig(); |
|
151 | + $session_name = $config['session']['name']; |
|
152 | + return $request->cookies->get($session_name, ''); |
|
153 | + } |
|
154 | 154 | } |