Merge pull request #11680 from nupplaphil/feat/log_forward

Respect Forwarded-For headers
This commit is contained in:
Hypolite Petovan 2022-06-24 10:12:19 -04:00 committed by GitHub
commit 4cdc0ef267
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 411 additions and 43 deletions

152
src/App/Request.php Normal file
View file

@ -0,0 +1,152 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @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 <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\App;
use Friendica\Core\Config\Capability\IManageConfigValues;
/**
* Container for the whole request
*
* @see https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface
*
* @todo future container class for whole requests, currently it's not :-)
*/
class Request
{
/**
* A comma separated list of default headers that could contain the client IP in a proxy request
*
* @var string
*/
const DEFAULT_FORWARD_FOR_HEADER = 'HTTP_X_FORWARDED_FOR';
/** @var string The remote IP address of the current request */
protected $remoteAddress;
/**
* @return string The remote IP address of the current request
*
* Do always use this instead of $_SERVER['REMOTE_ADDR']
*/
public function getRemoteAddress(): string
{
return $this->remoteAddress;
}
public function __construct(IManageConfigValues $config, array $server = [])
{
$this->remoteAddress = $this->determineRemoteAddress($config, $server);
}
/**
* Checks if given $remoteAddress matches given $trustedProxy.
* If $trustedProxy is an IPv4 IP range given in CIDR notation, true will be returned if
* $remoteAddress is an IPv4 address within that IP range.
* Otherwise, $remoteAddress will be compared to $trustedProxy literally and the result
* will be returned.
*
* @param string $trustedProxy The current, trusted proxy to check
* @param string $remoteAddress The current remote IP address
*
*
* @return boolean true if $remoteAddress matches $trustedProxy, false otherwise
*/
protected function matchesTrustedProxy(string $trustedProxy, string $remoteAddress): bool
{
$cidrre = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2})$/';
if (preg_match($cidrre, $trustedProxy, $match)) {
$net = $match[1];
$shiftbits = min(32, max(0, 32 - intval($match[2])));
$netnum = ip2long($net) >> $shiftbits;
$ipnum = ip2long($remoteAddress) >> $shiftbits;
return $ipnum === $netnum;
}
return $trustedProxy === $remoteAddress;
}
/**
* Checks if given $remoteAddress matches any entry in the given array $trustedProxies.
* For details regarding what "match" means, refer to `matchesTrustedProxy`.
*
* @param string[] $trustedProxies A list of the trusted proxies
* @param string $remoteAddress The current remote IP address
*
* @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise
*/
protected function isTrustedProxy(array $trustedProxies, string $remoteAddress): bool
{
foreach ($trustedProxies as $tp) {
if ($this->matchesTrustedProxy($tp, $remoteAddress)) {
return true;
}
}
return false;
}
/**
* Determines the remote address, if the connection came from a trusted proxy
* and `forwarded_for_headers` has been configured then the IP address
* specified in this header will be returned instead.
*
* @param IManageConfigValues $config
* @param array $server The $_SERVER array
*
* @return string
*/
protected function determineRemoteAddress(IManageConfigValues $config, array $server): string
{
$remoteAddress = $server['REMOTE_ADDR'] ?? '0.0.0.0';
$trustedProxies = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'trusted_proxies', ''));
if (\is_array($trustedProxies) && $this->isTrustedProxy($trustedProxies, $remoteAddress)) {
$forwardedForHeaders = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'forwarded_for_headers', static::DEFAULT_FORWARD_FOR_HEADER));
foreach ($forwardedForHeaders as $header) {
if (isset($server[$header])) {
foreach (explode(',', $server[$header]) as $IP) {
$IP = trim($IP);
// remove brackets from IPv6 addresses
if (strpos($IP, '[') === 0 && substr($IP, -1) === ']') {
$IP = substr($IP, 1, -1);
}
// skip trusted proxies in the list itself
if ($this->isTrustedProxy($trustedProxies, $IP)) {
continue;
}
if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
return $IP;
}
}
}
}
}
return $remoteAddress;
}
}

View file

@ -21,6 +21,7 @@
namespace Friendica\Core\Logger\Type\Monolog; namespace Friendica\Core\Logger\Type\Monolog;
use Friendica\App\Request;
use Monolog\Handler; use Monolog\Handler;
use Monolog\Logger; use Monolog\Logger;
@ -38,15 +39,22 @@ class DevelopHandler extends Handler\AbstractHandler
private $developerIp; private $developerIp;
/** /**
* @param string $developerIp The IP of the developer who wants to debug * @var string The IP of the current request
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($developerIp, $level = Logger::DEBUG, bool $bubble = true) private $remoteAddress;
/**
* @param Request $request The current http request
* @param string $developerIp The IP of the developer who wants to debug
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true)
{ {
parent::__construct($level, $bubble); parent::__construct($level, $bubble);
$this->developerIp = $developerIp; $this->developerIp = $developerIp;
$this->remoteAddress = $request->getRemoteAddress();
} }
/** /**
@ -59,7 +67,7 @@ class DevelopHandler extends Handler\AbstractHandler
} }
/// Just in case the remote IP is the same as the developer IP log the output /// Just in case the remote IP is the same as the developer IP log the output
if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp) { if (!is_null($this->developerIp) && $this->remoteAddress != $this->developerIp) {
return false; return false;
} }

View file

@ -52,12 +52,12 @@ class Cookie
private $data; private $data;
/** /**
* @param App\Request $request The current http request
* @param IManageConfigValues $config * @param IManageConfigValues $config
* @param App\BaseURL $baseURL * @param App\BaseURL $baseURL
* @param array $SERVER The $_SERVER array
* @param array $COOKIE The $_COOKIE array * @param array $COOKIE The $_COOKIE array
*/ */
public function __construct(IManageConfigValues $config, App\BaseURL $baseURL, array $SERVER = [], array $COOKIE = []) public function __construct(App\Request $request, IManageConfigValues $config, App\BaseURL $baseURL, array $COOKIE = [])
{ {
$this->sslEnabled = $baseURL->getSSLPolicy() === App\BaseURL::SSL_POLICY_FULL; $this->sslEnabled = $baseURL->getSSLPolicy() === App\BaseURL::SSL_POLICY_FULL;
$this->sitePrivateKey = $config->get('system', 'site_prvkey'); $this->sitePrivateKey = $config->get('system', 'site_prvkey');
@ -66,7 +66,7 @@ class Cookie
self::DEFAULT_EXPIRE); self::DEFAULT_EXPIRE);
$this->lifetime = $authCookieDays * 24 * 60 * 60; $this->lifetime = $authCookieDays * 24 * 60 * 60;
$this->remoteAddr = ($SERVER['REMOTE_ADDR'] ?? null) ?: '0.0.0.0'; $this->remoteAddr = $request->getRemoteAddress();
$this->data = json_decode($COOKIE[self::NAME] ?? '[]', true) ?: []; $this->data = json_decode($COOKIE[self::NAME] ?? '[]', true) ?: [];
} }

View file

@ -21,14 +21,29 @@
namespace Friendica\Module\HTTPException; namespace Friendica\Module\HTTPException;
use Friendica\App;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\DI; use Friendica\DI;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
class PageNotFound extends BaseModule class PageNotFound extends BaseModule
{ {
/** @var string */
private $remoteAddress;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->remoteAddress = $request->getRemoteAddress();
}
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.')); throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.'));
@ -58,7 +73,7 @@ class PageNotFound extends BaseModule
$this->logger->debug('index.php: page not found.', [ $this->logger->debug('index.php: page not found.', [
'request_uri' => $this->server['REQUEST_URI'], 'request_uri' => $this->server['REQUEST_URI'],
'address' => $this->server['REMOTE_ADDR'], 'address' => $this->remoteAddress,
'query' => $this->server['QUERY_STRING'] 'query' => $this->server['QUERY_STRING']
]); ]);

View file

@ -21,11 +21,13 @@
namespace Friendica\Module\Search; namespace Friendica\Module\Search;
use Friendica\App;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Content\Text\HTML; use Friendica\Content\Text\HTML;
use Friendica\Content\Widget; use Friendica\Content\Widget;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\L10n;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Search; use Friendica\Core\Search;
@ -37,11 +39,24 @@ use Friendica\Model\Item;
use Friendica\Model\Post; use Friendica\Model\Post;
use Friendica\Model\Tag; use Friendica\Model\Tag;
use Friendica\Module\BaseSearch; use Friendica\Module\BaseSearch;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Network; use Friendica\Util\Network;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
class Index extends BaseSearch class Index extends BaseSearch
{ {
/** @var string */
private $remoteAddress;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->remoteAddress = $request->getRemoteAddress();
}
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
$search = (!empty($_GET['q']) ? trim(rawurldecode($_GET['q'])) : ''); $search = (!empty($_GET['q']) ? trim(rawurldecode($_GET['q'])) : '');
@ -66,7 +81,7 @@ class Index extends BaseSearch
if ($crawl_permit_period == 0) if ($crawl_permit_period == 0)
$crawl_permit_period = 10; $crawl_permit_period = 10;
$remote = $_SERVER['REMOTE_ADDR']; $remote = $this->remoteAddress;
$result = DI::cache()->get('remote_search:' . $remote); $result = DI::cache()->get('remote_search:' . $remote);
if (!is_null($result)) { if (!is_null($result)) {
$resultdata = json_decode($result); $resultdata = json_decode($result);

View file

@ -64,6 +64,8 @@ class Authentication
private $session; private $session;
/** @var IManagePersonalConfigValues */ /** @var IManagePersonalConfigValues */
private $pConfig; private $pConfig;
/** @var string */
private $remoteAddress;
/** /**
* Sets the X-Account-Management-Status header * Sets the X-Account-Management-Status header
@ -80,27 +82,29 @@ class Authentication
/** /**
* Authentication constructor. * Authentication constructor.
* *
* @param IManageConfigValues $config * @param IManageConfigValues $config
* @param App\Mode $mode * @param App\Mode $mode
* @param App\BaseURL $baseUrl * @param App\BaseURL $baseUrl
* @param L10n $l10n * @param L10n $l10n
* @param Database $dba * @param Database $dba
* @param LoggerInterface $logger * @param LoggerInterface $logger
* @param User\Cookie $cookie * @param User\Cookie $cookie
* @param IHandleSessions $session * @param IHandleSessions $session
* @param IManagePersonalConfigValues $pConfig * @param IManagePersonalConfigValues $pConfig
* @param App\Request $request
*/ */
public function __construct(IManageConfigValues $config, App\Mode $mode, App\BaseURL $baseUrl, L10n $l10n, Database $dba, LoggerInterface $logger, User\Cookie $cookie, IHandleSessions $session, IManagePersonalConfigValues $pConfig) public function __construct(IManageConfigValues $config, App\Mode $mode, App\BaseURL $baseUrl, L10n $l10n, Database $dba, LoggerInterface $logger, User\Cookie $cookie, IHandleSessions $session, IManagePersonalConfigValues $pConfig, App\Request $request)
{ {
$this->config = $config; $this->config = $config;
$this->mode = $mode; $this->mode = $mode;
$this->baseUrl = $baseUrl; $this->baseUrl = $baseUrl;
$this->l10n = $l10n; $this->l10n = $l10n;
$this->dba = $dba; $this->dba = $dba;
$this->logger = $logger; $this->logger = $logger;
$this->cookie = $cookie; $this->cookie = $cookie;
$this->session = $session; $this->session = $session;
$this->pConfig = $pConfig; $this->pConfig = $pConfig;
$this->remoteAddress = $request->getRemoteAddress();
} }
/** /**
@ -163,10 +167,11 @@ class Authentication
// already logged in user returning // already logged in user returning
$check = $this->config->get('system', 'paranoia'); $check = $this->config->get('system', 'paranoia');
// extra paranoia - if the IP changed, log them out // extra paranoia - if the IP changed, log them out
if ($check && ($this->session->get('addr') != $_SERVER['REMOTE_ADDR'])) { if ($check && ($this->session->get('addr') != $this->remoteAddress)) {
$this->logger->notice('Session address changed. Paranoid setting in effect, blocking session. ', [ $this->logger->notice('Session address changed. Paranoid setting in effect, blocking session. ', [
'addr' => $this->session->get('addr'), 'addr' => $this->session->get('addr'),
'remote_addr' => $_SERVER['REMOTE_ADDR']] 'remote_addr' => $this->remoteAddress
]
); );
$this->session->clear(); $this->session->clear();
$this->baseUrl->redirect(); $this->baseUrl->redirect();
@ -258,7 +263,7 @@ class Authentication
['uid' => User::getIdFromPasswordAuthentication($username, $password)] ['uid' => User::getIdFromPasswordAuthentication($username, $password)]
); );
} catch (Exception $e) { } catch (Exception $e) {
$this->logger->warning('authenticate: failed login attempt', ['action' => 'login', 'username' => $username, 'ip' => $_SERVER['REMOTE_ADDR']]); $this->logger->warning('authenticate: failed login attempt', ['action' => 'login', 'username' => $username, 'ip' => $this->remoteAddress]);
notice($this->l10n->t('Login failed. Please check your credentials.')); notice($this->l10n->t('Login failed. Please check your credentials.'));
$this->baseUrl->redirect(); $this->baseUrl->redirect();
} }
@ -308,7 +313,7 @@ class Authentication
'page_flags' => $user_record['page-flags'], 'page_flags' => $user_record['page-flags'],
'my_url' => $this->baseUrl->get() . '/profile/' . $user_record['nickname'], 'my_url' => $this->baseUrl->get() . '/profile/' . $user_record['nickname'],
'my_address' => $user_record['nickname'] . '@' . substr($this->baseUrl->get(), strpos($this->baseUrl->get(), '://') + 3), 'my_address' => $user_record['nickname'] . '@' . substr($this->baseUrl->get(), strpos($this->baseUrl->get(), '://') + 3),
'addr' => ($_SERVER['REMOTE_ADDR'] ?? '') ?: '0.0.0.0' 'addr' => $this->remoteAddress,
]); ]);
Session::setVisitorsContacts(); Session::setVisitorsContacts();

View file

@ -632,6 +632,17 @@ return [
// Timeout in seconds for fetching the XRD links and other requests with an expected shorter timeout // Timeout in seconds for fetching the XRD links and other requests with an expected shorter timeout
'xrd_timeout' => 20, 'xrd_timeout' => 20,
], ],
'proxy' => [
// forwarded_for_headers (String)
// A comma separated list of all allowed header values to retrieve the real client IP
// The headers are evaluated in order.
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
// trusted_proxies (String)
// A comma separated list of all trusted proxies, which will get skipped during client IP retrieval
// IP ranges and CIDR notations are allowed
'trusted_proxies' => '',
],
'experimental' => [ 'experimental' => [
// exp_themes (Boolean) // exp_themes (Boolean)
// Show experimental themes in user settings. // Show experimental themes in user settings.

View file

@ -208,7 +208,7 @@ return [
], ],
Cookie::class => [ Cookie::class => [
'constructParams' => [ 'constructParams' => [
$_SERVER, $_COOKIE $_COOKIE
], ],
], ],
ICanWriteToStorage::class => [ ICanWriteToStorage::class => [
@ -238,4 +238,9 @@ return [
$_SERVER $_SERVER
], ],
], ],
App\Request::class => [
'constructParams' => [
$_SERVER
],
]
]; ];

View file

@ -61,4 +61,8 @@ return [
'REDIS_PORT' => ['system', 'redis_port'], 'REDIS_PORT' => ['system', 'redis_port'],
'REDIS_PW' => ['system', 'redis_password'], 'REDIS_PW' => ['system', 'redis_password'],
'REDIS_DB' => ['system', 'redis_db'], 'REDIS_DB' => ['system', 'redis_db'],
// Proxy Config
'FRIENDICA_FORWARDED_HEADERS' => ['proxy', 'forwarded_for_headers'],
'FRIENDICA_TRUSTED_PROXIES' => ['proxy', 'trusted_proxies'],
]; ];

View file

@ -0,0 +1,129 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @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 <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Test\src\App;
use Friendica\App\Request;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Test\MockedTest;
class RequestTest extends MockedTest
{
public function dataServerArray(): array
{
return [
'default' => [
'server' => ['REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '',
'forwarded_for_headers' => '',
],
'assertion' => '1.2.3.4',
],
'proxy_1' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
],
'assertion' => '4.5.6.7',
],
'proxy_2' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
],
'assertion' => '4.5.6.7',
],
'proxy_CIDR_multiple_proxies' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '10.0.1.1'],
'config' => [
'trusted_proxies' => '10.0.0.0/16, 1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
],
'assertion' => '4.5.6.7',
],
'proxy_wrong_CIDR' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '10.1.0.1'],
'config' => [
'trusted_proxies' => '10.0.0.0/24, 1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
],
'assertion' => '10.1.0.1',
],
'proxy_3' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR',
],
'assertion' => '4.5.6.7',
],
'proxy_multiple_header_1' => [
'server' => ['HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED',
],
'assertion' => '4.5.6.7',
],
'proxy_multiple_header_2' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED',
],
'assertion' => '4.5.6.7',
],
'proxy_multiple_header_wrong' => [
'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => '',
],
'assertion' => '1.2.3.4',
],
'no_remote_addr' => [
'server' => [],
'config' => [
'trusted_proxies' => '1.2.3.4',
'forwarded_for_headers' => '',
],
'assertion' => '0.0.0.0',
],
];
}
/**
* @dataProvider dataServerArray
*/
public function testRemoteAddress(array $server, array $config, string $assertion)
{
$configClass = \Mockery::mock(IManageConfigValues::class);
$configClass->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn($config['trusted_proxies']);
$configClass->shouldReceive('get')->with('proxy', 'forwarded_for_headers', Request::DEFAULT_FORWARD_FOR_HEADER)->andReturn($config['forwarded_for_headers']);
$request = new Request($configClass, $server);
self::assertEquals($assertion, $request->getRemoteAddress());
}
}

View file

@ -22,6 +22,7 @@
namespace Friendica\Test\src\Model\User; namespace Friendica\Test\src\Model\User;
use Friendica\App\BaseURL; use Friendica\App\BaseURL;
use Friendica\App\Request;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Model\User\Cookie; use Friendica\Model\User\Cookie;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
@ -35,13 +36,15 @@ class CookieTest extends MockedTest
/** @var MockInterface|BaseURL */ /** @var MockInterface|BaseURL */
private $baseUrl; private $baseUrl;
const SERVER_ARRAY = ['REMOTE_ADDR' => '1.2.3.4'];
protected function setUp(): void protected function setUp(): void
{ {
StaticCookie::clearStatic(); StaticCookie::clearStatic();
parent::setUp(); parent::setUp();
$this->config = \Mockery::mock(IManageConfigValues::class); $this->config = \Mockery::mock(IManageConfigValues::class);
$this->baseUrl = \Mockery::mock(BaseURL::class); $this->baseUrl = \Mockery::mock(BaseURL::class);
} }
@ -60,8 +63,11 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$cookie = new Cookie($this->config, $this->baseUrl); $request = new Request($this->config,static::SERVER_ARRAY);
$cookie = new Cookie($request, $this->config, $this->baseUrl);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
} }
@ -124,8 +130,11 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$cookie = new Cookie($this->config, $this->baseUrl, [], $cookieData); $request = new Request($this->config, static::SERVER_ARRAY);
$cookie = new Cookie($request, $this->config, $this->baseUrl, $cookieData);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
if (isset($uid)) { if (isset($uid)) {
@ -182,8 +191,11 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverPrivateKey)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverPrivateKey)->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$cookie = new Cookie($this->config, $this->baseUrl); $request = new Request($this->config, static::SERVER_ARRAY);
$cookie = new Cookie($request, $this->config, $this->baseUrl);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
self::assertEquals($assertTrue, $cookie->comparePrivateDataHash($assertHash, $password, $userPrivateKey)); self::assertEquals($assertTrue, $cookie->comparePrivateDataHash($assertHash, $password, $userPrivateKey));
@ -239,8 +251,13 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$this->config->shouldReceive('get')->with('proxy', 'forwarded_for_headers')->andReturn(Request::DEFAULT_FORWARD_FOR_HEADER);
$cookie = new StaticCookie($this->config, $this->baseUrl, $serverArray);
$request = new Request($this->config, $serverArray);
$cookie = new StaticCookie($request, $this->config, $this->baseUrl);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
$cookie->setMultiple([ $cookie->setMultiple([
@ -261,8 +278,12 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$this->config->shouldReceive('get')->with('proxy', 'forwarded_for_headers')->andReturn(Request::DEFAULT_FORWARD_FOR_HEADER);
$cookie = new StaticCookie($this->config, $this->baseUrl, $serverArray); $request = new Request($this->config, $serverArray);
$cookie = new StaticCookie($request, $this->config, $this->baseUrl, $serverArray);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
$cookie->set('uid', $uid); $cookie->set('uid', $uid);
@ -283,8 +304,11 @@ class CookieTest extends MockedTest
$this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once();
$this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn(24)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn(24)->once();
$this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once();
$this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once();
$cookie = new StaticCookie($this->config, $this->baseUrl); $request = new Request($this->config, static::SERVER_ARRAY);
$cookie = new StaticCookie($request, $this->config, $this->baseUrl);
self::assertInstanceOf(Cookie::class, $cookie); self::assertInstanceOf(Cookie::class, $cookie);
self::assertEquals('test', StaticCookie::$_COOKIE[Cookie::NAME]); self::assertEquals('test', StaticCookie::$_COOKIE[Cookie::NAME]);