Skip to content

Commit

Permalink
Added skipKeyWhen method + refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalbaljet committed Feb 3, 2022
1 parent 51f9c10 commit 6acbb0c
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 15 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to `laravel-xss-protection` will be documented in this file.

## 1.0.0 - 202X-XX-XX
## 1.2.0 - 2022-02-03

- added `skipKeyWhen` method

## 1.1.0 / 1.1.1 - 2022-02-02

- added `MaliciousInputFound` event

## 1.0.0 - 2022-02-02

- initial release
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ XssCleanInput::skipWhen(function (Request $request) {
});
```

You can also exclude keys by using the static `skipKeyWhen` method. This also allows you to interact with the value and request.

```php
XssCleanInput::skipKeyWhen(function (string $key, $value, Request $request) {
return in_array($key, [
'current_password',
'password',
'password_confirmation',
]);
});
```

## Configuration

### File uploads
Expand Down
63 changes: 57 additions & 6 deletions src/Middleware/XssCleanInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ class XssCleanInput extends TransformsRequest
*/
protected static $skipCallbacks = [];

/**
* All of the registered skip keys callbacks.
*
* @var array
*/
protected static $skipKeyCallbacks = [];

/**
* The attributes that should not be cleaned.
*
* @var array
*/
protected $exceptKeys = [
//
];
protected $exceptKeys = [];

/**
* Array of sanitized keys.
Expand All @@ -48,6 +53,13 @@ class XssCleanInput extends TransformsRequest
*/
protected $sanitizedKeys = [];

/**
* Original request.
*
* @var \Illuminate\Http\Request
*/
protected $originalRequest;

/**
* Create a new instance.
*
Expand Down Expand Up @@ -79,16 +91,20 @@ public function handle($request, Closure $next)
}
}

$originalRequest = clone $request;
$dispatchEvent = $this->enabledInConfig('dispatch_event_on_malicious_input');

if (count(static::$skipKeyCallbacks) > 0 || $dispatchEvent) {
$this->originalRequest = clone $request;
}

$this->clean($request);

if (count($this->sanitizedKeys) === 0) {
return $next($request);
}

if ($this->enabledInConfig('dispatch_event_on_malicious_input')) {
event(new MaliciousInputFound($this->sanitizedKeys, $originalRequest, $request));
if ($dispatchEvent) {
event(new MaliciousInputFound($this->sanitizedKeys, $this->originalRequest, $request));
}

if ($this->enabledInConfig('terminate_request_on_malicious_input')) {
Expand All @@ -111,6 +127,12 @@ protected function transform($key, $value)
return $value;
}

foreach (static::$skipKeyCallbacks as $callback) {
if ($callback($key, $value, $this->originalRequest)) {
return $value;
}
}

if ($value === null || is_bool($value) || is_int($value) || is_float($value)) {
return $value;
}
Expand Down Expand Up @@ -140,6 +162,12 @@ protected function transform($key, $value)
return $this->enabledInConfig('completely_replace_malicious_input') ? null : $output;
}

/**
* Returns a boolean whether an option has been enabled.
*
* @param string $key
* @return boolean
*/
private function enabledInConfig($key): bool
{
return (bool) config("xss-protection.middleware.{$key}");
Expand All @@ -155,4 +183,27 @@ public static function skipWhen(Closure $callback)
{
static::$skipCallbacks[] = $callback;
}

/**
* Register a callback that instructs the middleware to be skipped.
*
* @param \Closure $callback
* @return void
*/
public static function skipKeyWhen(Closure $callback)
{
static::$skipKeyCallbacks[] = $callback;
}

/**
* Clear static callback arrays.
*
* @return void
*/
public static function clearCallbacks()
{
static::$skipCallbacks = [];

static::$skipKeyCallbacks = [];
}
}
44 changes: 36 additions & 8 deletions tests/MiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
use ProtoneMedia\LaravelXssProtection\Middleware\XssCleanInput;
use Symfony\Component\HttpKernel\Exception\HttpException;

beforeEach(function () {
XssCleanInput::clearCallbacks();
});

it('can partly replace the malicious input', function () {
$request = Request::createFromGlobals()->merge([
'key' => 'test<script>script</script>',
Expand Down Expand Up @@ -42,19 +46,14 @@
});

it('can add a callback to skip a request', function () {
class SkipXssCleanInput extends XssCleanInput
{
protected static $skipCallbacks = [];
}

SkipXssCleanInput::skipWhen(fn () => true);
XssCleanInput::skipWhen(fn () => true);

$request = Request::createFromGlobals()->merge([
'key' => 'test<script>script</script>',
]);

/** @var SkipXssCleanInput $middleware */
$middleware = app(SkipXssCleanInput::class);
/** @var XssCleanInput $middleware */
$middleware = app(XssCleanInput::class);
$middleware->handle($request, fn ($request) => $request);

expect($request->input('key'))->toBe('test<script>script</script>');
Expand Down Expand Up @@ -189,3 +188,32 @@ class ExceptXssCleanInput extends XssCleanInput
expect($request->input('e'))->toBe('e');
expect($request->input('f'))->toBe('f');
});

it('can skip a key by a callback', function () {
XssCleanInput::skipKeyWhen(function (string $key, $value, $request) {
expect($request)->toBeInstanceOf(Request::class);
expect($value)->toBe('test<script>script</script>');

return in_array($key, ['allow', 'nested.allowed']);
});

$request = Request::createFromGlobals()->merge([
'key' => 'test<script>script</script>',
'allow' => 'test<script>script</script>',

'nested' => [
'key' => 'test<script>script</script>',
'allowed' => 'test<script>script</script>',
],
]);

/** @var XssCleanInput $middleware */
$middleware = app(XssCleanInput::class);
$middleware->handle($request, fn ($request) => $request);

expect($request->input('key'))->toBeNull();
expect($request->input('nested.key'))->toBeNull();

expect($request->input('allow'))->toBe('test<script>script</script>');
expect($request->input('nested.allowed'))->toBe('test<script>script</script>');
});

0 comments on commit 6acbb0c

Please sign in to comment.