Skip to content

Commit

Permalink
Use proper parameters to avoid injection in Expression Language
Browse files Browse the repository at this point in the history
  • Loading branch information
micoli committed Jul 14, 2023
1 parent b1d763f commit fd06dd1
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 18 deletions.
18 changes: 9 additions & 9 deletions src/Elql.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ public function add(object ...$records): void
*
* @return T[]
*/
public function find(string $model, string $where = null): array
public function find(string $model, string $where = null, array $parameters = []): array
{
return array_values(array_filter(
$this->persister->getRecords($model)->data,
fn (mixed $record) => $this->match($record, $where),
fn (mixed $record) => $this->match($record, $where, $parameters),
));
}

/**
* @param class-string $model
*/
public function delete(string $model, string $where = null): void
public function delete(string $model, string $where = null, array $parameters = []): void
{
$this->persister->updateRecords($model, array_values(array_filter(
$this->persister->getRecords($model)->data,
Expand All @@ -55,9 +55,9 @@ public function delete(string $model, string $where = null): void
/**
* @param class-string $model
*/
public function count(string $model, string $where = null): int
public function count(string $model, string $where = null, array $parameters = []): int
{
return count($this->find($model, $where));
return count($this->find($model, $where, $parameters));
}

/**
Expand All @@ -66,11 +66,11 @@ public function count(string $model, string $where = null): int
* @param class-string<T> $model
* @param callable(T):T $updater
*/
public function update(string $model, callable $updater, string $where = null): void
public function update(string $model, callable $updater, string $where = null, array $parameters = []): void
{
$this->persister->updateRecords($model, array_map(
/** @param T $record */
fn (mixed $record): mixed => $this->match($record, $where)
fn (mixed $record): mixed => $this->match($record, $where, $parameters)
? $updater($record)
: $record,
$this->persister->getRecords($model)->data,
Expand All @@ -82,12 +82,12 @@ public function update(string $model, callable $updater, string $where = null):
*
* @psalm-param T|object $record
*/
private function match(mixed $record, ?string $where): bool
private function match(mixed $record, ?string $where, array $parameters = []): bool
{
if ($where === null) {
return true;
}

return (bool) $this->expressionLanguageEvaluator->evaluate($where, $record);
return (bool) $this->expressionLanguageEvaluator->evaluate($where, $record, $parameters);
}
}
16 changes: 8 additions & 8 deletions src/ExpressionLanguage/ExpressionLanguageEvaluator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ public function __construct(
private readonly ExpressionLanguage $expressionLanguage = new ExpressionLanguage(new ArrayAdapter()),
) {
foreach ([
'strtoupper', 'strtolower',
'str_starts_with', 'str_ends_with', 'str_contains',
'substr', 'strlen',
'trim', 'ltrim', 'rtrim',
'abs', 'min', 'max', 'floor', 'ceil',
] as $nativeFunction) {
'strtoupper', 'strtolower',
'str_starts_with', 'str_ends_with', 'str_contains',
'substr', 'strlen',
'trim', 'ltrim', 'rtrim',
'abs', 'min', 'max', 'floor', 'ceil',
] as $nativeFunction) {
$this->expressionLanguage->addFunction(ExpressionFunction::fromPhp($nativeFunction));
}
}

public function evaluate(string $expression, mixed $record): mixed
public function evaluate(string $expression, mixed $record, array $parameters = []): mixed
{
return $this->expressionLanguage->evaluate($expression, ['record' => $record]);
return $this->expressionLanguage->evaluate($expression, [...$parameters, 'record' => $record]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

interface ExpressionLanguageEvaluatorInterface
{
public function evaluate(string $expression, mixed $record): mixed;
public function evaluate(string $expression, mixed $record, array $parameters = []): mixed;
}
10 changes: 10 additions & 0 deletions tests/ElqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,14 @@ public function testItUseExtendedExpressionLanguage(): void

self::assertCount(1, $this->database->find(Baz::class, 'strtoupper(record.firstName) === "A"'));
}

public function testItUseParametersInExpressionLanguage(): void
{
$this->database->add(
new Baz(1, 'a', 'a'),
new Baz(2, 'b', 'b'),
);

self::assertCount(1, $this->database->find(Baz::class, 'strtoupper(record.firstName) === value', ['value' => 'A']));
}
}

0 comments on commit fd06dd1

Please sign in to comment.