Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
medilies committed Aug 11, 2024
1 parent b67b331 commit 09b0411
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 120 deletions.
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CONTRIBUTING

## Testing

```bash
./vendor/bin/pest
```

## Formatting

```bash
./vendor/bin/pint
```
94 changes: 42 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@

## Why use Xssless

- **Prevent XSS Attacks:** Safeguard your application by cleaning user-submitted HTML, eliminating potential XSS threats.
- **Painless HTML 5 support:** Xssless leverages engines with the best HTML5 support.
- **Easy to build policies:** (todo).
- Your application features a [Rich Text Editor](https://en.wikipedia.org/wiki/Online_rich-text_editor) and you want to prevent all XSS.
- You want full HTML5 & CSS3 support.
- You want to allow all safe HTML elements, their attributes, and CSS properties without going deep into whitelist configs.
- [TODO] You want a fluent and an intuitive way to build policies.

The default driver aligns with [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#html-sanitization) recommendations:

> HTML Sanitization will strip dangerous HTML from a variable and return a safe string of HTML. OWASP recommends **DOMPurify** for HTML Sanitization.
> ... OWASP recommends **DOMPurify** for HTML Sanitization.
## Requirements

Expand All @@ -32,7 +33,7 @@ Install the package via composer:
composer require medilies/xssless
```

For non Laravel projects pick a config and run the following code:
For non Laravel projects, pick a config and run the following code:

```php
$config = new Medilies\Xssless\Dompurify\DompurifyCliConfig('node', 'npm');
Expand All @@ -42,44 +43,15 @@ $config = new Medilies\Xssless\Dompurify\DompurifyCliConfig('node', 'npm');
->setup();
```

### Laravel setup

You can publish the config file with:

```bash
php artisan vendor:publish --tag="xssless-config"
```

This is the contents of the published config file:

```php
return [
'default' => 'dompurify-cli',

'drivers' => [
'dompurify-cli' => new DompurifyCliConfig(
node: env('NODE_PATH'),
npm: env('NPM_PATH'),
binary: null,
tempFolder: null,
),
'dompurify-service' => new DompurifyServiceConfig(
node: env('NODE_PATH'),
npm: env('NPM_PATH'),
host: '127.0.0.1',
port: 63000,
binary: null,
),
],
];
```

Run the following command after picking your `xssless.default` config:
For non Laravel projects, run the following command:

```shell
php artisan xssless:setup
```

> [!IMPORTANT]
> You may need to re-run the setup when switching drivers.
## Usage

Using `Medilies\Xssless\Dompurify\DompurifyCliConfig`:
Expand Down Expand Up @@ -111,13 +83,43 @@ $xssless->clean($html);

### Laravel usage

Using `Medilies\Xssless\Dompurify\DompurifyCliConfig`:
You can publish the config file with:

```bash
php artisan vendor:publish --tag="xssless-config"
```

This is the contents of the published config file:

```php
return [
'default' => 'dompurify-cli',

'drivers' => [
'dompurify-cli' => new DompurifyCliConfig(
node: env('NODE_PATH'),
npm: env('NPM_PATH'),
binary: null,
tempFolder: null,
),
'dompurify-service' => new DompurifyServiceConfig(
node: env('NODE_PATH'),
npm: env('NPM_PATH'),
host: '127.0.0.1',
port: 63000,
binary: null,
),
],
];
```

Using `dompurify-cli`:

```php
Medilies\Xssless\Laravel\Facades\Xssless::clean($html);
```

Using `Medilies\Xssless\Dompurify\DompurifyServiceConfig`:
Using `dompurify-service`:

```shell
php artisan xssless:start
Expand All @@ -135,18 +137,6 @@ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed re

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

### Testing

```bash
./vendor/bin/pest
```

### Formatting

```bash
./vendor/bin/pint
```

## Security Vulnerabilities

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
Expand Down
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
"name": "medilies/xssless",
"description": "Clean your strings from XSS threats.",
"keywords": [
"html",
"xss",
"safe",
"prevent",
"sanitizer",
"purifier",
"html"
"cleaner",
"filter",
"laravel"
],
"homepage": "https://github.com/medilies/xssless",
"license": "MIT",
Expand Down
2 changes: 0 additions & 2 deletions src/Dompurify/DompurifyService.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,4 @@ private function isSigTerm(): bool
// {
// return $this->serviceProcess->getTermSignal() === 1;
// }

// 92..97, 104, 113..136
}
4 changes: 2 additions & 2 deletions src/Dompurify/DompurifyServiceConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

class DompurifyServiceConfig implements ConfigInterface
{
public readonly string $class;
private readonly string $class;

public function __construct(
public string $node = 'node',
public string $npm = 'npm',
public string $host = '127.0.0.1',
public int $port = 6300,
public int $port = 63000,
public ?string $binary = null,
) {
$this->class = DompurifyService::class;
Expand Down
16 changes: 8 additions & 8 deletions src/Xssless.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ class Xssless

// TODO: policy builder

public function clean(string $html, ?ConfigInterface $config = null): string
public function clean(string $html, ?ConfigInterface $tempConfig = null): string
{
$cleaner = $this->makeCleaner($config);
$cleaner = $this->makeCleaner($tempConfig);

return match (true) {
$cleaner instanceof CliInterface => $this->exec($cleaner, $html),
$cleaner instanceof ServiceInterface => $this->send($cleaner, $html),
};
}

public function start(?ConfigInterface $config = null): ServiceInterface
public function start(?ConfigInterface $tempConfig = null): ServiceInterface
{
$service = $this->makeCleaner($config);
$service = $this->makeCleaner($tempConfig);

if (! $service instanceof ServiceInterface) {
throw new XsslessException("'".$service::class."' must implement: '".ServiceInterface::class."'.");
Expand All @@ -29,9 +29,9 @@ public function start(?ConfigInterface $config = null): ServiceInterface
return $service->start();
}

public function setup(?ConfigInterface $config = null): void
public function setup(?ConfigInterface $tempConfig = null): void
{
$service = $this->makeCleaner($config);
$service = $this->makeCleaner($tempConfig);

if (! $service instanceof HasSetupInterface) {
throw new XsslessException("'".$service::class."' must implement: '".HasSetupInterface::class."'.");
Expand Down Expand Up @@ -66,9 +66,9 @@ public function using(ConfigInterface $config): static
return $this;
}

private function makeCleaner(?ConfigInterface $config = null): CliInterface|ServiceInterface
private function makeCleaner(?ConfigInterface $tempConfig = null): CliInterface|ServiceInterface
{
$config ??= $this->config ?? null;
$config = $tempConfig ?? $this->config ?? null;

if (is_null($config)) {
throw new XsslessException('A config must be provided.');
Expand Down
1 change: 1 addition & 0 deletions src/laravel/Commands/SetupCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class SetupCommand extends Command

public function handle(): void
{
// TODO: non Laravel command
Xssless::usingLaravelConfig()->setup();
}
}
1 change: 1 addition & 0 deletions src/laravel/Commands/StartCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class StartCommand extends Command

public function handle(): void
{
// TODO: non Laravel command
$service = Xssless::usingLaravelConfig()->start();

$terminate = function ($signal) use ($service) {
Expand Down
1 change: 1 addition & 0 deletions src/laravel/Facades/Xssless.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Xssless extends Facade
{
protected static function getFacadeAccessor(): string
{
// TODO: model cast
return \Medilies\Xssless\Xssless::class;
}
}
21 changes: 3 additions & 18 deletions tests/Dompurify/DompurifyCliTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,20 @@

it('throws on bad node path', function () {
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig(
'nodeZz',
'npm',
node: 'nodeZz',
));

expect(fn () => $cleaner->exec('foo'))->toThrow(ProcessFailedException::class);
});

test('setup()', function () {
$cleaner = (new Xssless)->using(new DompurifyCliConfig(
'node',
'npm',
));
$cleaner = (new Xssless)->using(new DompurifyCliConfig);

expect(fn () => $cleaner->setup())->not->toThrow(Exception::class);
});

test('exec()', function () {
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig(
'node',
'npm',
));
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig);

$clean = $cleaner->exec('<IMG """><SCRIPT>alert("XSS")</SCRIPT>">');

Expand All @@ -37,8 +30,6 @@

test('clean()', function () {
$cleaner = (new Xssless)->using(new DompurifyCliConfig(
node: 'node',
npm: 'npm',
tempFolder: __DIR__,
));

Expand All @@ -49,8 +40,6 @@

it('throws when cannot read cleaned file', function () {
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig(
node: 'node',
npm: 'npm',
binary: __DIR__.'/js-mocks/cli-returns-bad-path.js',
));

Expand All @@ -59,8 +48,6 @@

it('throws when cannot find binary file', function () {
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig(
node: 'node',
npm: 'npm',
binary: __DIR__.'/js-mocks/x.js',
));

Expand All @@ -69,8 +56,6 @@

it('throws when cannot locate temp folder', function () {
$cleaner = (new DompurifyCli)->configure(new DompurifyCliConfig(
node: 'node',
npm: 'npm',
tempFolder: __DIR__.'/x',
));

Expand Down
29 changes: 5 additions & 24 deletions tests/Dompurify/DompurifyServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,13 @@
use Symfony\Component\Process\Exception\ProcessFailedException;

test('setup()', function () {
$cleaner = (new DompurifyService)->configure(new DompurifyServiceConfig(
'node',
'npm',
'127.0.0.1',
63000,
));
$cleaner = (new DompurifyService)->configure(new DompurifyServiceConfig);

expect(fn () => $cleaner->setup())->not->toThrow(Exception::class);
});

test('send()', function () {
$cleaner = (new DompurifyService)->configure(new DompurifyServiceConfig(
'node',
'npm',
'127.0.0.1',
63000,
));
$cleaner = (new DompurifyService)->configure(new DompurifyServiceConfig);

$cleaner->start();

Expand All @@ -38,10 +28,7 @@

test('clean()', function () {
$config = new DompurifyServiceConfig(
'node',
'npm',
'127.0.0.1',
63001,
port: 63001, // for parallel tests
);

$cleaner = (new Xssless)->using($config);
Expand All @@ -59,10 +46,7 @@

it('throws on bad host', function () {
$cleaner = (new DompurifyService)->configure(new DompurifyServiceConfig(
'node',
'npm',
'a.b.c.example.com',
63000,
host: 'a.b.c.example.com',
));

$dirty = '<IMG """><SCRIPT>alert("XSS")</SCRIPT>">';
Expand All @@ -72,10 +56,7 @@

it('throws on bad node path', function () {
$service = (new DompurifyService)->configure(new DompurifyServiceConfig(
'nodeZz',
'npm',
'127.0.0.1',
5555555555,
node: 'nodeZz',
));

expect(fn () => $service->start())->toThrow(ProcessFailedException::class);
Expand Down
Loading

0 comments on commit 09b0411

Please sign in to comment.