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';
|
||||
|
||||
use Appwrite\Storage\Validator\Path;
|
||||
use Utopia\App;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
|
@ -525,8 +526,15 @@ App::get('/.well-known/acme-challenge')
|
|||
->inject('request')
|
||||
->inject('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);
|
||||
$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);
|
||||
|
||||
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;
|
||||
|
||||
use Exception;
|
||||
use function curl_setopt;
|
||||
use function http_build_query;
|
||||
use const CURLOPT_PATH_AS_IS;
|
||||
use const CURLOPT_TIMEOUT;
|
||||
|
||||
class Client
|
||||
{
|
||||
|
@ -119,7 +123,7 @@ class Client
|
|||
}
|
||||
|
||||
/**
|
||||
* @param mixed $endpoint
|
||||
* @param string $endpoint
|
||||
* @return self $this
|
||||
*/
|
||||
public function setEndpoint($endpoint): self
|
||||
|
@ -129,6 +133,14 @@ class Client
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEndpoint(): string
|
||||
{
|
||||
return $this->endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
|
@ -183,6 +195,7 @@ class Client
|
|||
unset($headers[$i]);
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_PATH_AS_IS, 1);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
|
|
@ -94,6 +94,23 @@ class HTTPTest extends Scope
|
|||
$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()
|
||||
// {
|
||||
// $response = $this->client->call(Client::METHOD_GET, '/specs/swagger2?platform=client', [
|
||||
|
|
Loading…
Reference in a new issue