Browse Source

switch the encryption secret from localStorage to IndexedDB (because localStorage gets lost so often)

split_build_process
Trent Larson 1 month ago
parent
commit
bb3807a805
  1. 2
      playwright.config-local.ts
  2. 7
      src/components/GiftedDialog.vue
  3. 12
      src/components/PushNotificationPermission.vue
  4. 111
      src/db/index.ts
  5. 4
      src/db/tables/accounts.ts
  6. 4
      src/db/tables/temp.ts
  7. 7
      src/libs/endorserServer.ts
  8. 60
      src/libs/util.ts
  9. 4
      src/router/index.ts
  10. 81
      src/views/AccountViewView.vue
  11. 12
      src/views/ClaimView.vue
  12. 10
      src/views/ConfirmGiftView.vue
  13. 6
      src/views/ContactAmountsView.vue
  14. 8
      src/views/ContactQRScanShowView.vue
  15. 12
      src/views/DIDView.vue
  16. 8
      src/views/DiscoverView.vue
  17. 13
      src/views/GiftedDetailsView.vue
  18. 9
      src/views/HomeView.vue
  19. 14
      src/views/IdentitySwitcherView.vue
  20. 12
      src/views/ImportAccountView.vue
  21. 8
      src/views/ImportDerivedAccountView.vue
  22. 9
      src/views/NewActivityView.vue
  23. 15
      src/views/NewEditProjectView.vue
  24. 13
      src/views/OfferDetailsView.vue
  25. 27
      src/views/ProjectViewView.vue
  26. 10
      src/views/ProjectsView.vue
  27. 2
      src/views/QuickActionBvcEndView.vue
  28. 9
      src/views/RecentOffersToUserProjectsView.vue
  29. 9
      src/views/RecentOffersToUserView.vue
  30. 13
      src/views/SeedBackupView.vue
  31. 8
      src/views/ShareMyContactInfoView.vue
  32. 10
      src/views/StartView.vue
  33. 14
      src/views/TestView.vue
  34. 2
      sw_scripts/additional-scripts.js
  35. 1
      sw_scripts/safari-notifications.js

2
playwright.config-local.ts

@ -74,7 +74,7 @@ export default defineConfig({
/* Configure global timeout; default is 30000 milliseconds */
// the image upload will often not succeed at 5 seconds
timeout: 25000, // various tests fail at various times with 20000
timeout: 30000, // various tests fail at various times with 25000
/* Run your local dev server before starting the tests */
/**

7
src/components/GiftedDialog.vue

@ -92,8 +92,9 @@ import { Vue, Component, Prop } from "vue-facing-decorator";
import { NotificationIface } from "@/constants/app";
import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { retrieveAccountDids } from "@/libs/util";
@Component
export default class GiftedDialog extends Vue {
@ -145,9 +146,7 @@ export default class GiftedDialog extends Vue {
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
this.allMyDids = await retrieveAccountDids();
if (this.giver && !this.giver.name) {
this.giver.name = didInfo(

12
src/components/PushNotificationPermission.vue

@ -101,7 +101,12 @@
import { Component, Vue } from "vue-facing-decorator";
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "@/db/index";
import {
logConsoleAndDb,
retrieveSettingsForActiveAccount,
secretDB,
} from "@/db/index";
import { MASTER_SECRET_KEY } from "@/db/tables/secret";
import { urlBase64ToUint8Array } from "@/libs/crypto/vc/util";
import * as libsUtil from "@/libs/util";
@ -270,7 +275,7 @@ export default class PushNotificationPermission extends Vue {
});
}
private askPermission(): Promise<NotificationPermission> {
private async askPermission(): Promise<NotificationPermission> {
logConsoleAndDb(
"Requesting permission for notifications: " + JSON.stringify(navigator),
);
@ -280,7 +285,8 @@ export default class PushNotificationPermission extends Vue {
return Promise.reject("Service worker not available.");
}
const secret = localStorage.getItem("secret");
await secretDB.open();
const secret = (await secretDB.secret.get(MASTER_SECRET_KEY))?.secret;
if (!secret) {
return Promise.reject("No secret found.");
}

111
src/db/index.ts

@ -5,6 +5,7 @@ import * as R from "ramda";
import { Account, AccountsSchema } from "./tables/accounts";
import { Contact, ContactSchema } from "./tables/contacts";
import { Log, LogSchema } from "./tables/logs";
import { MASTER_SECRET_KEY, Secret, SecretSchema } from "./tables/secret";
import {
MASTER_SETTINGS_KEY,
Settings,
@ -14,6 +15,7 @@ import { Temp, TempSchema } from "./tables/temp";
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
// Define types for tables that hold sensitive and non-sensitive data
type SecretTable = { secret: Table<Secret> };
type SensitiveTables = { accounts: Table<Account> };
type NonsensitiveTables = {
contacts: Table<Contact>;
@ -23,25 +25,39 @@ type NonsensitiveTables = {
};
// Using 'unknown' instead of 'any' for stricter typing and to avoid TypeScript warnings
export type SecretDexie<T extends unknown = SecretTable> = BaseDexie & T;
export type SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
BaseDexie & T;
// Initialize Dexie databases for sensitive and non-sensitive data
export const accountsDB = new BaseDexie("TimeSafariAccounts") as SensitiveDexie;
export const db = new BaseDexie("TimeSafari") as NonsensitiveDexie;
//// Initialize the DBs, starting with the sensitive ones.
// Manage the encryption key. If not present in localStorage, create and store it.
const secret =
localStorage.getItem("secret") || Encryption.createRandomEncryptionKey();
if (!localStorage.getItem("secret")) localStorage.setItem("secret", secret);
// Initialize Dexie database for secret, which is then used to encrypt accountsDB
export const secretDB = new BaseDexie("TimeSafariSecret") as SecretDexie;
secretDB.version(1).stores(SecretSchema);
// Apply encryption to the sensitive database using the secret key
encrypted(accountsDB, { secretKey: secret });
// Initialize Dexie database for accounts
const accountsDexie = new BaseDexie("TimeSafariAccounts") as SensitiveDexie;
// Instead of accountsDBPromise, use libs/util retrieveAccountMetadata or retrieveFullyDecryptedAccount
// so that it's clear whether the usage needs the private key inside.
//
// This is a promise because the decryption key comes from IndexedDB
// and someday it may come from a password or keystore or external wallet.
// It's important that usages take into account that there may be a delay due
// to a user action required to unlock the data.
export const accountsDBPromise = useSecretAndInitializeAccountsDB(
secretDB,
accountsDexie,
);
//// Now initialize the other DB.
// Initialize Dexie databases for non-sensitive data
export const db = new BaseDexie("TimeSafari") as NonsensitiveDexie;
// Define the schemas for our databases
// Only the tables with index modifications need listing. https://dexie.org/docs/Tutorial/Design#database-versioning
accountsDB.version(1).stores(AccountsSchema);
// v1 also had contacts & settings
// v2 added Log
db.version(2).stores({
@ -73,6 +89,79 @@ db.on("populate", async () => {
await db.settings.add(DEFAULT_SETTINGS);
});
// Manage the encryption key.
// It's not really secure to maintain the secret next to the user's data.
// However, until we have better hooks into a real wallet or reliable secure
// storage, we'll do this for user convenience. As they sign more records
// and integrate with more people, they'll value it more and want to be more
// secure, so we'll prompt them to take steps to back it up, properly encrypt,
// etc. At the beginning, we'll prompt for a password, then we'll prompt for a
// PWA so it's not in a browser... and then we hope to be integrated with a
// real wallet or something else more secure.
// One might ask: why encrypt at all? We figure a basic encryption is better
// than none. Plus, we expect to support their own password or keystore or
// external wallet as better signing options in the future, so it's gonna be
// important to have the structure where each account access might require
// user action.
// (Once upon a time we stored the secret in localStorage, but it frequently
// got erased, even though the IndexedDB still had the identity data. This
// ended up throwing lots of errors to the user... and they'd end up in a state
// where they couldn't take action because they couldn't unlock that identity.)
// check for the secret in storage
async function useSecretAndInitializeAccountsDB(
secretDB: SecretDexie,
accountsDB: SensitiveDexie,
): Promise<SensitiveDexie> {
return secretDB
.open()
.then(() => {
return secretDB.secret.get(MASTER_SECRET_KEY);
})
.then((secretRow?: Secret) => {
let secret = secretRow?.secret;
if (secret != null) {
// they already have it in IndexedDB, so just pass it along
return secret;
} else {
// check localStorage (for users before v 0.3.37)
const localSecret = localStorage.getItem("secret");
if (localSecret != null) {
// they had one, so we want to move it to IndexedDB
secret = localSecret;
} else {
// they didn't have one, so let's generate one
secret = Encryption.createRandomEncryptionKey();
}
// it is not in IndexedDB, so add it now
return secretDB.secret
.add({ id: MASTER_SECRET_KEY, secret })
.then(() => {
return secret;
});
}
})
.then((secret?: string) => {
if (secret == null) {
throw new Error("No secret found or created.");
} else {
// apply encryption to the sensitive database using the secret key
encrypted(accountsDB, { secretKey: secret });
accountsDB.version(1).stores(AccountsSchema);
accountsDB.open();
return accountsDB;
}
})
.catch((error) => {
logConsoleAndDb("Error processing secret & encrypted accountsDB.", error);
// alert("There was an error processing encrypted data. See the Help page.");
throw error;
});
}
// retrieves default settings
// calls db.open()
export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {

4
src/db/tables/accounts.ts

@ -5,7 +5,7 @@ export type Account = {
/**
* Auto-generated ID by Dexie
*/
id?: number;
id?: number; // this is only blank on input, when the database assigns it
/**
* The date the account was created
@ -48,7 +48,7 @@ export type Account = {
/**
* Schema for the accounts table in the database.
* Fields starting with a $ character are encrypted.
* @see {@link https://github.com/PVermeer/dexie-addon-suite-monorepo/tree/master/packages/dexie-encrypted-addon}
* @see {@link https://github.com/PVermeer/dexie-addon-suite-monorepo/tree/master/packages/dexie-encrypted-addon#added-schema-syntax}
*/
export const AccountsSchema = {
accounts:

4
src/db/tables/temp.ts

@ -9,6 +9,4 @@ export type Temp = {
/**
* Schema for the Temp table in the database.
*/
export const TempSchema = {
temp: "id",
};
export const TempSchema = { temp: "id" };

7
src/libs/endorserServer.ts

@ -9,7 +9,8 @@ import { Contact } from "@/db/tables/contacts";
import { accessToken, deriveAddress, nextDerivationPath } from "@/libs/crypto";
import { NonsensitiveDexie } from "@/db/index";
import {
getAccount,
retrieveAccountMetadata,
retrieveFullyDecryptedAccount,
getPasskeyExpirationSeconds,
GiverReceiverInputInfo,
} from "@/libs/util";
@ -506,7 +507,7 @@ export async function getHeaders(did?: string) {
};
if (did) {
let token;
const account = await getAccount(did);
const account = await retrieveAccountMetadata(did);
if (account?.passkeyCredIdHex) {
if (
passkeyAccessToken &&
@ -1054,7 +1055,7 @@ export async function createEndorserJwtForDid(
payload: object,
expiresIn?: number,
) {
const account = await getAccount(issuerDid);
const account = await retrieveFullyDecryptedAccount(issuerDid);
return createEndorserJwtForKey(account as KeyMeta, payload, expiresIn);
}

60
src/libs/util.ts

@ -7,7 +7,7 @@ import { useClipboard } from "@vueuse/core";
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
import {
accountsDB,
accountsDBPromise,
retrieveSettingsForActiveAccount,
updateAccountSettings,
updateDefaultSettings,
@ -422,10 +422,51 @@ export function findAllVisibleToDids(
export interface AccountKeyInfo extends Account, KeyMeta {}
export const getAccount = async (
export const retrieveAccountCount = async (): Promise<number> => {
const accountsDB = await accountsDBPromise;
return await accountsDB.accounts.count();
};
export const retrieveAccountDids = async (): Promise<string[]> => {
const accountsDB = await accountsDBPromise;
const allAccounts = await accountsDB.accounts.toArray();
const allDids = allAccounts.map((acc) => acc.did);
return allDids;
};
// This is provided and recommended when the full key is not necessary so that
// future work could separate this info from the sensitive key material.
export const retrieveAccountMetadata = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
if (account) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata;
} else {
return undefined;
}
};
export const retrieveAllAccountsMetadata = async (): Promise<Account[]> => {
const accountsDB = await accountsDBPromise;
const array = await accountsDB.accounts.toArray();
return array.map((account) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { identity, mnemonic, ...metadata } = account;
return metadata;
});
};
export const retrieveFullyDecryptedAccount = async (
activeDid: string,
): Promise<AccountKeyInfo | undefined> => {
await accountsDB.open();
const accountsDB = await accountsDBPromise;
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
@ -433,6 +474,15 @@ export const getAccount = async (
return account;
};
// let's try and eliminate this
export const retrieveAllFullyDecryptedAccounts = async (): Promise<
Array<AccountKeyInfo>
> => {
const accountsDB = await accountsDBPromise;
const allAccounts = await accountsDB.accounts.toArray();
return allAccounts;
};
/**
* Generates a new identity, saves it to the database, and sets it as the active identity.
* @return {Promise<string>} with the DID of the new identity
@ -446,7 +496,7 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
const identity = JSON.stringify(newId);
await accountsDB.open();
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: derivationPath,
@ -477,7 +527,7 @@ export const registerAndSavePasskey = async (
passkeyCredIdHex,
publicKeyHex: Buffer.from(publicKeyBytes).toString("hex"),
};
await accountsDB.open();
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add(account);
return account;
};

4
src/router/index.ts

@ -5,7 +5,7 @@ import {
RouteLocationNormalized,
RouteRecordRaw,
} from "vue-router";
import { accountsDB } from "@/db/index";
import { accountsDBPromise } from "@/db/index";
/**
*
@ -18,7 +18,7 @@ const enterOrStart = async (
from: RouteLocationNormalized,
next: NavigationGuardNext,
) => {
await accountsDB.open();
const accountsDB = await accountsDBPromise;
const num_accounts = await accountsDB.accounts.count();
if (num_accounts > 0) {
next();

81
src/views/AccountViewView.vue

@ -819,7 +819,6 @@ import {
} from "@/constants/app";
import {
db,
accountsDB,
retrieveSettingsForActiveAccount,
updateAccountSettings,
} from "@/db/index";
@ -839,7 +838,11 @@ import {
ImageRateLimits,
tokenExpiryTimeDescription,
} from "@/libs/endorserServer";
import { DAILY_CHECK_TITLE, DIRECT_PUSH_TITLE, getAccount } from "@/libs/util";
import {
DAILY_CHECK_TITLE,
DIRECT_PUSH_TITLE,
retrieveAccountMetadata,
} from "@/libs/util";
const inputImportFileNameRef = ref<Blob>();
@ -941,7 +944,7 @@ export default class AccountViewView extends Vue {
);
// this sometimes gives different information on the error
console.error(
"Telling user to clear cache at page create because (error added): " +
"To repeat with concatenated error: telling user to clear cache at page create because: " +
error,
);
this.$notify(
@ -1055,7 +1058,9 @@ export default class AccountViewView extends Vue {
* Processes the identity and updates the component's state.
*/
async processIdentity() {
const account: Account | undefined = await getAccount(this.activeDid);
const account: Account | undefined = await retrieveAccountMetadata(
this.activeDid,
);
if (account?.identity) {
const identity = JSON.parse(account.identity as string) as IIdentifier;
this.publicHex = identity.keys[0].publicKeyHex;
@ -1495,74 +1500,6 @@ export default class AccountViewView extends Vue {
}
}
/**
* Asynchronously switches the active account based on the provided account number.
*
* @param {number} accountNum - The account number to switch to. 0 means none.
*/
public async switchAccount(accountNum: number) {
await db.open(); // Assumes db needs to be open for both cases
if (accountNum === 0) {
this.switchToNoAccount();
} else {
await this.switchToAccountNumber(accountNum);
}
}
/**
* Switches to no active account and clears relevant properties.
*/
private async switchToNoAccount() {
await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: undefined });
this.clearActiveAccountProperties();
}
/**
* Clears properties related to the active account.
*/
private clearActiveAccountProperties() {
this.activeDid = "";
this.derivationPath = "";
this.publicHex = "";
this.publicBase64 = "";
}
/**
* Switches to an account based on its number in the list.
*
* @param {number} accountNum - The account number to switch to.
*/
private async switchToAccountNumber(accountNum: number) {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = accounts[accountNum - 1];
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did });
this.updateActiveAccountProperties(account);
}
/**
* Updates properties related to the active account.
*
* @param {AccountType} account - The account object.
*/
private updateActiveAccountProperties(account: Account) {
this.activeDid = account.did;
this.derivationPath = account.derivationPath || "";
this.publicHex = account.publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
}
public showContactGivesClassNames() {
return {
"bg-slate-900": !this.showContactGives,
"bg-green-600": this.showContactGives,
};
}
async onClickSaveApiServer() {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {

12
src/views/ClaimView.vue

@ -482,17 +482,16 @@ import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import GiftedDialog from "@/components/GiftedDialog.vue";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import * as serverUtil from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import QuickNav from "@/components/QuickNav.vue";
import { Account } from "@/db/tables/accounts";
import {
GenericCredWrapper,
OfferVerifiableCredential,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
interface ProviderInfo {
identifier: string; // could be a DID or a handleId
@ -560,10 +559,7 @@ export default class ClaimView extends Vue {
this.allContacts = await db.contacts.toArray();
this.isRegistered = settings.isRegistered || false;
await accountsDB.open();
const accounts = accountsDB.accounts;
const accountsArr: Array<Account> = await accounts?.toArray();
this.allMyDids = accountsArr.map((acc) => acc.did);
this.allMyDids = await libsUtil.retrieveAccountDids();
const pathParam = window.location.pathname.substring("/claim/".length);
let claimId;

10
src/views/ConfirmGiftView.vue

@ -412,13 +412,12 @@ import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import * as serverUtil from "@/libs/endorserServer";
import { displayAmount, GiveSummaryRecord } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { isGiveAction } from "@/libs/util";
import { isGiveAction, retrieveAccountDids } from "@/libs/util";
import TopMessage from "@/components/TopMessage.vue";
@Component({
@ -476,10 +475,7 @@ export default class ClaimView extends Vue {
this.allContacts = await db.contacts.toArray();
this.isRegistered = settings.isRegistered || false;
await accountsDB.open();
const accounts = accountsDB.accounts;
const accountsArr: Array<Account> = await accounts?.toArray();
this.allMyDids = accountsArr.map((acc) => acc.did);
this.allMyDids = await retrieveAccountDids();
const pathParam = window.location.pathname.substring(
"/confirm-gift/".length,

6
src/views/ContactAmountsView.vue

@ -112,7 +112,7 @@ import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import {
AgreeVerifiableCredential,
@ -123,6 +123,7 @@ import {
GiveVerifiableCredential,
SCHEMA_ORG_CONTEXT,
} from "@/libs/endorserServer";
import { retrieveAccountCount } from "@/libs/util";
@Component({ components: { QuickNav } })
export default class ContactAmountssView extends Vue {
@ -137,8 +138,7 @@ export default class ContactAmountssView extends Vue {
displayAmount = displayAmount;
async beforeCreate() {
await accountsDB.open();
this.numAccounts = await accountsDB.accounts.count();
this.numAccounts = await retrieveAccountCount();
}
async created() {

8
src/views/ContactQRScanShowView.vue

@ -91,7 +91,6 @@
<script lang="ts">
import { AxiosError } from "axios";
import QRCodeVue3 from "qr-code-generator-vue3";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { QrcodeStream } from "vue-qrcode-reader";
import { useClipboard } from "@vueuse/core";
@ -99,7 +98,7 @@ import { useClipboard } from "@vueuse/core";
import QuickNav from "@/components/QuickNav.vue";
import UserNameDialog from "@/components/UserNameDialog.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
@ -110,6 +109,7 @@ import {
setVisibilityUtil,
} from "@/libs/endorserServer";
import { ETHR_DID_PREFIX } from "@/libs/crypto/vc";
import { retrieveAccountMetadata } from "@/libs/util";
@Component({
components: {
@ -140,9 +140,7 @@ export default class ContactQRScanShow extends Vue {
!!settings.hideRegisterPromptOnNewContact;
this.isRegistered = !!settings.isRegistered;
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const account = await retrieveAccountMetadata(this.activeDid);
if (account) {
const name =
(settings.firstName || "") +

12
src/views/DIDView.vue

@ -254,7 +254,7 @@ import QuickNav from "@/components/QuickNav.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { BoundingBox } from "@/db/tables/settings";
import {
@ -320,14 +320,8 @@ export default class DIDView extends Vue {
}
await this.loadClaimsAbout();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
for (const account of allAccounts) {
if (account.did === this.viewingDid) {
this.isMyDid = true;
break;
}
}
const allAccountDids = await libsUtil.retrieveAccountDids();
this.isMyDid = allAccountDids.includes(this.viewingDid);
}
}

8
src/views/DiscoverView.vue

@ -153,11 +153,11 @@ import ProjectIcon from "@/components/ProjectIcon.vue";
import OnboardingDialog from "@/components/OnboardingDialog.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { BoundingBox } from "@/db/tables/settings";
import { didInfo, getHeaders, PlanData } from "@/libs/endorserServer";
import { OnboardPage } from "@/libs/util";
import { OnboardPage, retrieveAccountDids } from "@/libs/util";
@Component({
components: {
@ -195,9 +195,7 @@ export default class DiscoverView extends Vue {
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
this.allMyDids = await retrieveAccountDids();
this.searchTerms = (this.$route as Router).query["searchText"] || "";

13
src/views/GiftedDetailsView.vue

@ -267,7 +267,7 @@ import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import {
createAndSubmitGive,
didInfo,
@ -279,7 +279,7 @@ import {
hydrateGive,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { Contact } from "@/db/tables/contacts";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: {
@ -432,17 +432,12 @@ export default class GiftedDetails extends Vue {
this.apiServer = settings.apiServer || "";
this.activeDid = settings.activeDid || "";
let allContacts: Contact[] = [];
let allMyDids: string[] = [];
if (
(this.giverDid && !this.giverName) ||
(this.recipientDid && !this.recipientName)
) {
allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
allMyDids = allAccounts.map((acc) => acc.did);
const allContacts = await db.contacts.toArray();
const allMyDids = await retrieveAccountDids();
if (this.giverDid && !this.giverName) {
this.giverName = didInfo(
this.giverDid,

9
src/views/HomeView.vue

@ -388,7 +388,6 @@ import {
PASSKEYS_ENABLED,
} from "@/constants/app";
import {
accountsDB,
db,
retrieveSettingsForActiveAccount,
updateAccountSettings,
@ -412,6 +411,7 @@ import {
} from "@/libs/endorserServer";
import {
generateSaveAndActivateIdentity,
retrieveAccountDids,
GiverReceiverInputInfo,
OnboardPage,
registerSaveAndActivatePasskey,
@ -486,11 +486,8 @@ export default class HomeView extends Vue {
async mounted() {
try {
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
if (allAccounts.length > 0) {
this.allMyDids = allAccounts.map((acc) => acc.did);
} else {
this.allMyDids = await retrieveAccountDids();
if (this.allMyDids.length === 0) {
this.isCreatingIdentifier = true;
const newDid = await generateSaveAndActivateIdentity();
this.isCreatingIdentifier = false;

14
src/views/IdentitySwitcherView.vue

@ -101,10 +101,15 @@
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { db, accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
import {
accountsDBPromise,
db,
retrieveSettingsForActiveAccount,
} from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import QuickNav from "@/components/QuickNav.vue";
import { retrieveAllAccountsMetadata } from "@/libs/util";
@Component({ components: { QuickNav } })
export default class IdentitySwitcherView extends Vue {
@ -123,8 +128,7 @@ export default class IdentitySwitcherView extends Vue {
this.apiServer = settings.apiServer || "";
this.apiServerInput = settings.apiServer || "";
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const accounts = await retrieveAllAccountsMetadata();
for (let n = 0; n < accounts.length; n++) {
const acct = accounts[n];
this.otherIdentities.push({ id: acct.id as string, did: acct.did });
@ -166,7 +170,7 @@ export default class IdentitySwitcherView extends Vue {
title: "Delete Identity?",
text: "Are you sure you want to erase this identity? (There is no undo. You may want to select it and back it up just in case.)",
onYes: async () => {
await accountsDB.open();
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.delete(id);
this.otherIdentities = this.otherIdentities.filter(
(ident) => ident.id !== id,

12
src/views/ImportAccountView.vue

@ -87,13 +87,18 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import {
accountsDBPromise,
db,
retrieveSettingsForActiveAccount,
} from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import {
DEFAULT_ROOT_DERIVATION_PATH,
deriveAddress,
newIdentifier,
} from "@/libs/crypto";
import { retrieveAccountCount } from "@/libs/util";
@Component({
components: {},
@ -118,8 +123,7 @@ export default class ImportAccountView extends Vue {
shouldErase = false;
async created() {
await accountsDB.open();
this.numAccounts = await accountsDB.accounts.count();
this.numAccounts = await retrieveAccountCount();
// get the server, to help with import on the test server
const settings = await retrieveSettingsForActiveAccount();
this.apiServer = settings.apiServer || "";
@ -148,7 +152,7 @@ export default class ImportAccountView extends Vue {
this.derivationPath,
);
await accountsDB.open();
const accountsDB = await accountsDBPromise;
if (this.shouldErase) {
await accountsDB.accounts.clear();
}

8
src/views/ImportDerivedAccountView.vue

@ -78,8 +78,9 @@ import {
newIdentifier,
nextDerivationPath,
} from "@/libs/crypto";
import { accountsDB, db } from "@/db/index";
import { accountsDBPromise, db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { retrieveAllFullyDecryptedAccounts } from "@/libs/util";
@Component({
components: {},
@ -90,8 +91,7 @@ export default class ImportAccountView extends Vue {
selectedArrayFirstDid = "";
async mounted() {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const accounts = await retrieveAllFullyDecryptedAccounts(); // let's match derived accounts differently so we don't need the private info
const seedDids: Record<string, Array<string>> = {};
accounts.forEach((account) => {
const prevDids: Array<string> = seedDids[account.mnemonic] || [];
@ -110,11 +110,11 @@ export default class ImportAccountView extends Vue {
}
public async incrementDerivation() {
await accountsDB.open();
// find the maximum derivation path for the selected DIDs
const selectedArray: Array<string> =
this.didArrays.find((dids) => dids[0] === this.selectedArrayFirstDid) ||
[];
const accountsDB = await accountsDBPromise; // let's match derived accounts differently so we don't need the private info
const allMatchingAccounts = await accountsDB.accounts
.where("did")
.anyOf(...selectedArray)

9
src/views/NewActivityView.vue

@ -149,7 +149,6 @@ import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import { NotificationIface } from "@/constants/app";
import {
accountsDB,
db,
retrieveSettingsForActiveAccount,
updateAccountSettings,
@ -163,6 +162,7 @@ import {
OfferSummaryRecord,
OfferToPlanSummaryRecord,
} from "@/libs/endorserServer";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: { GiftedDialog, QuickNav, EntityIcon },
@ -196,12 +196,7 @@ export default class NewActivityView extends Vue {
settings.lastAckedOfferToUserProjectsJwtId || "";
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
if (allAccounts.length > 0) {
this.allMyDids = allAccounts.map((acc) => acc.did);
}
this.allMyDids = await retrieveAccountDids();
const offersToUserData = await getNewOffersToUser(
this.axios,

15
src/views/NewEditProjectView.vue

@ -209,13 +209,17 @@ import {
DEFAULT_PARTNER_API_SERVER,
NotificationIface,
} from "@/constants/app";
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
import { retrieveSettingsForActiveAccount } from "@/db/index";
import {
createEndorserJwtVcFromClaim,
getHeaders,
PlanVerifiableCredential,
} from "@/libs/endorserServer";
import { getAccount } from "@/libs/util";
import {
retrieveAccountCount,
retrieveAccountMetadata,
retrieveFullyDecryptedAccount,
} from "@/libs/util";
@Component({
components: { ImageMethodDialog, LMap, LMarker, LTileLayer, QuickNav },
@ -258,8 +262,7 @@ export default class NewEditProjectView extends Vue {
zoom = 2;
async mounted() {
await accountsDB.open();
this.numAccounts = await accountsDB.accounts.count();
this.numAccounts = await retrieveAccountCount();
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
@ -539,7 +542,7 @@ export default class NewEditProjectView extends Vue {
}
private async signPayload(): Promise<VerifiedEvent> {
const account = await getAccount(this.activeDid);
const account = await retrieveFullyDecryptedAccount(this.activeDid);
// get the last number of the derivationPath
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
// remove any trailing '
@ -572,7 +575,7 @@ export default class NewEditProjectView extends Vue {
signedPayload: VerifiedEvent,
) {
// first, get the public key for nostr
const account = await getAccount(this.activeDid);
const account = await retrieveAccountMetadata(this.activeDid);
// get the last number of the derivationPath
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
// remove any trailing '

13
src/views/OfferDetailsView.vue

@ -181,7 +181,7 @@ import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import {
createAndSubmitOffer,
didInfo,
@ -192,7 +192,7 @@ import {
OfferVerifiableCredential,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { Contact } from "@/db/tables/contacts";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: {
@ -301,14 +301,9 @@ export default class OfferDetailsView extends Vue {
this.activeDid = settings.activeDid ?? "";
this.showGeneralAdvanced = settings.showGeneralAdvanced ?? false;
let allContacts: Contact[] = [];
let allMyDids: string[] = [];
if (this.recipientDid && !this.recipientName) {
allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
allMyDids = allAccounts.map((acc) => acc.did);
const allContacts = await db.contacts.toArray();
const allMyDids = await retrieveAccountDids();
this.recipientName = didInfo(
this.recipientDid,
this.activeDid,

27
src/views/ProjectViewView.vue

@ -489,14 +489,11 @@ import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import ProjectIcon from "@/components/ProjectIcon.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import * as libsUtil from "@/libs/util";
import {
BLANK_GENERIC_SERVER_RECORD,
GenericCredWrapper,
getHeaders,
GiveSummaryRecord,
GiveVerifiableCredential,
OfferSummaryRecord,
@ -504,6 +501,7 @@ import {
PlanSummaryRecord,
} from "@/libs/endorserServer";
import * as serverUtil from "@/libs/endorserServer";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: {
@ -559,10 +557,7 @@ export default class ProjectViewView extends Vue {
this.allContacts = await db.contacts.toArray();
this.isRegistered = !!settings.isRegistered;
await accountsDB.open();
const accounts = accountsDB.accounts;
const accountsArr: Account[] = await accounts?.toArray();
this.allMyDids = accountsArr.map((acc) => acc.did);
this.allMyDids = await retrieveAccountDids();
const pathParam = window.location.pathname.substring("/project/".length);
if (pathParam) {
@ -593,7 +588,7 @@ export default class ProjectViewView extends Vue {
const url =
this.apiServer + "/api/claim/byHandle/" + encodeURIComponent(projectId);
const headers = await getHeaders(userDid);
const headers = await serverUtil.getHeaders(userDid);
try {
const resp = await this.axios.get(url, { headers });
@ -698,7 +693,7 @@ export default class ProjectViewView extends Vue {
}
const givesInUrl = givesUrl + postfix;
const headers = await getHeaders(this.activeDid);
const headers = await serverUtil.getHeaders(this.activeDid);
try {
const resp = await this.axios.get(givesInUrl, { headers });
if (resp.status === 200 && resp.data.data) {
@ -745,7 +740,7 @@ export default class ProjectViewView extends Vue {
}
const offersInUrl = offersUrl + postfix;
const headers = await getHeaders(this.activeDid);
const headers = await serverUtil.getHeaders(this.activeDid);
try {
const resp = await this.axios.get(offersInUrl, { headers });
if (resp.status === 200 && resp.data.data) {
@ -793,7 +788,7 @@ export default class ProjectViewView extends Vue {
}
const fulfillsInUrl = fulfillsUrl + postfix;
const headers = await getHeaders(this.activeDid);
const headers = await serverUtil.getHeaders(this.activeDid);
try {
const resp = await this.axios.get(fulfillsInUrl, { headers });
if (resp.status === 200) {
@ -841,7 +836,7 @@ export default class ProjectViewView extends Vue {
}
const providedByFullUrl = providedByUrl + postfix;
const headers = await getHeaders(this.activeDid);
const headers = await serverUtil.getHeaders(this.activeDid);
try {
const resp = await this.axios.get(providedByFullUrl, { headers });
if (resp.status === 200) {
@ -945,7 +940,7 @@ export default class ProjectViewView extends Vue {
checkIsFulfillable(offer: OfferSummaryRecord) {
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
...BLANK_GENERIC_SERVER_RECORD,
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
claim: offer.fullClaim,
claimType: "Offer",
issuer: offer.offeredByDid,
@ -955,7 +950,7 @@ export default class ProjectViewView extends Vue {
onClickFulfillGiveToOffer(offer: OfferSummaryRecord) {
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
...BLANK_GENERIC_SERVER_RECORD,
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
claim: offer.fullClaim,
issuer: offer.offeredByDid,
};
@ -1003,7 +998,7 @@ export default class ProjectViewView extends Vue {
*/
checkIsConfirmable(give: GiveSummaryRecord, confirmerIdList?: string[]) {
const giveDetails: GenericCredWrapper<GiveVerifiableCredential> = {
...BLANK_GENERIC_SERVER_RECORD,
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
claim: give.fullClaim,
claimType: "GiveAction",
issuer: give.issuerDid,

10
src/views/ProjectsView.vue

@ -263,8 +263,7 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import * as libsUtil from "@/libs/util";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import EntityIcon from "@/components/EntityIcon.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue";
@ -280,6 +279,7 @@ import {
OfferSummaryRecord,
PlanData,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { OnboardPage } from "@/libs/util";
@Component({
@ -328,9 +328,7 @@ export default class ProjectsView extends Vue {
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
this.allMyDids = await libsUtil.retrieveAccountDids();
if (!settings.finishedOnboarding) {
(this.$refs.onboardingDialog as OnboardingDialog).open(
@ -338,7 +336,7 @@ export default class ProjectsView extends Vue {
);
}
if (allAccounts.length === 0) {
if (this.allMyDids.length === 0) {
console.error("No accounts found.");
this.errNote("You need an identifier to load your projects.");
} else {

2
src/views/QuickActionBvcEndView.vue

@ -145,7 +145,7 @@ import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import {
BVC_MEETUPS_PROJECT_CLAIM_ID,

9
src/views/RecentOffersToUserProjectsView.vue

@ -81,7 +81,7 @@ import GiftedDialog from "@/components/GiftedDialog.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import {
didInfo,
@ -89,6 +89,7 @@ import {
getNewOffersToUserProjects,
OfferToPlanSummaryRecord,
} from "@/libs/endorserServer";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
@ -119,11 +120,7 @@ export default class RecentOffersToUserView extends Vue {
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
if (allAccounts.length > 0) {
this.allMyDids = allAccounts.map((acc) => acc.did);
}
this.allMyDids = await retrieveAccountDids();
const offersToUserProjectsData = await getNewOffersToUserProjects(
this.axios,

9
src/views/RecentOffersToUserView.vue

@ -74,7 +74,7 @@ import EntityIcon from "@/components/EntityIcon.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import {
didInfo,
@ -82,6 +82,7 @@ import {
getNewOffersToUser,
OfferSummaryRecord,
} from "@/libs/endorserServer";
import { retrieveAccountDids } from "@/libs/util";
@Component({
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
@ -111,11 +112,7 @@ export default class RecentOffersToUserView extends Vue {
this.allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
if (allAccounts.length > 0) {
this.allMyDids = allAccounts.map((acc) => acc.did);
}
this.allMyDids = await retrieveAccountDids();
const offersToUserData = await getNewOffersToUser(
this.axios,

13
src/views/SeedBackupView.vue

@ -99,14 +99,17 @@
</template>
<script lang="ts">
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
import { retrieveSettingsForActiveAccount } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import {
retrieveAccountCount,
retrieveFullyDecryptedAccount,
} from "@/libs/util";
@Component({ components: { QuickNav } })
export default class SeedBackupView extends Vue {
@ -124,10 +127,8 @@ export default class SeedBackupView extends Vue {
const settings = await retrieveSettingsForActiveAccount();
const activeDid = settings.activeDid || "";
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
this.numAccounts = accounts.length;
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
this.numAccounts = await retrieveAccountCount();
this.activeAccount = await retrieveFullyDecryptedAccount(activeDid);
} catch (err: unknown) {
console.error("Got an error loading an identifier:", err);
this.$notify(

8
src/views/ShareMyContactInfoView.vue

@ -41,7 +41,6 @@
</template>
<script lang="ts">
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
@ -49,8 +48,9 @@ import { useClipboard } from "@vueuse/core";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import { generateEndorserJwtForAccount } from "@/libs/endorserServer";
import { retrieveAccountMetadata } from "@/libs/util";
@Component({
components: { QuickNav, TopMessage },
@ -65,9 +65,7 @@ export default class ShareMyContactInfoView extends Vue {
const isRegistered = !!settings.isRegistered;
const profileImageUrl = settings.profileImageUrl || "";
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts);
const account = await retrieveAccountMetadata(activeDid);
const numContacts = await db.contacts.count();

10
src/views/StartView.vue

@ -92,8 +92,11 @@ import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, PASSKEYS_ENABLED } from "@/constants/app";
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
import { registerSaveAndActivatePasskey } from "@/libs/util";
import { retrieveSettingsForActiveAccount } from "@/db/index";
import {
registerSaveAndActivatePasskey,
retrieveAccountCount,
} from "@/libs/util";
@Component({
components: {},
@ -108,8 +111,7 @@ export default class StartView extends Vue {
const settings = await retrieveSettingsForActiveAccount();
this.givenName = settings.firstName || "";
await accountsDB.open();
this.numAccounts = await accountsDB.accounts.count();
this.numAccounts = await retrieveAccountCount();
}
public onClickNewSeed() {

14
src/views/TestView.vue

@ -247,7 +247,7 @@ import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import { AppString, NotificationIface } from "@/constants/app";
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
import * as vcLib from "@/libs/crypto/vc";
import {
PeerSetup,
@ -258,7 +258,7 @@ import {
import {
AccountKeyInfo,
blobToBase64,
getAccount,
retrieveAccountMetadata,
registerAndSavePasskey,
SHARED_PHOTO_BASE64_KEY,
} from "@/libs/util";
@ -294,11 +294,7 @@ export default class Help extends Vue {
this.activeDid = settings.activeDid || "";
this.userName = settings.firstName;
await accountsDB.open();
const account: { identity?: string } | undefined = await accountsDB.accounts
.where("did")
.equals(this.activeDid)
.first();
const account = await retrieveAccountMetadata(this.activeDid);
if (this.activeDid) {
if (account) {
this.credIdHex = account.passkeyCredIdHex as string;
@ -368,7 +364,7 @@ export default class Help extends Vue {
}
public async createJwtSimplewebauthn() {
const account: AccountKeyInfo | undefined = await getAccount(
const account: AccountKeyInfo | undefined = await retrieveAccountMetadata(
this.activeDid || "",
);
if (!vcLib.isFromPasskey(account)) {
@ -385,7 +381,7 @@ export default class Help extends Vue {
}
public async createJwtNavigator() {
const account: AccountKeyInfo | undefined = await getAccount(
const account: AccountKeyInfo | undefined = await retrieveAccountMetadata(
this.activeDid || "",
);
if (!vcLib.isFromPasskey(account)) {

2
sw_scripts/additional-scripts.js

@ -115,7 +115,7 @@ self.addEventListener("push", function (event) {
self.addEventListener("message", (event) => {
logConsoleAndDb("Service worker got a message...", event);
if (event.data && event.data.type === "SEND_LOCAL_DATA") {
self.secret = event.data.data;
self.secret = event.data.data; // used in safari-notifications.js to decrypt the account identity
event.ports[0].postMessage({ success: true });
}
logConsoleAndDb("Service worker posted a message.");

1
sw_scripts/safari-notifications.js

@ -515,6 +515,7 @@ async function getNotificationCount() {
const identity = activeAccount && activeAccount["identity"];
if (identity && "secret" in self) {
// get the "secret" pulled in additional-scripts.js to decrypt the "identity" inside the IndexedDB; see account.ts
const secret = self.secret;
const secretUint8Array = self.decodeBase64(secret);
const messageWithNonceAsUint8Array = self.decodeBase64(identity);

Loading…
Cancel
Save