From 8319ddcce42d41f2681776231942ecdf7caa13bd Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Tue, 1 Apr 2025 12:58:07 +0200 Subject: [PATCH] Only show fields when they have a value in main client (#746) --- .../Main/Components/Email/RecentEmails.razor | 30 ++--- .../Main/Pages/Credentials/AddEdit.razor | 21 +++- .../Main/Pages/Credentials/View.razor | 115 ++++++++++++++---- .../Services/EmailService.cs | 38 +++++- .../wwwroot/css/tailwind.css | 66 ++++------ 5 files changed, 177 insertions(+), 93 deletions(-) diff --git a/src/AliasVault.Client/Main/Components/Email/RecentEmails.razor b/src/AliasVault.Client/Main/Components/Email/RecentEmails.razor index 10960df34..6372805ba 100644 --- a/src/AliasVault.Client/Main/Components/Email/RecentEmails.razor +++ b/src/AliasVault.Client/Main/Components/Email/RecentEmails.razor @@ -198,8 +198,8 @@ } // Check if email has a known SpamOK domain, if not, don't show this component. - ShowComponent = IsSpamOkDomain(EmailAddress) || IsAliasVaultDomain(EmailAddress); - IsSpamOk = IsSpamOkDomain(EmailAddress); + ShowComponent = EmailService.IsAliasVaultSupportedDomain(EmailAddress); + IsSpamOk = EmailService.IsSpamOkDomain(EmailAddress); // Create a single object reference for JS interop _dotNetRef = DotNetObjectReference.Create(this); @@ -252,23 +252,7 @@ return; } - IsSpamOk = IsSpamOkDomain(EmailAddress); - } - - /// - /// Returns true if the email address is from a known SpamOK domain. - /// - private bool IsSpamOkDomain(string email) - { - return Config.PublicEmailDomains.Exists(x => email.EndsWith(x)); - } - - /// - /// Returns true if the email address is from a known AliasVault domain. - /// - private bool IsAliasVaultDomain(string email) - { - return Config.PrivateEmailDomains.Exists(x => email.EndsWith(x)); + IsSpamOk = EmailService.IsSpamOkDomain(EmailAddress); } /// @@ -299,11 +283,11 @@ // Get email prefix, which is the part before the @ symbol. string emailPrefix = EmailAddress.Split('@')[0]; - if (IsSpamOkDomain(EmailAddress)) + if (EmailService.IsSpamOkDomain(EmailAddress)) { await LoadSpamOkEmails(emailPrefix); } - else if (IsAliasVaultDomain(EmailAddress)) + else if (EmailService.IsAliasVaultDomain(EmailAddress)) { await LoadAliasVaultEmails(); } @@ -324,11 +308,11 @@ // Get email prefix, which is the part before the @ symbol. string emailPrefix = EmailAddress.Split('@')[0]; - if (IsSpamOkDomain(EmailAddress)) + if (EmailService.IsSpamOkDomain(EmailAddress)) { await ShowSpamOkEmailInModal(emailPrefix, emailId); } - else if (IsAliasVaultDomain(EmailAddress)) + else if (EmailService.IsAliasVaultDomain(EmailAddress)) { await ShowAliasVaultEmailInModal(emailId); } diff --git a/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor b/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor index 3c517f5ad..6a7ce9980 100644 --- a/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor +++ b/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor @@ -277,8 +277,25 @@ else GlobalLoadingSpinner.Show(); StateHasChanged(); - Obj = CredentialEdit.FromEntity(await CredentialService.GenerateRandomIdentity(Obj.ToEntity())); - IsPasswordVisible = true; + if (EditMode) + { + // Store current username and password + string currentUsername = Obj.Username; + string currentPassword = Obj.Password.Value ?? string.Empty; + + // Generate random identity but preserve username and password + Obj = CredentialEdit.FromEntity(await CredentialService.GenerateRandomIdentity(Obj.ToEntity())); + + // Restore username and password + Obj.Username = currentUsername; + Obj.Password.Value = currentPassword; + } + else + { + // For new credentials, generate everything + Obj = CredentialEdit.FromEntity(await CredentialService.GenerateRandomIdentity(Obj.ToEntity())); + IsPasswordVisible = true; + } GlobalLoadingSpinner.Hide(); StateHasChanged(); diff --git a/src/AliasVault.Client/Main/Pages/Credentials/View.razor b/src/AliasVault.Client/Main/Pages/Credentials/View.razor index e94710d1b..4f9727ada 100644 --- a/src/AliasVault.Client/Main/Pages/Credentials/View.razor +++ b/src/AliasVault.Client/Main/Pages/Credentials/View.razor @@ -69,13 +69,23 @@ else

Login credentials

- Use the generated credentials below to create your account. Any emails sent to the shown address will automatically appear on this page. + @if (EmailService.IsAliasVaultSupportedDomain(Alias.Alias.Email ?? string.Empty)) + { + Below you can view and copy the generated credentials for this account. Any emails sent to the shown address will automatically appear on this page. + } + else + { + Below you can view and copy the stored login credentials for this account. + }

-
- -
+ @if (!string.IsNullOrWhiteSpace(Alias.Alias.Email)) + { +
+ +
+ }
@@ -85,28 +95,46 @@ else
-
-

Alias

-
-
-
- + @if (HasAlias) + { +
+

Alias

+ +
+ @if (!string.IsNullOrWhiteSpace(Alias.Alias.FirstName) && !string.IsNullOrWhiteSpace(Alias.Alias.LastName)) + { +
+ +
+ } + @if (!string.IsNullOrWhiteSpace(Alias.Alias.FirstName)) + { +
+ +
+ } + @if (!string.IsNullOrWhiteSpace(Alias.Alias.LastName)) + { +
+ +
+ } + @if (IsValidDate(Alias.Alias.BirthDate)) + { +
+ +
+ } + @if (!string.IsNullOrWhiteSpace(Alias.Alias.NickName)) + { +
+ +
+ }
-
- -
-
- -
-
- -
-
- -
-
- -
+ +
+ }
} @@ -119,6 +147,40 @@ else public Guid Id { get; set; } private bool IsLoading { get; set; } = true; private Credential? Alias { get; set; } = new(); + private bool HasAlias { get; set; } = false; + + /// + /// Checks if a date is valid and not a min value. + /// + /// The date to check. + /// True if the date is valid and not a min value, false otherwise. + private bool IsValidDate(DateTime date) + { + // Check if date is min value (year 1 or 0001-01-01) + if (date.Year <= 1 || date.ToString("yyyy-MM-dd") == "0001-01-01") + { + return false; + } + return true; + } + + /// + /// Checks if the alias has any valid data. + /// + /// The credential containing alias information. + /// True if the alias has any valid data, false otherwise. + private bool CheckHasAlias(Credential alias) + { + if (alias?.Alias == null) + { + return false; + } + + return !string.IsNullOrWhiteSpace(alias.Alias.FirstName) || + !string.IsNullOrWhiteSpace(alias.Alias.LastName) || + !string.IsNullOrWhiteSpace(alias.Alias.NickName) || + IsValidDate(alias.Alias.BirthDate); + } /// protected override async Task OnInitializedAsync() @@ -153,6 +215,9 @@ else return; } + // Check if the alias has any valid data + HasAlias = CheckHasAlias(Alias); + IsLoading = false; StateHasChanged(); } diff --git a/src/AliasVault.Client/Services/EmailService.cs b/src/AliasVault.Client/Services/EmailService.cs index a88bc03b3..2c1c500f5 100644 --- a/src/AliasVault.Client/Services/EmailService.cs +++ b/src/AliasVault.Client/Services/EmailService.cs @@ -14,10 +14,46 @@ using Microsoft.EntityFrameworkCore; /// /// Email service that contains utility methods for handling email functionality such as client-side decryption. /// -public sealed class EmailService(DbService dbService, JsInteropService jsInteropService, GlobalNotificationService globalNotificationService, ILogger logger) +/// The database service. +/// The JavaScript interop service. +/// The global notification service. +/// The logger. +/// The configuration. +public sealed class EmailService(DbService dbService, JsInteropService jsInteropService, GlobalNotificationService globalNotificationService, ILogger logger, Config config) { private List _encryptionKeys = []; + /// + /// Returns true if the email address is from a known SpamOK public domain. + /// + /// The email address to check. + /// True if the email address is from a known SpamOK public domain, false otherwise. + public bool IsSpamOkDomain(string email) + { + return config.PublicEmailDomains.Exists(x => email.EndsWith(x)); + } + + /// + /// Returns true if the email address is from a known AliasVault private domain. + /// + /// The email address to check. + /// True if the email address is from a known AliasVault private domain, false otherwise. + public bool IsAliasVaultDomain(string email) + { + return config.PrivateEmailDomains.Exists(x => email.EndsWith(x)); + } + + /// + /// Returns true if the email address is from a known AliasVault supported domain + /// of which AliasVault is able to show the email content in the client. + /// + /// The email address to check. + /// True if the email address is from a known AliasVault supported domain, false otherwise. + public bool IsAliasVaultSupportedDomain(string email) + { + return IsSpamOkDomain(email) || IsAliasVaultDomain(email); + } + /// /// Decrypts a single email using the private key. /// diff --git a/src/AliasVault.Client/wwwroot/css/tailwind.css b/src/AliasVault.Client/wwwroot/css/tailwind.css index 2c40b7632..5e255ea5d 100644 --- a/src/AliasVault.Client/wwwroot/css/tailwind.css +++ b/src/AliasVault.Client/wwwroot/css/tailwind.css @@ -1445,6 +1445,11 @@ video { border-color: rgb(239 68 68 / var(--tw-border-opacity)); } +.bg-amber-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 243 199 / var(--tw-bg-opacity)); +} + .bg-amber-50 { --tw-bg-opacity: 1; background-color: rgb(255 251 235 / var(--tw-bg-opacity)); @@ -1515,11 +1520,6 @@ video { background-color: rgb(55 65 81 / var(--tw-bg-opacity)); } -.bg-gray-900 { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); -} - .bg-green-100 { --tw-bg-opacity: 1; background-color: rgb(220 252 231 / var(--tw-bg-opacity)); @@ -1604,11 +1604,6 @@ video { background-color: rgb(254 252 232 / var(--tw-bg-opacity)); } -.bg-amber-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 243 199 / var(--tw-bg-opacity)); -} - .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -1915,6 +1910,11 @@ video { letter-spacing: 0.05em; } +.text-amber-700 { + --tw-text-opacity: 1; + color: rgb(180 83 9 / var(--tw-text-opacity)); +} + .text-blue-500 { --tw-text-opacity: 1; color: rgb(59 130 246 / var(--tw-text-opacity)); @@ -2040,11 +2040,6 @@ video { color: rgb(133 77 14 / var(--tw-text-opacity)); } -.text-amber-700 { - --tw-text-opacity: 1; - color: rgb(180 83 9 / var(--tw-text-opacity)); -} - .opacity-0 { opacity: 0; } @@ -2053,18 +2048,10 @@ video { opacity: 1; } -.opacity-25 { - opacity: 0.25; -} - .opacity-50 { opacity: 0.5; } -.opacity-75 { - opacity: 0.75; -} - .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -2565,6 +2552,10 @@ video { background-color: rgb(30 64 175 / var(--tw-bg-opacity)); } +.dark\:bg-blue-800\/30:is(.dark *) { + background-color: rgb(30 64 175 / 0.3); +} + .dark\:bg-blue-900:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(30 58 138 / var(--tw-bg-opacity)); @@ -2649,20 +2640,11 @@ video { background-color: rgb(127 29 29 / 0.2); } -.dark\:bg-white:is(.dark *) { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - .dark\:bg-yellow-800:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(133 77 14 / var(--tw-bg-opacity)); } -.dark\:bg-blue-800\/30:is(.dark *) { - background-color: rgb(30 64 175 / 0.3); -} - .dark\:bg-opacity-80:is(.dark *) { --tw-bg-opacity: 0.8; } @@ -2677,6 +2659,16 @@ video { --tw-gradient-to: #f49541 var(--tw-gradient-to-position); } +.dark\:text-amber-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(252 211 77 / var(--tw-text-opacity)); +} + +.dark\:text-blue-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(147 197 253 / var(--tw-text-opacity)); +} + .dark\:text-blue-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(96 165 250 / var(--tw-text-opacity)); @@ -2762,16 +2754,6 @@ video { color: rgb(250 204 21 / var(--tw-text-opacity)); } -.dark\:text-amber-300:is(.dark *) { - --tw-text-opacity: 1; - color: rgb(252 211 77 / var(--tw-text-opacity)); -} - -.dark\:text-blue-300:is(.dark *) { - --tw-text-opacity: 1; - color: rgb(147 197 253 / var(--tw-text-opacity)); -} - .dark\:placeholder-gray-400:is(.dark *)::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(156 163 175 / var(--tw-placeholder-opacity));