forked from trent_larson/crowd-funder-for-time-pwa
switch the encryption secret from localStorage to IndexedDB (because localStorage gets lost so often)
This commit is contained in:
@@ -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 */
|
||||
/**
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
113
src/db/index.ts
113
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;
|
||||
//// Initialize the DBs, starting with the sensitive ones.
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
// Apply encryption to the sensitive database using the secret key
|
||||
encrypted(accountsDB, { secretKey: secret });
|
||||
|
||||
// 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> {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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" };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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> => {
|
||||
await accountsDB.open();
|
||||
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> => {
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 || "") +
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"] || "";
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -101,10 +101,15 @@
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db, accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import {
|
||||
accountsDBPromise,
|
||||
db,
|
||||
retrieveSettingsForActiveAccount,
|
||||
} from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 '
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user