Skip to content

Commit

Permalink
feature #5 Allow Stringable and HiddenString as token input (sstok)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.0-dev branch.

Discussion
----------

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | yes
| Deprecations? | yes/no
| Fixed tickets | 
| License       | MIT

While considering a BC break this only effects custom factory implementations.

Commits
-------

661ba98 Allow Stringable and HiddenString as token input
c700405 Add #[\SensitiveParameter] to token and verifier
  • Loading branch information
sstok committed Jan 6, 2024
2 parents 82b76ae + c700405 commit bdbe7f1
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 8 deletions.
6 changes: 6 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/Argon2SplitTokenFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(#[\SensitiveParameter] string | HiddenString | \Stringable $token): SplitToken
{
return Argon2SplitToken::fromString($token);
}
Expand Down
2 changes: 1 addition & 1 deletion src/FakeSplitTokenFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 9 additions & 3 deletions src/SplitToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ abstract class SplitToken
private ?string $verifierHash = null;
private ?\DateTimeImmutable $expiresAt = null;

final private function __construct(HiddenString $token, string $selector, string $verifier)
final private function __construct(HiddenString $token, string $selector, #[\SensitiveParameter] string $verifier)
{
$this->token = $token;
$this->selector = $selector;
Expand Down Expand Up @@ -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(#[\SensitiveParameter] 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.');
Expand Down Expand Up @@ -253,5 +259,5 @@ protected function configureHasher(array $config): void
abstract protected function verifyHash(string $hash, string $verifier): bool;

/** Produces a hashed version of the verifier. */
abstract protected function hashVerifier(string $verifier): string;
abstract protected function hashVerifier(#[\SensitiveParameter] string $verifier): string;
}
2 changes: 1 addition & 1 deletion src/SplitTokenFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ public function generate(\DateTimeImmutable | \DateInterval $expiresAt = null):
* return SplitToken::fromString($token);
* ```
*/
public function fromString(string $token): SplitToken;
public function fromString(#[\SensitiveParameter] string | HiddenString | \Stringable $token): SplitToken;
}
32 changes: 30 additions & 2 deletions tests/Argon2SplitTokenFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}
32 changes: 32 additions & 0 deletions tests/FakeSplitTokenFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,36 @@ 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(
#[\SensitiveParameter]
private string $value
) {}

public function __toString(): string
{
return $this->value;
}
};

$splitTokenFromString = $factory->fromString($stringObj);
self::assertTrue($splitTokenFromString->matches($splitToken->toValueHolder()));
}
}

0 comments on commit bdbe7f1

Please sign in to comment.