From 65382e9cc46816ce31a39a6ac932a3dbe2748720 Mon Sep 17 00:00:00 2001 From: TiaNex Date: Sun, 6 Oct 2024 12:32:52 +0800 Subject: [PATCH 1/6] Create interface CsrfParametersInjectionInterface Returns array of csrf parameters,then merge to common parameters and metaTag parameters. --- ...interface CsrfParametersInjectionInterface | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/interface CsrfParametersInjectionInterface diff --git a/src/interface CsrfParametersInjectionInterface b/src/interface CsrfParametersInjectionInterface new file mode 100644 index 0000000..2ec0b07 --- /dev/null +++ b/src/interface CsrfParametersInjectionInterface @@ -0,0 +1,38 @@ +|string> + */ +interface CsrfParametersInjectionInterface +{ + /** + * Returns array of csrf parameters,then merge to common parameters and metaTag parameters. + * + * + * For example: + * + * ```php + * [ + * [ '_csrf' => $csrf ], + * [ + * 'csrf' => [ + * 'name' => 'csrf' , + * 'content' => $tokenValue + * ], + * ], + * ... + * ] + * ``` + * + * @return array + * + * @psalm-return csrfParameters + */ + public function getCsrfParameters(): array; +} From fec315e75901835717fdd12b59a300d48bbf81e8 Mon Sep 17 00:00:00 2001 From: TiaNex Date: Sun, 6 Oct 2024 12:34:27 +0800 Subject: [PATCH 2/6] Update LayoutParametersInjectionInterface.php get csrftoken once --- src/LayoutParametersInjectionInterface.php | 59 ++++++++++++++++------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/LayoutParametersInjectionInterface.php b/src/LayoutParametersInjectionInterface.php index 91527e2..cb39471 100644 --- a/src/LayoutParametersInjectionInterface.php +++ b/src/LayoutParametersInjectionInterface.php @@ -4,25 +4,52 @@ namespace Yiisoft\Yii\View\Renderer; +use LogicException; +use Yiisoft\Csrf\CsrfTokenInterface; +use Yiisoft\Csrf\CsrfTrait; + /** - * LayoutParametersInjectionInterface is an interface that must be implemented by classes to inject layout parameters. + * `CsrfViewInjection` injects the necessary data into the view to protect against a CSRF attack. */ -interface LayoutParametersInjectionInterface +final class CsrfViewInjection implements CsrfParametersInjectionInterface { + use CsrfTrait; + + public const DEFAULT_META_ATTRIBUTE_NAME = 'csrf'; + public const DEFAULT_PARAMETER_NAME = 'csrf'; + public const META_TAG_KEY = 'csrf'; + + private string $metaAttributeName = self::DEFAULT_META_ATTRIBUTE_NAME; + private string $parameterName = self::DEFAULT_PARAMETER_NAME; + + public function __construct(private CsrfTokenInterface $token) + { + } + + /** - * Returns parameters for added to layout. - * - * For example: - * - * ``` - * [ - * 'paramA' => 'something', - * 'paramB' => 42, - * ... - * ] - * ``` - * - * @psalm-return array + * @throws LogicException when CSRF token is not defined */ - public function getLayoutParameters(): array; + public function getCsrfParameters(): array + { + $tokenValue = $this->token->getValue(); + $csrf = new Csrf( + $tokenValue, + $this->getFormParameterName(), + $this->getHeaderName(), + ); + return [ + [ + $this->parameterName => $csrf + ], + [ + self::META_TAG_KEY => [ + 'name' => $this->metaAttributeName, + 'content' => $tokenValue + ], + ], + ]; + } + + } From c0a26c8471b22635c78ffc8ea9b1b55eea5f9e3a Mon Sep 17 00:00:00 2001 From: TiaNex Date: Sun, 6 Oct 2024 12:36:16 +0800 Subject: [PATCH 3/6] Rename interface CsrfParametersInjectionInterface to CsrfParametersInjectionInterface --- ...ametersInjectionInterface => CsrfParametersInjectionInterface} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{interface CsrfParametersInjectionInterface => CsrfParametersInjectionInterface} (100%) diff --git a/src/interface CsrfParametersInjectionInterface b/src/CsrfParametersInjectionInterface similarity index 100% rename from src/interface CsrfParametersInjectionInterface rename to src/CsrfParametersInjectionInterface From aa3df2d7598d19c41fe15b63ed523cc6afd98b50 Mon Sep 17 00:00:00 2001 From: TiaNex Date: Sun, 6 Oct 2024 12:41:30 +0800 Subject: [PATCH 4/6] Update ViewRenderer.php get csrf token onece , --- src/ViewRenderer.php | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/ViewRenderer.php b/src/ViewRenderer.php index 2845f8d..1ec5a73 100644 --- a/src/ViewRenderer.php +++ b/src/ViewRenderer.php @@ -111,12 +111,13 @@ public function getViewPath(): string */ public function render(string $view, array $parameters = []): DataResponse { - $commonParameters = $this->getCommonParameters(); + $csrfParameters = $this->getCsrfParameters(); + $commonParameters = array_merge($this->getCommonParameters(), $csrfParameters[0]); $layoutParameters = $this->getLayoutParameters(); - $metaTags = $this->getMetaTags(); + $metaTags = array_merge($this->getMetaTags(), $csrfParameters[1]); $linkTags = $this->getLinkTags(); - return $this->responseFactory->createResponse(fn (): string => $this->renderProxy( + return $this->responseFactory->createResponse(fn(): string => $this->renderProxy( $view, $parameters, $commonParameters, @@ -336,7 +337,7 @@ private function renderProxy( $layoutParameters = array_filter( $injectLayoutParameters, /** @psalm-suppress MissingClosureParamType */ - static fn ($_value, string $key): bool => !$currentView->hasParameter($key), + static fn($_value, string $key): bool => !$currentView->hasParameter($key), ARRAY_FILTER_USE_BOTH, ); @@ -345,6 +346,24 @@ private function renderProxy( ->render($layout, ['content' => $content]); } + + /** + * Gets csrf injection parameters merged with parameters specified during rendering. + * + * + * @return array The csrf injection parameters ot merged to common parameters and metaTag parameters. + * + * @psalm-return array + */ + private function getCsrfParameters(): array + { + $parameters = []; + foreach ($this->getInjections($this->layout, CsrfParametersInjectionInterface::class) as $injection) { + $parameters[] = $injection->getCsrfParameters(); + } + return array_merge(...$parameters); + } + /** * Gets injection common parameters merged with parameters specified during rendering. * From d50403ff232b48d9f2ede70960741c9d87e42f6b Mon Sep 17 00:00:00 2001 From: TiaNex Date: Sun, 6 Oct 2024 13:05:11 +0800 Subject: [PATCH 5/6] Update LayoutParametersInjectionInterface.php reset --- src/LayoutParametersInjectionInterface.php | 59 ++++++---------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/src/LayoutParametersInjectionInterface.php b/src/LayoutParametersInjectionInterface.php index cb39471..91527e2 100644 --- a/src/LayoutParametersInjectionInterface.php +++ b/src/LayoutParametersInjectionInterface.php @@ -4,52 +4,25 @@ namespace Yiisoft\Yii\View\Renderer; -use LogicException; -use Yiisoft\Csrf\CsrfTokenInterface; -use Yiisoft\Csrf\CsrfTrait; - /** - * `CsrfViewInjection` injects the necessary data into the view to protect against a CSRF attack. + * LayoutParametersInjectionInterface is an interface that must be implemented by classes to inject layout parameters. */ -final class CsrfViewInjection implements CsrfParametersInjectionInterface +interface LayoutParametersInjectionInterface { - use CsrfTrait; - - public const DEFAULT_META_ATTRIBUTE_NAME = 'csrf'; - public const DEFAULT_PARAMETER_NAME = 'csrf'; - public const META_TAG_KEY = 'csrf'; - - private string $metaAttributeName = self::DEFAULT_META_ATTRIBUTE_NAME; - private string $parameterName = self::DEFAULT_PARAMETER_NAME; - - public function __construct(private CsrfTokenInterface $token) - { - } - - /** - * @throws LogicException when CSRF token is not defined + * Returns parameters for added to layout. + * + * For example: + * + * ``` + * [ + * 'paramA' => 'something', + * 'paramB' => 42, + * ... + * ] + * ``` + * + * @psalm-return array */ - public function getCsrfParameters(): array - { - $tokenValue = $this->token->getValue(); - $csrf = new Csrf( - $tokenValue, - $this->getFormParameterName(), - $this->getHeaderName(), - ); - return [ - [ - $this->parameterName => $csrf - ], - [ - self::META_TAG_KEY => [ - 'name' => $this->metaAttributeName, - 'content' => $tokenValue - ], - ], - ]; - } - - + public function getLayoutParameters(): array; } From e9cf64d79a863381f1165690fe3c9fa19e45a9be Mon Sep 17 00:00:00 2001 From: TiaNex Date: Mon, 7 Oct 2024 02:09:08 +0800 Subject: [PATCH 6/6] Update CsrfViewInjection.php won't call csrfmiddleware which will inital CsrfTokenInterface again --- src/CsrfViewInjection.php | 61 +++++++++++++-------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/src/CsrfViewInjection.php b/src/CsrfViewInjection.php index 8b03a56..cb39471 100644 --- a/src/CsrfViewInjection.php +++ b/src/CsrfViewInjection.php @@ -5,14 +5,16 @@ namespace Yiisoft\Yii\View\Renderer; use LogicException; -use Yiisoft\Csrf\CsrfMiddleware; use Yiisoft\Csrf\CsrfTokenInterface; +use Yiisoft\Csrf\CsrfTrait; /** * `CsrfViewInjection` injects the necessary data into the view to protect against a CSRF attack. */ -final class CsrfViewInjection implements CommonParametersInjectionInterface, MetaTagsInjectionInterface +final class CsrfViewInjection implements CsrfParametersInjectionInterface { + use CsrfTrait; + public const DEFAULT_META_ATTRIBUTE_NAME = 'csrf'; public const DEFAULT_PARAMETER_NAME = 'csrf'; public const META_TAG_KEY = 'csrf'; @@ -20,57 +22,34 @@ final class CsrfViewInjection implements CommonParametersInjectionInterface, Met private string $metaAttributeName = self::DEFAULT_META_ATTRIBUTE_NAME; private string $parameterName = self::DEFAULT_PARAMETER_NAME; - public function __construct(private CsrfTokenInterface $token, private CsrfMiddleware $middleware) - { - } - - /** - * Returns a new instance with the specified parameter name. - * - * @param string $parameterName The parameter name. - */ - public function withParameterName(string $parameterName): self + public function __construct(private CsrfTokenInterface $token) { - $new = clone $this; - $new->parameterName = $parameterName; - return $new; } - /** - * Returns a new instance with the specified meta attribute name. - * - * @param string $metaAttributeName The meta attribute name. - */ - public function withMetaAttributeName(string $metaAttributeName): self - { - $new = clone $this; - $new->metaAttributeName = $metaAttributeName; - return $new; - } /** * @throws LogicException when CSRF token is not defined */ - public function getCommonParameters(): array + public function getCsrfParameters(): array { + $tokenValue = $this->token->getValue(); $csrf = new Csrf( - $this->token->getValue(), - $this->middleware->getParameterName(), - $this->middleware->getHeaderName(), + $tokenValue, + $this->getFormParameterName(), + $this->getHeaderName(), ); - return [$this->parameterName => $csrf]; - } - - /** - * @throws LogicException when CSRF token is not defined - */ - public function getMetaTags(): array - { return [ - self::META_TAG_KEY => [ - 'name' => $this->metaAttributeName, - 'content' => $this->token->getValue(), + [ + $this->parameterName => $csrf + ], + [ + self::META_TAG_KEY => [ + 'name' => $this->metaAttributeName, + 'content' => $tokenValue + ], ], ]; } + + }