diff --git a/src/AliasVault.WebApp/AliasVault.WebApp.csproj b/src/AliasVault.WebApp/AliasVault.WebApp.csproj index c2c780f90..c725fdf63 100644 --- a/src/AliasVault.WebApp/AliasVault.WebApp.csproj +++ b/src/AliasVault.WebApp/AliasVault.WebApp.csproj @@ -1,6 +1,6 @@ - + AliasVault.WebApp net8.0 enable enable @@ -60,12 +60,6 @@ - - - - - true - PreserveNewest diff --git a/src/AliasVault.WebApp/Auth/Pages/Base/LoginBase.cs b/src/AliasVault.WebApp/Auth/Pages/Base/LoginBase.cs index 79dea2754..f91d9cc3b 100644 --- a/src/AliasVault.WebApp/Auth/Pages/Base/LoginBase.cs +++ b/src/AliasVault.WebApp/Auth/Pages/Base/LoginBase.cs @@ -9,9 +9,9 @@ namespace AliasVault.WebApp.Auth.Pages.Base; using System.Net.Http.Json; using System.Text.Json; +using AliasVault.Shared.Models.WebApi; using AliasVault.Shared.Models.WebApi.Auth; using AliasVault.WebApp.Auth.Services; -using AliasVault.WebApp.Components; using AliasVault.WebApp.Services; using AliasVault.WebApp.Services.Database; using Blazored.LocalStorage; @@ -75,14 +75,34 @@ public class LoginBase : OwningComponentBase [Inject] public ILocalStorageService LocalStorage { get; set; } = null!; + /// + /// Parses the response content and displays the server validation errors. + /// + /// Response content. + /// List of errors if something went wrong. + public static List ParseResponse(string responseContent) + { + var returnErrors = new List(); + + var errorResponse = System.Text.Json.JsonSerializer.Deserialize(responseContent); + if (errorResponse is not null) + { + foreach (var error in errorResponse.Errors) + { + returnErrors.AddRange(error.Value); + } + } + + return returnErrors; + } + /// /// Gets the username from the authentication state asynchronously. /// /// Email address. /// Password. - /// ServerValidationErrors Blazor component reference. - /// The username. - protected async Task ProcessLoginAsync(string email, string password, ServerValidationErrors serverValidationErrors) + /// List of errors if something went wrong. + protected async Task> ProcessLoginAsync(string email, string password) { // Send request to server with email to get server ephemeral public key. var result = await Http.PostAsJsonAsync("api/v1/Auth/login", new LoginRequest(email)); @@ -90,15 +110,16 @@ public class LoginBase : OwningComponentBase if (!result.IsSuccessStatusCode) { - serverValidationErrors.ParseResponse(responseContent); - return; + return ParseResponse(responseContent); } var loginResponse = JsonSerializer.Deserialize(responseContent); if (loginResponse == null) { - serverValidationErrors.AddError("An error occurred while processing the login request."); - return; + return new List + { + "An error occurred while processing the login request.", + }; } // 3. Client derives shared session key. @@ -120,15 +141,16 @@ public class LoginBase : OwningComponentBase if (!result.IsSuccessStatusCode) { - serverValidationErrors.ParseResponse(responseContent); - return; + return ParseResponse(responseContent); } var validateLoginResponse = JsonSerializer.Deserialize(responseContent); if (validateLoginResponse == null) { - serverValidationErrors.AddError("An error occurred while processing the login request."); - return; + return new List + { + "An error occurred while processing the login request.", + }; } // 5. Client verifies proof. @@ -155,5 +177,7 @@ public class LoginBase : OwningComponentBase { NavigationManager.NavigateTo("/"); } + + return new List(); } } diff --git a/src/AliasVault.WebApp/Auth/Pages/Login.razor b/src/AliasVault.WebApp/Auth/Pages/Login.razor index 81a952e33..71c84aab8 100644 --- a/src/AliasVault.WebApp/Auth/Pages/Login.razor +++ b/src/AliasVault.WebApp/Auth/Pages/Login.razor @@ -64,7 +64,11 @@ try { - await ProcessLoginAsync(_loginModel.Email, _loginModel.Password, _serverValidationErrors); + var errors = await ProcessLoginAsync(_loginModel.Email, _loginModel.Password); + foreach (var error in errors) + { + _serverValidationErrors.AddError(error); + } } #if DEBUG catch (Exception ex) diff --git a/src/AliasVault.WebApp/Auth/Pages/Register.razor b/src/AliasVault.WebApp/Auth/Pages/Register.razor index 58820d7de..18b94cc0d 100644 --- a/src/AliasVault.WebApp/Auth/Pages/Register.razor +++ b/src/AliasVault.WebApp/Auth/Pages/Register.razor @@ -8,6 +8,7 @@ @using System.Text.Json @using AliasVault.Shared.Models @using AliasVault.WebApp.Auth.Components +@using AliasVault.WebApp.Auth.Pages.Base @using AliasVault.WebApp.Auth.Services @using Cryptography @using SecureRemotePassword @@ -77,7 +78,7 @@ if (!result.IsSuccessStatusCode) { - _serverValidationErrors.ParseResponse(responseContent); + LoginBase.ParseResponse(responseContent); StateHasChanged(); return; } diff --git a/src/AliasVault.WebApp/Auth/Pages/Unlock.razor b/src/AliasVault.WebApp/Auth/Pages/Unlock.razor index 85bb4e50a..ca3fc5089 100644 --- a/src/AliasVault.WebApp/Auth/Pages/Unlock.razor +++ b/src/AliasVault.WebApp/Auth/Pages/Unlock.razor @@ -75,7 +75,7 @@ try { - await ProcessLoginAsync(Email, _unlockModel.Password, _serverValidationErrors); + await ProcessLoginAsync(Email, _unlockModel.Password); StateHasChanged(); } #if DEBUG diff --git a/src/AliasVault.WebApp/Auth/Services/AuthService.cs b/src/AliasVault.WebApp/Auth/Services/AuthService.cs index 7542b06c2..e914aeb87 100644 --- a/src/AliasVault.WebApp/Auth/Services/AuthService.cs +++ b/src/AliasVault.WebApp/Auth/Services/AuthService.cs @@ -107,6 +107,7 @@ public class AuthService(HttpClient httpClient, ILocalStorageService localStorag /// Encryption key as base64 string. public string GetEncryptionKeyAsBase64Async() { + // Enable this line for debugging to skip unlock screen. return Convert.ToBase64String(GetEncryptionKeyAsync()); } diff --git a/src/AliasVault.WebApp/Components/Alias/Alias.razor b/src/AliasVault.WebApp/Components/Credentials/Credential.razor similarity index 77% rename from src/AliasVault.WebApp/Components/Alias/Alias.razor rename to src/AliasVault.WebApp/Components/Credentials/Credential.razor index a92c346c9..4329cf6e1 100644 --- a/src/AliasVault.WebApp/Components/Alias/Alias.razor +++ b/src/AliasVault.WebApp/Components/Credentials/Credential.razor @@ -11,14 +11,14 @@ @code { /// - /// Gets or sets the alias object to show. + /// Gets or sets the credentials object to show. /// [Parameter] - public AliasVault.Shared.Models.WebApi.AliasListEntry Obj { get; set; } = null!; + public AliasVault.WebApp.Models.CredentialListEntry Obj { get; set; } = null!; private void ShowDetails() { // Redirect to view page instead for now. - NavigationManager.NavigateTo($"/login/{Obj.Id}"); + NavigationManager.NavigateTo($"/credentials/{Obj.Id}"); } } diff --git a/src/AliasVault.WebApp/Components/ServerValidationErrors.razor b/src/AliasVault.WebApp/Components/ServerValidationErrors.razor index 61c12031d..6fd7ec31d 100644 --- a/src/AliasVault.WebApp/Components/ServerValidationErrors.razor +++ b/src/AliasVault.WebApp/Components/ServerValidationErrors.razor @@ -11,24 +11,6 @@ @code { private readonly List _errors = []; - /// - /// Parses the response content and displays the server validation errors. - /// - public void ParseResponse(string responseContent) - { - _errors.Clear(); - var errorResponse = System.Text.Json.JsonSerializer.Deserialize(responseContent); - if (errorResponse is not null) - { - foreach (var error in errorResponse.Errors) - { - _errors.AddRange(error.Value); - } - } - - StateHasChanged(); - } - /// /// Adds a server validation error. /// diff --git a/src/AliasVault.WebApp/Layout/TopMenu.razor b/src/AliasVault.WebApp/Layout/TopMenu.razor index daf84c99e..756262c5b 100644 --- a/src/AliasVault.WebApp/Layout/TopMenu.razor +++ b/src/AliasVault.WebApp/Layout/TopMenu.razor @@ -15,8 +15,8 @@ Home - - Aliases + + Credentials @@ -74,8 +74,8 @@
  • - - Aliases + + Credentials
  • diff --git a/src/AliasVault.WebApp/Models/LoginEdit.cs b/src/AliasVault.WebApp/Models/CredentialEdit.cs similarity index 92% rename from src/AliasVault.WebApp/Models/LoginEdit.cs rename to src/AliasVault.WebApp/Models/CredentialEdit.cs index 20e0f6a04..5e19040e3 100644 --- a/src/AliasVault.WebApp/Models/LoginEdit.cs +++ b/src/AliasVault.WebApp/Models/CredentialEdit.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) lanedirt. All rights reserved. // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // @@ -11,9 +11,9 @@ using System.ComponentModel.DataAnnotations; using AliasClientDb; /// -/// Login model. +/// Credential edit model. /// -public class LoginEdit +public class CredentialEdit { /// /// Gets or sets the Id of the login. diff --git a/src/AliasVault.WebApp/Models/CredentialListEntry.cs b/src/AliasVault.WebApp/Models/CredentialListEntry.cs new file mode 100644 index 000000000..b43042428 --- /dev/null +++ b/src/AliasVault.WebApp/Models/CredentialListEntry.cs @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasVault.WebApp.Models; + +/// +/// Alias list entry model. This model is used to represent an alias in a list with simplified properties. +/// +public class CredentialListEntry +{ + /// + /// Gets or sets the alias id. + /// + public Guid Id { get; set; } + + /// + /// Gets or sets the alias logo byte array. + /// + public byte[]? Logo { get; set; } + + /// + /// Gets or sets the alias service name. + /// + public string Service { get; set; } = null!; + + /// + /// Gets or sets the alias create date. + /// + public DateTime CreateDate { get; set; } +} diff --git a/src/AliasVault.WebApp/Pages/Logins/AddEdit.razor b/src/AliasVault.WebApp/Pages/Credentials/AddEdit.razor similarity index 86% rename from src/AliasVault.WebApp/Pages/Logins/AddEdit.razor rename to src/AliasVault.WebApp/Pages/Credentials/AddEdit.razor index c5c9933a9..aaf80ab91 100644 --- a/src/AliasVault.WebApp/Pages/Logins/AddEdit.razor +++ b/src/AliasVault.WebApp/Pages/Credentials/AddEdit.razor @@ -1,21 +1,20 @@ -@page "/add-login" -@page "/login/{id:guid}/edit" +@page "/add-credentials" +@page "/credentials/{id:guid}/edit" @inherits PageBase @inject NavigationManager Navigation -@inject AliasService AliasService +@inject CredentialService CredentialService @using AliasGenerators.Implementations @using AliasGenerators.Password.Implementations -@using AliasVault.WebApp.Models @using Alias = AliasClientDb.Alias @using Password = AliasClientDb.Password @using Service = AliasClientDb.Service @if (EditMode) { - Edit login + Edit credentials } else { - Add login + Add credentials }
    @@ -24,18 +23,18 @@ else {
    @if (EditMode) { -

    Edit login

    +

    Edit credentials

    } else { -

    Add login

    +

    Add credentials

    }
    @if (EditMode) { -

    Edit the existing login below.

    +

    Edit the existing credentials entry below.

    } else { -

    Create a new login below.

    +

    Create a new credentials entry below.

    }
    @@ -68,7 +67,7 @@ else

    Login credentials

    - + @if (IsIdentityLoading) {

    Loading...

    @@ -140,7 +139,7 @@ else
    - + @@ -153,14 +152,14 @@ else @code { /// - /// Gets or sets the login ID. + /// Gets or sets the Credentials ID. /// [Parameter] public Guid? Id { get; set; } private bool EditMode { get; set; } private bool Loading { get; set; } = true; - private LoginEdit Obj { get; set; } = new(); + private CredentialEdit Obj { get; set; } = new(); private bool IsIdentityLoading { get; set; } private bool IsSaving { get; set; } @@ -186,11 +185,11 @@ else if (EditMode) { - BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Edit login" }); + BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Edit credential" }); } else { - BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Add new login" }); + BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Add new credential" }); } } @@ -206,32 +205,32 @@ else if (Id is null) { // Error loading alias. - GlobalNotificationService.AddErrorMessage("This login does not exist (anymore). Please try again."); + GlobalNotificationService.AddErrorMessage("This credential does not exist (anymore). Please try again."); NavigationManager.NavigateTo("/", false, true); return; } // Load existing Obj, retrieve from service - var alias = await AliasService.LoadEntryAsync(Id.Value); + var alias = await CredentialService.LoadEntryAsync(Id.Value); if (alias is null) { // Error loading alias. - GlobalNotificationService.AddErrorMessage("This login does not exist (anymore). Please try again."); + GlobalNotificationService.AddErrorMessage("This credential does not exist (anymore). Please try again."); NavigationManager.NavigateTo("/", false, true); return; } - Obj = LoginToLoginEdit(alias); + Obj = CredentialToCredentialEdit(alias); } else { // Create new Obj - var alias = new Login(); + var alias = new Credential(); alias.Alias = new Alias(); alias.Service = new Service(); alias.Passwords = new List { new Password() }; - Obj = LoginToLoginEdit(alias); + Obj = CredentialToCredentialEdit(alias); } // Hide loading spinner @@ -247,7 +246,7 @@ else StateHasChanged(); // Generate a random identity using the IIdentityGenerator implementation. - var identity = await AliasService.GenerateRandomIdentityAsync(); + var identity = await CredentialService.GenerateRandomIdentityAsync(); // Generate random values for the Identity properties Obj.Alias.FirstName = identity.FirstName; @@ -297,12 +296,12 @@ else { if (Id is not null) { - Id = await AliasService.UpdateLoginAsync(LoginEditToLogin(Obj)); + Id = await CredentialService.UpdateEntryAsync(CredentialEditToCredential(Obj)); } } else { - Id = await AliasService.InsertAliasAsync(LoginEditToLogin(Obj)); + Id = await CredentialService.InsertEntryAsync(CredentialEditToCredential(Obj)); } IsSaving = false; @@ -311,40 +310,46 @@ else if (Id is null || Id == Guid.Empty) { // Error saving. - GlobalNotificationService.AddErrorMessage("Error saving alias. Please try again.", true); + GlobalNotificationService.AddErrorMessage("Error saving credentials. Please try again.", true); return; } // No error, add success message. if (EditMode) { - GlobalNotificationService.AddSuccessMessage("Login updated successfully."); + GlobalNotificationService.AddSuccessMessage("Credentials updated successfully."); } else { - GlobalNotificationService.AddSuccessMessage("Login created successfully."); + GlobalNotificationService.AddSuccessMessage("Credentials created successfully."); } - Navigation.NavigateTo("/login/" + Id); + Navigation.NavigateTo("/credentials/" + Id); } - private LoginEdit LoginToLoginEdit(Login alias) + private CredentialEdit CredentialToCredentialEdit(Credential alias) { - return new LoginEdit + Console.WriteLine("passwordCount: " + alias.Passwords.Count); + return new CredentialEdit { Id = alias.Id, ServiceName = alias.Service.Name ?? string.Empty, ServiceUrl = alias.Service.Url, - Password = alias.Passwords.FirstOrDefault() ?? new Password(), + Password = alias.Passwords.FirstOrDefault() ?? new Password + { + Value = string.Empty, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow, + }, Alias = alias.Alias, CreateDate = alias.CreatedAt, LastUpdate = alias.UpdatedAt }; } - private Login LoginEditToLogin(LoginEdit alias) + private Credential CredentialEditToCredential(CredentialEdit alias) { - return new Login() + return new Credential() { Id = alias.Id, Service = new Service @@ -354,12 +359,7 @@ else }, Passwords = new List { - new Password - { - Value = alias.Password.Value ?? string.Empty, - CreatedAt = alias.CreateDate, - UpdatedAt = alias.LastUpdate, - }, + alias.Password, }, Alias = alias.Alias, }; diff --git a/src/AliasVault.WebApp/Pages/Logins/Delete.razor b/src/AliasVault.WebApp/Pages/Credentials/Delete.razor similarity index 77% rename from src/AliasVault.WebApp/Pages/Logins/Delete.razor rename to src/AliasVault.WebApp/Pages/Credentials/Delete.razor index 525dfb0d9..0f35f15cf 100644 --- a/src/AliasVault.WebApp/Pages/Logins/Delete.razor +++ b/src/AliasVault.WebApp/Pages/Credentials/Delete.razor @@ -1,16 +1,16 @@ -@page "/login/{id:guid}/delete" +@page "/credentials/{id:guid}/delete" @inherits PageBase -@inject AliasService AliasService +@inject CredentialService CredentialService -Delete login +Delete credentials entry
    -

    Delete login

    +

    Delete credentials

    -

    You can delete a login below.

    +

    You can delete a credentials entry below.

    @@ -22,7 +22,7 @@ else {
    -

    Login

    +

    Credential entry

    @Id
    @@ -49,14 +49,14 @@ else public Guid Id { get; set; } private bool IsLoading { get; set; } = true; - private Login? Obj { get; set; } + private Credential? Obj { get; set; } /// protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - BreadcrumbItems.Add(new BreadcrumbItem { Url = "login/" + Id, DisplayName = "View Login" }); - BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Delete login" }); + BreadcrumbItems.Add(new BreadcrumbItem { Url = "credentials/" + Id, DisplayName = "View Credentials Entry" }); + BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Delete credentials" }); } /// @@ -67,7 +67,7 @@ else if (firstRender) { // Load existing Obj, retrieve from service - Obj = await AliasService.LoadEntryAsync(Id); + Obj = await CredentialService.LoadEntryAsync(Id); // Hide loading spinner IsLoading = false; @@ -81,17 +81,17 @@ else { if (Obj is null) { - GlobalNotificationService.AddErrorMessage("Error deleting. Login not found.", true); + GlobalNotificationService.AddErrorMessage("Error deleting. Credentials entry not found.", true); return; } - await AliasService.DeleteEntryAsync(Id); - GlobalNotificationService.AddSuccessMessage("Login successfully deleted."); + await CredentialService.DeleteEntryAsync(Id); + GlobalNotificationService.AddSuccessMessage("Credentials entry successfully deleted."); NavigationManager.NavigateTo("/"); } private void Cancel() { - NavigationManager.NavigateTo("/login/" + Id); + NavigationManager.NavigateTo("/credentials/" + Id); } } diff --git a/src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/AttachmentApiModel.cs b/src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/AttachmentApiModel.cs similarity index 100% rename from src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/AttachmentApiModel.cs rename to src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/AttachmentApiModel.cs diff --git a/src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/Base/EmailApiModelBase.cs b/src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/Base/EmailApiModelBase.cs similarity index 100% rename from src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/Base/EmailApiModelBase.cs rename to src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/Base/EmailApiModelBase.cs diff --git a/src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/EmailApiModel.cs b/src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/EmailApiModel.cs similarity index 100% rename from src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/EmailApiModel.cs rename to src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/EmailApiModel.cs diff --git a/src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/MailboxApiModel.cs b/src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/MailboxApiModel.cs similarity index 100% rename from src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/MailboxApiModel.cs rename to src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/MailboxApiModel.cs diff --git a/src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/MailboxEmailApiModel.cs b/src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/MailboxEmailApiModel.cs similarity index 100% rename from src/AliasVault.WebApp/Pages/Logins/Mailbox/Models/Spamok/MailboxEmailApiModel.cs rename to src/AliasVault.WebApp/Pages/Credentials/Mailbox/Models/Spamok/MailboxEmailApiModel.cs diff --git a/src/AliasVault.WebApp/Pages/Logins/View.razor b/src/AliasVault.WebApp/Pages/Credentials/View.razor similarity index 87% rename from src/AliasVault.WebApp/Pages/Logins/View.razor rename to src/AliasVault.WebApp/Pages/Credentials/View.razor index 8385dc4f9..5ed0309af 100644 --- a/src/AliasVault.WebApp/Pages/Logins/View.razor +++ b/src/AliasVault.WebApp/Pages/Credentials/View.razor @@ -1,9 +1,9 @@ -@page "/login/{id:guid}" +@page "/credentials/{id:guid}" @inherits PageBase @using AliasVault.WebApp.Components.Email -@inject AliasService AliasService +@inject CredentialService CredentialService -View login +View credentials @if (IsLoading || Alias == null) { @@ -17,13 +17,13 @@ else @@ -119,19 +119,19 @@ else @code { /// - /// Gets or sets the login ID. + /// Gets or sets the credentials ID. /// [Parameter] public Guid Id { get; set; } private bool IsLoading { get; set; } = true; - private Login? Alias { get; set; } = new(); + private Credential? Alias { get; set; } = new(); private string AliasEmail { get; set; } = string.Empty; /// protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "View login" }); + BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "View credentials entry" }); } /// @@ -151,12 +151,12 @@ else StateHasChanged(); // Load the aliases from the webapi via AliasService. - Alias = await AliasService.LoadEntryAsync(Id); + Alias = await CredentialService.LoadEntryAsync(Id); if (Alias is null) { // Error loading alias. - GlobalNotificationService.AddErrorMessage("This login does not exist (anymore). Please try again."); + GlobalNotificationService.AddErrorMessage("This credentials entry does not exist (anymore). Please try again."); NavigationManager.NavigateTo("/", false, true); return; } diff --git a/src/AliasVault.WebApp/Pages/Home.razor b/src/AliasVault.WebApp/Pages/Home.razor index f3bad62a7..5b0d0fd99 100644 --- a/src/AliasVault.WebApp/Pages/Home.razor +++ b/src/AliasVault.WebApp/Pages/Home.razor @@ -1,8 +1,8 @@ @page "/" -@page "/aliases" +@page "/credentials" @inherits PageBase -@using AliasVault.WebApp.Components.Alias -@inject AliasService AliasService +@using AliasVault.WebApp.Components.Credentials +@inject CredentialService CredentialService Home @@ -10,12 +10,12 @@
    -

    Find all of your logins below.

    +

    Find all of your credentials below.

    @@ -25,16 +25,16 @@ }
    - @foreach (var alias in Aliases) + @foreach (var credential in Credentials) { - + }
    @code { private bool IsLoading { get; set; } = true; - private List Aliases { get; set; } = new(); + private List Credentials { get; set; } = new(); /// protected override async Task OnAfterRenderAsync(bool firstRender) @@ -53,15 +53,15 @@ StateHasChanged(); // Load the aliases from the webapi via AliasService. - var aliasListEntries = await AliasService.GetListAsync(); - if (aliasListEntries is null) + var credentialListEntries = await CredentialService.GetListAsync(); + if (credentialListEntries is null) { // Error loading aliases. - GlobalNotificationService.AddErrorMessage("Failed to load aliases.", true); + GlobalNotificationService.AddErrorMessage("Failed to load credentials.", true); return; } - Aliases = aliasListEntries; + Credentials = credentialListEntries; IsLoading = false; StateHasChanged(); } diff --git a/src/AliasVault.WebApp/Program.cs b/src/AliasVault.WebApp/Program.cs index 086422e45..0fb0ac3a0 100644 --- a/src/AliasVault.WebApp/Program.cs +++ b/src/AliasVault.WebApp/Program.cs @@ -43,7 +43,7 @@ builder.Services.AddScoped(sp => builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); diff --git a/src/AliasVault.WebApp/Services/AliasService.cs b/src/AliasVault.WebApp/Services/CredentialService.cs similarity index 85% rename from src/AliasVault.WebApp/Services/AliasService.cs rename to src/AliasVault.WebApp/Services/CredentialService.cs index 1cf3260d1..ae45fd14d 100644 --- a/src/AliasVault.WebApp/Services/AliasService.cs +++ b/src/AliasVault.WebApp/Services/CredentialService.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) lanedirt. All rights reserved. // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // @@ -9,7 +9,7 @@ namespace AliasVault.WebApp.Services; using System.Net.Http.Json; using AliasClientDb; -using AliasVault.Shared.Models.WebApi; +using AliasVault.WebApp.Models; using AliasVault.WebApp.Services.Database; using Microsoft.EntityFrameworkCore; using Identity = AliasGenerators.Identity.Models.Identity; @@ -17,7 +17,7 @@ using Identity = AliasGenerators.Identity.Models.Identity; /// /// Service class for alias operations. /// -public class AliasService(HttpClient httpClient, DbService dbService) +public class CredentialService(HttpClient httpClient, DbService dbService) { /// /// Generate random identity by calling the IdentityGenerator API. @@ -39,11 +39,11 @@ public class AliasService(HttpClient httpClient, DbService dbService) /// /// Login object to insert. /// Guid of inserted entry. - public async Task InsertAliasAsync(Login loginObject) + public async Task InsertEntryAsync(Credential loginObject) { var context = await dbService.GetDbContextAsync(); - var login = new Login + var login = new Credential { CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow, @@ -76,19 +76,18 @@ public class AliasService(HttpClient httpClient, DbService dbService) }, }; - await context.Logins.AddAsync(login); + login.Passwords.Add(new Password() + { + Value = loginObject.Passwords.First().Value, + }); + + await context.Credentials.AddAsync(login); await context.SaveChangesAsync(); Console.WriteLine("Inserted new alias without password."); // Add password. - context.Passwords.Add(new AliasClientDb.Password() - { - Value = loginObject.Passwords.FirstOrDefault()?.Value, - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow, - Login = login, - }); + login.Passwords.Add(loginObject.Passwords.First()); await dbService.SaveDatabaseAsync(); @@ -102,12 +101,12 @@ public class AliasService(HttpClient httpClient, DbService dbService) ///
    /// Login object to update. /// Guid of updated entry. - public async Task UpdateLoginAsync(Login loginObject) + public async Task UpdateEntryAsync(Credential loginObject) { var context = await dbService.GetDbContextAsync(); // Get the existing entry. - var login = await context.Logins + var login = await context.Credentials .Include(x => x.Alias) .Include(x => x.Service) .Include(x => x.Passwords) @@ -148,16 +147,16 @@ public class AliasService(HttpClient httpClient, DbService dbService) /// /// Id of login to load. /// Alias object. - public async Task LoadEntryAsync(Guid loginId) + public async Task LoadEntryAsync(Guid loginId) { var context = await dbService.GetDbContextAsync(); - var loginObject = await context.Logins + var loginObject = await context.Credentials .Include(x => x.Passwords) .Include(x => x.Alias) .Include(x => x.Service) .Where(x => x.Id == loginId) - .FirstAsync(); + .FirstOrDefaultAsync(); return loginObject; } @@ -165,16 +164,16 @@ public class AliasService(HttpClient httpClient, DbService dbService) /// /// Get list with all login entries. /// - /// List of AliasListEntry objects. - public async Task?> GetListAsync() + /// List of CredentialListEntry objects. + public async Task?> GetListAsync() { var context = await dbService.GetDbContextAsync(); // Retrieve all aliases from client DB. - return await context.Logins + return await context.Credentials .Include(x => x.Alias) .Include(x => x.Service) - .Select(x => new AliasListEntry + .Select(x => new CredentialListEntry { Id = x.Id, Logo = x.Service.Logo, @@ -193,11 +192,11 @@ public class AliasService(HttpClient httpClient, DbService dbService) { var context = await dbService.GetDbContextAsync(); - var login = await context.Logins + var login = await context.Credentials .Where(x => x.Id == id) .FirstAsync(); - context.Logins.Remove(login); + context.Credentials.Remove(login); await context.SaveChangesAsync(); await dbService.SaveDatabaseAsync(); } diff --git a/src/AliasVault.WebApp/_Imports.razor b/src/AliasVault.WebApp/_Imports.razor index bae80ee01..ccf76db47 100644 --- a/src/AliasVault.WebApp/_Imports.razor +++ b/src/AliasVault.WebApp/_Imports.razor @@ -15,6 +15,7 @@ @using AliasVault.WebApp.Components.Models @using AliasVault.WebApp.Components.Alerts @using AliasVault.WebApp.Components.Loading +@using AliasVault.WebApp.Models @using AliasVault.WebApp.Pages.Base @using AliasVault.WebApp.Services @using AliasVault.WebApp.Services.Database diff --git a/src/Databases/AliasClientDb/Alias.cs b/src/Databases/AliasClientDb/Alias.cs index 28738e154..5153afc03 100644 --- a/src/Databases/AliasClientDb/Alias.cs +++ b/src/Databases/AliasClientDb/Alias.cs @@ -121,4 +121,9 @@ public class Alias /// Gets or sets the updated timestamp. /// public DateTime UpdatedAt { get; set; } + + /// + /// Gets or sets the credential objects. + /// + public virtual ICollection Credentials { get; set; } = new List(); } diff --git a/src/Databases/AliasClientDb/AliasClientDbContext.cs b/src/Databases/AliasClientDb/AliasClientDbContext.cs index c0b690ee1..97ce02c62 100644 --- a/src/Databases/AliasClientDb/AliasClientDbContext.cs +++ b/src/Databases/AliasClientDb/AliasClientDbContext.cs @@ -46,27 +46,27 @@ public class AliasClientDbContext : DbContext /// /// Gets or sets the Alias DbSet. /// - public DbSet Aliases { get; set; } + public DbSet Aliases { get; set; } = null!; /// /// Gets or sets the Attachment DbSet. /// - public DbSet Attachment { get; set; } + public DbSet Attachment { get; set; } = null!; /// - /// Gets or sets the Login DbSet. + /// Gets or sets the Credential DbSet. /// - public DbSet Logins { get; set; } + public DbSet Credentials { get; set; } = null!; /// /// Gets or sets the Password DbSet. /// - public DbSet Passwords { get; set; } + public DbSet Passwords { get; set; } = null!; /// /// Gets or sets the Service DbSet. /// - public DbSet Services { get; set; } + public DbSet Services { get; set; } = null!; /// /// The OnModelCreating method. @@ -88,32 +88,32 @@ public class AliasClientDbContext : DbContext } } - // Configure Login - Alias relationship - modelBuilder.Entity() + // Configure Credential - Alias relationship + modelBuilder.Entity() .HasOne(l => l.Alias) - .WithMany() + .WithMany(c => c.Credentials) .HasForeignKey(l => l.AliasId) .OnDelete(DeleteBehavior.Cascade); - // Configure Login - Service relationship - modelBuilder.Entity() + // Configure Credential - Service relationship + modelBuilder.Entity() .HasOne(l => l.Service) - .WithMany() + .WithMany(c => c.Credentials) .HasForeignKey(l => l.ServiceId) .OnDelete(DeleteBehavior.Cascade); - // Configure Attachment - Login relationship + // Configure Attachment - Credential relationship modelBuilder.Entity() - .HasOne(l => l.Login) - .WithMany() - .HasForeignKey(l => l.LoginId) + .HasOne(l => l.Credential) + .WithMany(c => c.Attachments) + .HasForeignKey(l => l.CredentialId) .OnDelete(DeleteBehavior.Cascade); - // Configure Password - Login relationship + // Configure Password - Credential relationship modelBuilder.Entity() - .HasOne(l => l.Login) - .WithMany() - .HasForeignKey(l => l.LoginId) + .HasOne(l => l.Credential) + .WithMany(c => c.Passwords) + .HasForeignKey(l => l.CredentialId) .OnDelete(DeleteBehavior.Cascade); } diff --git a/src/Databases/AliasClientDb/Attachment.cs b/src/Databases/AliasClientDb/Attachment.cs index b5b86cc47..2f2ae5855 100644 --- a/src/Databases/AliasClientDb/Attachment.cs +++ b/src/Databases/AliasClientDb/Attachment.cs @@ -43,13 +43,13 @@ public class Attachment public DateTime UpdatedAt { get; set; } /// - /// Gets or sets the login foreign key. + /// Gets or sets the credential foreign key. /// - public Guid LoginId { get; set; } + public Guid CredentialId { get; set; } /// - /// Gets or sets the login navigation property. + /// Gets or sets the credential navigation property. /// - [ForeignKey("LoginId")] - public virtual Login Login { get; set; } = null!; + [ForeignKey("CredentialId")] + public virtual Credential Credential { get; set; } = null!; } diff --git a/src/Databases/AliasClientDb/Login.cs b/src/Databases/AliasClientDb/Credential.cs similarity index 96% rename from src/Databases/AliasClientDb/Login.cs rename to src/Databases/AliasClientDb/Credential.cs index 56dcca99f..620914fad 100644 --- a/src/Databases/AliasClientDb/Login.cs +++ b/src/Databases/AliasClientDb/Credential.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) lanedirt. All rights reserved. // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // @@ -12,7 +12,7 @@ using System.ComponentModel.DataAnnotations.Schema; /// /// Login object. /// -public class Login +public class Credential { /// /// Gets or sets Login ID. diff --git a/src/Databases/AliasClientDb/Password.cs b/src/Databases/AliasClientDb/Password.cs index ead10f5a8..b897a9d1a 100644 --- a/src/Databases/AliasClientDb/Password.cs +++ b/src/Databases/AliasClientDb/Password.cs @@ -38,13 +38,13 @@ public class Password public DateTime UpdatedAt { get; set; } /// - /// Gets or sets the login foreign key. + /// Gets or sets the credential foreign key. /// - public Guid LoginId { get; set; } + public Guid CredentialId { get; set; } /// - /// Gets or sets the login navigation property. + /// Gets or sets the credential navigation property. /// - [ForeignKey("LoginId")] - public virtual Login Login { get; set; } = null!; + [ForeignKey("CredentialId")] + public virtual Credential Credential { get; set; } = null!; } diff --git a/src/Databases/AliasClientDb/Service.cs b/src/Databases/AliasClientDb/Service.cs index 2f6d6ade1..68b52824c 100644 --- a/src/Databases/AliasClientDb/Service.cs +++ b/src/Databases/AliasClientDb/Service.cs @@ -45,4 +45,9 @@ public class Service /// Gets or sets the updated timestamp. /// public DateTime UpdatedAt { get; set; } + + /// + /// Gets or sets the credential objects. + /// + public virtual ICollection Credentials { get; set; } = new List(); } diff --git a/src/Tests/AliasVault.E2ETests/Tests/AuthTests.cs b/src/Tests/AliasVault.E2ETests/Tests/AuthTests.cs index 320f88613..97968bdd6 100644 --- a/src/Tests/AliasVault.E2ETests/Tests/AuthTests.cs +++ b/src/Tests/AliasVault.E2ETests/Tests/AuthTests.cs @@ -56,6 +56,6 @@ public class AuthTests : PlaywrightTest // Check if the login was successful by verifying content. var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain("Find all of your logins below"), "No index content after logging in."); + Assert.That(pageContent, Does.Contain("Find all of your credentials below"), "No index content after logging in."); } } diff --git a/src/Tests/AliasVault.E2ETests/Tests/AliasTests.cs b/src/Tests/AliasVault.E2ETests/Tests/CredentialTests.cs similarity index 59% rename from src/Tests/AliasVault.E2ETests/Tests/AliasTests.cs rename to src/Tests/AliasVault.E2ETests/Tests/CredentialTests.cs index ab28a39db..9dcb7b617 100644 --- a/src/Tests/AliasVault.E2ETests/Tests/AliasTests.cs +++ b/src/Tests/AliasVault.E2ETests/Tests/CredentialTests.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // Copyright (c) lanedirt. All rights reserved. // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // @@ -8,97 +8,95 @@ namespace AliasVault.E2ETests.Tests; /// -/// End-to-end tests for the alias management. +/// End-to-end tests for the credential management. /// [Parallelizable(ParallelScope.Self)] [TestFixture] -public class AliasTests : PlaywrightTest +public class CredentialTests : PlaywrightTest { private static readonly Random Random = new(); /// - /// Test if the alias listing index page works. + /// Test if the credential listing index page works. /// /// Async task. [Test] - public async Task AliasListingTest() + public async Task CredentialListingTest() { - await NavigateUsingBlazorRouter("aliases"); - await WaitForURLAsync("**/aliases", "AliasVault"); + await NavigateUsingBlazorRouter("credentials"); + await WaitForURLAsync("**/credentials", "AliasVault"); // Check if the expected content is present. var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain("Find all of your logins below"), "No index content after logging in."); + Assert.That(pageContent, Does.Contain("Find all of your credentials below"), "No index content after logging in."); } /// - /// Test if creating a new alias works. + /// Test if creating a new credential entry works. /// /// Async task. [Test] - public async Task CreateAliasTest() + public async Task CreateCredentialTest() { // Create a new alias with service name = "Test Service". var serviceName = "Test Service"; - await CreateAlias(new Dictionary + await CreateCredentialEntry(new Dictionary { { "service-name", serviceName }, }); // Check that the service name is present in the content. var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain(serviceName), "Created alias service name does not appear on alias page."); + Assert.That(pageContent, Does.Contain(serviceName), "Created credential service name does not appear on alias page."); } /// - /// Test if editing a created alias works. + /// Test if editing a created credential entry works. /// /// Async task. [Test] - public async Task EditAliasTest() + public async Task EditCredentialTest() { - // Create a new alias with service name = "Alias service before". - var serviceNameBefore = "Login service before"; - await CreateAlias(new Dictionary + var serviceNameBefore = "Credential service before"; + await CreateCredentialEntry(new Dictionary { { "service-name", serviceNameBefore }, }); // Check that the service name is present in the content. var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain(serviceNameBefore), "Created login service name does not appear on login page."); + Assert.That(pageContent, Does.Contain(serviceNameBefore), "Created credential service name does not appear on login page."); // Click the edit button. - var editButton = Page.Locator("text=Edit login").First; + var editButton = Page.Locator("text=Edit credentials entry").First; await editButton.ClickAsync(); - await WaitForURLAsync("**/edit", "Save Login"); + await WaitForURLAsync("**/edit", "Save Credentials"); - // Replace the service name with "Alias service after". - var serviceNameAfter = "Login service after"; + var serviceNameAfter = "Credential service after"; await InputHelper.FillInputFields( fieldValues: new Dictionary { { "service-name", serviceNameAfter }, }); - var submitButton = Page.Locator("text=Save Login").First; + var submitButton = Page.Locator("text=Save Credentials").First; await submitButton.ClickAsync(); - await WaitForURLAsync("**/login/**", "View Login"); + await WaitForURLAsync("**/credentials/**", "View credentials entry"); pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain("Login updated"), "Login update confirmation message not shown."); - Assert.That(pageContent, Does.Contain(serviceNameAfter), "Login not updated correctly."); + Assert.That(pageContent, Does.Contain("Credentials updated"), "Credential update confirmation message not shown."); + Assert.That(pageContent, Does.Contain(serviceNameAfter), "Credential not updated correctly."); } /// - /// Create new alias. + /// Create new credential entry. /// /// Dictionary with html element ids and values to input as field value. /// Async task. - private async Task CreateAlias(Dictionary? formValues = null) + private async Task CreateCredentialEntry(Dictionary? formValues = null) { - await NavigateUsingBlazorRouter("add-login"); - await WaitForURLAsync("**/add-login", "Add login"); + await NavigateUsingBlazorRouter("add-credentials"); + await WaitForURLAsync("**/add-credentials", "Add credentials"); // Check if a button with text "Generate Random Identity" appears var generateButton = Page.Locator("text=Generate Random Identity"); @@ -108,12 +106,12 @@ public class AliasTests : PlaywrightTest await InputHelper.FillInputFields(formValues); await InputHelper.FillEmptyInputFieldsWithRandom(); - var submitButton = Page.Locator("text=Save Login").First; + var submitButton = Page.Locator("text=Save Credentials").First; await submitButton.ClickAsync(); - await WaitForURLAsync("**/login/**", "Login credentials"); + await WaitForURLAsync("**/credentials/**", "Login credentials"); - // Check if the alias was created + // Check if the credential was created var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain("Login credentials"), "Alias not created."); + Assert.That(pageContent, Does.Contain("Login credentials"), "Credential not created."); } }