From aab69ab1b4dbfcc6fa70cd0e551cef2d6b911443 Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Fri, 21 Nov 2025 09:55:06 +0100 Subject: [PATCH] Add identity generator age setting to AliasVault.Client (#1379) --- .../Main/Pages/Settings/General.razor | 65 +++++++++++++----- .../Pages/Main/Settings/General.en.resx | 20 ++++-- .../Services/CredentialService.cs | 5 +- .../Services/JsInterop/JsInteropService.cs | 66 +++++++++++++++++-- 4 files changed, 128 insertions(+), 28 deletions(-) diff --git a/apps/server/AliasVault.Client/Main/Pages/Settings/General.razor b/apps/server/AliasVault.Client/Main/Pages/Settings/General.razor index 39cd5428d..e6b5252b7 100644 --- a/apps/server/AliasVault.Client/Main/Pages/Settings/General.razor +++ b/apps/server/AliasVault.Client/Main/Pages/Settings/General.razor @@ -3,6 +3,7 @@ @inject LanguageService LanguageService @using Microsoft.Extensions.Localization @using AliasVault.Client.Services +@using AliasVault.Client.Services.JsInterop.Models @Localizer["PageTitle"] @@ -12,6 +13,22 @@ Description="@Localizer["PageDescription"]"> +

@Localizer["AppLanguageTitle"]

+ +
+ + + + @Localizer["AppLanguageDescription"] + +
+ +

@Localizer["EmailSettingsTitle"]

@@ -50,23 +67,6 @@
-
-

@Localizer["AppLanguageTitle"]

- -
- - - - @Localizer["AppLanguageDescription"] - -
-
-

@Localizer["AliasSettingsTitle"]

@@ -75,6 +75,7 @@ @Localizer["AliasGenerationLanguageDescription"] @@ -92,6 +93,21 @@ @Localizer["AliasGenerationGenderDescription"]
+ +
+ + + + @Localizer["AliasGenerationAgeRangeDescription"] + +
@@ -134,8 +150,10 @@ private bool AutoEmailRefresh { get; set; } private string DefaultIdentityLanguage { get; set; } = string.Empty; private string DefaultIdentityGender { get; set; } = string.Empty; + private string DefaultIdentityAgeRange { get; set; } = string.Empty; private string AppLanguage { get; set; } = string.Empty; private int ClipboardClearSeconds { get; set; } + private List AvailableAgeRanges { get; set; } = new(); /// protected override async Task OnInitializedAsync() @@ -143,6 +161,9 @@ await base.OnInitializedAsync(); BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["BreadcrumbTitle"] }); + // Load available age ranges from JavaScript utility + AvailableAgeRanges = await JsInteropService.GetAvailableAgeRangesAsync(); + DefaultEmailDomain = DbService.Settings.DefaultEmailDomain; if (DefaultEmailDomain == string.Empty || Config.HiddenPrivateEmailDomains.Contains(DefaultEmailDomain)) { @@ -158,6 +179,7 @@ AutoEmailRefresh = DbService.Settings.AutoEmailRefresh; DefaultIdentityLanguage = DbService.Settings.DefaultIdentityLanguage; DefaultIdentityGender = DbService.Settings.DefaultIdentityGender; + DefaultIdentityAgeRange = DbService.Settings.DefaultIdentityAgeRange; AppLanguage = DbService.Settings.AppLanguage; ClipboardClearSeconds = DbService.Settings.ClipboardClearSeconds; } @@ -198,6 +220,15 @@ StateHasChanged(); } + /// + /// Updates the default identity age range setting. + /// + private async Task UpdateDefaultIdentityAgeRange() + { + await DbService.Settings.SetDefaultIdentityAgeRange(DefaultIdentityAgeRange); + StateHasChanged(); + } + /// /// Updates the app language setting. /// diff --git a/apps/server/AliasVault.Client/Resources/Pages/Main/Settings/General.en.resx b/apps/server/AliasVault.Client/Resources/Pages/Main/Settings/General.en.resx index 47aaa89a0..bf13c0207 100644 --- a/apps/server/AliasVault.Client/Resources/Pages/Main/Settings/General.en.resx +++ b/apps/server/AliasVault.Client/Resources/Pages/Main/Settings/General.en.resx @@ -74,11 +74,11 @@ - Alias Settings - Title for alias settings section + Identity Generator Settings + Title for identity generator settings section - Alias generation language + Language Label for alias generation language setting @@ -93,8 +93,12 @@ Dutch Dutch language option + + German + German language option + - Alias generation gender + Gender Label for alias generation gender setting @@ -113,6 +117,14 @@ Female Female gender option + + Age range + Label for alias generation age range setting + + + Set the default age range for generating new identities. This affects the birthdate assigned to the generated identity. + Description for alias generation age range setting + diff --git a/apps/server/AliasVault.Client/Services/CredentialService.cs b/apps/server/AliasVault.Client/Services/CredentialService.cs index 5dd22b8f0..8ffcd6c97 100644 --- a/apps/server/AliasVault.Client/Services/CredentialService.cs +++ b/apps/server/AliasVault.Client/Services/CredentialService.cs @@ -58,8 +58,11 @@ public sealed class CredentialService(HttpClient httpClient, DbService dbService do { + // Convert age range to birthdate options using shared JS utility + var birthdateOptions = await jsInteropService.ConvertAgeRangeToBirthdateOptionsAsync(dbService.Settings.DefaultIdentityAgeRange); + // Generate a random identity using the TypeScript library - var identity = await jsInteropService.GenerateRandomIdentityAsync(dbService.Settings.DefaultIdentityLanguage, dbService.Settings.DefaultIdentityGender); + var identity = await jsInteropService.GenerateRandomIdentityAsync(dbService.Settings.DefaultIdentityLanguage, dbService.Settings.DefaultIdentityGender, birthdateOptions); // Generate random values for the Identity properties credential.Username = identity.NickName; diff --git a/apps/server/AliasVault.Client/Services/JsInterop/JsInteropService.cs b/apps/server/AliasVault.Client/Services/JsInterop/JsInteropService.cs index b7dcca87c..4dc6a75d4 100644 --- a/apps/server/AliasVault.Client/Services/JsInterop/JsInteropService.cs +++ b/apps/server/AliasVault.Client/Services/JsInterop/JsInteropService.cs @@ -360,13 +360,61 @@ public sealed class JsInteropService(IJSRuntime jsRuntime) return await jsRuntime.InvokeAsync("cryptoInterop.decryptBytes", base64Ciphertext, encryptionKey); } + /// + /// Gets all available age range options from the shared JavaScript utility. + /// + /// Array of age range options. + public async Task> GetAvailableAgeRangesAsync() + { + try + { + if (_identityGeneratorModule == null) + { + await InitializeAsync(); + } + + var result = await _identityGeneratorModule!.InvokeAsync>("getAvailableAgeRanges"); + return result ?? new List(); + } + catch (JSException ex) + { + await Console.Error.WriteLineAsync($"JavaScript error getting age ranges: {ex.Message}"); + return new List(); + } + } + + /// + /// Converts an age range string to birthdate options using the shared JavaScript utility. + /// + /// Age range string (e.g., "21-25", "30-35", or "random"). + /// Birthdate options object or null if random. + public async Task ConvertAgeRangeToBirthdateOptionsAsync(string ageRange) + { + try + { + if (_identityGeneratorModule == null) + { + await InitializeAsync(); + } + + var result = await _identityGeneratorModule!.InvokeAsync("convertAgeRangeToBirthdateOptions", ageRange); + return result; + } + catch (JSException ex) + { + await Console.Error.WriteLineAsync($"JavaScript error converting age range: {ex.Message}"); + return null; + } + } + /// /// Generates a random identity using the specified language. /// - /// The language to use for generating the identity (e.g. "en", "nl"). - /// The gender preference for generating the identity (optional, defaults to random). + /// The language to use for generating the identity (e.g. "en", "nl", "de"). + /// The gender preference for generating the identity (defaults to "random"). + /// Optional birthdate options (targetYear and yearDeviation). /// An AliasVaultIdentity containing the generated identity information. - public async Task GenerateRandomIdentityAsync(string language, string? gender = null) + public async Task GenerateRandomIdentityAsync(string language, string? gender = null, object? birthdateOptions = null) { try { @@ -376,9 +424,15 @@ public sealed class JsInteropService(IJSRuntime jsRuntime) } var generatorInstance = await _identityGeneratorModule!.InvokeAsync("CreateIdentityGenerator", language); - var result = string.IsNullOrEmpty(gender) || gender == "random" - ? await generatorInstance.InvokeAsync("generateRandomIdentity") - : await generatorInstance.InvokeAsync("generateRandomIdentity", gender); + + // Use "random" as default if gender is null or empty + var genderValue = "random"; + if (!string.IsNullOrEmpty(gender)) + { + genderValue = gender; + } + + var result = await generatorInstance.InvokeAsync("generateRandomIdentity", genderValue, birthdateOptions); return result; }