From 321670a25d3757a3335912ea3254d485055cfba5 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Mon, 1 Feb 2021 00:40:02 +0100 Subject: [PATCH] Hashids salt doesn't accept a binary string. Convert hash to alphanumeric (base 36) string. Removed oldCalcChecksum BC for HashidsConfirmation. Use hmac to create hashids salt. Fixes #16 **BC break!** --- src/Confirmation/HashidsConfirmation.php | 28 +++---------------- .../Confirmation/HashidsConfirmationTest.php | 16 ++--------- 2 files changed, 7 insertions(+), 37 deletions(-) diff --git a/src/Confirmation/HashidsConfirmation.php b/src/Confirmation/HashidsConfirmation.php index ed054e2..b9c4369 100644 --- a/src/Confirmation/HashidsConfirmation.php +++ b/src/Confirmation/HashidsConfirmation.php @@ -37,8 +37,8 @@ class HashidsConfirmation implements ConfirmationInterface /** * HashidsConfirmation constructor. * - * @phpstan-param string $secret - * @phpstan-param null|callable(string):Hashids $createHashids + * @param string $secret + * @param null|callable(string):Hashids $createHashids */ public function __construct(string $secret, ?callable $createHashids = null) { @@ -246,9 +246,8 @@ protected function fetchUserFromStorage(string $uid, array $context): User protected function verifyChecksum(string $checksum, User $user, CarbonImmutable $expire, array $context): void { $expected = $this->calcChecksum($user, $expire); - $expectedOld = $this->calcOldChecksum($user, $expire); - if ($checksum === $expected || $checksum === $expectedOld) { + if ($checksum === $expected) { return; } @@ -288,31 +287,12 @@ protected function calcChecksum(User $user, \DateTimeInterface $expire): string return hash_hmac('sha256', join("\0", $parts), $this->secret); } - /** - * Calculate confirmation checksum, before switching to hmac. - * Temporary so existing confirmation tokens will continue working. Will be removed. - * - * @deprecated - */ - protected function calcOldChecksum(User $user, \DateTimeInterface $expire): string - { - $parts = [ - CarbonImmutable::instance($expire)->utc()->format('YmdHis'), - $user->getAuthId(), - $user->getAuthChecksum(), - $this->secret, - ]; - - return hash('sha256', join("\0", $parts)); - } - - /** * Create a hashids service. */ public function createHashids(): Hashids { - $salt = hash('sha256', $this->subject . $this->secret, true); + $salt = base_convert(hash_hmac('sha256', $this->subject, $this->secret), 16, 36); return ($this->createHashids)($salt); } diff --git a/tests/Confirmation/HashidsConfirmationTest.php b/tests/Confirmation/HashidsConfirmationTest.php index e22413b..234d57b 100644 --- a/tests/Confirmation/HashidsConfirmationTest.php +++ b/tests/Confirmation/HashidsConfirmationTest.php @@ -23,7 +23,7 @@ class HashidsConfirmationTest extends TestCase use ExpectWarningTrait; use CallbackMockTrait; - protected const TOKEN = 'kR2wngZKmZsKRN6xWKy7U1qEWBnWxaf60YjPDakjcXKB1v2rOZt831bDOGk6hJ6WBgGBm'; + protected const TOKEN = 'o1rLAl8m28S8v34QK8V7So8nrKOrBVFjdZgOkzmguBMNzQvyjXIn6ma1Ro9Bh8L7Mk1M0'; protected const STD_HEX = '43b87e6e92e84566b79f6f16ee4c982accec20d16bc3e46c8656bcef93dafba6202001011200003432'; protected const OLD_HEX = '8930d6fab596adc131412a8309d5391611047dcf9dad6e106ccbb5b8ee2ae7fb202001011200003432'; @@ -152,16 +152,6 @@ public function testFrom() $this->assertSame($this->user, $confirm->from(self::TOKEN)); } - public function testFromWithOldToken() - { - $confirm = $this->createService(self::OLD_HEX, $this->user); - - $this->logger->expects($this->once())->method('info') - ->with('Verified confirmation token', $this->expectedContext('42', '2020-01-01T12:00:00+00:00')); - - $this->assertSame($this->user, $confirm->from(self::TOKEN)); - } - public function testFromWithCustomUidEncoding() { $hex = substr(self::STD_HEX, 0, -4) . '2a'; @@ -254,7 +244,7 @@ public function testFromTokenWithInvalidExpireDate() public function testFromExpiredToken() { - $hex = 'b087edc903ba55d052e51aa2f8a01bc8e68c9503778eedc941e9932b36dd8d09' . '20191101120000' . '3432'; + $hex = '3e912b083116f9063a7e0f6fb67179c024d4419aba564f4d898b0c033dc3285b' . '20191101120000' . '3432'; $confirm = $this->createService($hex, $this->user); @@ -274,7 +264,7 @@ public function testCreateHashIdsWithCallback() /** @var Hashids&MockObject $hashids */ $hashids = $this->createMock(Hashids::class); - $salt = hash('sha256', 'testsecret', true); + $salt = base_convert(hash_hmac('sha256', 'test', 'secret'), 16, 36); $callback = $this->createCallbackMock($this->once(), [$salt], $hashids); $service = (new HashidsConfirmation('secret', $callback))