1 | <?php |
||||||
2 | declare(strict_types=1); |
||||||
3 | defined('BASEPATH') OR exit('No direct script access allowed'); |
||||||
4 | |||||||
5 | require_once('RESTAuth.php'); |
||||||
6 | require_once('RESTResponse.php'); |
||||||
7 | require_once('RESTExceptions.php'); |
||||||
8 | |||||||
9 | class REST |
||||||
10 | { |
||||||
11 | /** |
||||||
12 | * [private description] |
||||||
13 | * @var [type] |
||||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
Loading history...
|
|||||||
14 | */ |
||||||
15 | private $ci; |
||||||
16 | |||||||
17 | /** |
||||||
18 | * [private description] |
||||||
19 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
20 | */ |
||||||
21 | private $api_key_limit_column; |
||||||
22 | |||||||
23 | /** |
||||||
24 | * [private description] |
||||||
25 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
26 | */ |
||||||
27 | private $api_key_column; |
||||||
28 | |||||||
29 | /** |
||||||
30 | * [private description] |
||||||
31 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
32 | */ |
||||||
33 | private $per_hour; |
||||||
34 | |||||||
35 | /** |
||||||
36 | * [private description] |
||||||
37 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
38 | */ |
||||||
39 | private $ip_per_hour; |
||||||
40 | |||||||
41 | /** |
||||||
42 | * [private description] |
||||||
43 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
44 | */ |
||||||
45 | private $show_header; |
||||||
46 | |||||||
47 | /** |
||||||
48 | * [private description] |
||||||
49 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
50 | */ |
||||||
51 | private $whitelist; |
||||||
52 | |||||||
53 | /** |
||||||
54 | * [private description] |
||||||
55 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
56 | */ |
||||||
57 | private $checked_rate_limit = false; |
||||||
58 | |||||||
59 | /** |
||||||
60 | * [private description] |
||||||
61 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
62 | */ |
||||||
63 | private $header_prefix; |
||||||
64 | |||||||
65 | /** |
||||||
66 | * [private description] |
||||||
67 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
68 | */ |
||||||
69 | private $limit_api; |
||||||
70 | |||||||
71 | /** |
||||||
72 | * [public description] |
||||||
73 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
74 | */ |
||||||
75 | public $userId; |
||||||
76 | |||||||
77 | /** |
||||||
78 | * [public description] |
||||||
79 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
80 | */ |
||||||
81 | public $apiKey; |
||||||
82 | |||||||
83 | /** |
||||||
84 | * [public description] |
||||||
85 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
86 | */ |
||||||
87 | public $apiKeyHeader; |
||||||
88 | |||||||
89 | /** |
||||||
90 | * [public description] |
||||||
91 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
92 | */ |
||||||
93 | public $token; |
||||||
94 | |||||||
95 | /** |
||||||
96 | * [public description] |
||||||
97 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
98 | */ |
||||||
99 | public $allowedIps; |
||||||
100 | |||||||
101 | /** |
||||||
102 | * [public description] |
||||||
103 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
104 | */ |
||||||
105 | public $config; |
||||||
106 | |||||||
107 | /** |
||||||
108 | * [public description] |
||||||
109 | * @var [type] |
||||||
0 ignored issues
–
show
|
|||||||
110 | */ |
||||||
111 | public $authPreempted = false; |
||||||
112 | |||||||
113 | /** |
||||||
114 | * [PACKAGE description] |
||||||
115 | * @var string |
||||||
116 | */ |
||||||
117 | const PACKAGE = "francis94c/ci-rest"; |
||||||
118 | |||||||
119 | /** |
||||||
120 | * [RATE_LIMIT description] |
||||||
121 | * @var string |
||||||
122 | */ |
||||||
123 | const RATE_LIMIT = "RateLimit"; |
||||||
124 | |||||||
125 | /** |
||||||
126 | * [AUTH_GRAVITY description] |
||||||
127 | * @var integer |
||||||
128 | */ |
||||||
129 | const AUTH_GRAVITY = 0b100; |
||||||
130 | const AUTH_PASSIVE = 0b010; |
||||||
131 | const AUTH_FINAL = 0b001; |
||||||
132 | |||||||
133 | /** |
||||||
134 | * [__construct This is the part of the code that takes care of all |
||||||
135 | * authentiations. allowing you to focus on building wonderful things at REST. |
||||||
136 | * pun intended ;-)] |
||||||
137 | * @param array|null $params Initialization parameters from the Slint system. |
||||||
138 | * There's no use for this arg yet. |
||||||
139 | */ |
||||||
140 | function __construct(?array $params=null) |
||||||
141 | { |
||||||
142 | $this->ci =& get_instance(); |
||||||
0 ignored issues
–
show
The function
get_instance was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
143 | |||||||
144 | if ($this->ci->input->is_cli_request()) return; |
||||||
145 | |||||||
146 | // Load Config If Exists. |
||||||
147 | //$this->ci->config->load('rest', true, true); |
||||||
148 | if (is_file(APPPATH . 'config/rest.php')) { |
||||||
0 ignored issues
–
show
|
|||||||
149 | include APPPATH . 'config/rest.php'; |
||||||
150 | } else { |
||||||
151 | $config = []; |
||||||
152 | } |
||||||
153 | |||||||
154 | $this->config = $config; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
155 | |||||||
156 | // Load Database. |
||||||
157 | $this->ci->load->database(); |
||||||
158 | |||||||
159 | // load URL Helper |
||||||
160 | $this->ci->load->helper('url'); |
||||||
161 | |||||||
162 | // Load REST Helper. |
||||||
163 | $this->ci->load->splint(self::PACKAGE, '%rest'); |
||||||
164 | |||||||
165 | // Load Model. |
||||||
166 | $this->ci->load->splint(self::PACKAGE, '*RESTModel', 'rest_model'); |
||||||
167 | $this->rest_model =& $this->ci->rest_model; |
||||||
0 ignored issues
–
show
|
|||||||
168 | |||||||
169 | $this->rest_model->init([ |
||||||
170 | 'users_table' => $config['basic_auth']['users_table'] ?? null, |
||||||
171 | 'users_id_column' => $config['basic_auth']['id_column'] ?? null, |
||||||
172 | 'users_username_column' => $config['basic_auth']['username_column'] ?? null, |
||||||
173 | 'users_email_column' => $config['basic_auth']['email_column'] ?? null, |
||||||
174 | 'users_password_column' => $config['basic_auth']['password_column'] ?? null, |
||||||
175 | 'api_key_table' => $config['api_key_auth']['api_key_table'] ?? null, |
||||||
176 | 'api_key_column' => $config['api_key_auth']['api_key_column'] ?? null, |
||||||
177 | 'api_key_limit_column' => $config['api_key_auth']['api_key_limit_column'] ?? null |
||||||
178 | ]); |
||||||
179 | |||||||
180 | // Load Variable(s) from Config. |
||||||
181 | $this->allowedIps = $config['allowed_ips'] ?? ['127.0.0.1', '[::1]']; |
||||||
182 | $this->apiKeyHeader = $config['api_key_header'] ?? 'X-API-KEY'; |
||||||
183 | $this->api_key_limit_column = $config['api_key_auth']['api_key_limit_column'] ?? null; |
||||||
184 | $this->api_key_column = $config['api_key_auth']['api_key_column'] ?? null; |
||||||
185 | $this->limit_api = $config['api_limiter']['api_limiter'] ?? false; |
||||||
186 | $this->per_hour = $config['api_limiter']['per_hour'] ?? 100; |
||||||
187 | $this->ip_per_hour = $config['api_limiter']['ip_per_hour'] ?? 50; |
||||||
188 | $this->show_header = $config['api_limiter']['show_header'] ?? null; |
||||||
189 | $this->whitelist = $config['api_limiter']['whitelist'] ?? []; |
||||||
190 | $this->header_prefix = $config['api_limiter']['header_prefix'] ?? 'X-RateLimit-'; |
||||||
191 | |||||||
192 | // Limit Only? |
||||||
193 | //if ($this->config['api_limiter']['api_limit_only'] ?? false) { |
||||||
194 | //return; |
||||||
195 | //} |
||||||
196 | |||||||
197 | // Authenticate |
||||||
198 | if ($this->ci->uri->total_segments() > 0) { |
||||||
199 | $this->authenticate(); |
||||||
200 | } |
||||||
201 | |||||||
202 | // Generic Rate Limiter. |
||||||
203 | if ($this->limit_api && !$this->checked_rate_limit && |
||||||
204 | ($config['api_limiter']['limit_by_ip'] ?? false)) { |
||||||
205 | $this->api_rest_limit_by_ip_address(); |
||||||
206 | } |
||||||
207 | |||||||
208 | log_message('debug', 'REST Request Authenticated and REST Library Initialized.'); |
||||||
0 ignored issues
–
show
The function
log_message was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
209 | } |
||||||
210 | |||||||
211 | /** |
||||||
212 | * [authenticate description] |
||||||
213 | * @date 2020-01-30 |
||||||
214 | */ |
||||||
215 | private function authenticate():void |
||||||
216 | { |
||||||
217 | $auths = null; |
||||||
0 ignored issues
–
show
|
|||||||
218 | $auths = $this->config['auth'] ?? null; |
||||||
219 | if ($auths) $auths = is_array($auths) ? $auths : [$auths]; |
||||||
220 | |||||||
221 | if (!$auths) return; // No authentication(s) to carry out. |
||||||
222 | |||||||
223 | /** |
||||||
224 | * $this->process_auth() terminates the script if authentication fails |
||||||
225 | * It will call the callable in the rest.php config file under |
||||||
226 | * response_callbacks which matches the necesarry RESTResponse constant |
||||||
227 | * before exiting. Which callable is called in any situation is documented |
||||||
228 | * in README.md |
||||||
229 | */ |
||||||
230 | |||||||
231 | foreach ($auths as $key => $auth) { |
||||||
232 | if ($this->authPreempted) break; |
||||||
233 | if (is_numeric($key)) { |
||||||
234 | $this->process_auth($auth, self::AUTH_GRAVITY); |
||||||
235 | } else { |
||||||
236 | $this->process_auth($key, $auth); |
||||||
237 | } |
||||||
238 | } |
||||||
239 | } |
||||||
240 | |||||||
241 | /** |
||||||
242 | * [process_auth description] |
||||||
243 | * @date 2020-04-07 |
||||||
244 | * @param string $auth [description] |
||||||
245 | * @param int $flags [description] |
||||||
246 | */ |
||||||
247 | private function process_auth(string &$auth, int $flags):void |
||||||
248 | { |
||||||
249 | switch ($auth) { |
||||||
250 | case RESTAuth::IP: $this->ip_auth($flags); break; |
||||||
251 | case RESTAuth::BASIC: $this->basic_auth($flags); break; |
||||||
252 | case RESTAuth::API_KEY: $this->api_key_auth($flags); break; |
||||||
253 | case RESTAuth::OAUTH2: $this->bearer_auth(RESTAuth::OAUTH2, $flags); break; |
||||||
254 | case RESTAuth::BEARER: $this->bearer_auth(RESTAuth::BEARER, $flags); break; |
||||||
255 | case RESTAuth::SECRET: $this->bearer_auth(RESTAuth::SECRET, $flags); break; |
||||||
256 | default: $this->custom_auth($auth, $flags); |
||||||
0 ignored issues
–
show
The call to
REST::custom_auth() has too many arguments starting with $flags .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||||
257 | } |
||||||
258 | } |
||||||
259 | |||||||
260 | /** |
||||||
261 | * [auth_proceed description] |
||||||
262 | * @date 2020-04-07 |
||||||
263 | * @param bool $success [description] |
||||||
264 | * @param int $flags [description] |
||||||
265 | * @return bool [description] |
||||||
266 | */ |
||||||
267 | private function auth_proceed(bool $success, int $flags):bool |
||||||
268 | { |
||||||
269 | if ($flags & self::AUTH_GRAVITY) return $success; |
||||||
270 | if ($success) { |
||||||
271 | if ($flags & self::AUTH_FINAL) { |
||||||
272 | $this->authPreempted = true; |
||||||
273 | return true; |
||||||
274 | } |
||||||
0 ignored issues
–
show
The function implicitly returns
null when the if condition on line 271 is false . This is incompatible with the type-hinted return boolean . Consider adding a return statement or allowing null as return value.
For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example: interface ReturnsInt {
public function returnsIntHinted(): int;
}
class MyClass implements ReturnsInt {
public function returnsIntHinted(): int
{
if (foo()) {
return 123;
}
// here: null is implicitly returned
}
}
Loading history...
|
|||||||
275 | } else { |
||||||
276 | return $flags & self::AUTH_PASSIVE ? true : false; |
||||||
277 | } |
||||||
278 | } |
||||||
279 | |||||||
280 | /** |
||||||
281 | * [ip_auth description] |
||||||
282 | * @date 2020-04-07 |
||||||
283 | * @param int $flags [description] |
||||||
284 | */ |
||||||
285 | private function ip_auth(int $flags):void |
||||||
286 | { |
||||||
287 | if (!$this->auth_proceed(in_array($this->ci->input->ip_address(), $this->allowedIps), $flags)) { |
||||||
288 | $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::IP); // Exits. |
||||||
289 | } |
||||||
290 | } |
||||||
291 | |||||||
292 | /** |
||||||
293 | * [bearer_auth description] |
||||||
294 | * @date 2020-04-07 |
||||||
295 | * @param string $auth [description] |
||||||
296 | * @param int $flags [description] |
||||||
297 | */ |
||||||
298 | private function bearer_auth(string $auth, int $flags):void |
||||||
299 | { |
||||||
300 | $authorization = $this->get_authorization_header(); |
||||||
301 | $shouldProceed = $this->auth_proceed(false, $flags); |
||||||
302 | if ($authorization == null || substr_count($authorization, ' ') != 1) { |
||||||
0 ignored issues
–
show
|
|||||||
303 | if ($shouldProceed) return; |
||||||
304 | $this->handle_response(RESTResponse::BAD_REQUEST, $auth, 'Bad Request'); // Exits. |
||||||
305 | } |
||||||
306 | $token = explode(" ", $authorization); |
||||||
307 | if ($token[0] != $auth) { |
||||||
308 | if ($shouldProceed) return; |
||||||
309 | $this->handle_response(RESTResponse::BAD_REQUEST, $auth, 'Bad Request'); // Exits. |
||||||
310 | } |
||||||
311 | $this->token = $token[1]; |
||||||
312 | // Call Up Custom Implemented Bearer/Token Authorization. |
||||||
313 | // Callback Check. |
||||||
314 | if (!isset($this->config['auth_callbacks'][$auth])) { |
||||||
315 | $this->handle_response(RESTResponse::NOT_IMPLEMENTED, $auth); // Exits. |
||||||
316 | } |
||||||
317 | // Authorization. |
||||||
318 | if (!$this->auth_proceed($this->config['auth_callbacks'][$auth]($this, $this->token), $flags)) { |
||||||
319 | $this->handle_response(RESTResponse::UN_AUTHORIZED, $auth); // Exits. |
||||||
320 | } |
||||||
321 | } |
||||||
322 | |||||||
323 | /** |
||||||
324 | * [basic_auth description] |
||||||
325 | * @date 2020-04-07 |
||||||
326 | * @param int $flags [description] |
||||||
327 | */ |
||||||
328 | private function basic_auth(int $flags):void |
||||||
329 | { |
||||||
330 | $username = $_SERVER['PHP_AUTH_USER'] ?? null; |
||||||
331 | $password = $_SERVER['PHP_AUTH_PW'] ?? null; |
||||||
332 | if (!$this->auth_proceed(!$username || !$password, $flags)) $this->handle_response(RESTResponse::BAD_REQUEST, RESTAuth::BASIC); // Exits. |
||||||
333 | if (!$this->auth_proceed($this->rest_model->basicAuth($this, $username, $password), $flags)) $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::BASIC); // Exits. |
||||||
334 | } |
||||||
335 | /** |
||||||
336 | * [api_key_auth description] |
||||||
337 | */ |
||||||
338 | private function api_key_auth(int $flags=self::AUTH_GRAVITY):void |
||||||
339 | { |
||||||
340 | if (uri_string() == '') return; |
||||||
0 ignored issues
–
show
The function
uri_string was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
341 | $shouldProceed = $this->auth_proceed(false, $flags); |
||||||
342 | |||||||
343 | if (!$this->ci->input->get_request_header($this->apiKeyHeader, true) && !$shouldProceed) { |
||||||
344 | // if (!isset($_SERVER['HTTP_' . str_replace("-", "_", $this->apiKeyHeader)])) { |
||||||
345 | $this->handle_response(RESTResponse::BAD_REQUEST, RESTAuth::API_KEY); // Exits. |
||||||
346 | } |
||||||
347 | |||||||
348 | $apiKey = $this->rest_model->getAPIKeyData( |
||||||
349 | $this->ci->input->get_request_header($this->apiKeyHeader, true) |
||||||
350 | ); |
||||||
351 | |||||||
352 | if ($apiKey == null && !$shouldProceed) { |
||||||
353 | $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::API_KEY); // Exits. |
||||||
354 | } |
||||||
355 | |||||||
356 | $this->apiKey = $apiKey; |
||||||
357 | |||||||
358 | if (!$this->auth_proceed(true, $flags)) return; |
||||||
359 | |||||||
360 | // ==== API KEY Auth Passed ==== // |
||||||
361 | |||||||
362 | if ($this->limit_api && $this->api_key_limit_column != null && $apiKey->{$this->api_key_limit_column} == 1) { |
||||||
363 | $this->limitAPIKey($apiKey->{$this->api_key_column}); |
||||||
364 | } |
||||||
365 | |||||||
366 | $this->checked_rate_limit = true; // Ignore Limit By IP. |
||||||
367 | } |
||||||
368 | |||||||
369 | /** |
||||||
370 | * [limitAPIKey description] |
||||||
371 | * @date 2020-04-08 |
||||||
372 | * @param string $apiKey [description] |
||||||
373 | */ |
||||||
374 | public function limitAPIKey(string $apiKey):void |
||||||
375 | { |
||||||
376 | // Trunctate Rate Limit Data. |
||||||
377 | $this->rest_model->truncateRatelimitData(); |
||||||
378 | // Check Whitelist. |
||||||
379 | if (in_array($this->ci->input->ip_address(), $this->whitelist)) { |
||||||
380 | $this->checked_rate_limit = true; // Ignore Limit By IP. |
||||||
381 | return; |
||||||
382 | } |
||||||
383 | // Should we acyually Limit? |
||||||
384 | if ($this->per_hour > 0) { |
||||||
385 | $client = hash('md5', $this->ci->input->ip_address() . "%" . $apiKey); |
||||||
386 | $limitData = $this->rest_model->getLimitData($client, '_api_keyed_user'); |
||||||
387 | if ($limitData == null) { |
||||||
388 | $limitData = []; |
||||||
389 | $limitData['count'] = 0; |
||||||
390 | $limitData['reset_epoch'] = gmdate('d M Y H:i:s', time() + (60 * 60)); |
||||||
391 | $limitData['start'] = date('d M Y H:i:s'); |
||||||
392 | } |
||||||
393 | if ($this->per_hour - $limitData['count'] > 0) { |
||||||
394 | if (!$this->rest_model->insertLimitData($client, '_api_keyed_user')) { |
||||||
395 | $this->handle_response(RESTResponse::INTERNAL_SERVER_ERROR, self::RATE_LIMIT); // Exits. |
||||||
396 | } |
||||||
397 | ++$limitData['count']; |
||||||
398 | if ($this->show_header) { |
||||||
399 | header($this->header_prefix.'Limit: '.$this->per_hour); |
||||||
400 | header($this->header_prefix.'Remaining: '.($this->per_hour - $limitData['count'])); |
||||||
401 | header($this->header_prefix.'Reset: '.strtotime($limitData['reset_epoch'])); |
||||||
402 | } |
||||||
403 | } else { |
||||||
404 | header('Retry-After: '.(strtotime($limitData['reset_epoch']) - strtotime(gmdate('d M Y H:i:s')))); |
||||||
405 | $this->handle_response(RESTResponse::TOO_MANY_REQUESTS, self::RATE_LIMIT); // Exits. |
||||||
406 | } |
||||||
407 | } |
||||||
408 | } |
||||||
409 | |||||||
410 | /** |
||||||
411 | * [api_rest_limit_by_ip_address description] |
||||||
412 | * TODO: Implement. |
||||||
413 | */ |
||||||
414 | private function api_rest_limit_by_ip_address():void |
||||||
415 | { |
||||||
416 | // Trunctate Rate Limit Data. |
||||||
417 | $this->rest_model->truncateRatelimitData(); |
||||||
418 | // Check Whitelist. |
||||||
419 | if (in_array($this->ci->input->ip_address(), $this->whitelist)) return; |
||||||
420 | // Should we acyually Limit? |
||||||
421 | if ($this->ip_per_hour > 0) { |
||||||
422 | $client = hash('md5', $this->ci->input->ip_address()); |
||||||
423 | $limitData = $this->rest_model->getLimitData($client, '_ip_address'); |
||||||
424 | if ($limitData == null) { |
||||||
425 | $limitData = []; |
||||||
426 | $limitData['count'] = 0; |
||||||
427 | $limitData['reset_epoch'] = gmdate('d M Y H:i:s', time() + (60 * 60)); |
||||||
428 | $limitData['start'] = date('d M Y H:i:s'); |
||||||
429 | } |
||||||
430 | if ($this->ip_per_hour - $limitData['count'] > 0) { |
||||||
431 | if (!$this->rest_model->insertLimitData($client, '_ip_address')) { |
||||||
432 | $this->handle_response(RESTResponse::INTERNAL_SERVER_ERROR, self::RATE_LIMIT); // Exits. |
||||||
433 | } |
||||||
434 | ++$limitData['count']; |
||||||
435 | if ($this->show_header) { |
||||||
436 | header($this->header_prefix.'Limit: '.$this->ip_per_hour); |
||||||
437 | header($this->header_prefix.'Remaining: '.($this->ip_per_hour - $limitData['count'])); |
||||||
438 | header($this->header_prefix.'Reset: '.strtotime($limitData['reset_epoch'])); |
||||||
439 | } |
||||||
440 | } else { |
||||||
441 | header('Retry-After: '.(strtotime($limitData['reset_epoch']) - strtotime(gmdate('d M Y H:i:s')))); |
||||||
442 | $this->handle_response(RESTResponse::TOO_MANY_REQUESTS, self::RATE_LIMIT); // Exits. |
||||||
443 | } |
||||||
444 | } |
||||||
445 | } |
||||||
446 | /** |
||||||
447 | * [custom_auth description] |
||||||
448 | * @param string $auth [description] |
||||||
449 | */ |
||||||
450 | private function custom_auth(string &$auth):void |
||||||
451 | { |
||||||
452 | // Header Check. |
||||||
453 | if (!isset($_SERVER[$auth])) { |
||||||
454 | $this->handle_response(RESTResponse::BAD_REQUEST, $auth); |
||||||
455 | } |
||||||
456 | // Callback Check. |
||||||
457 | if (!isset($this->config['auth_callbacks'][$auth])) { |
||||||
458 | $this->handle_response(RESTResponse::NOT_IMPLEMENTED, $auth); // Exits. |
||||||
459 | } |
||||||
460 | // Authentication. |
||||||
461 | if (!$this->config['auth_callbacks'][$auth]($this, $this->ci->security->xss_clean($_SERVER[$auth]))) { |
||||||
462 | $this->handle_response(RESTResponse::UN_AUTHORIZED, $auth); // Exits. |
||||||
463 | } |
||||||
464 | } |
||||||
465 | /** |
||||||
466 | * [get_authorization_header description] |
||||||
467 | * @return [type] [description] |
||||||
0 ignored issues
–
show
|
|||||||
468 | */ |
||||||
469 | private function get_authorization_header():?string |
||||||
470 | { |
||||||
471 | if (isset($_SERVER['Authorization'])) { |
||||||
472 | return trim($_SERVER["Authorization"]); |
||||||
473 | } else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI |
||||||
474 | return trim($_SERVER["HTTP_AUTHORIZATION"]); |
||||||
475 | } elseif (function_exists('apache_request_headers')) { |
||||||
476 | $requestHeaders = apache_request_headers(); |
||||||
477 | |||||||
478 | // Avoid Surprises. |
||||||
479 | $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders)); |
||||||
0 ignored issues
–
show
It seems like
$requestHeaders can also be of type false ; however, parameter $input of array_keys() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
$requestHeaders can also be of type false ; however, parameter $input of array_values() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
480 | |||||||
481 | if (isset($requestHeaders['Authorization'])) { |
||||||
482 | return trim($requestHeaders['Authorization']); |
||||||
483 | } |
||||||
484 | } |
||||||
485 | return null; |
||||||
486 | } |
||||||
487 | |||||||
488 | /** |
||||||
489 | * [handle_response description] |
||||||
490 | * @param int $code [description] |
||||||
491 | */ |
||||||
492 | private function handle_response(int $code, $auth=null, ?string $errorReason=null):void |
||||||
493 | { |
||||||
494 | http_response_code($code); |
||||||
495 | header("Content-Type: application/json"); |
||||||
496 | if (isset($this->config['response_callbacks'][$code])) { |
||||||
497 | $this->config['response_callbacks'][$code]($auth, $errorReason); |
||||||
498 | } |
||||||
499 | if (ENVIRONMENT != 'testing') exit($code); |
||||||
0 ignored issues
–
show
|
|||||||
500 | throw new Exception("Error $code in $auth", $code); |
||||||
501 | } |
||||||
502 | } |
||||||
503 | ?> |
||||||
0 ignored issues
–
show
It is not recommended to use PHP's closing tag
?> in files other than templates.
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore. A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.
Loading history...
|
|||||||
504 |