Path validator + tests
This commit is contained in:
parent
22290c21dd
commit
4161a65e0b
4 changed files with 119 additions and 3 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
require_once __DIR__.'/../init.php';
|
require_once __DIR__.'/../init.php';
|
||||||
|
|
||||||
|
use Appwrite\Storage\Validator\Path;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Logger\Log;
|
use Utopia\Logger\Log;
|
||||||
use Utopia\Logger\Log\User;
|
use Utopia\Logger\Log\User;
|
||||||
|
@ -525,8 +526,15 @@ App::get('/.well-known/acme-challenge')
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function ($request, $response) {
|
->action(function ($request, $response) {
|
||||||
|
$filePath = $request->getURI();
|
||||||
|
|
||||||
|
$validator = new Path();
|
||||||
|
if (!$validator->isValid($filePath)) {
|
||||||
|
throw new Exception('Invalid file path. Please use relative path without \'../\'', 400);
|
||||||
|
}
|
||||||
|
|
||||||
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
||||||
$path = \str_replace('/.well-known/acme-challenge/', '', $request->getURI());
|
$path = \str_replace('/.well-known/acme-challenge/', '', $filePath);
|
||||||
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$path);
|
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$path);
|
||||||
|
|
||||||
if (!$base) {
|
if (!$base) {
|
||||||
|
|
78
src/Appwrite/Storage/Validator/Path.php
Normal file
78
src/Appwrite/Storage/Validator/Path.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\Network\Validator;
|
||||||
|
|
||||||
|
use Utopia\Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain
|
||||||
|
*
|
||||||
|
* Validate that an variable is a valid domain address
|
||||||
|
*
|
||||||
|
* @package Utopia\Validator
|
||||||
|
*/
|
||||||
|
class Path extends Validator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get Description
|
||||||
|
*
|
||||||
|
* Returns validator description
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Value must be a relative path without \'../\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is valid
|
||||||
|
*
|
||||||
|
* Validation will pass when $value is valid domain.
|
||||||
|
*
|
||||||
|
* Validates domain names against RFC 1034, RFC 1035, RFC 952, RFC 1123, RFC 2732, RFC 2181, and RFC 1123.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValid($value): bool
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(\str_contains($value, '..')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is array
|
||||||
|
*
|
||||||
|
* Function will return true if object is array.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isArray(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Type
|
||||||
|
*
|
||||||
|
* Returns validator type.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return self::TYPE_STRING;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,10 @@
|
||||||
namespace Tests\E2E;
|
namespace Tests\E2E;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use function curl_setopt;
|
||||||
|
use function http_build_query;
|
||||||
|
use const CURLOPT_PATH_AS_IS;
|
||||||
|
use const CURLOPT_TIMEOUT;
|
||||||
|
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
|
@ -119,7 +123,7 @@ class Client
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $endpoint
|
* @param string $endpoint
|
||||||
* @return self $this
|
* @return self $this
|
||||||
*/
|
*/
|
||||||
public function setEndpoint($endpoint): self
|
public function setEndpoint($endpoint): self
|
||||||
|
@ -129,6 +133,14 @@ class Client
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEndpoint(): string
|
||||||
|
{
|
||||||
|
return $this->endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param string $value
|
* @param string $value
|
||||||
|
@ -183,6 +195,7 @@ class Client
|
||||||
unset($headers[$i]);
|
unset($headers[$i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curl_setopt($ch, CURLOPT_PATH_AS_IS, 1);
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
|
|
@ -94,6 +94,23 @@ class HTTPTest extends Scope
|
||||||
$this->assertStringContainsString('# robotstxt.org/', $response['body']);
|
$this->assertStringContainsString('# robotstxt.org/', $response['body']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAcmeChallenge()
|
||||||
|
{
|
||||||
|
$previousEndpoint = $this->client->getEndpoint();
|
||||||
|
$this->client->setEndpoint("http://localhost");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for FAILURE
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/.well-known/acme-challenge/../../../../../../../etc/passwd', \array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
]), []);
|
||||||
|
|
||||||
|
$this->client->setEndpoint($previousEndpoint);
|
||||||
|
|
||||||
|
$this->assertEquals(400, $response['headers']['status-code']);
|
||||||
|
}
|
||||||
|
|
||||||
// public function testSpecSwagger2()
|
// public function testSpecSwagger2()
|
||||||
// {
|
// {
|
||||||
// $response = $this->client->call(Client::METHOD_GET, '/specs/swagger2?platform=client', [
|
// $response = $this->client->call(Client::METHOD_GET, '/specs/swagger2?platform=client', [
|
||||||
|
|
Loading…
Reference in a new issue