Browse Source

refactor: consolidate duplicate account checking logic into unified utility

- Extract checkForDuplicateAccount methods from ImportAccountView and ImportDerivedAccountView
- Create unified utility function in src/libs/util.ts with TypeScript overloads
- Support both direct DID checking and mnemonic+derivation path checking
- Improve error handling with centralized logging via PlatformServiceFactory
- Add comprehensive JSDoc documentation for both function overloads
- Remove unused imports (deriveAddress, newIdentifier) from ImportAccountView

The utility function now provides a clean API:
- checkForDuplicateAccount(did) - for direct DID checking
- checkForDuplicateAccount(mnemonic, derivationPath) - for derivation + checking

Both components maintain identical functionality while using centralized logic.
pull/189/head
Jose Olarte III 3 days ago
parent
commit
25e37cc415
  1. 66
      src/libs/util.ts
  2. 53
      src/views/ImportAccountView.vue
  3. 25
      src/views/ImportDerivedAccountView.vue

66
src/libs/util.ts

@ -1042,3 +1042,69 @@ export async function importFromMnemonic(
}
}
}
/**
* Checks if an account with the given DID already exists in the database
*
* @param did - The DID to check for duplicates
* @returns Promise<boolean> - True if account already exists, false otherwise
* @throws Error if database query fails
*/
export async function checkForDuplicateAccount(did: string): Promise<boolean>;
/**
* Checks if an account with the given DID already exists in the database
*
* @param mnemonic - The mnemonic phrase to derive DID from
* @param derivationPath - The derivation path to use
* @returns Promise<boolean> - True if account already exists, false otherwise
* @throws Error if database query fails
*/
export async function checkForDuplicateAccount(
mnemonic: string,
derivationPath: string,
): Promise<boolean>;
/**
* Implementation of checkForDuplicateAccount with overloaded signatures
*/
export async function checkForDuplicateAccount(
didOrMnemonic: string,
derivationPath?: string,
): Promise<boolean> {
try {
let didToCheck: string;
if (derivationPath) {
// Derive the DID from mnemonic and derivation path
const [address, privateHex, publicHex] = deriveAddress(
didOrMnemonic.trim().toLowerCase(),
derivationPath,
);
const newId = newIdentifier(
address,
privateHex,
publicHex,
derivationPath,
);
didToCheck = newId.did;
} else {
// Use the provided DID directly
didToCheck = didOrMnemonic;
}
// Check if an account with this DID already exists
const platformService = await getPlatformService();
const existingAccount = await platformService.dbQuery(
"SELECT did FROM accounts WHERE did = ?",
[didToCheck],
);
return (existingAccount?.values?.length ?? 0) > 0;
} catch (error) {
// If we can't check for duplicates, let the calling process handle the error
logger.error("Error checking for duplicate account:", error);
throw error;
}
}

53
src/views/ImportAccountView.vue

@ -87,12 +87,12 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "../constants/app";
import { DEFAULT_ROOT_DERIVATION_PATH } from "../libs/crypto";
import {
DEFAULT_ROOT_DERIVATION_PATH,
deriveAddress,
newIdentifier,
} from "../libs/crypto";
import { retrieveAccountCount, importFromMnemonic } from "../libs/util";
retrieveAccountCount,
importFromMnemonic,
checkForDuplicateAccount,
} from "../libs/util";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { NOTIFY_DUPLICATE_ACCOUNT_IMPORT } from "@/constants/notifications";
@ -204,7 +204,10 @@ export default class ImportAccountView extends Vue {
try {
// Check for duplicate account before importing
const isDuplicate = await this.checkForDuplicateAccount();
const isDuplicate = await checkForDuplicateAccount(
this.mnemonic,
this.derivationPath,
);
if (isDuplicate) {
this.notify.warning(
NOTIFY_DUPLICATE_ACCOUNT_IMPORT.message,
@ -259,43 +262,5 @@ export default class ImportAccountView extends Vue {
);
}
}
/**
* Checks if the account to be imported already exists
*
* Derives the DID from the mnemonic and checks if it exists in the database
* @returns Promise<boolean> - True if account already exists, false otherwise
*/
private async checkForDuplicateAccount(): Promise<boolean> {
try {
// Derive the address and create the identifier to get the DID
const [address, privateHex, publicHex] = deriveAddress(
this.mnemonic.trim().toLowerCase(),
this.derivationPath,
);
const newId = newIdentifier(
address,
publicHex,
privateHex,
this.derivationPath,
);
const didToCheck = newId.did;
// Check if an account with this DID already exists
const existingAccount = await this.$query(
"SELECT did FROM accounts WHERE did = ?",
[didToCheck],
);
return existingAccount?.values?.length > 0;
} catch (error) {
// If we can't check for duplicates (e.g., invalid mnemonic),
// let the import process handle the error
this.$logError("Error checking for duplicate account: " + error);
// Return false to let the import process continue and handle the error
return false;
}
}
}
</script>

25
src/views/ImportDerivedAccountView.vue

@ -83,6 +83,7 @@ import {
retrieveAllAccountsMetadata,
retrieveFullyDecryptedAccount,
saveNewIdentity,
checkForDuplicateAccount,
} from "../libs/util";
import { logger } from "../utils/logger";
import { Account, AccountEncrypted } from "../db/tables/accounts";
@ -172,7 +173,7 @@ export default class ImportAccountView extends Vue {
try {
// Check for duplicate account before creating
const isDuplicate = await this.checkForDuplicateAccount(newId.did);
const isDuplicate = await checkForDuplicateAccount(newId.did);
if (isDuplicate) {
this.notify.warning(
"This derived account already exists. Please try a different derivation path.",
@ -202,27 +203,5 @@ export default class ImportAccountView extends Vue {
this.notify.error(NOTIFY_ACCOUNT_DERIVATION_ERROR.message, TIMEOUTS.LONG);
}
}
/**
* Checks if the account to be created already exists
*
* @param did - The DID to check for duplicates
* @returns Promise<boolean> - True if account already exists, false otherwise
*/
private async checkForDuplicateAccount(did: string): Promise<boolean> {
try {
// Check if an account with this DID already exists
const existingAccount = await this.$query(
"SELECT did FROM accounts WHERE did = ?",
[did],
);
return existingAccount?.values?.length > 0;
} catch (error) {
// If we can't check for duplicates, let the save process handle the error
this.$logError("Error checking for duplicate account: " + error);
return false;
}
}
}
</script>

Loading…
Cancel
Save