Add vault outdated status flag (#957)

This commit is contained in:
Leendert de Borst
2025-06-25 11:41:21 +02:00
committed by Leendert de Borst
parent 00fb290598
commit 70bb8ef3e4
10 changed files with 49 additions and 14 deletions

View File

@@ -70,9 +70,12 @@ export function useVaultMutate() : {
await dbContext.setCurrentVaultRevisionNumber(response.newRevisionNumber);
options.onSuccess?.();
} else if (response.status === 1) {
// Note: vault merge is no longer allowed by the API as of 0.20.0, updates with the same revision number are rejected. So this check can be removed later.
throw new Error('Vault merge required. Please login via the web app to merge the multiple pending updates to your vault.');
} else if (response.status === 2) {
throw new Error('Your vault is outdated. Please login on the AliasVault website and follow the steps.');
} else {
throw new Error('Failed to upload vault to server');
throw new Error('Failed to upload vault to server. Please try again by re-opening the app.');
}
} catch (error) {
// Check if it's a network error

View File

@@ -132,7 +132,7 @@ export const useVaultSync = () : {
return false;
}
// Vault could not be decrypted, throw an error
throw new Error('Vault could not be decrypted, if problem persists please logout and login again.');
throw new Error('Vault could not be decrypted, if the problem persists please logout and login again.');
}
}

View File

@@ -292,10 +292,15 @@ export class WebApiService {
* Status 0 = OK, vault is ready.
* Status 1 = Merge required, which only the web client supports.
*/
if (vaultResponseJson.status !== 0) {
if (vaultResponseJson.status === 1) {
// Note: vault merge is no longer allowed by the API as of 0.20.0, updates with the same revision number are rejected. So this check can be removed later.
return 'Your vault needs to be updated. Please login on the AliasVault website and follow the steps.';
}
if (vaultResponseJson.status === 2) {
return 'Your vault is outdated. Please login on the AliasVault website and follow the steps.';
}
if (!vaultResponseJson.vault?.blob) {
return 'Your account does not have a vault yet. Please complete the tutorial in the AliasVault web client before using the browser extension.';
}

View File

@@ -135,7 +135,7 @@ export default function UpgradeScreen() : React.ReactNode {
} catch (error) {
console.error(`Error executing SQL command ${i + 1}:`, sqlCommand, error);
await NativeVaultManager.rollbackTransaction();
throw new Error(`Failed to apply migration ${i + 1}: ${error instanceof Error ? error.message : 'Unknown error'}`);
throw new Error(`Failed to apply migration (${i + 1} of ${upgradeResult.sqlCommands.length})`);
}
}

View File

@@ -116,9 +116,12 @@ export function useVaultMutate() : {
await NativeVaultManager.setCurrentVaultRevisionNumber(response.newRevisionNumber);
options.onSuccess?.();
} else if (response.status === 1) {
// Note: vault merge is no longer allowed by the API as of 0.20.0, updates with the same revision number are rejected. So this check can be removed later.
throw new Error('Vault merge required. Please login via the web app to merge the multiple pending updates to your vault.');
} else if (response.status === 2) {
throw new Error('Your vault is outdated. Please login on the AliasVault website and follow the steps.');
} else {
throw new Error('Failed to upload vault to server');
throw new Error('Failed to upload vault to server. Please try again by re-opening the app.');
}
} catch (error) {
// Check if it's a network error

View File

@@ -125,7 +125,7 @@ export const useVaultSync = () : {
return true;
} catch {
// Vault could not be decrypted, throw an error
throw new Error('Vault could not be decrypted, if problem persists please logout and login again.');
throw new Error('Vault could not be decrypted, if the problem persists please logout and login again.');
}
}

View File

@@ -306,11 +306,17 @@ export class WebApiService {
/**
* Status 0 = OK, vault is ready.
* Status 1 = Merge required, which only the web client supports.
* Status 2 = Outdated, which means the local vault is outdated and the client should fetch the latest vault from the server before saving can continue.
*/
if (vaultResponseJson.status !== 0) {
if (vaultResponseJson.status === 1) {
// Note: vault merge is no longer allowed by the API as of 0.20.0, updates with the same revision number are rejected. So this check can be removed later.
return 'Your vault needs to be updated. Please login on the AliasVault website and follow the steps.';
}
if (vaultResponseJson.status === 2) {
return 'Your vault is outdated. Please login on the AliasVault website and follow the steps.';
}
if (!vaultResponseJson.vault?.blob) {
return 'Your account does not have a vault yet. Please complete the tutorial in the AliasVault web client before using the browser extension.';
}

View File

@@ -117,6 +117,10 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
// Check if there are no other vaults with the same revision number.
// If there are, return a merge required status.
// NOTE: a vault merge is no longer allowed by the API as of 0.20.0, updates with the same revision number are now rejected.
// So the logic below can be removed later, together with the local merge logic in the WASM client.
// We do probably want to still keep this until the datamodel has been updated to accomodate improved offline mode which might warrant
// a new and improved merge logic. So we keep this here for reference purposes for now.
var duplicateRevisionCount = await context.Vaults
.Where(x => x.UserId == user.Id && x.RevisionNumber == vault.RevisionNumber)
.CountAsync();
@@ -237,10 +241,10 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
var newRevisionNumber = model.CurrentRevisionNumber + 1;
// Check if the latest vault revision number is equal to or higher than the new revision number.
// If so, reject update and return a merge required status.
// If so it means the client's vault is outdated and the client should fetch the latest vault from the server before saving can continue.
if (latestVault.RevisionNumber >= newRevisionNumber)
{
return Ok(new VaultUpdateResponse { Status = VaultStatus.MergeRequired, NewRevisionNumber = latestVault.RevisionNumber });
return Ok(new VaultUpdateResponse { Status = VaultStatus.Outdated, NewRevisionNumber = latestVault.RevisionNumber });
}
// Create new vault entry with salt and verifier of current vault.
@@ -332,11 +336,15 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
}
// Calculate the new revision number for the vault.
// Note: it is possible multiple clients are updating the vault at the same time which would cause
// multiple vaults with the same revision number. This is expected and will trigger a vault
// synchronize/merge process on the client side.
var newRevisionNumber = model.CurrentRevisionNumber + 1;
// Check if the latest vault revision number is equal to or higher than the new revision number.
// If so it means the client's vault is outdated and the client should fetch the latest vault from the server before saving can continue.
if (latestVault.RevisionNumber >= newRevisionNumber)
{
return Ok(new VaultUpdateResponse { Status = VaultStatus.Outdated, NewRevisionNumber = latestVault.RevisionNumber });
}
// Create new vault entry with salt and verifier of current vault.
var newVault = new AliasServerDb.Vault
{

View File

@@ -724,6 +724,11 @@ public sealed class DbService : IDisposable
_state.UpdateState(DbServiceState.DatabaseStatus.MergeRequired);
return await MergeDatabasesAsync();
}
else if (vaultUpdateResponse.Status == VaultStatus.Outdated)
{
// If the server responds with an outdated status, we need to fetch the latest vault from the server before we can continue.
return false;
}
_vaultRevisionNumber = vaultUpdateResponse.NewRevisionNumber;
return true;

View File

@@ -15,10 +15,15 @@ public enum VaultStatus
/// <summary>
/// The vault was retrieved or updated successfully.
/// </summary>
Ok,
Ok = 0,
/// <summary>
/// A client-side merge is required before the vault can be retrieved or updated.
/// </summary>
MergeRequired,
MergeRequired = 1,
/// <summary>
/// The local vault is outdated and the client should fetch the latest vault from the server before saving can continue.
/// </summary>
Outdated = 2,
}