From 661ba98f39d070a382a6be56cbd9f9bbf4aba2fd Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Sat, 6 Jan 2024 11:34:24 +0100 Subject: [PATCH] Allow Stringable and HiddenString as token input --- UPGRADE.md | 6 +++++ src/Argon2SplitTokenFactory.php | 2 +- src/FakeSplitTokenFactory.php | 2 +- src/SplitToken.php | 8 ++++++- src/SplitTokenFactory.php | 2 +- tests/Argon2SplitTokenFactoryTest.php | 32 +++++++++++++++++++++++++-- tests/FakeSplitTokenFactoryTest.php | 29 ++++++++++++++++++++++++ 7 files changed, 75 insertions(+), 6 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index f63d63d..2b8425b 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,6 +1,12 @@ UPGRADE ======= +## Upgrade from 1.0.0-BETA1 + +* The `Rollerworks\Component\SplitToken\SplitTokenFactory::fromString()` method + now also accepts a `Stringable` object or `HiddenString`. Unless a custom factory + implementation is used this should not effect your code. + ## Upgrade from 0.1.2 * Support for PHP 8.1 and lower was dropped; diff --git a/src/Argon2SplitTokenFactory.php b/src/Argon2SplitTokenFactory.php index ad5f987..96f7830 100644 --- a/src/Argon2SplitTokenFactory.php +++ b/src/Argon2SplitTokenFactory.php @@ -40,7 +40,7 @@ public function generate(\DateTimeImmutable | \DateInterval $expiresAt = null): return $splitToken->expireAt($this->getExpirationTimestamp($expiresAt)); } - public function fromString(string $token): SplitToken + public function fromString(string | HiddenString | \Stringable $token): SplitToken { return Argon2SplitToken::fromString($token); } diff --git a/src/FakeSplitTokenFactory.php b/src/FakeSplitTokenFactory.php index db3c5e6..e99c4d5 100644 --- a/src/FakeSplitTokenFactory.php +++ b/src/FakeSplitTokenFactory.php @@ -43,7 +43,7 @@ public function generate(\DateTimeImmutable | \DateInterval $expiresAt = null): ->expireAt($this->getExpirationTimestamp($expiresAt)); } - public function fromString(string $token): SplitToken + public function fromString(string | HiddenString | \Stringable $token): SplitToken { return FakeSplitToken::fromString($token); } diff --git a/src/SplitToken.php b/src/SplitToken.php index 1a145cf..10e7496 100644 --- a/src/SplitToken.php +++ b/src/SplitToken.php @@ -150,8 +150,14 @@ public function expireAt(\DateTimeImmutable $expiresAt = null): static * * Note: The provided $token is zeroed from memory when it's length is valid. */ - final public static function fromString(string $token): static + final public static function fromString(string | HiddenString | \Stringable $token): static { + if ($token instanceof HiddenString) { + $token = $token->getString(); + } + + $token = (string) $token; + if (Binary::safeStrlen($token) !== self::TOKEN_CHAR_LENGTH) { // Don't zero memory as the value is invalid. throw new \RuntimeException('Invalid token provided.'); diff --git a/src/SplitTokenFactory.php b/src/SplitTokenFactory.php index e6b7eec..2e25eae 100644 --- a/src/SplitTokenFactory.php +++ b/src/SplitTokenFactory.php @@ -46,5 +46,5 @@ public function generate(\DateTimeImmutable | \DateInterval $expiresAt = null): * return SplitToken::fromString($token); * ``` */ - public function fromString(string $token): SplitToken; + public function fromString(string | HiddenString | \Stringable $token): SplitToken; } diff --git a/tests/Argon2SplitTokenFactoryTest.php b/tests/Argon2SplitTokenFactoryTest.php index 217e335..cb13f6f 100644 --- a/tests/Argon2SplitTokenFactoryTest.php +++ b/tests/Argon2SplitTokenFactoryTest.php @@ -71,9 +71,37 @@ public function it_creates_from_string(): void { $factory = new Argon2SplitTokenFactory(); $splitToken = $factory->generate(); - $fullToken = $splitToken->token()->getString(); - $splitTokenFromString = $factory->fromString($fullToken); + $splitTokenFromString = $factory->fromString($splitToken->token()->getString()); + self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); + } + + #[Test] + public function it_creates_from_hidden_string(): void + { + $factory = new Argon2SplitTokenFactory(); + $splitToken = $factory->generate(); + + $splitTokenFromString = $factory->fromString($splitToken->token()); + self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); + } + + #[Test] + public function it_creates_from_stringable_object(): void + { + $factory = new Argon2SplitTokenFactory(); + $splitToken = $factory->generate(); + + $stringObj = new class($splitToken->token()->getString()) implements \Stringable { + public function __construct(private string $value) {} + + public function __toString(): string + { + return $this->value; + } + }; + + $splitTokenFromString = $factory->fromString($stringObj); self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); } } diff --git a/tests/FakeSplitTokenFactoryTest.php b/tests/FakeSplitTokenFactoryTest.php index c8fc6ad..80b5545 100644 --- a/tests/FakeSplitTokenFactoryTest.php +++ b/tests/FakeSplitTokenFactoryTest.php @@ -100,4 +100,33 @@ public function it_creates_from_string_with_mock_provided_selector(): void self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); self::assertTrue($splitTokenFromString2->matches($splitToken->toValueHolder())); } + + #[Test] + public function it_creates_from_hidden_string(): void + { + $factory = new FakeSplitTokenFactory(); + $splitToken = $factory->generate(); + + $splitTokenFromString = $factory->fromString($splitToken->token()); + self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); + } + + #[Test] + public function it_creates_from_stringable_object(): void + { + $factory = new FakeSplitTokenFactory(); + $splitToken = $factory->generate(); + + $stringObj = new class($splitToken->token()->getString()) implements \Stringable { + public function __construct(private string $value) {} + + public function __toString(): string + { + return $this->value; + } + }; + + $splitTokenFromString = $factory->fromString($stringObj); + self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder())); + } }