mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-02 05:46:39 -05:00
Refactored change password to change pass and upload new vault in one atomic webapi operation (#200)
This commit is contained in:
@@ -12,6 +12,7 @@ using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using AliasServerDb;
|
||||
using AliasVault.Api.Helpers;
|
||||
using AliasVault.AuthLogging;
|
||||
using AliasVault.Shared.Models.Enums;
|
||||
using AliasVault.Shared.Models.WebApi;
|
||||
@@ -48,11 +49,6 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
/// </summary>
|
||||
private static readonly string[] InvalidUsernameOrPasswordError = ["Invalid username or password. Please try again."];
|
||||
|
||||
/// <summary>
|
||||
/// Error message for providing an invalid current password (during password change).
|
||||
/// </summary>
|
||||
private static readonly string[] InvalidCurrentPassword = ["The current password provided is invalid. Please try again."];
|
||||
|
||||
/// <summary>
|
||||
/// Error message for invalid 2-factor authentication code.
|
||||
/// </summary>
|
||||
@@ -68,11 +64,6 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
/// </summary>
|
||||
private static readonly string[] AccountLocked = ["You have entered an incorrect password too many times and your account has now been locked out. You can try again in 30 minutes.."];
|
||||
|
||||
/// <summary>
|
||||
/// Cache prefix for storing generated login ephemeral.
|
||||
/// </summary>
|
||||
private static readonly string CachePrefixEphemeral = "LoginEphemeral_";
|
||||
|
||||
/// <summary>
|
||||
/// Login endpoint used to process login attempt using credentials.
|
||||
/// </summary>
|
||||
@@ -96,13 +87,13 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
}
|
||||
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVaultSaltAndVerifier = GetUserLatestVaultSaltAndVerifier(user);
|
||||
var latestVaultSaltAndVerifier = AuthHelper.GetUserLatestVaultSaltAndVerifier(user);
|
||||
|
||||
// Server creates ephemeral and sends to client
|
||||
var ephemeral = Srp.GenerateEphemeralServer(latestVaultSaltAndVerifier.Verifier);
|
||||
|
||||
// Store the server ephemeral in memory cache for Validate() endpoint to use.
|
||||
cache.Set(CachePrefixEphemeral + model.Username, ephemeral.Secret, TimeSpan.FromMinutes(5));
|
||||
cache.Set(AuthHelper.CachePrefixEphemeral + model.Username, ephemeral.Secret, TimeSpan.FromMinutes(5));
|
||||
|
||||
return Ok(new LoginInitiateResponse(latestVaultSaltAndVerifier.Salt, ephemeral.Public));
|
||||
}
|
||||
@@ -365,6 +356,9 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
/// <summary>
|
||||
/// Password change request is done by verifying the current password and then saving the new password via SRP.
|
||||
/// </summary>
|
||||
/// <remarks>The submit handler for the change password logic is in VaultController.UpdateChangePassword()
|
||||
/// because changing the password of the AliasVault user also requires a new vault encrypted with that same
|
||||
/// password in order for things to work properly.</remarks>
|
||||
/// <returns>Task.</returns>
|
||||
[HttpGet("change-password/initiate")]
|
||||
[Authorize]
|
||||
@@ -377,57 +371,17 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
}
|
||||
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVaultSaltAndVerifier = GetUserLatestVaultSaltAndVerifier(user);
|
||||
var latestVaultSaltAndVerifier = AuthHelper.GetUserLatestVaultSaltAndVerifier(user);
|
||||
|
||||
// Server creates ephemeral and sends to client
|
||||
var ephemeral = Srp.GenerateEphemeralServer(latestVaultSaltAndVerifier.Verifier);
|
||||
|
||||
// Store the server ephemeral in memory cache for Validate() endpoint to use.
|
||||
cache.Set(CachePrefixEphemeral + user.UserName!, ephemeral.Secret, TimeSpan.FromMinutes(5));
|
||||
// Store the server ephemeral in memory cache for the Vault update (and set new password) endpoint to use.
|
||||
cache.Set(AuthHelper.CachePrefixEphemeral + user.UserName!, ephemeral.Secret, TimeSpan.FromMinutes(5));
|
||||
|
||||
return Ok(new PasswordChangeInitiateResponse(latestVaultSaltAndVerifier.Salt, ephemeral.Public));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Password change request is done by verifying the current password and then saving the new password via SRP.
|
||||
/// </summary>
|
||||
/// <param name="model">The password change initiation request model.</param>
|
||||
/// <returns>Task.</returns>
|
||||
[HttpPost("change-password/process")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> ProcessPasswordChange([FromBody] PasswordChangeRequest model)
|
||||
{
|
||||
var user = await userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(ServerValidationErrorResponse.Create("User not found.", 404));
|
||||
}
|
||||
|
||||
// Verify current password using SRP
|
||||
var (_, _, error) = await ValidateUserAndPassword(new ValidateLoginRequest(user.UserName!, model.CurrentClientPublicEphemeral, model.CurrentClientSessionProof));
|
||||
|
||||
if (error != null)
|
||||
{
|
||||
await authLoggingService.LogAuthEventFailAsync(user.UserName!, AuthEventType.PasswordChange, AuthFailureReason.InvalidPassword);
|
||||
return BadRequest(ServerValidationErrorResponse.Create(InvalidCurrentPassword, 400));
|
||||
}
|
||||
|
||||
// Set new password using SRP.
|
||||
user.Salt = model.NewPasswordSalt;
|
||||
user.Verifier = model.NewPasswordVerifier;
|
||||
user.UpdatedAt = DateTime.UtcNow;
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await authLoggingService.LogAuthEventSuccessAsync(user.UserName!, AuthEventType.PasswordChange);
|
||||
return Ok(new { Message = "Password changed successfully." });
|
||||
}
|
||||
|
||||
var errors = result.Errors.Select(e => e.Description).ToArray();
|
||||
return BadRequest(ServerValidationErrorResponse.Create(errors, 400));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a device identifier based on request headers. This is used to associate refresh tokens
|
||||
/// with a specific device for a specific user.
|
||||
@@ -529,7 +483,7 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
}
|
||||
|
||||
// Validate the SRP session (actual password check).
|
||||
var serverSession = ValidateSrpSession(user, model.ClientPublicEphemeral, model.ClientSessionProof);
|
||||
var serverSession = AuthHelper.ValidateSrpSession(cache, user, model.ClientPublicEphemeral, model.ClientSessionProof);
|
||||
if (serverSession is null)
|
||||
{
|
||||
// Increment failed login attempts in order to lock out the account when the limit is reached.
|
||||
@@ -542,39 +496,6 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
return (user, serverSession, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that validates the SRP session based on provided username, ephemeral and proof.
|
||||
/// </summary>
|
||||
/// <param name="user">The user object.</param>
|
||||
/// <param name="clientEphemeral">The client ephemeral value.</param>
|
||||
/// <param name="clientSessionProof">The client session proof.</param>
|
||||
/// <returns>Tuple.</returns>
|
||||
private SrpSession? ValidateSrpSession(AliasVaultUser user, string clientEphemeral, string clientSessionProof)
|
||||
{
|
||||
if (!cache.TryGetValue(CachePrefixEphemeral + user.UserName, out var serverSecretEphemeral) || serverSecretEphemeral is not string)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVaultSaltAndVerifier = GetUserLatestVaultSaltAndVerifier(user);
|
||||
|
||||
var serverSession = Srp.DeriveSessionServer(
|
||||
serverSecretEphemeral.ToString() ?? string.Empty,
|
||||
clientEphemeral,
|
||||
latestVaultSaltAndVerifier.Salt,
|
||||
user.UserName ?? string.Empty,
|
||||
latestVaultSaltAndVerifier.Verifier,
|
||||
clientSessionProof);
|
||||
|
||||
if (serverSession is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return serverSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a Jwt access token for a user. This token is used to authenticate the user for a limited time
|
||||
/// and is short-lived by design. With the separate refresh token, the user can request a new access token
|
||||
@@ -638,16 +559,4 @@ public class AuthController(IDbContextFactory<AliasServerDbContext> dbContextFac
|
||||
|
||||
return new TokenModel { Token = token, RefreshToken = refreshToken };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user's latest vault which contains the current salt and verifier.
|
||||
/// </summary>
|
||||
/// <param name="user">User object.</param>
|
||||
/// <returns>Tuple with salt and verifier.</returns>
|
||||
private (string Salt, string Verifier) GetUserLatestVaultSaltAndVerifier(AliasVaultUser user)
|
||||
{
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVault = user.Vaults.OrderByDescending(x => x.UpdatedAt).Select(x => new { x.Salt, x.Verifier }).First();
|
||||
return (latestVault.Salt, latestVault.Verifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,16 @@ using AliasVault.Api.Controllers.Abstracts;
|
||||
using AliasVault.Api.Helpers;
|
||||
using AliasVault.Api.Vault;
|
||||
using AliasVault.Api.Vault.RetentionRules;
|
||||
using AliasVault.AuthLogging;
|
||||
using AliasVault.Shared.Models.Enums;
|
||||
using AliasVault.Shared.Models.WebApi;
|
||||
using AliasVault.Shared.Models.WebApi.PasswordChange;
|
||||
using AliasVault.Shared.Providers.Time;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Vault controller for handling CRUD operations on the database for encrypted vault entities.
|
||||
@@ -26,9 +31,16 @@ using Microsoft.EntityFrameworkCore;
|
||||
/// <param name="dbContextFactory">DbContext instance.</param>
|
||||
/// <param name="userManager">UserManager instance.</param>
|
||||
/// <param name="timeProvider">ITimeProvider instance.</param>
|
||||
/// <param name="authLoggingService">AuthLoggingService instance.</param>
|
||||
/// <param name="cache">IMemoryCache instance.</param>
|
||||
[ApiVersion("1")]
|
||||
public class VaultController(ILogger<VaultController> logger, IDbContextFactory<AliasServerDbContext> dbContextFactory, UserManager<AliasVaultUser> userManager, ITimeProvider timeProvider) : AuthenticatedRequestController(userManager)
|
||||
public class VaultController(ILogger<VaultController> logger, IDbContextFactory<AliasServerDbContext> dbContextFactory, UserManager<AliasVaultUser> userManager, ITimeProvider timeProvider, AuthLoggingService authLoggingService, IMemoryCache cache) : AuthenticatedRequestController(userManager)
|
||||
{
|
||||
/// <summary>
|
||||
/// Error message for providing an invalid current password (during password change).
|
||||
/// </summary>
|
||||
private static readonly string[] InvalidCurrentPassword = ["The current password provided is invalid. Please try again."];
|
||||
|
||||
/// <summary>
|
||||
/// Default retention policy for vaults.
|
||||
/// </summary>
|
||||
@@ -95,7 +107,7 @@ public class VaultController(ILogger<VaultController> logger, IDbContextFactory<
|
||||
var latestVault = user.Vaults.OrderByDescending(x => x.UpdatedAt).Select(x => new { x.Salt, x.Verifier }).First();
|
||||
|
||||
// Create new vault entry with salt and verifier of current vault.
|
||||
var newVault = new Vault
|
||||
var newVault = new AliasServerDb.Vault
|
||||
{
|
||||
UserId = user.Id,
|
||||
VaultBlob = model.Blob,
|
||||
@@ -140,6 +152,68 @@ public class VaultController(ILogger<VaultController> logger, IDbContextFactory<
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a new vault to the database based on a new encryption password for the current user.
|
||||
/// </summary>
|
||||
/// <param name="model">Vault model.</param>
|
||||
/// <returns>IActionResult.</returns>
|
||||
[HttpPost("change-password")]
|
||||
public async Task<IActionResult> UpdateChangePassword([FromBody] VaultPasswordChangeRequest model)
|
||||
{
|
||||
await using var context = await dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
// Validate the SRP session (actual password check). ,
|
||||
var serverSession = AuthHelper.ValidateSrpSession(cache, user, model.CurrentClientPublicEphemeral, model.CurrentClientSessionProof);
|
||||
if (serverSession is null)
|
||||
{
|
||||
// Increment failed login attempts in order to lock out the account when the limit is reached.
|
||||
await GetUserManager().AccessFailedAsync(user);
|
||||
|
||||
await authLoggingService.LogAuthEventFailAsync(user.UserName!, AuthEventType.PasswordChange, AuthFailureReason.InvalidPassword);
|
||||
return BadRequest(ServerValidationErrorResponse.Create(InvalidCurrentPassword, 400));
|
||||
}
|
||||
|
||||
// Create new vault entry with salt and verifier of current vault.
|
||||
var newVault = new AliasServerDb.Vault
|
||||
{
|
||||
UserId = user.Id,
|
||||
VaultBlob = model.Blob,
|
||||
Version = model.Version,
|
||||
FileSize = FileHelper.Base64StringToKilobytes(model.Blob),
|
||||
Salt = model.NewPasswordSalt,
|
||||
Verifier = model.NewPasswordVerifier,
|
||||
CreatedAt = timeProvider.UtcNow,
|
||||
UpdatedAt = timeProvider.UtcNow,
|
||||
};
|
||||
|
||||
// Run the vault retention manager to keep the required vaults according
|
||||
// to the applied retention policies and delete the rest.
|
||||
// We only select the Id and UpdatedAt fields to reduce the amount of data transferred from the database.
|
||||
var existingVaults = await context.Vaults
|
||||
.Where(x => x.UserId == user.Id)
|
||||
.OrderByDescending(v => v.UpdatedAt)
|
||||
.Select(x => new AliasServerDb.Vault { Id = x.Id, UpdatedAt = x.UpdatedAt })
|
||||
.ToListAsync();
|
||||
|
||||
var vaultsToDelete = VaultRetentionManager.ApplyRetention(_retentionPolicy, existingVaults, timeProvider.UtcNow, newVault);
|
||||
|
||||
// Delete vaults that are not needed anymore.
|
||||
context.Vaults.RemoveRange(vaultsToDelete);
|
||||
|
||||
// Add the new vault and commit to database.
|
||||
context.Vaults.Add(newVault);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
await authLoggingService.LogAuthEventSuccessAsync(user.UserName!, AuthEventType.PasswordChange);
|
||||
return Ok(new { Message = "Password changed successfully." });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the user's email claims based on the provided email address list.
|
||||
/// </summary>
|
||||
|
||||
70
src/AliasVault.Api/Helpers/AuthHelper.cs
Normal file
70
src/AliasVault.Api/Helpers/AuthHelper.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="AuthHelper.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.Api.Helpers;
|
||||
|
||||
using AliasServerDb;
|
||||
using Cryptography.Client;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using SecureRemotePassword;
|
||||
|
||||
/// <summary>
|
||||
/// AuthHelper class.
|
||||
/// </summary>
|
||||
public static class AuthHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache prefix for storing generated login ephemeral.
|
||||
/// </summary>
|
||||
public static readonly string CachePrefixEphemeral = "LoginEphemeral_";
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that validates the SRP session based on provided username, ephemeral and proof.
|
||||
/// </summary>
|
||||
/// <param name="cache">IMemoryCache instance.</param>
|
||||
/// <param name="user">The user object.</param>
|
||||
/// <param name="clientEphemeral">The client ephemeral value.</param>
|
||||
/// <param name="clientSessionProof">The client session proof.</param>
|
||||
/// <returns>Tuple.</returns>
|
||||
public static SrpSession? ValidateSrpSession(IMemoryCache cache, AliasVaultUser user, string clientEphemeral, string clientSessionProof)
|
||||
{
|
||||
if (!cache.TryGetValue(CachePrefixEphemeral + user.UserName, out var serverSecretEphemeral) || serverSecretEphemeral is not string)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVaultSaltAndVerifier = GetUserLatestVaultSaltAndVerifier(user);
|
||||
|
||||
var serverSession = Srp.DeriveSessionServer(
|
||||
serverSecretEphemeral.ToString() ?? string.Empty,
|
||||
clientEphemeral,
|
||||
latestVaultSaltAndVerifier.Salt,
|
||||
user.UserName ?? string.Empty,
|
||||
latestVaultSaltAndVerifier.Verifier,
|
||||
clientSessionProof);
|
||||
|
||||
if (serverSession is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return serverSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user's latest vault which contains the current salt and verifier.
|
||||
/// </summary>
|
||||
/// <param name="user">User object.</param>
|
||||
/// <returns>Tuple with salt and verifier.</returns>
|
||||
public static (string Salt, string Verifier) GetUserLatestVaultSaltAndVerifier(AliasVaultUser user)
|
||||
{
|
||||
// Retrieve latest vault of user which contains the current salt and verifier.
|
||||
var latestVault = user.Vaults.OrderByDescending(x => x.UpdatedAt).Select(x => new { x.Salt, x.Verifier }).First();
|
||||
return (latestVault.Salt, latestVault.Verifier);
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@ builder.Services.ConfigureLogging(builder.Configuration, Assembly.GetExecutingAs
|
||||
|
||||
builder.Services.AddSingleton<ITimeProvider, SystemTimeProvider>();
|
||||
builder.Services.AddScoped<TimeValidationJwtBearerEvents>();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddScoped<AuthLoggingService>();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
builder.Services.AddLogging(logging =>
|
||||
{
|
||||
|
||||
@@ -146,11 +146,31 @@ else
|
||||
byte[] newPasswordHash = await Encryption.DeriveKeyFromPasswordAsync(PasswordChangeModel.NewPassword, newSalt);
|
||||
var newPasswordHashString = BitConverter.ToString(newPasswordHash).Replace("-", string.Empty);
|
||||
|
||||
// Backup current password hash in case of failure.
|
||||
var backupPasswordHash = AuthService.GetEncryptionKey();
|
||||
|
||||
// Set new currentPasswordHash locally as it is required for the new database encryption call below so
|
||||
// it is encrypted with the new password hash.
|
||||
AuthService.StoreEncryptionKey(newPasswordHash);
|
||||
|
||||
// TODO: rename Srp.SignupPrepareAsync to something more generic as its used for both signup and password change now.
|
||||
var srpSignup = Srp.SignupPrepareAsync(client, newSalt, username, newPasswordHashString);
|
||||
|
||||
// Prepare new vault model to update to.
|
||||
var databaseVersion = await DbService.GetCurrentDatabaseVersionAsync();
|
||||
var encryptedBase64String = await DbService.GetEncryptedDatabaseBase64String();
|
||||
var vaultPasswordChangeObject = new VaultPasswordChangeRequest(
|
||||
encryptedBase64String,
|
||||
databaseVersion,
|
||||
DateTime.Now,
|
||||
DateTime.Now,
|
||||
ClientEphemeral.Public,
|
||||
ClientSession.Proof,
|
||||
srpSignup.Salt,
|
||||
srpSignup.Verifier);
|
||||
|
||||
// 4. Client sends proof of session key to server.
|
||||
var response = await Http.PostAsJsonAsync("api/v1/Auth/change-password/process", new PasswordChangeRequest(ClientEphemeral.Public, ClientSession.Proof, srpSignup.Salt, srpSignup.Verifier));
|
||||
var response = await Http.PostAsJsonAsync("api/v1/Vault/change-password", vaultPasswordChangeObject);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
@@ -163,17 +183,14 @@ else
|
||||
// Clear form.
|
||||
PasswordChangeModel = new PasswordChangeModel();
|
||||
|
||||
// Set currentPasswordHash back to original so we're back to the original state.
|
||||
AuthService.StoreEncryptionKey(backupPasswordHash);
|
||||
|
||||
GlobalLoadingSpinner.Hide();
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set new currentPasswordHash locally.
|
||||
AuthService.StoreEncryptionKey(newPasswordHash);
|
||||
|
||||
// Upload new database encrypted with new password.
|
||||
await DbService.SaveDatabaseAsync();
|
||||
|
||||
// Set success message.
|
||||
GlobalNotificationService.AddSuccessMessage("Password changed successfully.", true);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed class AuthService(HttpClient httpClient, ILocalStorageService loca
|
||||
/// Get encryption key.
|
||||
/// </summary>
|
||||
/// <returns>SrpArgonEncryption key as byte[].</returns>
|
||||
public byte[] GetEncryptionKeyAsync()
|
||||
public byte[] GetEncryptionKey()
|
||||
{
|
||||
return _encryptionKey;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public sealed class AuthService(HttpClient httpClient, ILocalStorageService loca
|
||||
return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB=";
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(GetEncryptionKeyAsync());
|
||||
return Convert.ToBase64String(GetEncryptionKey());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="PasswordChangeResponse.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.Shared.Models.WebApi.PasswordChange
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a response to initiate a password change.
|
||||
/// </summary>
|
||||
public class PasswordChangeResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PasswordChangeResponse"/> class.
|
||||
/// </summary>
|
||||
/// <param name="newSalt">New salt.</param>
|
||||
/// <param name="currentPasswordServerProof">Current password server proof.</param>
|
||||
public PasswordChangeResponse(string newSalt, string currentPasswordServerProof)
|
||||
{
|
||||
NewSalt = newSalt;
|
||||
CurrentPasswordServerProof = currentPasswordServerProof;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the new salt for the new password.
|
||||
/// </summary>
|
||||
public string NewSalt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server's proof for the current password verification.
|
||||
/// </summary>
|
||||
public string CurrentPasswordServerProof { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="PasswordChangeRequest.cs" company="lanedirt">
|
||||
// <copyright file="VaultPasswordChangeRequest.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
@@ -8,18 +8,31 @@
|
||||
namespace AliasVault.Shared.Models.WebApi.PasswordChange;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to initiate a password change.
|
||||
/// Represents a request to change the users password including a new vault that is encrypted with the new password.
|
||||
/// </summary>
|
||||
public class PasswordChangeRequest
|
||||
public class VaultPasswordChangeRequest : Vault
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PasswordChangeRequest"/> class.
|
||||
/// Initializes a new instance of the <see cref="VaultPasswordChangeRequest"/> class.
|
||||
/// </summary>
|
||||
/// <param name="blob">Blob.</param>
|
||||
/// <param name="version">Version of the vault data model (migration).</param>
|
||||
/// <param name="createdAt">CreatedAt.</param>
|
||||
/// <param name="updatedAt">UpdatedAt.</param>
|
||||
/// <param name="currentClientPublicEphemeral">Client public ephemeral.</param>
|
||||
/// <param name="currentClientSessionProof">Client session proof.</param>
|
||||
/// <param name="newPasswordSalt">New password salt.</param>
|
||||
/// <param name="newPasswordVerifier">New password verifier.</param>
|
||||
public PasswordChangeRequest(string currentClientPublicEphemeral, string currentClientSessionProof, string newPasswordSalt, string newPasswordVerifier)
|
||||
public VaultPasswordChangeRequest(
|
||||
string blob,
|
||||
string version,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
string currentClientPublicEphemeral,
|
||||
string currentClientSessionProof,
|
||||
string newPasswordSalt,
|
||||
string newPasswordVerifier)
|
||||
: base(blob, version, string.Empty, new List<string>(), createdAt, updatedAt)
|
||||
{
|
||||
CurrentClientPublicEphemeral = currentClientPublicEphemeral;
|
||||
CurrentClientSessionProof = currentClientSessionProof;
|
||||
Reference in New Issue
Block a user