From f48791e9614262c2cedeaa83c760b304c22e023d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 24 Aug 2025 20:04:52 +0200 Subject: [PATCH] Use a special form type for api key settings, that hide the api key by default as dots --- assets/controllers.json | 9 ++ assets/css/app/bs-overrides.css | 9 +- composer.json | 1 + composer.lock | 86 ++++++++++++++++++- config/bundles.php | 1 + package.json | 1 + src/Form/Type/APIKeyType.php | 53 ++++++++++++ .../InfoProviderSystem/DigikeySettings.php | 5 +- .../InfoProviderSystem/Element14Settings.php | 6 +- .../InfoProviderSystem/MouserSettings.php | 4 +- .../InfoProviderSystem/OEMSecretsSettings.php | 4 +- .../InfoProviderSystem/OctopartSettings.php | 7 +- .../InfoProviderSystem/TMESettings.php | 7 +- .../MiscSettings/ExchangeRateSettings.php | 4 +- symfony.lock | 3 + yarn.lock | 3 + 16 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 src/Form/Type/APIKeyType.php diff --git a/assets/controllers.json b/assets/controllers.json index 29ea244b..480ad64e 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -1,5 +1,14 @@ { "controllers": { + "@symfony/ux-toggle-password": { + "toggle-password": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "@symfony/ux-toggle-password/dist/style.min.css": true + } + } + }, "@symfony/ux-turbo": { "turbo-core": { "enabled": true, diff --git a/assets/css/app/bs-overrides.css b/assets/css/app/bs-overrides.css index 070f353d..ec5a8f7c 100644 --- a/assets/css/app/bs-overrides.css +++ b/assets/css/app/bs-overrides.css @@ -120,4 +120,11 @@ ins { del { background-color: #f09595; font-weight: bold; -} \ No newline at end of file +} + +/**************************************** + * Password toggle + ****************************************/ +.toggle-password-button { + top: 0.7rem !important; +} diff --git a/composer.json b/composer.json index 8e3d1194..a602e505 100644 --- a/composer.json +++ b/composer.json @@ -80,6 +80,7 @@ "symfony/string": "7.3.*", "symfony/translation": "7.3.*", "symfony/twig-bundle": "7.3.*", + "symfony/ux-toggle-password": "^2.29", "symfony/ux-translator": "^2.10", "symfony/ux-turbo": "^2.0", "symfony/validator": "7.3.*", diff --git a/composer.lock b/composer.lock index 7c5ef265..2a59f016 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "09b78f345ea8115b5b29ea3e67dcb579", + "content-hash": "3b97b6338827ba56e0404860f3e98359", "packages": [ { "name": "amphp/amp", @@ -15188,6 +15188,90 @@ ], "time": "2025-06-27T19:55:54+00:00" }, + { + "name": "symfony/ux-toggle-password", + "version": "v2.29.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-toggle-password.git", + "reference": "ea74e8611e30979d9ec9b4c29d194f18a460a781" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-toggle-password/zipball/ea74e8611e30979d9ec9b4c29d194f18a460a781", + "reference": "ea74e8611e30979d9ec9b4c29d194f18a460a781", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0|^7.0|^8.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0|^8.0", + "symfony/form": "^5.4|^6.0|^7.0|^8.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0|^8.0", + "symfony/options-resolver": "^5.4|^6.0|^7.0|^8.0", + "symfony/translation": "^5.4|^6.0|^7.0|^8.0" + }, + "require-dev": { + "symfony/framework-bundle": "^5.4|^6.0|^7.0|^8.0", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0|^8.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0|^8.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0|^8.0", + "twig/twig": "^2.14.7|^3.0.4" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TogglePassword\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Félix Eymonot", + "email": "felix.eymonot@alximy.io" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Toggle visibility of password inputs for Symfony Forms", + "homepage": "https://symfony.com", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/ux-toggle-password/tree/v2.29.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-08-18T09:13:24+00:00" + }, { "name": "symfony/ux-translator", "version": "v2.29.2", diff --git a/config/bundles.php b/config/bundles.php index ae7dc9cc..084e6870 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -33,4 +33,5 @@ return [ Jbtronics\SettingsBundle\JbtronicsSettingsBundle::class => ['all' => true], Jbtronics\TranslationEditorBundle\JbtronicsTranslationEditorBundle::class => ['dev' => true], ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], + Symfony\UX\TogglePassword\TogglePasswordBundle::class => ['all' => true], ]; diff --git a/package.json b/package.json index 7a3efaa4..1080a74c 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@hotwired/turbo": "^8.0.1", "@popperjs/core": "^2.10.2", "@symfony/stimulus-bridge": "^4.0.0", + "@symfony/ux-toggle-password": "file:vendor/symfony/ux-toggle-password/assets", "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets", "@symfony/webpack-encore": "^5.0.0", diff --git a/src/Form/Type/APIKeyType.php b/src/Form/Type/APIKeyType.php new file mode 100644 index 00000000..3960524b --- /dev/null +++ b/src/Form/Type/APIKeyType.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class APIKeyType extends AbstractType +{ + public function getParent(): string + { + return PasswordType::class; + } + + public function buildView(FormView $view, FormInterface $form, array $options): void + { + //Ensure that the field is never empty + $view->vars['value'] = $form->getViewData(); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'always_empty' => false, + 'toggle' => true, + 'attr' => ['autocomplete' => 'off'], + ]); + } +} diff --git a/src/Settings/InfoProviderSystem/DigikeySettings.php b/src/Settings/InfoProviderSystem/DigikeySettings.php index 17d05c5b..f42c1c1c 100644 --- a/src/Settings/InfoProviderSystem/DigikeySettings.php +++ b/src/Settings/InfoProviderSystem/DigikeySettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -42,12 +43,14 @@ class DigikeySettings #[SettingsParameter( label: new TM("settings.ips.digikey.client_id"), + formType: APIKeyType::class, envVar: "PROVIDER_DIGIKEY_CLIENT_ID", envVarMode: EnvVarMode::OVERWRITE )] public ?string $clientId = null; #[SettingsParameter( label: new TM("settings.ips.digikey.secret"), + formType: APIKeyType::class, envVar: "PROVIDER_DIGIKEY_SECRET", envVarMode: EnvVarMode::OVERWRITE )] public ?string $secret = null; @@ -67,4 +70,4 @@ class DigikeySettings envVar: "PROVIDER_DIGIKEY_LANGUAGE", envVarMode: EnvVarMode::OVERWRITE)] #[Assert\Language] public string $language = "en"; -} \ No newline at end of file +} diff --git a/src/Settings/InfoProviderSystem/Element14Settings.php b/src/Settings/InfoProviderSystem/Element14Settings.php index 42e2de5d..a4cdbf0d 100644 --- a/src/Settings/InfoProviderSystem/Element14Settings.php +++ b/src/Settings/InfoProviderSystem/Element14Settings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -36,11 +37,12 @@ class Element14Settings { use SettingsTrait; - #[SettingsParameter(label: new TM("settings.ips.element14.apiKey"), description: new TM("settings.ips.element14.apiKey.help"), + #[SettingsParameter(label: new TM("settings.ips.element14.apiKey"), description: new TM("settings.ips.element14.apiKey.help"),# + formType: APIKeyType::class, formOptions: ["help_html" => true], envVar: "PROVIDER_ELEMENT14_KEY", envVarMode: EnvVarMode::OVERWRITE)] public ?string $apiKey = null; #[SettingsParameter(label: new TM("settings.ips.element14.storeId"), description: new TM("settings.ips.element14.storeId.help"), formOptions: ["help_html" => true], envVar: "PROVIDER_ELEMENT14_STORE_ID", envVarMode: EnvVarMode::OVERWRITE)] public string $storeId = "de.farnell.com"; -} \ No newline at end of file +} diff --git a/src/Settings/InfoProviderSystem/MouserSettings.php b/src/Settings/InfoProviderSystem/MouserSettings.php index b84deb50..0abaa7f2 100644 --- a/src/Settings/InfoProviderSystem/MouserSettings.php +++ b/src/Settings/InfoProviderSystem/MouserSettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -35,6 +36,7 @@ use Symfony\Component\Translation\TranslatableMessage as TM; class MouserSettings { #[SettingsParameter(label: new TM("settings.ips.mouser.apiKey"), description: new TM("settings.ips.mouser.apiKey.help"), + formType: APIKeyType::class, formOptions: ["help_html" => true], envVar: "PROVIDER_MOUSER_KEY", envVarMode: EnvVarMode::OVERWRITE)] public ?string $apiKey = null; @@ -64,4 +66,4 @@ class MouserSettings return MouserSearchOptions::tryFrom($value) ?? MouserSearchOptions::NONE; } -} \ No newline at end of file +} diff --git a/src/Settings/InfoProviderSystem/OEMSecretsSettings.php b/src/Settings/InfoProviderSystem/OEMSecretsSettings.php index 75c2c821..77cf9080 100644 --- a/src/Settings/InfoProviderSystem/OEMSecretsSettings.php +++ b/src/Settings/InfoProviderSystem/OEMSecretsSettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -43,6 +44,7 @@ class OEMSecretsSettings "NZD", "RUB", "SEK", "SGD", "TWD", "USD"]; #[SettingsParameter(label: new TM("settings.ips.element14.apiKey"), + formType: APIKeyType::class, envVar: "PROVIDER_OEMSECRETS_KEY", envVarMode: EnvVarMode::OVERWRITE)] public ?string $apiKey = null; @@ -85,4 +87,4 @@ class OEMSecretsSettings return OEMSecretsSortMode::tryFrom($value) ?? OEMSecretsSortMode::NONE; } -} \ No newline at end of file +} diff --git a/src/Settings/InfoProviderSystem/OctopartSettings.php b/src/Settings/InfoProviderSystem/OctopartSettings.php index 1b39d87a..c28da459 100644 --- a/src/Settings/InfoProviderSystem/OctopartSettings.php +++ b/src/Settings/InfoProviderSystem/OctopartSettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -42,12 +43,14 @@ class OctopartSettings #[SettingsParameter( label: new TM("settings.ips.digikey.client_id"), - envVar: "PROVIDER_OCTOPART_CLIENT_ID", envVarMode: EnvVarMode::OVERWRITE + formType: APIKeyType::class, + envVar: "PROVIDER_OCTOPART_CLIENT_ID", envVarMode: EnvVarMode::OVERWRITE, )] public ?string $clientId = null; #[SettingsParameter( label: new TM("settings.ips.digikey.secret"), + formType: APIKeyType::class, envVar: "PROVIDER_OCTOPART_SECRET", envVarMode: EnvVarMode::OVERWRITE )] public ?string $secret = null; @@ -75,4 +78,4 @@ class OctopartSettings )] public bool $onlyAuthorizedSellers = true; -} \ No newline at end of file +} diff --git a/src/Settings/InfoProviderSystem/TMESettings.php b/src/Settings/InfoProviderSystem/TMESettings.php index c7b57ae7..d6f03d34 100644 --- a/src/Settings/InfoProviderSystem/TMESettings.php +++ b/src/Settings/InfoProviderSystem/TMESettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\InfoProviderSystem; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -43,11 +44,13 @@ class TMESettings private const SUPPORTED_CURRENCIES = ["EUR", "USD", "PLN", "GBP"]; #[SettingsParameter(label: new TM("settings.ips.tme.token"), - description: new TM("settings.ips.tme.token.help"), formOptions: ["help_html" => true], + description: new TM("settings.ips.tme.token.help"), + formType: APIKeyType::class, formOptions: ["help_html" => true], envVar: "PROVIDER_TME_KEY", envVarMode: EnvVarMode::OVERWRITE)] public ?string $apiToken = null; #[SettingsParameter(label: new TM("settings.ips.tme.secret"), + formType: APIKeyType::class, envVar: "PROVIDER_TME_SECRET", envVarMode: EnvVarMode::OVERWRITE)] public ?string $apiSecret = null; @@ -69,4 +72,4 @@ class TMESettings #[SettingsParameter(label: new TM("settings.ips.tme.grossPrices"), envVar: "bool:PROVIDER_TME_GET_GROSS_PRICES", envVarMode: EnvVarMode::OVERWRITE)] public bool $grossPrices = true; -} \ No newline at end of file +} diff --git a/src/Settings/MiscSettings/ExchangeRateSettings.php b/src/Settings/MiscSettings/ExchangeRateSettings.php index 70bf15dd..744523c6 100644 --- a/src/Settings/MiscSettings/ExchangeRateSettings.php +++ b/src/Settings/MiscSettings/ExchangeRateSettings.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Settings\MiscSettings; +use App\Form\Type\APIKeyType; use App\Settings\SettingsIcon; use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Settings\Settings; @@ -35,7 +36,8 @@ class ExchangeRateSettings { #[SettingsParameter(label: new TM("settings.misc.exchange_rate.fixer_api_key"), description: new TM("settings.misc.exchange_rate.fixer_api_key.help"), + formType: APIKeyType::class, envVar: "FIXER_API_KEY", envVarMode: EnvVarMode::OVERWRITE, )] public ?string $fixerApiKey = null; -} \ No newline at end of file +} diff --git a/symfony.lock b/symfony.lock index d301c269..f484d13c 100644 --- a/symfony.lock +++ b/symfony.lock @@ -729,6 +729,9 @@ }, "files": [] }, + "symfony/ux-toggle-password": { + "version": "v2.29.2" + }, "symfony/ux-translator": { "version": "2.9", "recipe": { diff --git a/yarn.lock b/yarn.lock index 2a0b08eb..da4d24a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2023,6 +2023,9 @@ loader-utils "^2.0.0 || ^3.0.0" schema-utils "^3.0.0 || ^4.0.0" +"@symfony/ux-toggle-password@file:vendor/symfony/ux-toggle-password/assets": + version "2.29.1" + "@symfony/ux-translator@file:vendor/symfony/ux-translator/assets": version "2.29.1"