Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
PasswordInputTransformer
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
4 / 4
9
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
 supports
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 transformRead
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 transformWrite
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
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\Engine\Application\Transformer;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Engine\Domain\Model\FieldMetadata;
12use App\Core\Security\Encryption\AesGcmEncryptionService;
13use App\Core\Security\Encryption\EncryptionServiceInterface;
14
15/**
16 * Enterprise Password & Secret Input UiType Transformer.
17 *
18 * Enforces OWASP ASVS v5 and NIST SP 800-53 SC-28 cryptographic requirements:
19 * - Read: Returns masked presentation (••••••••) to prevent credential leakage.
20 * - Write: Automatically encrypts plaintext secrets using AES-256-GCM authenticated encryption.
21 *
22 * @package App\Core\Engine\Application\Transformer
23 */
24final readonly class PasswordInputTransformer implements UiTypeTransformerInterface
25{
26    /** @var string[] Supported UiType names. */
27    private const array SUPPORTED = ['password_input', 'password'];
28
29    /** @var string Masked presentation placeholder. */
30    private const string MASKED = '••••••••';
31
32    private EncryptionServiceInterface $encryption;
33
34    /**
35     * PasswordInputTransformer constructor.
36     *
37     * @param EncryptionServiceInterface|null $encryption Encryption service.
38     */
39    public function __construct(?EncryptionServiceInterface $encryption = null)
40    {
41        $this->encryption = $encryption ?? new AesGcmEncryptionService();
42    }
43
44    /** {@inheritdoc} */
45    public function supports(string $uitypeName): bool
46    {
47        return in_array($uitypeName, self::SUPPORTED, true);
48    }
49
50    /** {@inheritdoc} */
51    public function transformRead(mixed $rawValue, FieldMetadata $field): string
52    {
53        if ($rawValue === null || $rawValue === '') {
54            return '';
55        }
56
57        return self::MASKED;
58    }
59
60    /** {@inheritdoc} */
61    public function transformWrite(mixed $inputValue, FieldMetadata $field): mixed
62    {
63        $stringVal = trim((string) $inputValue);
64        if ($stringVal === '' || $stringVal === self::MASKED) {
65            return null;
66        }
67
68        return $this->encryption->isEncrypted($stringVal)
69            ? $stringVal
70            : $this->encryption->encrypt($stringVal);
71    }
72}