Skip to content

Commit

Permalink
Use better exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
SamMousa committed Oct 8, 2018
1 parent 60bec7e commit 51a529d
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 38 deletions.
14 changes: 14 additions & 0 deletions src/ExpiredLinkException.php
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);


namespace SamIT\Yii2\UrlSigner;


class ExpiredLinkException extends UrlSignerException
{
public function __construct(int $code = 0, \Exception $previous = null)
{
parent::__construct('This URL has expired', $code, $previous);
}
}
4 changes: 1 addition & 3 deletions src/HmacFilter.php
Expand Up @@ -43,9 +43,7 @@ public function beforeAction($action)
* @var Request $request
*/
$request = $action->controller->module->get('request');
if (!$this->signer->verify($request->queryParams, $action->controller->route)) {
throw new ForbiddenHttpException("No or invalid HMAC");
}
$this->signer->verify($request->queryParams, $action->controller->route);
return true;
}

Expand Down
14 changes: 14 additions & 0 deletions src/InvalidHmacException.php
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);


namespace SamIT\Yii2\UrlSigner;


class InvalidHmacException extends UrlSignerException
{
public function __construct(int $code = 0, \Exception $previous = null)
{
parent::__construct('This security code in this URL invalid', $code, $previous);
}
}
14 changes: 14 additions & 0 deletions src/MissingHmacException.php
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);


namespace SamIT\Yii2\UrlSigner;


class MissingHmacException extends UrlSignerException
{
public function __construct(int $code = 0, \Exception $previous = null)
{
parent::__construct('This security code for this URL is missing', $code, $previous);
}
}
17 changes: 11 additions & 6 deletions src/UrlSigner.php
Expand Up @@ -140,10 +140,15 @@ private function time(): int
{
return $this->_currentTimestamp ?? \time();
}
private function checkExpiration(array $params): bool

private function checkExpiration(array $params): void
{
// Check expiration date.
return !isset($params[$this->expirationParam]) || $params[$this->expirationParam] > $this->time();
if (isset($params[$this->expirationParam])
&& $params[$this->expirationParam] <= $this->time()
) {
throw new ExpiredLinkException();
}
}

/**
Expand Down Expand Up @@ -190,21 +195,21 @@ private function getSignedParams(array $params): array
* @throws \Exception
* @return bool
*/
public function verify(array $params, string $route):bool
public function verify(array $params, string $route):void
{
if (!isset($params[$this->hmacParam])) {
return false;
throw new MissingHmacException();
}
$hmac = $params[$this->hmacParam];

$signedParams = $this->getSignedParams($params);

$calculated = $this->calculateHMAC($signedParams, $route);
if (!\hash_equals($calculated, $hmac)) {
return false;
throw new InvalidHmacException();
}

return $this->checkExpiration($params);
$this->checkExpiration($params);
}

private function urlEncode(string $bytes): string
Expand Down
12 changes: 12 additions & 0 deletions src/UrlSignerException.php
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);


namespace SamIT\Yii2\UrlSigner;


use yii\web\ForbiddenHttpException;

abstract class UrlSignerException extends ForbiddenHttpException
{
}
8 changes: 1 addition & 7 deletions tests/unit/HmacFilterTest.php
Expand Up @@ -33,14 +33,8 @@ public function testValidConfig(): void

public function testVerifyFalse(): void
{
$mock = $this->make(SamIT\Yii2\UrlSigner\UrlSigner::class, [
'verify' => \Codeception\Stub\Expected::once(function() {
return false;
})
]);

$filter = new \SamIT\Yii2\UrlSigner\HmacFilter([
'signer' => $mock
'signer' => new SamIT\Yii2\UrlSigner\UrlSigner(['secret' => 'test123'])
]);


Expand Down
51 changes: 29 additions & 22 deletions tests/unit/UrlSignerTest.php
@@ -1,17 +1,20 @@
<?php
declare(strict_types=1);

use SamIT\Yii2\UrlSigner\InvalidHmacException;
use SamIT\Yii2\UrlSigner\MissingHmacException;
use SamIT\Yii2\UrlSigner\UrlSigner;
class UrlSignerTest extends \Codeception\Test\Unit
{
public function testInvalidConfig(): void
{
$this->expectException(\yii\base\InvalidConfigException::class);
$signer = new SamIT\Yii2\UrlSigner\UrlSigner();
$signer = new UrlSigner();

}
public function testSimple(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);

Expand All @@ -26,12 +29,12 @@ public function testSimple(): void
$this->assertArrayNotHasKey($signer->paramsParam, $params);
$route = $params[0];
unset($params[0]);
$this->assertTrue($signer->verify($params, $route));
$signer->verify($params, $route);
}

public function testAdditions(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);

Expand All @@ -46,14 +49,14 @@ public function testAdditions(): void
$this->assertArrayHasKey($signer->paramsParam, $params);
$route = $params[0];
unset($params[0]);
$this->assertTrue($signer->verify($params, $route));
$signer->verify($params, $route);
$params['extra'] = 'cool';
$this->assertTrue($signer->verify($params, $route));
$signer->verify($params, $route);
}

public function testDoubleSign(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);

Expand All @@ -69,7 +72,7 @@ public function testDoubleSign(): void

public function testMissingHmac(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);
$params = [
Expand All @@ -83,14 +86,15 @@ public function testMissingHmac(): void
$this->assertArrayNotHasKey($signer->paramsParam, $params);
$route = $params[0];
unset($params[0]);
$this->assertTrue($signer->verify($params, $route));
$signer->verify($params, $route);
unset($params[$signer->hmacParam]);
$this->assertFalse($signer->verify($params, $route));
$this->expectException(MissingHmacException::class);
$signer->verify($params, $route);
}

public function testModification(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);
$params = [
Expand All @@ -106,12 +110,13 @@ public function testModification(): void
unset($params[0]);

$params['test'] = 'abd';
$this->assertFalse($signer->verify($params, $route));
$this->expectException(InvalidHmacException::class);
$signer->verify($params, $route);
}

public function testRelativeRoute(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);

Expand All @@ -125,7 +130,7 @@ public function testRelativeRoute(): void

public function testMissingExpiration(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);

Expand All @@ -136,12 +141,13 @@ public function testMissingExpiration(): void
$signer->signParams($params);

unset($params[$signer->expirationParam]);
$this->assertFalse($signer->verify($params, '/controller/action'));
$this->expectException(InvalidHmacException::class);
$signer->verify($params, '/controller/action');
}

public function testNoExpiration(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123'
]);
$expirationParam = $signer->expirationParam;
Expand All @@ -154,14 +160,14 @@ public function testNoExpiration(): void
$signer->signParams($params);
$this->assertNotContains($expirationParam, $params);

$this->assertTrue($signer->verify($params, '/controller/action'));
$signer->verify($params, '/controller/action');
$signer->expirationParam = $expirationParam;
$this->assertTrue($signer->verify($params, '/controller/action'));
$signer->verify($params, '/controller/action');
}

public function testDefaultExpiration(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123',
'defaultExpirationInterval' => 'P14D'
]);
Expand All @@ -175,7 +181,7 @@ public function testDefaultExpiration(): void

public function testTimeMocking(): void
{
$signer = new SamIT\Yii2\UrlSigner\UrlSigner([
$signer = new UrlSigner([
'secret' => 'test123',
'defaultExpirationInterval' => 'PT01S'
]);
Expand All @@ -186,10 +192,11 @@ public function testTimeMocking(): void
$this->assertContains('expires', $params);
$this->assertSame(\time() + 1, $params['expires']);
$signer->setCurrentTimestamp(\time() - 10);
$this->assertTrue($signer->verify($params, '/controller/action'));
$signer->verify($params, '/controller/action');
$signer->setCurrentTimestamp(null);
$this->assertTrue($signer->verify($params, '/controller/action'));
$signer->verify($params, '/controller/action');
$signer->setCurrentTimestamp(\time() + 5);
$this->expectException(\SamIT\Yii2\UrlSigner\ExpiredLinkException::class);
$this->assertFalse($signer->verify($params, '/controller/action'));
}
}

0 comments on commit 51a529d

Please sign in to comment.