Only show fields when they have a value in main client (#746)

This commit is contained in:
Leendert de Borst
2025-04-01 12:58:07 +02:00
parent adc6293f4b
commit 8319ddcce4
5 changed files with 177 additions and 93 deletions

View File

@@ -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);
}
/// <summary>
/// Returns true if the email address is from a known SpamOK domain.
/// </summary>
private bool IsSpamOkDomain(string email)
{
return Config.PublicEmailDomains.Exists(x => email.EndsWith(x));
}
/// <summary>
/// Returns true if the email address is from a known AliasVault domain.
/// </summary>
private bool IsAliasVaultDomain(string email)
{
return Config.PrivateEmailDomains.Exists(x => email.EndsWith(x));
IsSpamOk = EmailService.IsSpamOkDomain(EmailAddress);
}
/// <summary>
@@ -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);
}

View File

@@ -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();

View File

@@ -69,13 +69,23 @@ else
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-2 text-xl font-semibold dark:text-white">Login credentials</h3>
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400">
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))
{
<span>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.</span>
}
else
{
<span>Below you can view and copy the stored login credentials for this account.</span>
}
</p>
<form action="#">
<div class="grid gap-6">
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Id="email" Label="Email" Value="@Alias.Alias.Email"></CopyPasteFormRow>
</div>
@if (!string.IsNullOrWhiteSpace(Alias.Alias.Email))
{
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Id="email" Label="Email" Value="@Alias.Alias.Email"></CopyPasteFormRow>
</div>
}
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Id="username" Label="Username" Value="@(Alias.Username)"></CopyPasteFormRow>
</div>
@@ -85,28 +95,46 @@ else
</div>
</form>
</div>
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-xl font-semibold dark:text-white">Alias</h3>
<form action="#">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<CopyPasteFormRow Label="Full name" Value="@(Alias.Alias.FirstName + " " + Alias.Alias.LastName)"></CopyPasteFormRow>
@if (HasAlias)
{
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-xl font-semibold dark:text-white">Alias</h3>
<form action="#">
<div class="grid grid-cols-6 gap-6">
@if (!string.IsNullOrWhiteSpace(Alias.Alias.FirstName) && !string.IsNullOrWhiteSpace(Alias.Alias.LastName))
{
<div class="col-span-6">
<CopyPasteFormRow Label="Full name" Value="@(Alias.Alias.FirstName + " " + Alias.Alias.LastName)"></CopyPasteFormRow>
</div>
}
@if (!string.IsNullOrWhiteSpace(Alias.Alias.FirstName))
{
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="First name" Value="@(Alias.Alias.FirstName)"></CopyPasteFormRow>
</div>
}
@if (!string.IsNullOrWhiteSpace(Alias.Alias.LastName))
{
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Last name" Value="@(Alias.Alias.LastName)"></CopyPasteFormRow>
</div>
}
@if (IsValidDate(Alias.Alias.BirthDate))
{
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Birthdate" Value="@(Alias.Alias.BirthDate.ToString("yyyy-MM-dd"))"></CopyPasteFormRow>
</div>
}
@if (!string.IsNullOrWhiteSpace(Alias.Alias.NickName))
{
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Nickname" Value="@(Alias.Alias.NickName)"></CopyPasteFormRow>
</div>
}
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="First name" Value="@(Alias.Alias.FirstName)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Last name" Value="@(Alias.Alias.LastName)"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Birthdate" Value="@(Alias.Alias.BirthDate.ToString("yyyy-MM-dd"))"></CopyPasteFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<CopyPasteFormRow Label="Nickname" Value="@(Alias.Alias.NickName)"></CopyPasteFormRow>
</div>
</div>
</form>
</div>
</form>
</div>
}
</div>
</div>
}
@@ -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;
/// <summary>
/// Checks if a date is valid and not a min value.
/// </summary>
/// <param name="date">The date to check.</param>
/// <returns>True if the date is valid and not a min value, false otherwise.</returns>
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;
}
/// <summary>
/// Checks if the alias has any valid data.
/// </summary>
/// <param name="alias">The credential containing alias information.</param>
/// <returns>True if the alias has any valid data, false otherwise.</returns>
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);
}
/// <inheritdoc />
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();
}

View File

@@ -14,10 +14,46 @@ using Microsoft.EntityFrameworkCore;
/// <summary>
/// Email service that contains utility methods for handling email functionality such as client-side decryption.
/// </summary>
public sealed class EmailService(DbService dbService, JsInteropService jsInteropService, GlobalNotificationService globalNotificationService, ILogger<EmailService> logger)
/// <param name="dbService">The database service.</param>
/// <param name="jsInteropService">The JavaScript interop service.</param>
/// <param name="globalNotificationService">The global notification service.</param>
/// <param name="logger">The logger.</param>
/// <param name="config">The configuration.</param>
public sealed class EmailService(DbService dbService, JsInteropService jsInteropService, GlobalNotificationService globalNotificationService, ILogger<EmailService> logger, Config config)
{
private List<EncryptionKey> _encryptionKeys = [];
/// <summary>
/// Returns true if the email address is from a known SpamOK public domain.
/// </summary>
/// <param name="email">The email address to check.</param>
/// <returns>True if the email address is from a known SpamOK public domain, false otherwise.</returns>
public bool IsSpamOkDomain(string email)
{
return config.PublicEmailDomains.Exists(x => email.EndsWith(x));
}
/// <summary>
/// Returns true if the email address is from a known AliasVault private domain.
/// </summary>
/// <param name="email">The email address to check.</param>
/// <returns>True if the email address is from a known AliasVault private domain, false otherwise.</returns>
public bool IsAliasVaultDomain(string email)
{
return config.PrivateEmailDomains.Exists(x => email.EndsWith(x));
}
/// <summary>
/// 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.
/// </summary>
/// <param name="email">The email address to check.</param>
/// <returns>True if the email address is from a known AliasVault supported domain, false otherwise.</returns>
public bool IsAliasVaultSupportedDomain(string email)
{
return IsSpamOkDomain(email) || IsAliasVaultDomain(email);
}
/// <summary>
/// Decrypts a single email using the private key.
/// </summary>

View File

@@ -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));