Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add a more limited version of IRequest to prevent injection loops
Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 committed Sep 16, 2023
commit d8cb8358445234421189aeebf4708321e835ac26
14 changes: 7 additions & 7 deletions lib/private/AppFramework/Http/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
public const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
public const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
public const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|\[::1\])$/';

protected string $inputStream;
protected $content;
protected array $items = [];
protected array $allowedKeys = [
public const ALLOWED_KEYS = [
'get',
'post',
'files',
Expand All @@ -94,6 +90,10 @@ class Request implements \ArrayAccess, \Countable, IRequest {
'method',
'requesttoken',
];

protected string $inputStream;
protected $content;
protected array $items = [];
protected IRequestId $requestId;
protected IConfig $config;
protected ?CsrfTokenManager $csrfTokenManager;
Expand Down Expand Up @@ -132,7 +132,7 @@ public function __construct(array $vars,
$vars['method'] = 'GET';
}

foreach ($this->allowedKeys as $name) {
foreach (self::ALLOWED_KEYS as $name) {
$this->items[$name] = $vars[$name] ?? [];
}

Expand Down Expand Up @@ -276,7 +276,7 @@ public function __get($name) {
* @return bool
*/
public function __isset($name) {
if (\in_array($name, $this->allowedKeys, true)) {
if (\in_array($name, self::ALLOWED_KEYS, true)) {
return true;
}
return isset($this->items['parameters'][$name]);
Expand Down
104 changes: 104 additions & 0 deletions lib/private/AppFramework/Http/RequestVars.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Robin Appelman <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OC\AppFramework\Http;

/**
* A restricted version of IRequest that only contains the request parameters
*/
class RequestVars {
private array $items = [];

public function __construct(array $vars) {
if (!array_key_exists('method', $vars)) {
$vars['method'] = 'GET';
}

foreach (Request::ALLOWED_KEYS as $name) {
$this->items[$name] = $vars[$name] ?? [];
}

$this->items['parameters'] = array_merge(
$this->items['get'],
$this->items['post'],
$this->items['urlParams']
);
}

/**
* Returns the value for a specific http header.
*
* This method returns an empty string if the header did not exist.
*
* @param string $name
* @return string
*/
public function getHeader(string $name): string {
$server = $this->items['server'];
$name = strtoupper(str_replace('-', '_', $name));
if (isset($server['HTTP_' . $name])) {
return $server['HTTP_' . $name];
}

// There's a few headers that seem to end up in the top-level
// server array.
switch ($name) {
case 'CONTENT_TYPE':
case 'CONTENT_LENGTH':
case 'REMOTE_ADDR':
if (isset($server[$name])) {
return $server[$name];
}
break;
}

return '';
}

/**
* Returns the method of the request
*
* @return string the method of the request (POST, GET, etc)
*/
public function getMethod(): string {
return $this->items['method'];
}

/**
* Lets you access post and get parameters by the index
* In case of json requests the encoded json body is accessed
*
* @param string $key the key which you want to access in the URL Parameter
* placeholder, $_POST or $_GET array.
* The priority how they're returned is the following:
* 1. URL parameters
* 2. POST parameters
* 3. GET parameters
* @param mixed $default If the key is not found, this value will be returned
* @return mixed the content of the array
*/
public function getParam(string $key, $default = null) {
$parameters = $this->items['parameters'];
return $parameters[$key] ?? $default;
}
}
22 changes: 22 additions & 0 deletions lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
use OC\AppFramework\Bootstrap\Coordinator;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Http\RequestId;
use OC\AppFramework\Http\RequestVars;
use OC\AppFramework\Utility\TimeFactory;
use OC\Authentication\Events\LoginFailed;
use OC\Authentication\Listeners\LoginFailedListener;
Expand Down Expand Up @@ -984,6 +985,27 @@ public function __construct($webRoot, \OC\Config $config) {
$c->get(IMimeTypeDetector::class)
);
});
$this->registerService(RequestVars::class, function (ContainerInterface $c) {
if (isset($this['urlParams'])) {
$urlParams = $this['urlParams'];
} else {
$urlParams = [];
}

return new RequestVars(
[
'get' => $_GET,
'post' => $_POST,
'files' => $_FILES,
'server' => $_SERVER,
'env' => $_ENV,
'cookies' => $_COOKIE,
'method' => (isset($_SERVER) && isset($_SERVER['REQUEST_METHOD']))
? $_SERVER['REQUEST_METHOD']
: '',
'urlParams' => $urlParams,
]);
});
$this->registerService(\OCP\IRequest::class, function (ContainerInterface $c) {
if (isset($this['urlParams'])) {
$urlParams = $this['urlParams'];
Expand Down