Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v3] Blade component #62

Merged
merged 13 commits into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 0 additions & 52 deletions .github/workflows/phpunit-l7.yml

This file was deleted.

53 changes: 44 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
[![Latest Version on Packagist](https://img.shields.io/packagist/v/elhebert/laravel-sri.svg?style=flat-square)](https://packagist.org/packages/elhebert/laravel-sri)
[![Total Downloads](https://img.shields.io/packagist/dt/elhebert/laravel-sri.svg?style=flat-square)](https://packagist.org/packages/elhebert/laravel-sri)

Small Laravel 6+ package that'll generate the integrity hashes for your style and script files.
Small Laravel 8+ package that'll generate the integrity hashes for your style and script files.

For Laravel 5.5+ support, use the [v1 branch](https://github.com/Elhebert/laravel-sri/tree/v1).
For Laravel 6+ support, use the [v2 branch](https://github.com/Elhebert/laravel-sri/tree/v2).

## About Subresources Integrity

Expand Down Expand Up @@ -71,20 +72,51 @@ To generate the HTML for the `integrity` and the `crossorigin` attributes, use `
/>
```

### Blade directive
### Blade Component

Two blade directive are available to make your views cleaner:
Alternatively you can use blade components:

Use `@mixSri` to generate the `<link>` or `<script>` tag with the proper attributes and using the `mix()` helper to generate the asset path:
```html
<x:sri-link href="css/app.css" rel="stylesheet" />
<!-- is the equivalent of doing -->
<link
href="{{ asset('css/app.css') }}"
rel="stylesheet"
integrity="{{ Sri::hash('css/app.css') }}"
crossorigin="anonymous"
/>
```

```php
@mixSri(string $path, bool $useCredentials = 'false', string $attributes = '')
If you add a `mix` attributet to the component it'll use `mix()` instead of `asset()` to generate the link to the assets:

```html
<x:sri-link mix href="css/app.css" rel="stylesheet" />
<!-- is the equivalent of doing -->
<link
href="{{ mix('css/app.css') }}"
rel="stylesheet"
integrity="{{ Sri::hash('css/app.css') }}"
crossorigin="anonymous"
/>
```

Use `@assetSri` to generate the `<link>` or `<script>` tag with the proper attributes and using the `asset()` helper to generate the asset path:
### Improve performance

```php
@assetSri(string $path, bool $useCredentials = 'false', string $attributes = '')
You should wrap your `<link>` and `<script>` tags with the [`@once`](https://laravel.com/docs/master/blade#the-once-directive) directive to ensure that your tags are only rendered once. This will help with performances as it'll avoid a potential re-hashing of the files (in case you want to hash them on the fly).

Be careful that this should only be use for production as it won't re-render the html tag. Thus preventing new cache busting id to be added to the path by `mix`.

```html
@once
<link
href="{{ mix('css/app.css') }}"
rel="stylesheet"
integrity="{{ Sri::hash('css/app.css') }}"
crossorigin="anonymous"
/>
<!-- Or using the blade component -->
<x:sri-link mix href="css/app.css" rel="stylesheet" />
@endonce
```

## How to get a hash
Expand Down Expand Up @@ -137,6 +169,9 @@ This package also work for remote resources. Be careful that resources like Goog
integrity="{{ Sri::hash('http://code.jquery.com/jquery-3.3.1.min.js') }}"
crossorigin="anonymous"
></script>

<!-- or with a blade component -->
<x:sri-script src="http://code.jquery.com/jquery-3.3.1.min.js"></x:sri-script>
```

## Contributing
Expand Down
11 changes: 5 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@
"license": "MIT",
"authors": [
{
"name": "Dieter Stinglhamber",
"email": "[email protected]"
"name": "Dieter Stinglhamber"
}
],
"require": {
"php": "^7.2.5",
"illuminate/support": "^6.0 | ^7.0 | ^8.0"
"php": "^7.3",
"illuminate/support": "^8.0"
},
"require-dev": {
"orchestra/testbench": "^4.0 | ^5.0 | ^6.0",
"phpunit/phpunit": "^8.0 | ^9.0 | ^9.3"
"orchestra/testbench": "^6.0",
"phpunit/phpunit": "^9.3"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 31 additions & 27 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Sri test suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
<testsuites>
<testsuite name="Sri test suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
</phpunit>
42 changes: 42 additions & 0 deletions src/Components/Link.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Elhebert\SubresourceIntegrity\Components;

use Elhebert\SubresourceIntegrity\SriFacade as Sri;
use Illuminate\View\Component;

class Link extends Component
{
/** @var string */
public $href;

/** @var bool */
public $mix = false;

/** @var string */
public $crossorigin = 'anonymous';

public function __construct(string $href, bool $mix = false, string $crossorigin = 'anonymous')
{
$this->href = $href;
$this->mix = $mix;
$this->crossorigin = $crossorigin;
}

public function integrity(): string
{
return Sri::hash($this->href);
}

public function path(): string
{
return $this->mix ? mix($this->href) : asset($this->href);
}

public function render(): string
{
return <<<'blade'
<link href="{{ $path() }}" integrity="{{ $integrity() }}" crossorigin="{{ $crossorigin }}" {{ $attributes }} />
blade;
}
}
42 changes: 42 additions & 0 deletions src/Components/Script.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Elhebert\SubresourceIntegrity\Components;

use Elhebert\SubresourceIntegrity\SriFacade as Sri;
use Illuminate\View\Component;

class Script extends Component
{
/** @var string */
public $src;

/** @var bool */
public $mix;

/** @var string */
public $crossorigin = 'anonymous';

public function __construct(string $src, bool $mix = false, string $crossorigin = 'anonymous')
{
$this->src = $src;
$this->mix = $mix;
$this->crossorigin = $crossorigin;
}

public function integrity(): string
{
return Sri::hash($this->src);
}

public function path(): string
{
return $this->mix ? mix($this->src) : asset($this->src);
}

public function render(): string
{
return <<<'blade'
<script src="{{ $path() }}" integrity="{{ $integrity() }}" crossorigin="{{ $crossorigin }}" {{ $attributes }} />
blade;
}
}
48 changes: 6 additions & 42 deletions src/Sri.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ class Sri
/** @var string */
private $algorithm;

/** @var string */
private $jsonFilePath;

public function __construct(string $algorithm)
{
$this->algorithm = in_array($algorithm, ['sha256', 'sha384', 'sha512'])
? $algorithm
: 'sha256';
$this->jsonFilePath = config('subresource-integrity.mix_sri_path');
}

public function html(string $path, bool $useCredentials = false): HtmlString
Expand Down Expand Up @@ -50,7 +54,7 @@ public function hash(string $path): string
}

if ($this->mixFileExists()) {
$json = json_decode(file_get_contents($this->jsonFilePath()));
$json = json_decode(file_get_contents($this->jsonFilePath));
$prefixedPath = Str::startsWith($path, '/') ? $path : "/{$path}";

if (property_exists($json, $prefixedPath)) {
Expand All @@ -64,49 +68,14 @@ public function hash(string $path): string
return "{$this->algorithm}-{$base64Hash}";
}

public function mix(string $path, bool $useCredentials = false, string $attributes = ''): string
{
if (Str::startsWith($path, ['http', 'https', '//'])) {
$href = $path;
} else {
$href = mix($path);
}

return $this->generateHtmlTag($href, $path, $useCredentials, $attributes);
}

public function asset(string $path, bool $useCredentials = false, string $attributes = ''): string
{
if (Str::startsWith($path, ['http', 'https', '//'])) {
$href = $path;
} else {
$href = asset($path);
}

return $this->generateHtmlTag($href, $path, $useCredentials, $attributes);
}

private function generateHtmlTag(string $href, string $path, bool $useCredentials, string $attributes): string
{
$integrity = $this->html($path, $useCredentials);

if (Str::endsWith($path, 'css')) {
return "<link href='{$href}' rel='stylesheet' {$integrity} {$attributes}>";
} elseif (Str::endsWith($path, 'js')) {
return "<script src='{$href}' {$integrity} {$attributes}></script>";
} else {
throw new \Exception('Invalid file');
}
}

private function existsInConfigFile(string $path): bool
{
return array_key_exists($path, config('subresource-integrity.hashes'));
}

private function mixFileExists(): bool
{
return file_exists($this->jsonFilePath());
return file_exists($this->jsonFilePath);
}

private function getFileContent(string $path): string
Expand All @@ -130,9 +99,4 @@ private function getFileContent(string $path): string

return $fileContent;
}

private function jsonFilePath(): string
{
return config('subresource-integrity.mix_sri_path');
}
}
Loading