From 0b40650ed2d3b5626f1cb010c5d47260022790ed Mon Sep 17 00:00:00 2001
From: Vincent Chalamon <407859+vincentchalamon@users.noreply.github.com>
Date: Thu, 23 May 2024 11:25:11 +0200
Subject: [PATCH] feat: introduce TokenGenerator
---
config/services.xml | 2 ++
docs/index.md | 8 +++++
docs/use_custom_token_generator.md | 36 +++++++++++++++++++
src/DependencyInjection/Configuration.php | 5 +++
src/Manager/PasswordTokenManager.php | 5 +--
.../Bridge/Bin2HexTokenGenerator.php | 24 +++++++++++++
.../TokenGeneratorInterface.php | 22 ++++++++++++
7 files changed, 100 insertions(+), 2 deletions(-)
create mode 100644 docs/use_custom_token_generator.md
create mode 100644 src/TokenGenerator/Bridge/Bin2HexTokenGenerator.php
create mode 100644 src/TokenGenerator/TokenGeneratorInterface.php
diff --git a/config/services.xml b/config/services.xml
index 6cdc5dc..9dfb3d3 100644
--- a/config/services.xml
+++ b/config/services.xml
@@ -36,6 +36,8 @@
+
+
diff --git a/docs/index.md b/docs/index.md
index 5170941..502d421 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -324,3 +324,11 @@ Read full documentation about [usage](usage.md).
By default, this bundle works with Doctrine ORM, but you're free to connect with any system.
Read full documentation about [how to connect your manager](use_custom_manager.md).
+
+## Generate your own token
+
+By default, this bundle works uses [`bin2hex`](https://www.php.net/bin2hex) combined with
+[`random_bytes`](https://www.php.net/random_bytes) to generate the token, but you're free to create your own
+TokenGenerator to create your token.
+
+Read full documentation about [how to generate your own token](use_custom_token_generator.md).
diff --git a/docs/use_custom_token_generator.md b/docs/use_custom_token_generator.md
new file mode 100644
index 0000000..708c869
--- /dev/null
+++ b/docs/use_custom_token_generator.md
@@ -0,0 +1,36 @@
+# Use custom token generator
+
+By default, this bundle works uses [`bin2hex`](https://www.php.net/bin2hex) combined with
+[`random_bytes`](https://www.php.net/random_bytes) to generate the token, but you're free to create your own
+TokenGenerator to create your token.
+
+## Create your custom token generator
+
+Supposing you want to generate your own token, you'll have to create a service that will implement
+`CoopTilleuls\ForgotPasswordBundle\TokenGenerator\TokenGeneratorInterface`:
+
+```php
+// src/TokenGenerator/FooTokenGenerator.php
+namespace App\TokenGenerator;
+
+use CoopTilleuls\ForgotPasswordBundle\TokenGenerator\TokenGeneratorInterface;
+
+final class FooTokenGenerator implements TokenGeneratorInterface
+{
+ public function generate(): string
+ {
+ // generate your own token and return it as string
+ }
+}
+```
+
+## Update configuration
+
+Update your configuration to set your service as default one to use by this bundle:
+
+```yaml
+# config/packages/coop_tilleuls_forgot_password.yaml
+coop_tilleuls_forgot_password:
+ # ...
+ token_generator: 'App\TokenGenerator\FooTokenGenerator'
+```
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index c67e5cf..177e2dd 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -134,6 +134,11 @@ public function getConfigTreeBuilder(): TreeBuilder
->booleanNode('use_jms_serializer')
->defaultFalse()
->end()
+ ->scalarNode('token_generator')
+ ->defaultValue('coop_tilleuls_forgot_password.token_generator.bin2hex')
+ ->cannotBeEmpty()
+ ->info('Persistence manager service to handle the token storage.')
+ ->end()
->end();
return $treeBuilder;
diff --git a/src/Manager/PasswordTokenManager.php b/src/Manager/PasswordTokenManager.php
index 1709ace..258c3ff 100644
--- a/src/Manager/PasswordTokenManager.php
+++ b/src/Manager/PasswordTokenManager.php
@@ -17,13 +17,14 @@
use CoopTilleuls\ForgotPasswordBundle\Provider\Provider;
use CoopTilleuls\ForgotPasswordBundle\Provider\ProviderChainInterface;
use CoopTilleuls\ForgotPasswordBundle\Provider\ProviderInterface;
+use CoopTilleuls\ForgotPasswordBundle\TokenGenerator\TokenGeneratorInterface;
/**
* @author Vincent CHALAMON
*/
class PasswordTokenManager
{
- public function __construct(private readonly ProviderChainInterface $providerChain)
+ public function __construct(private readonly ProviderChainInterface $providerChain, private readonly TokenGeneratorInterface $tokenGenerator)
{
}
@@ -47,7 +48,7 @@ public function createPasswordToken($user, ?\DateTime $expiresAt = null, ?Provid
/** @var AbstractPasswordToken $passwordToken */
$passwordToken = new $tokenClass();
- $passwordToken->setToken(bin2hex(random_bytes(25)));
+ $passwordToken->setToken($this->tokenGenerator->generate());
$passwordToken->setUser($user);
$passwordToken->setExpiresAt($expiresAt);
$provider->getManager()->persist($passwordToken);
diff --git a/src/TokenGenerator/Bridge/Bin2HexTokenGenerator.php b/src/TokenGenerator/Bridge/Bin2HexTokenGenerator.php
new file mode 100644
index 0000000..a1d9fa4
--- /dev/null
+++ b/src/TokenGenerator/Bridge/Bin2HexTokenGenerator.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace CoopTilleuls\ForgotPasswordBundle\TokenGenerator\Bridge;
+
+use CoopTilleuls\ForgotPasswordBundle\TokenGenerator\TokenGeneratorInterface;
+
+final class Bin2HexTokenGenerator implements TokenGeneratorInterface
+{
+ public function generate(): string
+ {
+ return bin2hex(random_bytes(25));
+ }
+}
diff --git a/src/TokenGenerator/TokenGeneratorInterface.php b/src/TokenGenerator/TokenGeneratorInterface.php
new file mode 100644
index 0000000..79da083
--- /dev/null
+++ b/src/TokenGenerator/TokenGeneratorInterface.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace CoopTilleuls\ForgotPasswordBundle\TokenGenerator;
+
+/**
+ * @author Vincent CHALAMON
+ */
+interface TokenGeneratorInterface
+{
+ public function generate(): string;
+}