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 */
|
/* Configure global timeout; default is 30000 milliseconds */
|
||||||
// the image upload will often not succeed at 5 seconds
|
// 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 */
|
/* 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 { NotificationIface } from "@/constants/app";
|
||||||
import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
|
import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class GiftedDialog extends Vue {
|
export default class GiftedDialog extends Vue {
|
||||||
@@ -145,9 +146,7 @@ export default class GiftedDialog extends Vue {
|
|||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
|
|
||||||
if (this.giver && !this.giver.name) {
|
if (this.giver && !this.giver.name) {
|
||||||
this.giver.name = didInfo(
|
this.giver.name = didInfo(
|
||||||
|
|||||||
@@ -101,7 +101,12 @@
|
|||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
|
||||||
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
|
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 { urlBase64ToUint8Array } from "@/libs/crypto/vc/util";
|
||||||
import * as libsUtil from "@/libs/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(
|
logConsoleAndDb(
|
||||||
"Requesting permission for notifications: " + JSON.stringify(navigator),
|
"Requesting permission for notifications: " + JSON.stringify(navigator),
|
||||||
);
|
);
|
||||||
@@ -280,7 +285,8 @@ export default class PushNotificationPermission extends Vue {
|
|||||||
return Promise.reject("Service worker not available.");
|
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) {
|
if (!secret) {
|
||||||
return Promise.reject("No secret found.");
|
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 { Account, AccountsSchema } from "./tables/accounts";
|
||||||
import { Contact, ContactSchema } from "./tables/contacts";
|
import { Contact, ContactSchema } from "./tables/contacts";
|
||||||
import { Log, LogSchema } from "./tables/logs";
|
import { Log, LogSchema } from "./tables/logs";
|
||||||
|
import { MASTER_SECRET_KEY, Secret, SecretSchema } from "./tables/secret";
|
||||||
import {
|
import {
|
||||||
MASTER_SETTINGS_KEY,
|
MASTER_SETTINGS_KEY,
|
||||||
Settings,
|
Settings,
|
||||||
@@ -14,6 +15,7 @@ import { Temp, TempSchema } from "./tables/temp";
|
|||||||
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
||||||
|
|
||||||
// Define types for tables that hold sensitive and non-sensitive data
|
// Define types for tables that hold sensitive and non-sensitive data
|
||||||
|
type SecretTable = { secret: Table<Secret> };
|
||||||
type SensitiveTables = { accounts: Table<Account> };
|
type SensitiveTables = { accounts: Table<Account> };
|
||||||
type NonsensitiveTables = {
|
type NonsensitiveTables = {
|
||||||
contacts: Table<Contact>;
|
contacts: Table<Contact>;
|
||||||
@@ -23,25 +25,39 @@ type NonsensitiveTables = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Using 'unknown' instead of 'any' for stricter typing and to avoid TypeScript warnings
|
// 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 SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
|
||||||
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
|
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
|
||||||
BaseDexie & T;
|
BaseDexie & T;
|
||||||
|
|
||||||
// Initialize Dexie databases for sensitive and non-sensitive data
|
//// Initialize the DBs, starting with the sensitive ones.
|
||||||
export const accountsDB = new BaseDexie("TimeSafariAccounts") as SensitiveDexie;
|
|
||||||
|
// 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;
|
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
|
// 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
|
// v1 also had contacts & settings
|
||||||
// v2 added Log
|
// v2 added Log
|
||||||
db.version(2).stores({
|
db.version(2).stores({
|
||||||
@@ -73,6 +89,79 @@ db.on("populate", async () => {
|
|||||||
await db.settings.add(DEFAULT_SETTINGS);
|
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
|
// retrieves default settings
|
||||||
// calls db.open()
|
// calls db.open()
|
||||||
export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {
|
export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export type Account = {
|
|||||||
/**
|
/**
|
||||||
* Auto-generated ID by Dexie
|
* 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
|
* The date the account was created
|
||||||
@@ -48,7 +48,7 @@ export type Account = {
|
|||||||
/**
|
/**
|
||||||
* Schema for the accounts table in the database.
|
* Schema for the accounts table in the database.
|
||||||
* Fields starting with a $ character are encrypted.
|
* 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 = {
|
export const AccountsSchema = {
|
||||||
accounts:
|
accounts:
|
||||||
|
|||||||
@@ -9,6 +9,4 @@ export type Temp = {
|
|||||||
/**
|
/**
|
||||||
* Schema for the Temp table in the database.
|
* Schema for the Temp table in the database.
|
||||||
*/
|
*/
|
||||||
export const TempSchema = {
|
export const TempSchema = { temp: "id" };
|
||||||
temp: "id",
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import { Contact } from "@/db/tables/contacts";
|
|||||||
import { accessToken, deriveAddress, nextDerivationPath } from "@/libs/crypto";
|
import { accessToken, deriveAddress, nextDerivationPath } from "@/libs/crypto";
|
||||||
import { NonsensitiveDexie } from "@/db/index";
|
import { NonsensitiveDexie } from "@/db/index";
|
||||||
import {
|
import {
|
||||||
getAccount,
|
retrieveAccountMetadata,
|
||||||
|
retrieveFullyDecryptedAccount,
|
||||||
getPasskeyExpirationSeconds,
|
getPasskeyExpirationSeconds,
|
||||||
GiverReceiverInputInfo,
|
GiverReceiverInputInfo,
|
||||||
} from "@/libs/util";
|
} from "@/libs/util";
|
||||||
@@ -506,7 +507,7 @@ export async function getHeaders(did?: string) {
|
|||||||
};
|
};
|
||||||
if (did) {
|
if (did) {
|
||||||
let token;
|
let token;
|
||||||
const account = await getAccount(did);
|
const account = await retrieveAccountMetadata(did);
|
||||||
if (account?.passkeyCredIdHex) {
|
if (account?.passkeyCredIdHex) {
|
||||||
if (
|
if (
|
||||||
passkeyAccessToken &&
|
passkeyAccessToken &&
|
||||||
@@ -1054,7 +1055,7 @@ export async function createEndorserJwtForDid(
|
|||||||
payload: object,
|
payload: object,
|
||||||
expiresIn?: number,
|
expiresIn?: number,
|
||||||
) {
|
) {
|
||||||
const account = await getAccount(issuerDid);
|
const account = await retrieveFullyDecryptedAccount(issuerDid);
|
||||||
return createEndorserJwtForKey(account as KeyMeta, payload, expiresIn);
|
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 { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
|
||||||
import {
|
import {
|
||||||
accountsDB,
|
accountsDBPromise,
|
||||||
retrieveSettingsForActiveAccount,
|
retrieveSettingsForActiveAccount,
|
||||||
updateAccountSettings,
|
updateAccountSettings,
|
||||||
updateDefaultSettings,
|
updateDefaultSettings,
|
||||||
@@ -422,10 +422,51 @@ export function findAllVisibleToDids(
|
|||||||
|
|
||||||
export interface AccountKeyInfo extends Account, KeyMeta {}
|
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,
|
activeDid: string,
|
||||||
): Promise<AccountKeyInfo | undefined> => {
|
): 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
|
const account = (await accountsDB.accounts
|
||||||
.where("did")
|
.where("did")
|
||||||
.equals(activeDid)
|
.equals(activeDid)
|
||||||
@@ -433,6 +474,15 @@ export const getAccount = async (
|
|||||||
return account;
|
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.
|
* 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
|
* @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 newId = newIdentifier(address, publicHex, privateHex, derivationPath);
|
||||||
const identity = JSON.stringify(newId);
|
const identity = JSON.stringify(newId);
|
||||||
|
|
||||||
await accountsDB.open();
|
const accountsDB = await accountsDBPromise;
|
||||||
await accountsDB.accounts.add({
|
await accountsDB.accounts.add({
|
||||||
dateCreated: new Date().toISOString(),
|
dateCreated: new Date().toISOString(),
|
||||||
derivationPath: derivationPath,
|
derivationPath: derivationPath,
|
||||||
@@ -477,7 +527,7 @@ export const registerAndSavePasskey = async (
|
|||||||
passkeyCredIdHex,
|
passkeyCredIdHex,
|
||||||
publicKeyHex: Buffer.from(publicKeyBytes).toString("hex"),
|
publicKeyHex: Buffer.from(publicKeyBytes).toString("hex"),
|
||||||
};
|
};
|
||||||
await accountsDB.open();
|
const accountsDB = await accountsDBPromise;
|
||||||
await accountsDB.accounts.add(account);
|
await accountsDB.accounts.add(account);
|
||||||
return account;
|
return account;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
RouteLocationNormalized,
|
RouteLocationNormalized,
|
||||||
RouteRecordRaw,
|
RouteRecordRaw,
|
||||||
} from "vue-router";
|
} from "vue-router";
|
||||||
import { accountsDB } from "@/db/index";
|
import { accountsDBPromise } from "@/db/index";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -18,7 +18,7 @@ const enterOrStart = async (
|
|||||||
from: RouteLocationNormalized,
|
from: RouteLocationNormalized,
|
||||||
next: NavigationGuardNext,
|
next: NavigationGuardNext,
|
||||||
) => {
|
) => {
|
||||||
await accountsDB.open();
|
const accountsDB = await accountsDBPromise;
|
||||||
const num_accounts = await accountsDB.accounts.count();
|
const num_accounts = await accountsDB.accounts.count();
|
||||||
if (num_accounts > 0) {
|
if (num_accounts > 0) {
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -819,7 +819,6 @@ import {
|
|||||||
} from "@/constants/app";
|
} from "@/constants/app";
|
||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
accountsDB,
|
|
||||||
retrieveSettingsForActiveAccount,
|
retrieveSettingsForActiveAccount,
|
||||||
updateAccountSettings,
|
updateAccountSettings,
|
||||||
} from "@/db/index";
|
} from "@/db/index";
|
||||||
@@ -839,7 +838,11 @@ import {
|
|||||||
ImageRateLimits,
|
ImageRateLimits,
|
||||||
tokenExpiryTimeDescription,
|
tokenExpiryTimeDescription,
|
||||||
} from "@/libs/endorserServer";
|
} 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>();
|
const inputImportFileNameRef = ref<Blob>();
|
||||||
|
|
||||||
@@ -941,7 +944,7 @@ export default class AccountViewView extends Vue {
|
|||||||
);
|
);
|
||||||
// this sometimes gives different information on the error
|
// this sometimes gives different information on the error
|
||||||
console.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,
|
error,
|
||||||
);
|
);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
@@ -1055,7 +1058,9 @@ export default class AccountViewView extends Vue {
|
|||||||
* Processes the identity and updates the component's state.
|
* Processes the identity and updates the component's state.
|
||||||
*/
|
*/
|
||||||
async processIdentity() {
|
async processIdentity() {
|
||||||
const account: Account | undefined = await getAccount(this.activeDid);
|
const account: Account | undefined = await retrieveAccountMetadata(
|
||||||
|
this.activeDid,
|
||||||
|
);
|
||||||
if (account?.identity) {
|
if (account?.identity) {
|
||||||
const identity = JSON.parse(account.identity as string) as IIdentifier;
|
const identity = JSON.parse(account.identity as string) as IIdentifier;
|
||||||
this.publicHex = identity.keys[0].publicKeyHex;
|
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() {
|
async onClickSaveApiServer() {
|
||||||
await db.open();
|
await db.open();
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
|
|||||||
@@ -482,17 +482,16 @@ import { Router } from "vue-router";
|
|||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
|
||||||
import GiftedDialog from "@/components/GiftedDialog.vue";
|
import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||||
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
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 {
|
import {
|
||||||
GenericCredWrapper,
|
GenericCredWrapper,
|
||||||
OfferVerifiableCredential,
|
OfferVerifiableCredential,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import * as libsUtil from "@/libs/util";
|
||||||
|
|
||||||
interface ProviderInfo {
|
interface ProviderInfo {
|
||||||
identifier: string; // could be a DID or a handleId
|
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.allContacts = await db.contacts.toArray();
|
||||||
this.isRegistered = settings.isRegistered || false;
|
this.isRegistered = settings.isRegistered || false;
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await libsUtil.retrieveAccountDids();
|
||||||
const accounts = accountsDB.accounts;
|
|
||||||
const accountsArr: Array<Account> = await accounts?.toArray();
|
|
||||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
|
||||||
|
|
||||||
const pathParam = window.location.pathname.substring("/claim/".length);
|
const pathParam = window.location.pathname.substring("/claim/".length);
|
||||||
let claimId;
|
let claimId;
|
||||||
|
|||||||
@@ -412,13 +412,12 @@ import { Router } from "vue-router";
|
|||||||
|
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { Account } from "@/db/tables/accounts";
|
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
import { displayAmount, GiveSummaryRecord } from "@/libs/endorserServer";
|
import { displayAmount, GiveSummaryRecord } from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { isGiveAction } from "@/libs/util";
|
import { isGiveAction, retrieveAccountDids } from "@/libs/util";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -476,10 +475,7 @@ export default class ClaimView extends Vue {
|
|||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
this.isRegistered = settings.isRegistered || false;
|
this.isRegistered = settings.isRegistered || false;
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const accounts = accountsDB.accounts;
|
|
||||||
const accountsArr: Array<Account> = await accounts?.toArray();
|
|
||||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
|
||||||
|
|
||||||
const pathParam = window.location.pathname.substring(
|
const pathParam = window.location.pathname.substring(
|
||||||
"/confirm-gift/".length,
|
"/confirm-gift/".length,
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ import { Router } from "vue-router";
|
|||||||
|
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import {
|
import {
|
||||||
AgreeVerifiableCredential,
|
AgreeVerifiableCredential,
|
||||||
@@ -123,6 +123,7 @@ import {
|
|||||||
GiveVerifiableCredential,
|
GiveVerifiableCredential,
|
||||||
SCHEMA_ORG_CONTEXT,
|
SCHEMA_ORG_CONTEXT,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountCount } from "@/libs/util";
|
||||||
|
|
||||||
@Component({ components: { QuickNav } })
|
@Component({ components: { QuickNav } })
|
||||||
export default class ContactAmountssView extends Vue {
|
export default class ContactAmountssView extends Vue {
|
||||||
@@ -137,8 +138,7 @@ export default class ContactAmountssView extends Vue {
|
|||||||
displayAmount = displayAmount;
|
displayAmount = displayAmount;
|
||||||
|
|
||||||
async beforeCreate() {
|
async beforeCreate() {
|
||||||
await accountsDB.open();
|
this.numAccounts = await retrieveAccountCount();
|
||||||
this.numAccounts = await accountsDB.accounts.count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async created() {
|
async created() {
|
||||||
|
|||||||
@@ -91,7 +91,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import QRCodeVue3 from "qr-code-generator-vue3";
|
import QRCodeVue3 from "qr-code-generator-vue3";
|
||||||
import * as R from "ramda";
|
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { QrcodeStream } from "vue-qrcode-reader";
|
import { QrcodeStream } from "vue-qrcode-reader";
|
||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
@@ -99,7 +98,7 @@ import { useClipboard } from "@vueuse/core";
|
|||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import UserNameDialog from "@/components/UserNameDialog.vue";
|
import UserNameDialog from "@/components/UserNameDialog.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
||||||
@@ -110,6 +109,7 @@ import {
|
|||||||
setVisibilityUtil,
|
setVisibilityUtil,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import { ETHR_DID_PREFIX } from "@/libs/crypto/vc";
|
import { ETHR_DID_PREFIX } from "@/libs/crypto/vc";
|
||||||
|
import { retrieveAccountMetadata } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -140,9 +140,7 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
!!settings.hideRegisterPromptOnNewContact;
|
!!settings.hideRegisterPromptOnNewContact;
|
||||||
this.isRegistered = !!settings.isRegistered;
|
this.isRegistered = !!settings.isRegistered;
|
||||||
|
|
||||||
await accountsDB.open();
|
const account = await retrieveAccountMetadata(this.activeDid);
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
|
||||||
const account = R.find((acc) => acc.did === this.activeDid, accounts);
|
|
||||||
if (account) {
|
if (account) {
|
||||||
const name =
|
const name =
|
||||||
(settings.firstName || "") +
|
(settings.firstName || "") +
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ import QuickNav from "@/components/QuickNav.vue";
|
|||||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import { BoundingBox } from "@/db/tables/settings";
|
import { BoundingBox } from "@/db/tables/settings";
|
||||||
import {
|
import {
|
||||||
@@ -320,14 +320,8 @@ export default class DIDView extends Vue {
|
|||||||
}
|
}
|
||||||
await this.loadClaimsAbout();
|
await this.loadClaimsAbout();
|
||||||
|
|
||||||
await accountsDB.open();
|
const allAccountDids = await libsUtil.retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
this.isMyDid = allAccountDids.includes(this.viewingDid);
|
||||||
for (const account of allAccounts) {
|
|
||||||
if (account.did === this.viewingDid) {
|
|
||||||
this.isMyDid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,11 +153,11 @@ import ProjectIcon from "@/components/ProjectIcon.vue";
|
|||||||
import OnboardingDialog from "@/components/OnboardingDialog.vue";
|
import OnboardingDialog from "@/components/OnboardingDialog.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import { BoundingBox } from "@/db/tables/settings";
|
import { BoundingBox } from "@/db/tables/settings";
|
||||||
import { didInfo, getHeaders, PlanData } from "@/libs/endorserServer";
|
import { didInfo, getHeaders, PlanData } from "@/libs/endorserServer";
|
||||||
import { OnboardPage } from "@/libs/util";
|
import { OnboardPage, retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -195,9 +195,7 @@ export default class DiscoverView extends Vue {
|
|||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
|
|
||||||
this.searchTerms = (this.$route as Router).query["searchText"] || "";
|
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 QuickNav from "@/components/QuickNav.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import {
|
import {
|
||||||
createAndSubmitGive,
|
createAndSubmitGive,
|
||||||
didInfo,
|
didInfo,
|
||||||
@@ -279,7 +279,7 @@ import {
|
|||||||
hydrateGive,
|
hydrateGive,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -432,17 +432,12 @@ export default class GiftedDetails extends Vue {
|
|||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
this.activeDid = settings.activeDid || "";
|
this.activeDid = settings.activeDid || "";
|
||||||
|
|
||||||
let allContacts: Contact[] = [];
|
|
||||||
let allMyDids: string[] = [];
|
|
||||||
if (
|
if (
|
||||||
(this.giverDid && !this.giverName) ||
|
(this.giverDid && !this.giverName) ||
|
||||||
(this.recipientDid && !this.recipientName)
|
(this.recipientDid && !this.recipientName)
|
||||||
) {
|
) {
|
||||||
allContacts = await db.contacts.toArray();
|
const allContacts = await db.contacts.toArray();
|
||||||
|
const allMyDids = await retrieveAccountDids();
|
||||||
await accountsDB.open();
|
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
if (this.giverDid && !this.giverName) {
|
if (this.giverDid && !this.giverName) {
|
||||||
this.giverName = didInfo(
|
this.giverName = didInfo(
|
||||||
this.giverDid,
|
this.giverDid,
|
||||||
|
|||||||
@@ -388,7 +388,6 @@ import {
|
|||||||
PASSKEYS_ENABLED,
|
PASSKEYS_ENABLED,
|
||||||
} from "@/constants/app";
|
} from "@/constants/app";
|
||||||
import {
|
import {
|
||||||
accountsDB,
|
|
||||||
db,
|
db,
|
||||||
retrieveSettingsForActiveAccount,
|
retrieveSettingsForActiveAccount,
|
||||||
updateAccountSettings,
|
updateAccountSettings,
|
||||||
@@ -412,6 +411,7 @@ import {
|
|||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import {
|
import {
|
||||||
generateSaveAndActivateIdentity,
|
generateSaveAndActivateIdentity,
|
||||||
|
retrieveAccountDids,
|
||||||
GiverReceiverInputInfo,
|
GiverReceiverInputInfo,
|
||||||
OnboardPage,
|
OnboardPage,
|
||||||
registerSaveAndActivatePasskey,
|
registerSaveAndActivatePasskey,
|
||||||
@@ -486,11 +486,8 @@ export default class HomeView extends Vue {
|
|||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
if (this.allMyDids.length === 0) {
|
||||||
if (allAccounts.length > 0) {
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
} else {
|
|
||||||
this.isCreatingIdentifier = true;
|
this.isCreatingIdentifier = true;
|
||||||
const newDid = await generateSaveAndActivateIdentity();
|
const newDid = await generateSaveAndActivateIdentity();
|
||||||
this.isCreatingIdentifier = false;
|
this.isCreatingIdentifier = false;
|
||||||
|
|||||||
@@ -101,10 +101,15 @@
|
|||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { Router } from "vue-router";
|
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 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 } })
|
@Component({ components: { QuickNav } })
|
||||||
export default class IdentitySwitcherView extends Vue {
|
export default class IdentitySwitcherView extends Vue {
|
||||||
@@ -123,8 +128,7 @@ export default class IdentitySwitcherView extends Vue {
|
|||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
this.apiServerInput = settings.apiServer || "";
|
this.apiServerInput = settings.apiServer || "";
|
||||||
|
|
||||||
await accountsDB.open();
|
const accounts = await retrieveAllAccountsMetadata();
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
|
||||||
for (let n = 0; n < accounts.length; n++) {
|
for (let n = 0; n < accounts.length; n++) {
|
||||||
const acct = accounts[n];
|
const acct = accounts[n];
|
||||||
this.otherIdentities.push({ id: acct.id as string, did: acct.did });
|
this.otherIdentities.push({ id: acct.id as string, did: acct.did });
|
||||||
@@ -166,7 +170,7 @@ export default class IdentitySwitcherView extends Vue {
|
|||||||
title: "Delete Identity?",
|
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.)",
|
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 () => {
|
onYes: async () => {
|
||||||
await accountsDB.open();
|
const accountsDB = await accountsDBPromise;
|
||||||
await accountsDB.accounts.delete(id);
|
await accountsDB.accounts.delete(id);
|
||||||
this.otherIdentities = this.otherIdentities.filter(
|
this.otherIdentities = this.otherIdentities.filter(
|
||||||
(ident) => ident.id !== id,
|
(ident) => ident.id !== id,
|
||||||
|
|||||||
@@ -87,13 +87,18 @@ import { Component, Vue } from "vue-facing-decorator";
|
|||||||
import { Router } from "vue-router";
|
import { Router } from "vue-router";
|
||||||
|
|
||||||
import { AppString, NotificationIface } from "@/constants/app";
|
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 { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ROOT_DERIVATION_PATH,
|
DEFAULT_ROOT_DERIVATION_PATH,
|
||||||
deriveAddress,
|
deriveAddress,
|
||||||
newIdentifier,
|
newIdentifier,
|
||||||
} from "@/libs/crypto";
|
} from "@/libs/crypto";
|
||||||
|
import { retrieveAccountCount } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {},
|
components: {},
|
||||||
@@ -118,8 +123,7 @@ export default class ImportAccountView extends Vue {
|
|||||||
shouldErase = false;
|
shouldErase = false;
|
||||||
|
|
||||||
async created() {
|
async created() {
|
||||||
await accountsDB.open();
|
this.numAccounts = await retrieveAccountCount();
|
||||||
this.numAccounts = await accountsDB.accounts.count();
|
|
||||||
// get the server, to help with import on the test server
|
// get the server, to help with import on the test server
|
||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
@@ -148,7 +152,7 @@ export default class ImportAccountView extends Vue {
|
|||||||
this.derivationPath,
|
this.derivationPath,
|
||||||
);
|
);
|
||||||
|
|
||||||
await accountsDB.open();
|
const accountsDB = await accountsDBPromise;
|
||||||
if (this.shouldErase) {
|
if (this.shouldErase) {
|
||||||
await accountsDB.accounts.clear();
|
await accountsDB.accounts.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,8 +78,9 @@ import {
|
|||||||
newIdentifier,
|
newIdentifier,
|
||||||
nextDerivationPath,
|
nextDerivationPath,
|
||||||
} from "@/libs/crypto";
|
} from "@/libs/crypto";
|
||||||
import { accountsDB, db } from "@/db/index";
|
import { accountsDBPromise, db } from "@/db/index";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
|
import { retrieveAllFullyDecryptedAccounts } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {},
|
components: {},
|
||||||
@@ -90,8 +91,7 @@ export default class ImportAccountView extends Vue {
|
|||||||
selectedArrayFirstDid = "";
|
selectedArrayFirstDid = "";
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await accountsDB.open();
|
const accounts = await retrieveAllFullyDecryptedAccounts(); // let's match derived accounts differently so we don't need the private info
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
|
||||||
const seedDids: Record<string, Array<string>> = {};
|
const seedDids: Record<string, Array<string>> = {};
|
||||||
accounts.forEach((account) => {
|
accounts.forEach((account) => {
|
||||||
const prevDids: Array<string> = seedDids[account.mnemonic] || [];
|
const prevDids: Array<string> = seedDids[account.mnemonic] || [];
|
||||||
@@ -110,11 +110,11 @@ export default class ImportAccountView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async incrementDerivation() {
|
public async incrementDerivation() {
|
||||||
await accountsDB.open();
|
|
||||||
// find the maximum derivation path for the selected DIDs
|
// find the maximum derivation path for the selected DIDs
|
||||||
const selectedArray: Array<string> =
|
const selectedArray: Array<string> =
|
||||||
this.didArrays.find((dids) => dids[0] === this.selectedArrayFirstDid) ||
|
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
|
const allMatchingAccounts = await accountsDB.accounts
|
||||||
.where("did")
|
.where("did")
|
||||||
.anyOf(...selectedArray)
|
.anyOf(...selectedArray)
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ import QuickNav from "@/components/QuickNav.vue";
|
|||||||
import EntityIcon from "@/components/EntityIcon.vue";
|
import EntityIcon from "@/components/EntityIcon.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import {
|
import {
|
||||||
accountsDB,
|
|
||||||
db,
|
db,
|
||||||
retrieveSettingsForActiveAccount,
|
retrieveSettingsForActiveAccount,
|
||||||
updateAccountSettings,
|
updateAccountSettings,
|
||||||
@@ -163,6 +162,7 @@ import {
|
|||||||
OfferSummaryRecord,
|
OfferSummaryRecord,
|
||||||
OfferToPlanSummaryRecord,
|
OfferToPlanSummaryRecord,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { GiftedDialog, QuickNav, EntityIcon },
|
components: { GiftedDialog, QuickNav, EntityIcon },
|
||||||
@@ -196,12 +196,7 @@ export default class NewActivityView extends Vue {
|
|||||||
settings.lastAckedOfferToUserProjectsJwtId || "";
|
settings.lastAckedOfferToUserProjectsJwtId || "";
|
||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
this.allMyDids = await retrieveAccountDids();
|
||||||
await accountsDB.open();
|
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
if (allAccounts.length > 0) {
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
}
|
|
||||||
|
|
||||||
const offersToUserData = await getNewOffersToUser(
|
const offersToUserData = await getNewOffersToUser(
|
||||||
this.axios,
|
this.axios,
|
||||||
|
|||||||
@@ -209,13 +209,17 @@ import {
|
|||||||
DEFAULT_PARTNER_API_SERVER,
|
DEFAULT_PARTNER_API_SERVER,
|
||||||
NotificationIface,
|
NotificationIface,
|
||||||
} from "@/constants/app";
|
} from "@/constants/app";
|
||||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import {
|
import {
|
||||||
createEndorserJwtVcFromClaim,
|
createEndorserJwtVcFromClaim,
|
||||||
getHeaders,
|
getHeaders,
|
||||||
PlanVerifiableCredential,
|
PlanVerifiableCredential,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import { getAccount } from "@/libs/util";
|
import {
|
||||||
|
retrieveAccountCount,
|
||||||
|
retrieveAccountMetadata,
|
||||||
|
retrieveFullyDecryptedAccount,
|
||||||
|
} from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { ImageMethodDialog, LMap, LMarker, LTileLayer, QuickNav },
|
components: { ImageMethodDialog, LMap, LMarker, LTileLayer, QuickNav },
|
||||||
@@ -258,8 +262,7 @@ export default class NewEditProjectView extends Vue {
|
|||||||
zoom = 2;
|
zoom = 2;
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await accountsDB.open();
|
this.numAccounts = await retrieveAccountCount();
|
||||||
this.numAccounts = await accountsDB.accounts.count();
|
|
||||||
|
|
||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
this.activeDid = settings.activeDid || "";
|
this.activeDid = settings.activeDid || "";
|
||||||
@@ -539,7 +542,7 @@ export default class NewEditProjectView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async signPayload(): Promise<VerifiedEvent> {
|
private async signPayload(): Promise<VerifiedEvent> {
|
||||||
const account = await getAccount(this.activeDid);
|
const account = await retrieveFullyDecryptedAccount(this.activeDid);
|
||||||
// get the last number of the derivationPath
|
// get the last number of the derivationPath
|
||||||
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
||||||
// remove any trailing '
|
// remove any trailing '
|
||||||
@@ -572,7 +575,7 @@ export default class NewEditProjectView extends Vue {
|
|||||||
signedPayload: VerifiedEvent,
|
signedPayload: VerifiedEvent,
|
||||||
) {
|
) {
|
||||||
// first, get the public key for nostr
|
// 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
|
// get the last number of the derivationPath
|
||||||
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
||||||
// remove any trailing '
|
// remove any trailing '
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ import { Router } from "vue-router";
|
|||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import {
|
import {
|
||||||
createAndSubmitOffer,
|
createAndSubmitOffer,
|
||||||
didInfo,
|
didInfo,
|
||||||
@@ -192,7 +192,7 @@ import {
|
|||||||
OfferVerifiableCredential,
|
OfferVerifiableCredential,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -301,14 +301,9 @@ export default class OfferDetailsView extends Vue {
|
|||||||
this.activeDid = settings.activeDid ?? "";
|
this.activeDid = settings.activeDid ?? "";
|
||||||
this.showGeneralAdvanced = settings.showGeneralAdvanced ?? false;
|
this.showGeneralAdvanced = settings.showGeneralAdvanced ?? false;
|
||||||
|
|
||||||
let allContacts: Contact[] = [];
|
|
||||||
let allMyDids: string[] = [];
|
|
||||||
if (this.recipientDid && !this.recipientName) {
|
if (this.recipientDid && !this.recipientName) {
|
||||||
allContacts = await db.contacts.toArray();
|
const allContacts = await db.contacts.toArray();
|
||||||
|
const allMyDids = await retrieveAccountDids();
|
||||||
await accountsDB.open();
|
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
this.recipientName = didInfo(
|
this.recipientName = didInfo(
|
||||||
this.recipientDid,
|
this.recipientDid,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
|
|||||||
@@ -489,14 +489,11 @@ import QuickNav from "@/components/QuickNav.vue";
|
|||||||
import EntityIcon from "@/components/EntityIcon.vue";
|
import EntityIcon from "@/components/EntityIcon.vue";
|
||||||
import ProjectIcon from "@/components/ProjectIcon.vue";
|
import ProjectIcon from "@/components/ProjectIcon.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { Account } from "@/db/tables/accounts";
|
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import {
|
import {
|
||||||
BLANK_GENERIC_SERVER_RECORD,
|
|
||||||
GenericCredWrapper,
|
GenericCredWrapper,
|
||||||
getHeaders,
|
|
||||||
GiveSummaryRecord,
|
GiveSummaryRecord,
|
||||||
GiveVerifiableCredential,
|
GiveVerifiableCredential,
|
||||||
OfferSummaryRecord,
|
OfferSummaryRecord,
|
||||||
@@ -504,6 +501,7 @@ import {
|
|||||||
PlanSummaryRecord,
|
PlanSummaryRecord,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -559,10 +557,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
this.isRegistered = !!settings.isRegistered;
|
this.isRegistered = !!settings.isRegistered;
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const accounts = accountsDB.accounts;
|
|
||||||
const accountsArr: Account[] = await accounts?.toArray();
|
|
||||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
|
||||||
|
|
||||||
const pathParam = window.location.pathname.substring("/project/".length);
|
const pathParam = window.location.pathname.substring("/project/".length);
|
||||||
if (pathParam) {
|
if (pathParam) {
|
||||||
@@ -593,7 +588,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
|
|
||||||
const url =
|
const url =
|
||||||
this.apiServer + "/api/claim/byHandle/" + encodeURIComponent(projectId);
|
this.apiServer + "/api/claim/byHandle/" + encodeURIComponent(projectId);
|
||||||
const headers = await getHeaders(userDid);
|
const headers = await serverUtil.getHeaders(userDid);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await this.axios.get(url, { headers });
|
const resp = await this.axios.get(url, { headers });
|
||||||
@@ -698,7 +693,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
}
|
}
|
||||||
const givesInUrl = givesUrl + postfix;
|
const givesInUrl = givesUrl + postfix;
|
||||||
|
|
||||||
const headers = await getHeaders(this.activeDid);
|
const headers = await serverUtil.getHeaders(this.activeDid);
|
||||||
try {
|
try {
|
||||||
const resp = await this.axios.get(givesInUrl, { headers });
|
const resp = await this.axios.get(givesInUrl, { headers });
|
||||||
if (resp.status === 200 && resp.data.data) {
|
if (resp.status === 200 && resp.data.data) {
|
||||||
@@ -745,7 +740,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
}
|
}
|
||||||
const offersInUrl = offersUrl + postfix;
|
const offersInUrl = offersUrl + postfix;
|
||||||
|
|
||||||
const headers = await getHeaders(this.activeDid);
|
const headers = await serverUtil.getHeaders(this.activeDid);
|
||||||
try {
|
try {
|
||||||
const resp = await this.axios.get(offersInUrl, { headers });
|
const resp = await this.axios.get(offersInUrl, { headers });
|
||||||
if (resp.status === 200 && resp.data.data) {
|
if (resp.status === 200 && resp.data.data) {
|
||||||
@@ -793,7 +788,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
}
|
}
|
||||||
const fulfillsInUrl = fulfillsUrl + postfix;
|
const fulfillsInUrl = fulfillsUrl + postfix;
|
||||||
|
|
||||||
const headers = await getHeaders(this.activeDid);
|
const headers = await serverUtil.getHeaders(this.activeDid);
|
||||||
try {
|
try {
|
||||||
const resp = await this.axios.get(fulfillsInUrl, { headers });
|
const resp = await this.axios.get(fulfillsInUrl, { headers });
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
@@ -841,7 +836,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
}
|
}
|
||||||
const providedByFullUrl = providedByUrl + postfix;
|
const providedByFullUrl = providedByUrl + postfix;
|
||||||
|
|
||||||
const headers = await getHeaders(this.activeDid);
|
const headers = await serverUtil.getHeaders(this.activeDid);
|
||||||
try {
|
try {
|
||||||
const resp = await this.axios.get(providedByFullUrl, { headers });
|
const resp = await this.axios.get(providedByFullUrl, { headers });
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
@@ -945,7 +940,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
|
|
||||||
checkIsFulfillable(offer: OfferSummaryRecord) {
|
checkIsFulfillable(offer: OfferSummaryRecord) {
|
||||||
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
|
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
|
||||||
...BLANK_GENERIC_SERVER_RECORD,
|
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
|
||||||
claim: offer.fullClaim,
|
claim: offer.fullClaim,
|
||||||
claimType: "Offer",
|
claimType: "Offer",
|
||||||
issuer: offer.offeredByDid,
|
issuer: offer.offeredByDid,
|
||||||
@@ -955,7 +950,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
|
|
||||||
onClickFulfillGiveToOffer(offer: OfferSummaryRecord) {
|
onClickFulfillGiveToOffer(offer: OfferSummaryRecord) {
|
||||||
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
|
const offerRecord: GenericCredWrapper<OfferVerifiableCredential> = {
|
||||||
...BLANK_GENERIC_SERVER_RECORD,
|
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
|
||||||
claim: offer.fullClaim,
|
claim: offer.fullClaim,
|
||||||
issuer: offer.offeredByDid,
|
issuer: offer.offeredByDid,
|
||||||
};
|
};
|
||||||
@@ -1003,7 +998,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
*/
|
*/
|
||||||
checkIsConfirmable(give: GiveSummaryRecord, confirmerIdList?: string[]) {
|
checkIsConfirmable(give: GiveSummaryRecord, confirmerIdList?: string[]) {
|
||||||
const giveDetails: GenericCredWrapper<GiveVerifiableCredential> = {
|
const giveDetails: GenericCredWrapper<GiveVerifiableCredential> = {
|
||||||
...BLANK_GENERIC_SERVER_RECORD,
|
...serverUtil.BLANK_GENERIC_SERVER_RECORD,
|
||||||
claim: give.fullClaim,
|
claim: give.fullClaim,
|
||||||
claimType: "GiveAction",
|
claimType: "GiveAction",
|
||||||
issuer: give.issuerDid,
|
issuer: give.issuerDid,
|
||||||
|
|||||||
@@ -263,8 +263,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
|||||||
import { Router } from "vue-router";
|
import { Router } from "vue-router";
|
||||||
|
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import * as libsUtil from "@/libs/util";
|
|
||||||
import EntityIcon from "@/components/EntityIcon.vue";
|
import EntityIcon from "@/components/EntityIcon.vue";
|
||||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
@@ -280,6 +279,7 @@ import {
|
|||||||
OfferSummaryRecord,
|
OfferSummaryRecord,
|
||||||
PlanData,
|
PlanData,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import * as libsUtil from "@/libs/util";
|
||||||
import { OnboardPage } from "@/libs/util";
|
import { OnboardPage } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -328,9 +328,7 @@ export default class ProjectsView extends Vue {
|
|||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await libsUtil.retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
|
|
||||||
if (!settings.finishedOnboarding) {
|
if (!settings.finishedOnboarding) {
|
||||||
(this.$refs.onboardingDialog as OnboardingDialog).open(
|
(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.");
|
console.error("No accounts found.");
|
||||||
this.errNote("You need an identifier to load your projects.");
|
this.errNote("You need an identifier to load your projects.");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ import { Router } from "vue-router";
|
|||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import {
|
import {
|
||||||
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ import GiftedDialog from "@/components/GiftedDialog.vue";
|
|||||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import {
|
import {
|
||||||
didInfo,
|
didInfo,
|
||||||
@@ -89,6 +89,7 @@ import {
|
|||||||
getNewOffersToUserProjects,
|
getNewOffersToUserProjects,
|
||||||
OfferToPlanSummaryRecord,
|
OfferToPlanSummaryRecord,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
|
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
|
||||||
@@ -119,11 +120,7 @@ export default class RecentOffersToUserView extends Vue {
|
|||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
if (allAccounts.length > 0) {
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
}
|
|
||||||
|
|
||||||
const offersToUserProjectsData = await getNewOffersToUserProjects(
|
const offersToUserProjectsData = await getNewOffersToUserProjects(
|
||||||
this.axios,
|
this.axios,
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ import EntityIcon from "@/components/EntityIcon.vue";
|
|||||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
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 { Contact } from "@/db/tables/contacts";
|
||||||
import {
|
import {
|
||||||
didInfo,
|
didInfo,
|
||||||
@@ -82,6 +82,7 @@ import {
|
|||||||
getNewOffersToUser,
|
getNewOffersToUser,
|
||||||
OfferSummaryRecord,
|
OfferSummaryRecord,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
|
components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav },
|
||||||
@@ -111,11 +112,7 @@ export default class RecentOffersToUserView extends Vue {
|
|||||||
|
|
||||||
this.allContacts = await db.contacts.toArray();
|
this.allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
await accountsDB.open();
|
this.allMyDids = await retrieveAccountDids();
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
if (allAccounts.length > 0) {
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
}
|
|
||||||
|
|
||||||
const offersToUserData = await getNewOffersToUser(
|
const offersToUserData = await getNewOffersToUser(
|
||||||
this.axios,
|
this.axios,
|
||||||
|
|||||||
@@ -99,14 +99,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as R from "ramda";
|
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { Account } from "@/db/tables/accounts";
|
import { Account } from "@/db/tables/accounts";
|
||||||
|
import {
|
||||||
|
retrieveAccountCount,
|
||||||
|
retrieveFullyDecryptedAccount,
|
||||||
|
} from "@/libs/util";
|
||||||
|
|
||||||
@Component({ components: { QuickNav } })
|
@Component({ components: { QuickNav } })
|
||||||
export default class SeedBackupView extends Vue {
|
export default class SeedBackupView extends Vue {
|
||||||
@@ -124,10 +127,8 @@ export default class SeedBackupView extends Vue {
|
|||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
const activeDid = settings.activeDid || "";
|
const activeDid = settings.activeDid || "";
|
||||||
|
|
||||||
await accountsDB.open();
|
this.numAccounts = await retrieveAccountCount();
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
this.activeAccount = await retrieveFullyDecryptedAccount(activeDid);
|
||||||
this.numAccounts = accounts.length;
|
|
||||||
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
console.error("Got an error loading an identifier:", err);
|
console.error("Got an error loading an identifier:", err);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as R from "ramda";
|
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { Router } from "vue-router";
|
import { Router } from "vue-router";
|
||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
@@ -49,8 +48,9 @@ import { useClipboard } from "@vueuse/core";
|
|||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { generateEndorserJwtForAccount } from "@/libs/endorserServer";
|
import { generateEndorserJwtForAccount } from "@/libs/endorserServer";
|
||||||
|
import { retrieveAccountMetadata } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { QuickNav, TopMessage },
|
components: { QuickNav, TopMessage },
|
||||||
@@ -65,9 +65,7 @@ export default class ShareMyContactInfoView extends Vue {
|
|||||||
const isRegistered = !!settings.isRegistered;
|
const isRegistered = !!settings.isRegistered;
|
||||||
const profileImageUrl = settings.profileImageUrl || "";
|
const profileImageUrl = settings.profileImageUrl || "";
|
||||||
|
|
||||||
await accountsDB.open();
|
const account = await retrieveAccountMetadata(activeDid);
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
|
||||||
const account = R.find((acc) => acc.did === activeDid, accounts);
|
|
||||||
|
|
||||||
const numContacts = await db.contacts.count();
|
const numContacts = await db.contacts.count();
|
||||||
|
|
||||||
|
|||||||
@@ -92,8 +92,11 @@ import { Component, Vue } from "vue-facing-decorator";
|
|||||||
import { Router } from "vue-router";
|
import { Router } from "vue-router";
|
||||||
|
|
||||||
import { AppString, PASSKEYS_ENABLED } from "@/constants/app";
|
import { AppString, PASSKEYS_ENABLED } from "@/constants/app";
|
||||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import { registerSaveAndActivatePasskey } from "@/libs/util";
|
import {
|
||||||
|
registerSaveAndActivatePasskey,
|
||||||
|
retrieveAccountCount,
|
||||||
|
} from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {},
|
components: {},
|
||||||
@@ -108,8 +111,7 @@ export default class StartView extends Vue {
|
|||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
this.givenName = settings.firstName || "";
|
this.givenName = settings.firstName || "";
|
||||||
|
|
||||||
await accountsDB.open();
|
this.numAccounts = await retrieveAccountCount();
|
||||||
this.numAccounts = await accountsDB.accounts.count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onClickNewSeed() {
|
public onClickNewSeed() {
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ import { Router } from "vue-router";
|
|||||||
|
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { AppString, NotificationIface } from "@/constants/app";
|
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 * as vcLib from "@/libs/crypto/vc";
|
||||||
import {
|
import {
|
||||||
PeerSetup,
|
PeerSetup,
|
||||||
@@ -258,7 +258,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
AccountKeyInfo,
|
AccountKeyInfo,
|
||||||
blobToBase64,
|
blobToBase64,
|
||||||
getAccount,
|
retrieveAccountMetadata,
|
||||||
registerAndSavePasskey,
|
registerAndSavePasskey,
|
||||||
SHARED_PHOTO_BASE64_KEY,
|
SHARED_PHOTO_BASE64_KEY,
|
||||||
} from "@/libs/util";
|
} from "@/libs/util";
|
||||||
@@ -294,11 +294,7 @@ export default class Help extends Vue {
|
|||||||
this.activeDid = settings.activeDid || "";
|
this.activeDid = settings.activeDid || "";
|
||||||
this.userName = settings.firstName;
|
this.userName = settings.firstName;
|
||||||
|
|
||||||
await accountsDB.open();
|
const account = await retrieveAccountMetadata(this.activeDid);
|
||||||
const account: { identity?: string } | undefined = await accountsDB.accounts
|
|
||||||
.where("did")
|
|
||||||
.equals(this.activeDid)
|
|
||||||
.first();
|
|
||||||
if (this.activeDid) {
|
if (this.activeDid) {
|
||||||
if (account) {
|
if (account) {
|
||||||
this.credIdHex = account.passkeyCredIdHex as string;
|
this.credIdHex = account.passkeyCredIdHex as string;
|
||||||
@@ -368,7 +364,7 @@ export default class Help extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createJwtSimplewebauthn() {
|
public async createJwtSimplewebauthn() {
|
||||||
const account: AccountKeyInfo | undefined = await getAccount(
|
const account: AccountKeyInfo | undefined = await retrieveAccountMetadata(
|
||||||
this.activeDid || "",
|
this.activeDid || "",
|
||||||
);
|
);
|
||||||
if (!vcLib.isFromPasskey(account)) {
|
if (!vcLib.isFromPasskey(account)) {
|
||||||
@@ -385,7 +381,7 @@ export default class Help extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async createJwtNavigator() {
|
public async createJwtNavigator() {
|
||||||
const account: AccountKeyInfo | undefined = await getAccount(
|
const account: AccountKeyInfo | undefined = await retrieveAccountMetadata(
|
||||||
this.activeDid || "",
|
this.activeDid || "",
|
||||||
);
|
);
|
||||||
if (!vcLib.isFromPasskey(account)) {
|
if (!vcLib.isFromPasskey(account)) {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ self.addEventListener("push", function (event) {
|
|||||||
self.addEventListener("message", (event) => {
|
self.addEventListener("message", (event) => {
|
||||||
logConsoleAndDb("Service worker got a message...", event);
|
logConsoleAndDb("Service worker got a message...", event);
|
||||||
if (event.data && event.data.type === "SEND_LOCAL_DATA") {
|
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 });
|
event.ports[0].postMessage({ success: true });
|
||||||
}
|
}
|
||||||
logConsoleAndDb("Service worker posted a message.");
|
logConsoleAndDb("Service worker posted a message.");
|
||||||
|
|||||||
@@ -515,6 +515,7 @@ async function getNotificationCount() {
|
|||||||
|
|
||||||
const identity = activeAccount && activeAccount["identity"];
|
const identity = activeAccount && activeAccount["identity"];
|
||||||
if (identity && "secret" in self) {
|
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 secret = self.secret;
|
||||||
const secretUint8Array = self.decodeBase64(secret);
|
const secretUint8Array = self.decodeBase64(secret);
|
||||||
const messageWithNonceAsUint8Array = self.decodeBase64(identity);
|
const messageWithNonceAsUint8Array = self.decodeBase64(identity);
|
||||||
|
|||||||
Reference in New Issue
Block a user