From f5f817179c7873e5fc1c1c50208c6f5906acf1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Tou=C5=A1ek?= Date: Sat, 10 Sep 2016 16:55:11 +0200 Subject: [PATCH] Prevent PHP errors using more strict filters --- src/FilterIn/BooleanFilterIn.php | 5 + src/FilterIn/FloatFilterIn.php | 5 + src/FilterIn/IntegerFilterIn.php | 5 + src/FilterIn/StringFilterIn.php | 7 +- tests/functional/config/config.neon | 2 +- .../src/Fixtures/ArticlePresenter.php | 23 +++- .../functional/src/Fixtures/RouterFactory.php | 9 +- .../src/RequestEntityLoaderTest.php | 130 +++++++++++++++--- .../src/RequestEntityUnloaderTest.php | 2 +- 9 files changed, 162 insertions(+), 26 deletions(-) diff --git a/src/FilterIn/BooleanFilterIn.php b/src/FilterIn/BooleanFilterIn.php index 04122b6..55d2644 100644 --- a/src/FilterIn/BooleanFilterIn.php +++ b/src/FilterIn/BooleanFilterIn.php @@ -11,6 +11,7 @@ namespace Arachne\EntityLoader\FilterIn; use Arachne\EntityLoader\FilterInInterface; +use Nette\Application\BadRequestException; /** * @author Jáchym Toušek @@ -22,6 +23,10 @@ class BooleanFilterIn implements FilterInInterface */ public function filterIn($value) { + if (!is_string($value)) { + throw new BadRequestException(); + } + return (bool) $value; } } diff --git a/src/FilterIn/FloatFilterIn.php b/src/FilterIn/FloatFilterIn.php index 3cdddc4..da2ea85 100644 --- a/src/FilterIn/FloatFilterIn.php +++ b/src/FilterIn/FloatFilterIn.php @@ -11,6 +11,7 @@ namespace Arachne\EntityLoader\FilterIn; use Arachne\EntityLoader\FilterInInterface; +use Nette\Application\BadRequestException; /** * @author Jáchym Toušek @@ -22,6 +23,10 @@ class FloatFilterIn implements FilterInInterface */ public function filterIn($value) { + if (!is_string($value)) { + throw new BadRequestException(); + } + return (float) $value; } } diff --git a/src/FilterIn/IntegerFilterIn.php b/src/FilterIn/IntegerFilterIn.php index 70a3534..5c2eca3 100644 --- a/src/FilterIn/IntegerFilterIn.php +++ b/src/FilterIn/IntegerFilterIn.php @@ -11,6 +11,7 @@ namespace Arachne\EntityLoader\FilterIn; use Arachne\EntityLoader\FilterInInterface; +use Nette\Application\BadRequestException; /** * @author Jáchym Toušek @@ -22,6 +23,10 @@ class IntegerFilterIn implements FilterInInterface */ public function filterIn($value) { + if (!is_string($value)) { + throw new BadRequestException(); + } + return (int) $value; } } diff --git a/src/FilterIn/StringFilterIn.php b/src/FilterIn/StringFilterIn.php index 4b235b1..65d2a5e 100644 --- a/src/FilterIn/StringFilterIn.php +++ b/src/FilterIn/StringFilterIn.php @@ -11,6 +11,7 @@ namespace Arachne\EntityLoader\FilterIn; use Arachne\EntityLoader\FilterInInterface; +use Nette\Application\BadRequestException; /** * @author Jáchym Toušek @@ -22,6 +23,10 @@ class StringFilterIn implements FilterInInterface */ public function filterIn($value) { - return (string) $value; + if (!is_string($value)) { + throw new BadRequestException(); + } + + return $value; } } diff --git a/tests/functional/config/config.neon b/tests/functional/config/config.neon index c93fdd4..105ae05 100644 --- a/tests/functional/config/config.neon +++ b/tests/functional/config/config.neon @@ -11,7 +11,7 @@ extensions: oops.cachefactory: Oops\CacheFactory\DI\CacheFactoryExtension nette.application: - catchExceptions: null + catchExceptions: false mapping: *: Tests\Functional\Fixtures\*Presenter diff --git a/tests/functional/src/Fixtures/ArticlePresenter.php b/tests/functional/src/Fixtures/ArticlePresenter.php index f4c7505..e2dccfa 100644 --- a/tests/functional/src/Fixtures/ArticlePresenter.php +++ b/tests/functional/src/Fixtures/ArticlePresenter.php @@ -18,6 +18,10 @@ public function actionUntyped($parameter) { } + public function actionEntity(Article $parameter) + { + } + /** * @param int $parameter */ @@ -25,7 +29,24 @@ public function actionInt($parameter = 1) { } - public function actionEntity(Article $parameter) + /** + * @param bool $parameter + */ + public function actionBool($parameter) + { + } + + /** + * @param float $parameter + */ + public function actionFloat($parameter) + { + } + + /** + * @param string $parameter + */ + public function actionString($parameter) { } } diff --git a/tests/functional/src/Fixtures/RouterFactory.php b/tests/functional/src/Fixtures/RouterFactory.php index e56c59c..fe40b23 100644 --- a/tests/functional/src/Fixtures/RouterFactory.php +++ b/tests/functional/src/Fixtures/RouterFactory.php @@ -29,9 +29,12 @@ public function __construct(RequestEntityUnloader $unloader) public function create() { $router = new RouteList(); - $router[] = new Route('/[/]', [ - 'presenter' => 'Article', - ]); + $router[] = new Route( + '/', + [ + 'presenter' => 'Article', + ] + ); return new RouterWrapper($router, $this->unloader); } diff --git a/tests/functional/src/RequestEntityLoaderTest.php b/tests/functional/src/RequestEntityLoaderTest.php index f3ccfe9..1f35a1d 100644 --- a/tests/functional/src/RequestEntityLoaderTest.php +++ b/tests/functional/src/RequestEntityLoaderTest.php @@ -4,6 +4,7 @@ use Codeception\TestCase\Test; use Nette\Application\Application; +use Nette\Application\UI\Presenter; use Tests\Functional\Fixtures\Article; /** @@ -17,36 +18,127 @@ class RequestEntityLoaderTest extends Test */ public function testUntyped() { - $this->tester->amOnPage('/untyped/5'); + $this->tester->amOnPage('/untyped?parameter=5'); + } + + public function testEntity() + { + $this->tester->amOnPage('/entity?parameter=5'); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertEquals( + [ + 'action' => 'entity', + 'parameter' => new Article(5), + ], + $request->getParameters() + ); } public function testInt() { - $this->tester->amOnPage('/int/5'); - $request = $this->tester->grabService(Application::class)->getPresenter()->getRequest(); - $this->assertSame([ - 'action' => 'int', - 'parameter' => 5, - ], $request->getParameters()); + $this->tester->amOnPage('/int?parameter=5'); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertSame( + [ + 'action' => 'int', + 'parameter' => 5, + ], + $request->getParameters() + ); } public function testIntWithDefault() { $this->tester->amOnPage('/int'); - $request = $this->tester->grabService(Application::class)->getPresenter()->getRequest(); - $this->assertSame([ - 'action' => 'int', - 'parameter' => null, - ], $request->getParameters()); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertSame( + [ + 'action' => 'int', + ], + $request->getParameters() + ); } - public function testEntity() + /** + * @expectedException Nette\Application\BadRequestException + */ + public function testIntError() + { + $this->tester->amOnPage('/int?parameter[]=0'); + } + + public function testBool() + { + $this->tester->amOnPage('/bool?parameter=1'); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertSame( + [ + 'action' => 'bool', + 'parameter' => true, + ], + $request->getParameters() + ); + } + + /** + * @expectedException Nette\Application\BadRequestException + */ + public function testBoolError() + { + $this->tester->amOnPage('/bool?parameter[]=0'); + } + + public function testFloat() + { + $this->tester->amOnPage('/float?parameter=1'); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertSame( + [ + 'action' => 'float', + 'parameter' => 1.0, + ], + $request->getParameters() + ); + } + + /** + * @expectedException Nette\Application\BadRequestException + */ + public function testFloatError() + { + $this->tester->amOnPage('/float?parameter[]=0'); + } + + public function testString() + { + $this->tester->amOnPage('/string?parameter=1'); + $presenter = $this->tester->grabService(Application::class)->getPresenter(); + self::assertInstanceOf(Presenter::class, $presenter); + $request = $presenter->getRequest(); + self::assertSame( + [ + 'action' => 'string', + 'parameter' => '1', + ], + $request->getParameters() + ); + } + + /** + * @expectedException Nette\Application\BadRequestException + */ + public function testStringError() { - $this->tester->amOnPage('/entity/5'); - $request = $this->tester->grabService(Application::class)->getPresenter()->getRequest(); - $this->assertEquals([ - 'action' => 'entity', - 'parameter' => new Article(5), - ], $request->getParameters()); + $this->tester->amOnPage('/string?parameter[]=0'); } } diff --git a/tests/functional/src/RequestEntityUnloaderTest.php b/tests/functional/src/RequestEntityUnloaderTest.php index 87d9b88..2de5eaf 100644 --- a/tests/functional/src/RequestEntityUnloaderTest.php +++ b/tests/functional/src/RequestEntityUnloaderTest.php @@ -15,6 +15,6 @@ public function testLink() { $this->tester->amOnPage('/default'); $presenter = $this->tester->grabService(Application::class)->getPresenter(); - $this->assertSame('/entity/5', $presenter->link('Article:entity', new Article(5))); + $this->assertSame('/entity?parameter=5', $presenter->link('Article:entity', new Article(5))); } }