Skip to content

Commit

Permalink
feat: upgrade to spatie/url-signer 2.x (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
thbil committed Mar 15, 2023
1 parent a863e4b commit 683d4ce
Show file tree
Hide file tree
Showing 13 changed files with 37 additions and 66 deletions.
10 changes: 2 additions & 8 deletions .github/workflows/ci.yml
Expand Up @@ -14,25 +14,19 @@ jobs:
strategy:
matrix:
php:
- '7.4'
- '8.0'
- '8.1'
- '8.2'
symfony:
- '4.4.*'
- '5.4.*'
- '6.1.*'
- '6.2.*'
coverage:
- none
include:
- php: '8.1'
symfony: '5.4.*'
bootable: true
coverage: pcov
exclude:
- php: '7.4'
symfony: '6.1.*'
- php: '8.0'
symfony: '6.1.*'
fail-fast: false
steps:
- name: Checkout
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,11 @@
# Change Log

## 2.0.0

* Upgrade to `spatie/url-signer` 2.x
* Minimal PHP version is now 8.1
* Expiration time is now in seconds instead of days

## 1.2.0

### New Features
Expand Down
4 changes: 2 additions & 2 deletions DependencyInjection/Configuration.php
Expand Up @@ -45,9 +45,9 @@ public function getConfigTreeBuilder(): TreeBuilder
/** @var NodeBuilder $childNode */
$childNode = $childNode
->scalarNode('default_expiration')
->defaultValue(1)
->defaultValue(86400)
->cannotBeEmpty()
->info('default expiration time in days')
->info('default expiration time in seconds')
->end()
;
/** @var NodeBuilder $childNode */
Expand Down
4 changes: 1 addition & 3 deletions DependencyInjection/CoopTilleulsUrlSignerExtension.php
Expand Up @@ -21,9 +21,7 @@

final class CoopTilleulsUrlSignerExtension extends Extension
{
/**
* @phpstan-ignore-next-line
*/
/** @param mixed[] $configs */
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();
Expand Down
17 changes: 7 additions & 10 deletions README.md
Expand Up @@ -62,12 +62,12 @@ coop_tilleuls_url_signer:
signer: 'md5' # 'sha256' by default
```

The default expiration time (in days) can be changed too:
The default expiration time (in seconds) can be changed too:

```yml
# config/packages/url_signer.yaml
coop_tilleuls_url_signer:
default_expiration: 3 # 1 by default
default_expiration: 3600 # 86400 by default
```

You can also customize the URL parameter names:
Expand Down Expand Up @@ -127,10 +127,10 @@ class DocumentController extends AbstractController
$url = $this->generateUrl('secured_document', ['id' => 42]);
// Will expire after one hour.
$expiration = (new \DateTime('now'))->add(new \DateInterval('PT1H'));
// An integer can also be used for the expiration: it will correspond to a number of days. For 3 days:
// $expiration = 3;
// An integer can also be used for the expiration: it will correspond to a number of seconds. For 1 hour:
// $expiration = 3600;

// Not passing the second argument will use the default expiration time (1 day by default).
// Not passing the second argument will use the default expiration time (86400 seconds by default).
// return $this->urlSigner->sign($url);

// Will return a path like this: /documents/42?expires=1611316656&signature=82f6958bd5c96fda58b7a55ade7f651fadb51e12171d58ed271e744bcc7c85c3
Expand Down Expand Up @@ -167,7 +167,6 @@ Create a class extending the `AbstractUrlSigner` class:
namespace App\UrlSigner;

use CoopTilleuls\UrlSignerBundle\UrlSigner\AbstractUrlSigner;
use Psr\Http\Message\UriInterface;

class CustomUrlSigner extends AbstractUrlSigner
{
Expand All @@ -176,11 +175,9 @@ class CustomUrlSigner extends AbstractUrlSigner
return 'custom';
}

protected function createSignature(UriInterface|string $url, string $expiration): string
protected function createSignature(string $url, string $expiration, string $signatureKey): string
{
$url = (string) $url;

return hash_hmac('algo', "{$url}::{$expiration}", $this->signatureKey);
return hash_hmac('algo', "{$url}::{$expiration}", $signatureKey);
}
}
```
Expand Down
10 changes: 2 additions & 8 deletions UrlSigner/AbstractUrlSigner.php
Expand Up @@ -26,14 +26,8 @@ public function __construct(string $signatureKey, int $defaultExpiration, string
$this->defaultExpiration = $defaultExpiration;
}

/**
* @param string $url
* @param \DateTime|int|null $expiration
*
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function sign($url, $expiration = null): string
public function sign(string $url, int|\DateTime $expiration = null, string $signatureKey = null): string
{
return parent::sign($url, $expiration ?? $this->defaultExpiration);
return parent::sign($url, $expiration ?? $this->defaultExpiration, $signatureKey);
}
}
8 changes: 2 additions & 6 deletions UrlSigner/Md5UrlSigner.php
Expand Up @@ -13,8 +13,6 @@

namespace CoopTilleuls\UrlSignerBundle\UrlSigner;

use Psr\Http\Message\UriInterface;

final class Md5UrlSigner extends AbstractUrlSigner
{
public static function getName(): string
Expand All @@ -24,11 +22,9 @@ public static function getName(): string

/**
* Generate a token to identify the secure action.
*
* @param UriInterface|string $url
*/
protected function createSignature($url, string $expiration): string
protected function createSignature(string $url, string $expiration, string $signatureKey): string
{
return hash_hmac('md5', "{$url}::{$expiration}", $this->signatureKey);
return hash_hmac(self::getName(), "{$url}::{$expiration}", $signatureKey);
}
}
8 changes: 2 additions & 6 deletions UrlSigner/Sha256UrlSigner.php
Expand Up @@ -13,8 +13,6 @@

namespace CoopTilleuls\UrlSignerBundle\UrlSigner;

use Psr\Http\Message\UriInterface;

final class Sha256UrlSigner extends AbstractUrlSigner
{
public static function getName(): string
Expand All @@ -24,11 +22,9 @@ public static function getName(): string

/**
* Generate a token to identify the secure action.
*
* @param UriInterface|string $url
*/
protected function createSignature($url, string $expiration): string
protected function createSignature(string $url, string $expiration, string $signatureKey): string
{
return hash_hmac('sha256', "{$url}::{$expiration}", $this->signatureKey);
return hash_hmac(self::getName(), "{$url}::{$expiration}", $signatureKey);
}
}
8 changes: 1 addition & 7 deletions UrlSigner/UrlSignerInterface.php
Expand Up @@ -17,13 +17,7 @@

interface UrlSignerInterface extends UrlSigner
{
/**
* @param string $url
* @param \DateTime|int|null $expiration
*
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function sign($url, $expiration = null): string;
public function sign(string $url, int|\DateTime $expiration, string $signatureKey = null): string;

public static function getName(): string;
}
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -23,8 +23,8 @@
}
},
"require": {
"php": ">=7.4",
"spatie/url-signer": "^1.1",
"php": ">=8.1",
"spatie/url-signer": "^2.0",
"symfony/config": "^4.4 || ^5.1 || ^6.0",
"symfony/dependency-injection": "^4.4 || ^5.1 || ^6.0",
"symfony/event-dispatcher": "^4.4 || ^5.1 || ^6.0",
Expand Down
Expand Up @@ -67,7 +67,7 @@ public function testLoadDefaultConfiguration(): void
$childDefinitionProphecy->addTag('url_signer.signer')->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.signer', Sha256UrlSigner::getName())->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.signature_key', $signatureKey)->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.default_expiration', 1)->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.default_expiration', 86400)->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.expires_parameter', 'expires')->shouldHaveBeenCalledOnce();
$this->containerBuilderProphecy->setParameter('url_signer.signature_parameter', 'signature')->shouldHaveBeenCalledOnce();
$definitions = [
Expand Down
4 changes: 3 additions & 1 deletion tests/EventListener/ValidateSignedRouteListenerTest.php
Expand Up @@ -57,11 +57,13 @@ public function testValidateSignedRoute(string $validUrl): void
$request = Request::create('http://test.org/valid-signature');
$request->attributes->set('_route_params', ['_signed' => true]);
$event = new RequestEvent($this->prophesize(HttpKernelInterface::class)->reveal(), $request, null);
$this->signerProphecy->validate(Argument::any())->willReturn(false);
$this->signerProphecy->validate($validUrl)->willReturn(true);

$this->dispatcher->dispatch($event);

$isPath = 0 === strpos($validUrl, '/');
$isPath = str_starts_with($validUrl, '/');

$this->signerProphecy->validate(Argument::any())->shouldHaveBeenCalledTimes($isPath ? 1 : 2);
}

Expand Down
18 changes: 6 additions & 12 deletions tests/UrlSigner/AbstractUrlSignerTest.php
Expand Up @@ -15,7 +15,6 @@

use CoopTilleuls\UrlSignerBundle\UrlSigner\AbstractUrlSigner;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\UriInterface;

/**
* @internal
Expand All @@ -34,19 +33,14 @@ public static function getName(): string
return 'abstract';
}

/**
* @param UriInterface|string $url
*/
protected function createSignature($url, string $expiration): string
protected function createSignature(string $url, string $expiration, string $signatureKey): string
{
$url = (string) $url;

return "{$url}::{$expiration}::{$this->signatureKey}";
return "{$url}::{$expiration}::{$signatureKey}";
}

protected function getExpirationTimestamp($expiration): string
protected function getExpirationTimestamp(int|\DateTime $expirationInSeconds): string
{
return $expiration instanceof \DateTime ? 'datetime' : (string) $expiration;
return $expirationInSeconds instanceof \DateTime ? 'datetime' : (string) $expirationInSeconds;
}
};
}
Expand All @@ -55,13 +49,13 @@ public function testSignDefaultExpiration(): void
{
$signedUrl = $this->signer->sign('http://test.org/valid-signature');

static::assertSame('http://test.org/valid-signature?exp=5&sign=http://test.org/valid-signature::5::secret', $signedUrl);
static::assertSame('http://test.org/valid-signature?exp=5&sign=http%3A%2F%2Ftest.org%2Fvalid-signature%3A%3A5%3A%3Asecret', $signedUrl);
}

public function testSignWithExpiration(): void
{
$signedUrl = $this->signer->sign('http://test.org/valid-signature', 7);

static::assertSame('http://test.org/valid-signature?exp=7&sign=http://test.org/valid-signature::7::secret', $signedUrl);
static::assertSame('http://test.org/valid-signature?exp=7&sign=http%3A%2F%2Ftest.org%2Fvalid-signature%3A%3A7%3A%3Asecret', $signedUrl);
}
}

0 comments on commit 683d4ce

Please sign in to comment.