From d7b580d995b2143ebdc5175ae008fe61b99482de Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Sat, 14 Feb 2026 21:41:14 +0100 Subject: [PATCH] Increase max password generator length to 256 chars in web app (#1701) --- .../Settings/PasswordSettingsPopup.razor | 19 +++-- .../Main/Utilities/PasswordLengthSlider.cs | 76 +++++++++++++++++++ .../wwwroot/css/tailwind.css | 5 ++ 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 apps/server/AliasVault.Client/Main/Utilities/PasswordLengthSlider.cs diff --git a/apps/server/AliasVault.Client/Main/Components/Settings/PasswordSettingsPopup.razor b/apps/server/AliasVault.Client/Main/Components/Settings/PasswordSettingsPopup.razor index ee866b52b..b172f152a 100644 --- a/apps/server/AliasVault.Client/Main/Components/Settings/PasswordSettingsPopup.razor +++ b/apps/server/AliasVault.Client/Main/Components/Settings/PasswordSettingsPopup.razor @@ -1,4 +1,5 @@ @using AliasVault.Client.Main.Components.Layout +@using AliasVault.Client.Main.Utilities @inject DbService DbService @inject GlobalLoadingService GlobalLoadingService @inject GlobalNotificationService GlobalNotificationService @@ -14,9 +15,9 @@
- + value="@_sliderValue" @oninput="HandleLengthInput">
@@ -119,6 +120,11 @@ /// private string _previewPassword = string.Empty; + /// + /// The slider value (0-100) for non-linear password length selection. + /// + private double _sliderValue; + /// protected override async Task OnInitializedAsync() { @@ -133,6 +139,9 @@ UseNonAmbiguousChars = PasswordSettings.UseNonAmbiguousChars }; + // Initialize slider value from password length + _sliderValue = PasswordLengthSlider.LengthToSlider(_workingSettings.Length); + await RefreshPreview(); } @@ -156,10 +165,10 @@ /// private async Task HandleLengthInput(ChangeEventArgs e) { - int newLength; - if (int.TryParse(e.Value?.ToString(), out newLength)) + if (double.TryParse(e.Value?.ToString(), out var sliderValue)) { - _workingSettings.Length = newLength; + _sliderValue = sliderValue; + _workingSettings.Length = PasswordLengthSlider.SliderToLength(sliderValue); await RefreshPreview(); } } diff --git a/apps/server/AliasVault.Client/Main/Utilities/PasswordLengthSlider.cs b/apps/server/AliasVault.Client/Main/Utilities/PasswordLengthSlider.cs new file mode 100644 index 000000000..d2e963500 --- /dev/null +++ b/apps/server/AliasVault.Client/Main/Utilities/PasswordLengthSlider.cs @@ -0,0 +1,76 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) aliasvault. All rights reserved. +// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information. +// +// ----------------------------------------------------------------------- + +namespace AliasVault.Client.Main.Utilities; + +/// +/// Utility functions for password length slider with non-linear scaling. +/// +/// The slider uses a power curve to provide fine-grained control at lower values +/// (where most users operate, e.g., 12-32 chars) and coarser control at higher values +/// (64-256 chars). +/// +/// This makes it easy to select common password lengths while still allowing +/// very long passwords when needed. +/// +public static class PasswordLengthSlider +{ + /// + /// Minimum password length. + /// + public const int MinPasswordLength = 8; + + /// + /// Maximum password length. + /// + public const int MaxPasswordLength = 256; + + /// + /// Slider minimum value (internal representation). + /// + public const double SliderMin = 0; + + /// + /// Slider maximum value (internal representation). + /// + public const double SliderMax = 100; + + /// + /// Exponent for the power curve. + /// Higher values = more precision at lower lengths. + /// 2.0 gives a good balance where ~50% slider = ~70 chars. + /// + private const double Exponent = 2.0; + + /// + /// Convert a slider position (0-100) to an actual password length (8-256). + /// Uses a power curve for non-linear scaling. + /// + /// The slider position (0-100). + /// The password length (8-256). + public static int SliderToLength(double sliderValue) + { + var normalized = Math.Max(0, Math.Min(1, sliderValue / SliderMax)); + var curved = Math.Pow(normalized, Exponent); + var length = MinPasswordLength + (curved * (MaxPasswordLength - MinPasswordLength)); + return (int)Math.Round(length); + } + + /// + /// Convert a password length (8-256) to a slider position (0-100). + /// Inverse of SliderToLength. + /// + /// The password length (8-256). + /// The slider position (0-100). + public static double LengthToSlider(int length) + { + var clampedLength = Math.Max(MinPasswordLength, Math.Min(MaxPasswordLength, length)); + var normalized = (double)(clampedLength - MinPasswordLength) / (MaxPasswordLength - MinPasswordLength); + var curved = Math.Pow(normalized, 1.0 / Exponent); + return curved * SliderMax; + } +} diff --git a/apps/server/AliasVault.Client/wwwroot/css/tailwind.css b/apps/server/AliasVault.Client/wwwroot/css/tailwind.css index d396f891f..43e7e09bb 100644 --- a/apps/server/AliasVault.Client/wwwroot/css/tailwind.css +++ b/apps/server/AliasVault.Client/wwwroot/css/tailwind.css @@ -1237,6 +1237,11 @@ video { min-width: 100%; } +.min-w-max { + min-width: -moz-max-content; + min-width: max-content; +} + .max-w-2xl { max-width: 42rem; }