add encryption & decryption for the sensitive identity & mnemonic in SQL DB

This commit is contained in:
2025-05-26 22:42:20 -06:00
parent 4d35760a65
commit fe77dbdcdd
8 changed files with 105 additions and 48 deletions

View File

@@ -16,11 +16,11 @@ import {
updateAccountSettings,
updateDefaultSettings,
} from "../db/index";
import { Account } from "../db/tables/accounts";
import { Account, AccountEncrypted } from "../db/tables/accounts";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { DEFAULT_PASSKEY_EXPIRATION_MINUTES } from "../db/tables/settings";
import { deriveAddress, generateSeed, newIdentifier } from "../libs/crypto";
import { arrayBufferToBase64, base64ToArrayBuffer, deriveAddress, generateSeed, newIdentifier, simpleDecrypt, simpleEncrypt } from "../libs/crypto";
import * as serverUtil from "../libs/endorserServer";
import {
containsHiddenDid,
@@ -466,9 +466,17 @@ export function findAllVisibleToDids(
export interface AccountKeyInfo extends Account, KeyMeta {}
export const retrieveAccountCount = async (): Promise<number> => {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
return await accountsDB.accounts.count();
let result;
const platformService = PlatformServiceFactory.getInstance();
const dbResult = await platformService.dbQuery(`SELECT COUNT(*) FROM accounts`);
result = dbResult.values[0][0] as number;
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
result = await accountsDB.accounts.count();
}
return result;
};
export const retrieveAccountDids = async (): Promise<string[]> => {
@@ -513,13 +521,35 @@ export const retrieveAllAccountsMetadata = async (): Promise<Account[]> => {
export const retrieveFullyDecryptedAccount = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
return account;
let result: AccountKeyInfo | undefined = undefined;
const platformService = PlatformServiceFactory.getInstance();
const dbSecrets = await platformService.dbQuery(`SELECT secretBase64 from secret`);
if (!dbSecrets || dbSecrets.values.length === 0 || dbSecrets.values[0].length === 0) {
throw new Error("No secret found. We recommend you clear your data and start over.");
}
const secretBase64 = dbSecrets.values[0][0] as string;
const secret = base64ToArrayBuffer(secretBase64);
const dbAccount = await platformService.dbQuery(`SELECT * FROM accounts WHERE did = ?`, [activeDid]);
if (!dbAccount || dbAccount.values.length === 0 || dbAccount.values[0].length === 0) {
throw new Error("Account not found.");
}
const fullAccountData = databaseUtil.mapColumnsToValues(dbAccount.columns, dbAccount.values)[0] as AccountEncrypted;
const identityEncr = base64ToArrayBuffer(fullAccountData.identityEncrBase64);
const mnemonicEncr = base64ToArrayBuffer(fullAccountData.mnemonicEncrBase64);
fullAccountData.identity = await simpleDecrypt(identityEncr, secret);
fullAccountData.mnemonic = await simpleDecrypt(mnemonicEncr, secret);
result = fullAccountData;
if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
result = account;
}
return result;
};
// let's try and eliminate this
@@ -548,15 +578,25 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
try {
// add to the new sql db
const platformService = PlatformServiceFactory.getInstance();
const secrets = await platformService.dbQuery(`SELECT secretBase64 FROM secret`);
if (secrets.values.length === 0 || secrets.values[0].length === 0) {
throw new Error("No initial encryption supported. We recommend you clear your data and start over.");
}
const secretBase64 = secrets.values[0][0] as string;
const secret = base64ToArrayBuffer(secretBase64);
const encryptedIdentity = await simpleEncrypt(identity, secret);
const encryptedMnemonic = await simpleEncrypt(mnemonic, secret);
const encryptedIdentityBase64 = arrayBufferToBase64(encryptedIdentity);
const encryptedMnemonicBase64 = arrayBufferToBase64(encryptedMnemonic);
await platformService.dbExec(
`INSERT INTO accounts (dateCreated, derivationPath, did, identity, mnemonic, publicKeyHex)
`INSERT INTO accounts (dateCreated, derivationPath, did, identityEncrBase64, mnemonicEncrBase64, publicKeyHex)
VALUES (?, ?, ?, ?, ?, ?)`,
[
new Date().toISOString(),
derivationPath,
newId.did,
identity,
mnemonic,
encryptedIdentityBase64,
encryptedMnemonicBase64,
newId.keys[0].publicKeyHex,
],
);