Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
TwigCsrfExtension
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
5 / 5
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFunctions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getCsrfToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderCsrfField
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 renderCsrfMeta
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Security\Csrf;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use Twig\Extension\AbstractExtension;
12use Twig\TwigFunction;
13
14/**
15 * Twig Extension for Universal CSRF Helpers.
16 *
17 * Provides dynamic Twig functions for CSRF tokens, hidden form inputs, and meta tags.
18 *
19 * @package App\Core\Security\Csrf
20 */
21final class TwigCsrfExtension extends AbstractExtension
22{
23    /**
24     * TwigCsrfExtension constructor.
25     *
26     * @param CsrfTokenManagerInterface $csrfTokenManager CSRF token manager instance.
27     */
28    public function __construct(
29        private readonly CsrfTokenManagerInterface $csrfTokenManager
30    ) {
31    }
32
33    /**
34     * {@inheritdoc}
35     */
36    public function getFunctions(): array
37    {
38        return [
39            new TwigFunction('csrf_token', [$this, 'getCsrfToken']),
40            new TwigFunction('csrf_field', [$this, 'renderCsrfField'], ['is_safe' => ['html']]),
41            new TwigFunction('csrf_meta', [$this, 'renderCsrfMeta'], ['is_safe' => ['html']]),
42        ];
43    }
44
45    /**
46     * Returns active CSRF token string.
47     *
48     * @return string Active CSRF token.
49     */
50    public function getCsrfToken(): string
51    {
52        return $this->csrfTokenManager->getToken();
53    }
54
55    /**
56     * Renders hidden HTML input element with active CSRF token.
57     *
58     * @return string HTML hidden input tag.
59     */
60    public function renderCsrfField(): string
61    {
62        $token = htmlspecialchars($this->getCsrfToken(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
63        return sprintf('<input type="hidden" name="_csrf" value="%s">', $token);
64    }
65
66    /**
67     * Renders HTML meta tag with active CSRF token for JavaScript and HTMX.
68     *
69     * @return string HTML meta tag.
70     */
71    public function renderCsrfMeta(): string
72    {
73        $token = htmlspecialchars($this->getCsrfToken(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
74        return sprintf('<meta name="csrf-token" content="%s">', $token);
75    }
76}