Use a special form type for api key settings, that hide the api key by default as dots

This commit is contained in:
Jan Böhmer 2025-08-24 20:04:52 +02:00
parent a75a60fecd
commit f48791e961
16 changed files with 191 additions and 12 deletions

View file

@ -1,5 +1,14 @@
{ {
"controllers": { "controllers": {
"@symfony/ux-toggle-password": {
"toggle-password": {
"enabled": true,
"fetch": "eager",
"autoimport": {
"@symfony/ux-toggle-password/dist/style.min.css": true
}
}
},
"@symfony/ux-turbo": { "@symfony/ux-turbo": {
"turbo-core": { "turbo-core": {
"enabled": true, "enabled": true,

View file

@ -120,4 +120,11 @@ ins {
del { del {
background-color: #f09595; background-color: #f09595;
font-weight: bold; font-weight: bold;
} }
/****************************************
* Password toggle
****************************************/
.toggle-password-button {
top: 0.7rem !important;
}

View file

@ -80,6 +80,7 @@
"symfony/string": "7.3.*", "symfony/string": "7.3.*",
"symfony/translation": "7.3.*", "symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*", "symfony/twig-bundle": "7.3.*",
"symfony/ux-toggle-password": "^2.29",
"symfony/ux-translator": "^2.10", "symfony/ux-translator": "^2.10",
"symfony/ux-turbo": "^2.0", "symfony/ux-turbo": "^2.0",
"symfony/validator": "7.3.*", "symfony/validator": "7.3.*",

86
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "09b78f345ea8115b5b29ea3e67dcb579", "content-hash": "3b97b6338827ba56e0404860f3e98359",
"packages": [ "packages": [
{ {
"name": "amphp/amp", "name": "amphp/amp",
@ -15188,6 +15188,90 @@
], ],
"time": "2025-06-27T19:55:54+00:00" "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", "name": "symfony/ux-translator",
"version": "v2.29.2", "version": "v2.29.2",

View file

@ -33,4 +33,5 @@ return [
Jbtronics\SettingsBundle\JbtronicsSettingsBundle::class => ['all' => true], Jbtronics\SettingsBundle\JbtronicsSettingsBundle::class => ['all' => true],
Jbtronics\TranslationEditorBundle\JbtronicsTranslationEditorBundle::class => ['dev' => true], Jbtronics\TranslationEditorBundle\JbtronicsTranslationEditorBundle::class => ['dev' => true],
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
Symfony\UX\TogglePassword\TogglePasswordBundle::class => ['all' => true],
]; ];

View file

@ -7,6 +7,7 @@
"@hotwired/turbo": "^8.0.1", "@hotwired/turbo": "^8.0.1",
"@popperjs/core": "^2.10.2", "@popperjs/core": "^2.10.2",
"@symfony/stimulus-bridge": "^4.0.0", "@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-translator": "file:vendor/symfony/ux-translator/assets",
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets", "@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets",
"@symfony/webpack-encore": "^5.0.0", "@symfony/webpack-encore": "^5.0.0",

View file

@ -0,0 +1,53 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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'],
]);
}
}

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -42,12 +43,14 @@ class DigikeySettings
#[SettingsParameter( #[SettingsParameter(
label: new TM("settings.ips.digikey.client_id"), label: new TM("settings.ips.digikey.client_id"),
formType: APIKeyType::class,
envVar: "PROVIDER_DIGIKEY_CLIENT_ID", envVarMode: EnvVarMode::OVERWRITE envVar: "PROVIDER_DIGIKEY_CLIENT_ID", envVarMode: EnvVarMode::OVERWRITE
)] )]
public ?string $clientId = null; public ?string $clientId = null;
#[SettingsParameter( #[SettingsParameter(
label: new TM("settings.ips.digikey.secret"), label: new TM("settings.ips.digikey.secret"),
formType: APIKeyType::class,
envVar: "PROVIDER_DIGIKEY_SECRET", envVarMode: EnvVarMode::OVERWRITE envVar: "PROVIDER_DIGIKEY_SECRET", envVarMode: EnvVarMode::OVERWRITE
)] )]
public ?string $secret = null; public ?string $secret = null;
@ -67,4 +70,4 @@ class DigikeySettings
envVar: "PROVIDER_DIGIKEY_LANGUAGE", envVarMode: EnvVarMode::OVERWRITE)] envVar: "PROVIDER_DIGIKEY_LANGUAGE", envVarMode: EnvVarMode::OVERWRITE)]
#[Assert\Language] #[Assert\Language]
public string $language = "en"; public string $language = "en";
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -36,11 +37,12 @@ class Element14Settings
{ {
use SettingsTrait; 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)] formOptions: ["help_html" => true], envVar: "PROVIDER_ELEMENT14_KEY", envVarMode: EnvVarMode::OVERWRITE)]
public ?string $apiKey = null; public ?string $apiKey = null;
#[SettingsParameter(label: new TM("settings.ips.element14.storeId"), description: new TM("settings.ips.element14.storeId.help"), #[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)] formOptions: ["help_html" => true], envVar: "PROVIDER_ELEMENT14_STORE_ID", envVarMode: EnvVarMode::OVERWRITE)]
public string $storeId = "de.farnell.com"; public string $storeId = "de.farnell.com";
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -35,6 +36,7 @@ use Symfony\Component\Translation\TranslatableMessage as TM;
class MouserSettings class MouserSettings
{ {
#[SettingsParameter(label: new TM("settings.ips.mouser.apiKey"), description: new TM("settings.ips.mouser.apiKey.help"), #[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)] formOptions: ["help_html" => true], envVar: "PROVIDER_MOUSER_KEY", envVarMode: EnvVarMode::OVERWRITE)]
public ?string $apiKey = null; public ?string $apiKey = null;
@ -64,4 +66,4 @@ class MouserSettings
return MouserSearchOptions::tryFrom($value) ?? MouserSearchOptions::NONE; return MouserSearchOptions::tryFrom($value) ?? MouserSearchOptions::NONE;
} }
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -43,6 +44,7 @@ class OEMSecretsSettings
"NZD", "RUB", "SEK", "SGD", "TWD", "USD"]; "NZD", "RUB", "SEK", "SGD", "TWD", "USD"];
#[SettingsParameter(label: new TM("settings.ips.element14.apiKey"), #[SettingsParameter(label: new TM("settings.ips.element14.apiKey"),
formType: APIKeyType::class,
envVar: "PROVIDER_OEMSECRETS_KEY", envVarMode: EnvVarMode::OVERWRITE)] envVar: "PROVIDER_OEMSECRETS_KEY", envVarMode: EnvVarMode::OVERWRITE)]
public ?string $apiKey = null; public ?string $apiKey = null;
@ -85,4 +87,4 @@ class OEMSecretsSettings
return OEMSecretsSortMode::tryFrom($value) ?? OEMSecretsSortMode::NONE; return OEMSecretsSortMode::tryFrom($value) ?? OEMSecretsSortMode::NONE;
} }
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -42,12 +43,14 @@ class OctopartSettings
#[SettingsParameter( #[SettingsParameter(
label: new TM("settings.ips.digikey.client_id"), 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; public ?string $clientId = null;
#[SettingsParameter( #[SettingsParameter(
label: new TM("settings.ips.digikey.secret"), label: new TM("settings.ips.digikey.secret"),
formType: APIKeyType::class,
envVar: "PROVIDER_OCTOPART_SECRET", envVarMode: EnvVarMode::OVERWRITE envVar: "PROVIDER_OCTOPART_SECRET", envVarMode: EnvVarMode::OVERWRITE
)] )]
public ?string $secret = null; public ?string $secret = null;
@ -75,4 +78,4 @@ class OctopartSettings
)] )]
public bool $onlyAuthorizedSellers = true; public bool $onlyAuthorizedSellers = true;
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\InfoProviderSystem; namespace App\Settings\InfoProviderSystem;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -43,11 +44,13 @@ class TMESettings
private const SUPPORTED_CURRENCIES = ["EUR", "USD", "PLN", "GBP"]; private const SUPPORTED_CURRENCIES = ["EUR", "USD", "PLN", "GBP"];
#[SettingsParameter(label: new TM("settings.ips.tme.token"), #[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)] envVar: "PROVIDER_TME_KEY", envVarMode: EnvVarMode::OVERWRITE)]
public ?string $apiToken = null; public ?string $apiToken = null;
#[SettingsParameter(label: new TM("settings.ips.tme.secret"), #[SettingsParameter(label: new TM("settings.ips.tme.secret"),
formType: APIKeyType::class,
envVar: "PROVIDER_TME_SECRET", envVarMode: EnvVarMode::OVERWRITE)] envVar: "PROVIDER_TME_SECRET", envVarMode: EnvVarMode::OVERWRITE)]
public ?string $apiSecret = null; public ?string $apiSecret = null;
@ -69,4 +72,4 @@ class TMESettings
#[SettingsParameter(label: new TM("settings.ips.tme.grossPrices"), #[SettingsParameter(label: new TM("settings.ips.tme.grossPrices"),
envVar: "bool:PROVIDER_TME_GET_GROSS_PRICES", envVarMode: EnvVarMode::OVERWRITE)] envVar: "bool:PROVIDER_TME_GET_GROSS_PRICES", envVarMode: EnvVarMode::OVERWRITE)]
public bool $grossPrices = true; public bool $grossPrices = true;
} }

View file

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace App\Settings\MiscSettings; namespace App\Settings\MiscSettings;
use App\Form\Type\APIKeyType;
use App\Settings\SettingsIcon; use App\Settings\SettingsIcon;
use Jbtronics\SettingsBundle\Metadata\EnvVarMode; use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\Settings;
@ -35,7 +36,8 @@ class ExchangeRateSettings
{ {
#[SettingsParameter(label: new TM("settings.misc.exchange_rate.fixer_api_key"), #[SettingsParameter(label: new TM("settings.misc.exchange_rate.fixer_api_key"),
description: new TM("settings.misc.exchange_rate.fixer_api_key.help"), description: new TM("settings.misc.exchange_rate.fixer_api_key.help"),
formType: APIKeyType::class,
envVar: "FIXER_API_KEY", envVarMode: EnvVarMode::OVERWRITE, envVar: "FIXER_API_KEY", envVarMode: EnvVarMode::OVERWRITE,
)] )]
public ?string $fixerApiKey = null; public ?string $fixerApiKey = null;
} }

View file

@ -729,6 +729,9 @@
}, },
"files": [] "files": []
}, },
"symfony/ux-toggle-password": {
"version": "v2.29.2"
},
"symfony/ux-translator": { "symfony/ux-translator": {
"version": "2.9", "version": "2.9",
"recipe": { "recipe": {

View file

@ -2023,6 +2023,9 @@
loader-utils "^2.0.0 || ^3.0.0" loader-utils "^2.0.0 || ^3.0.0"
schema-utils "^3.0.0 || ^4.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": "@symfony/ux-translator@file:vendor/symfony/ux-translator/assets":
version "2.29.1" version "2.29.1"