Improve headers validator
This commit is contained in:
parent
22b054453c
commit
bbefdc3405
4 changed files with 55 additions and 45 deletions
2
.github/workflows/bench.yml
vendored
2
.github/workflows/bench.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
|||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run Linter
|
||||
- name: Run Benchmark
|
||||
run: |
|
||||
docker run --rm -v $PWD:/app composer sh -c \
|
||||
"composer install --profile --ignore-platform-reqs && git config --global --add safe.directory /app && composer bench -- --progress=plain"
|
|
@ -11,11 +11,8 @@ use Utopia\Validator;
|
|||
*/
|
||||
class Headers extends Validator
|
||||
{
|
||||
protected bool $allowEmpty;
|
||||
|
||||
public function __construct(bool $allowEmpty = true)
|
||||
public function __construct(protected bool $allowEmpty = true, protected int $maxKeys = 100, protected int $maxSize = 16384)
|
||||
{
|
||||
$this->allowEmpty = $allowEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,7 +24,7 @@ class Headers extends Validator
|
|||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Invalid header format. Header keys can only contain alphanumeric characters, underscores, and hyphens. Header keys cannot start with "x-appwrite-" prefix.';
|
||||
return 'Invalid headers: Alphanumeric characters or hyphens only, cannot start with "x-appwrite", maximum ' . $this->maxKeys . ' keys, and total size ' . $this->maxSize . '.';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,34 +44,41 @@ class Headers extends Validator
|
|||
return false;
|
||||
}
|
||||
|
||||
if (\is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
$length = \strlen($key);
|
||||
// Reject non-string keys
|
||||
if (!\is_string($key) || $length === 0) {
|
||||
return false;
|
||||
}
|
||||
if(\count($value) > $this->maxKeys) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check first and last character
|
||||
if (!ctype_alnum($key[0]) || !ctype_alnum($key[$length - 1])) {
|
||||
return false;
|
||||
}
|
||||
$size = 0;
|
||||
foreach ($value as $key => $val) {
|
||||
$length = \strlen($key);
|
||||
// Reject non-string keys
|
||||
if (!\is_string($key) || $length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check middle characters
|
||||
for ($i = 1; $i < $length - 1; $i++) {
|
||||
if (!ctype_alnum($key[$i]) && $key[$i] !== '-') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$size += $length + \strlen($val);
|
||||
if($size >= $this->maxSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for x-appwrite- prefix
|
||||
if (str_starts_with($key, 'x-appwrite-')) {
|
||||
// Check first and last character
|
||||
if (!ctype_alnum($key[0]) || !ctype_alnum($key[$length - 1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check middle characters
|
||||
for ($i = 1; $i < $length - 1; $i++) {
|
||||
if (!ctype_alnum($key[$i]) && $key[$i] !== '-') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// Check for x-appwrite- prefix
|
||||
if (str_starts_with($key, 'x-appwrite-')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,38 +28,26 @@ final class HeadersBench
|
|||
for($i = 0; $i < 10; $i++) {
|
||||
$value[bin2hex(random_bytes(8))] = bin2hex(random_bytes(8));
|
||||
}
|
||||
yield 'xxs' => [ 'value' => $value ];
|
||||
yield 'items_10-size_320' => [ 'value' => $value ];
|
||||
|
||||
$value = [];
|
||||
for($i = 0; $i < 100; $i++) {
|
||||
$value[bin2hex(random_bytes(8))] = bin2hex(random_bytes(8));
|
||||
}
|
||||
yield 'xs' => [ 'value' => $value ];
|
||||
yield 'items_100-size_3200' => [ 'value' => $value ];
|
||||
|
||||
$value = [];
|
||||
for($i = 0; $i < 1000; $i++) {
|
||||
$value[bin2hex(random_bytes(8))] = bin2hex(random_bytes(8));
|
||||
for($i = 0; $i < 100; $i++) {
|
||||
$value[bin2hex(random_bytes(64))] = bin2hex(random_bytes(64));
|
||||
}
|
||||
yield 'sm' => [ 'value' => $value ];
|
||||
|
||||
$value = [];
|
||||
for($i = 0; $i < 10000; $i++) {
|
||||
$value[bin2hex(random_bytes(16))] = bin2hex(random_bytes(16));
|
||||
}
|
||||
yield 'md' => [ 'value' => $value ];
|
||||
|
||||
$value = [];
|
||||
for($i = 0; $i < 100000; $i++) {
|
||||
$value[bin2hex(random_bytes(16))] = bin2hex(random_bytes(16));
|
||||
}
|
||||
yield 'lg' => [ 'value' => $value ];
|
||||
yield 'items_100-size_25600' => [ 'value' => $value ];
|
||||
}
|
||||
|
||||
#[BeforeMethods('prepare')]
|
||||
#[AfterMethods('tearDown')]
|
||||
#[ParamProviders('providers')]
|
||||
#[Iterations(50)]
|
||||
#[Assert('mode(variant.time.avg) < 500 ms')]
|
||||
#[Assert('mode(variant.time.avg) < 1 ms')]
|
||||
public function benchHeadersValidator(array $data): void
|
||||
{
|
||||
$assertion = $this->validator->isValid($data['value']);
|
||||
|
|
|
@ -104,5 +104,23 @@ class HeadersTest extends TestCase
|
|||
|
||||
$headers = 'string';
|
||||
$this->assertFalse($this->object->isValid($headers));
|
||||
|
||||
$headers = [ ];
|
||||
$this->assertTrue($this->object->isValid($headers));
|
||||
|
||||
$headers = [];
|
||||
for($i = 0; $i < 100; $i++) {
|
||||
$headers['key-' . $i] = 'value_' . $i;
|
||||
}
|
||||
$this->assertTrue($this->object->isValid($headers));
|
||||
|
||||
$headers['key-oversized'] = bin2hex(random_bytes(100000));
|
||||
$this->assertFalse($this->object->isValid($headers));
|
||||
|
||||
unset($headers['key-oversized']);
|
||||
$this->assertTrue($this->object->isValid($headers));
|
||||
|
||||
$headers['key-101'] = 'value_101';
|
||||
$this->assertFalse($this->object->isValid($headers));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue