X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=tests%2Fapi%2FApiUtilsTest.php;h=96787014c1318a1fa155a0435899837e77ad797e;hb=ee07b7283faa197fc062ed85f4f96f98e8e77b03;hp=516ee6860edd169ba2cf6ea962669e59a0296896;hpb=c3b00963fe22479e87998c82bc83827a54c8d972;p=github%2Fshaarli%2FShaarli.git diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php index 516ee686..96787014 100644 --- a/tests/api/ApiUtilsTest.php +++ b/tests/api/ApiUtilsTest.php @@ -2,15 +2,18 @@ namespace Shaarli\Api; +use Shaarli\Bookmark\Bookmark; +use Shaarli\Http\Base64Url; + /** * Class ApiUtilsTest */ -class ApiUtilsTest extends \PHPUnit_Framework_TestCase +class ApiUtilsTest extends \PHPUnit\Framework\TestCase { /** * Force the timezone for ISO datetimes. */ - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { date_default_timezone_set('UTC'); } @@ -24,14 +27,14 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase */ public static function generateValidJwtToken($secret) { - $header = base64_encode('{ + $header = Base64Url::encode('{ "typ": "JWT", "alg": "HS512" }'); - $payload = base64_encode('{ + $payload = Base64Url::encode('{ "iat": '. time() .' }'); - $signature = hash_hmac('sha512', $header .'.'. $payload , $secret); + $signature = Base64Url::encode(hash_hmac('sha512', $header .'.'. $payload, $secret, true)); return $header .'.'. $payload .'.'. $signature; } @@ -46,9 +49,9 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase */ public static function generateCustomJwtToken($header, $payload, $secret) { - $header = base64_encode($header); - $payload = base64_encode($payload); - $signature = hash_hmac('sha512', $header . '.' . $payload, $secret); + $header = Base64Url::encode($header); + $payload = Base64Url::encode($payload); + $signature = Base64Url::encode(hash_hmac('sha512', $header . '.' . $payload, $secret, true)); return $header . '.' . $payload . '.' . $signature; } @@ -58,148 +61,148 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase public function testValidateJwtTokenValid() { $secret = 'WarIsPeace'; - ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret); + $this->assertTrue(ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret)); } /** * Test validateJwtToken() with a malformed JWT token. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Malformed JWT token */ public function testValidateJwtTokenMalformed() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Malformed JWT token'); + $token = 'ABC.DEF'; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with an empty JWT token. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Malformed JWT token */ public function testValidateJwtTokenMalformedEmpty() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Malformed JWT token'); + $token = false; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with a JWT token without header. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Malformed JWT token */ public function testValidateJwtTokenMalformedEmptyHeader() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Malformed JWT token'); + $token = '.payload.signature'; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with a JWT token without payload - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Malformed JWT token */ public function testValidateJwtTokenMalformedEmptyPayload() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Malformed JWT token'); + $token = 'header..signature'; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with a JWT token with an empty signature. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT signature */ public function testValidateJwtTokenInvalidSignatureEmpty() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT signature'); + $token = 'header.payload.'; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with a JWT token with an invalid signature. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT signature */ public function testValidateJwtTokenInvalidSignature() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT signature'); + $token = 'header.payload.nope'; ApiUtils::validateJwtToken($token, 'foo'); } /** * Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT signature */ public function testValidateJwtTokenInvalidSignatureSecret() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT signature'); + ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar'); } /** * Test validateJwtToken() with a JWT token with a an invalid header (not JSON). - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT header */ public function testValidateJwtTokenInvalidHeader() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT header'); + $token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret'); ApiUtils::validateJwtToken($token, 'secret'); } /** * Test validateJwtToken() with a JWT token with a an invalid payload (not JSON). - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT payload */ public function testValidateJwtTokenInvalidPayload() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT payload'); + $token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret'); ApiUtils::validateJwtToken($token, 'secret'); } /** * Test validateJwtToken() with a JWT token without issued time. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT issued time */ public function testValidateJwtTokenInvalidTimeEmpty() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT issued time'); + $token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret'); ApiUtils::validateJwtToken($token, 'secret'); } /** * Test validateJwtToken() with an expired JWT token. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT issued time */ public function testValidateJwtTokenInvalidTimeExpired() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT issued time'); + $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret'); ApiUtils::validateJwtToken($token, 'secret'); } /** * Test validateJwtToken() with a JWT token issued in the future. - * - * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException - * @expectedExceptionMessage Invalid JWT issued time */ public function testValidateJwtTokenInvalidTimeFuture() { + $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class); + $this->expectExceptionMessage('Invalid JWT issued time'); + $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret'); ApiUtils::validateJwtToken($token, 'secret'); } @@ -210,7 +213,7 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase public function testFormatLinkComplete() { $indexUrl = 'https://domain.tld/sub/'; - $link = [ + $data = [ 'id' => 12, 'url' => 'http://lol.lol', 'shorturl' => 'abc', @@ -221,6 +224,8 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'), 'updated' => \DateTime::createFromFormat('Ymd_His', '20170107_160612'), ]; + $bookmark = new Bookmark(); + $bookmark->fromArray($data); $expected = [ 'id' => 12, @@ -234,7 +239,7 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase 'updated' => '2017-01-07T16:06:12+00:00', ]; - $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl)); + $this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl)); } /** @@ -243,7 +248,7 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase public function testFormatLinkMinimalNote() { $indexUrl = 'https://domain.tld/sub/'; - $link = [ + $data = [ 'id' => 12, 'url' => '?abc', 'shorturl' => 'abc', @@ -253,6 +258,8 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase 'private' => '', 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'), ]; + $bookmark = new Bookmark(); + $bookmark->fromArray($data); $expected = [ 'id' => 12, @@ -266,6 +273,82 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase 'updated' => '', ]; - $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl)); + $this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl)); + } + + /** + * Test updateLink with valid data, and also unnecessary fields. + */ + public function testUpdateLink() + { + $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102'); + $data = [ + 'id' => 12, + 'url' => '?abc', + 'shorturl' => 'abc', + 'title' => 'Note', + 'description' => '', + 'tags' => '', + 'private' => '', + 'created' => $created, + ]; + $old = new Bookmark(); + $old->fromArray($data); + + $data = [ + 'id' => 13, + 'shorturl' => 'nope', + 'url' => 'http://somewhere.else', + 'title' => 'Le Cid', + 'description' => 'Percé jusques au fond du cœur [...]', + 'tags' => 'corneille rodrigue', + 'private' => true, + 'created' => 'creation', + 'updated' => 'updation', + ]; + $new = new Bookmark(); + $new->fromArray($data); + + $result = ApiUtils::updateLink($old, $new); + $this->assertEquals(12, $result->getId()); + $this->assertEquals('http://somewhere.else', $result->getUrl()); + $this->assertEquals('abc', $result->getShortUrl()); + $this->assertEquals('Le Cid', $result->getTitle()); + $this->assertEquals('Percé jusques au fond du cœur [...]', $result->getDescription()); + $this->assertEquals('corneille rodrigue', $result->getTagsString()); + $this->assertEquals(true, $result->isPrivate()); + $this->assertEquals($created, $result->getCreated()); + } + + /** + * Test updateLink with minimal data. + */ + public function testUpdateLinkMinimal() + { + $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102'); + $data = [ + 'id' => 12, + 'url' => '?abc', + 'shorturl' => 'abc', + 'title' => 'Note', + 'description' => 'Interesting description!', + 'tags' => 'doggo', + 'private' => true, + 'created' => $created, + ]; + $old = new Bookmark(); + $old->fromArray($data); + + $new = new Bookmark(); + + $result = ApiUtils::updateLink($old, $new); + $this->assertEquals(12, $result->getId()); + $this->assertEquals('', $result->getUrl()); + $this->assertEquals('abc', $result->getShortUrl()); + $this->assertEquals('', $result->getTitle()); + $this->assertEquals('', $result->getDescription()); + $this->assertEquals('', $result->getTagsString()); + $this->assertEquals(false, $result->isPrivate()); + $this->assertEquals($created, $result->getCreated()); } }