diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index ffd2870b7..000000000 --- a/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -nodejs 16.18.0 diff --git a/README.md b/README.md index 31291bc5e..9b43e43fb 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ New users require registration. This can be done with a claim payload like this const vcClaim = { "@context": "https://schema.org", "@type": "RegisterAction", - agent: { did: identity0.did }, + agent: { identifier: identity0.did }, object: SERVICE_ID, - participant: { did: newIdentity.did }, + participant: { identifier: newIdentity.did }, }; ``` @@ -62,6 +62,14 @@ See [this page](openssl_signing_console.rst) See [Configuration Reference](https://cli.vuejs.org/config/). +## Dependencies + +See https://tea.xyz + +| Project | Version | +| ---------- | --------- | +| nodejs.org | ^16.0.0 | +| npmjs.com | ^8.0.0 | ## Other diff --git a/project.yaml b/project.yaml index a0f3f1310..8e2141f53 100644 --- a/project.yaml +++ b/project.yaml @@ -12,7 +12,9 @@ - replace user-affecting console.logs with error messages (eg. catches) - contacts v1: - - parse input correctly (with CSV lib and not commas) + - .5 make advanced "show/hide amounts" button into a nice UI toggle + - .2 show error to user when adding a duplicate contact + - parse input more robustly (with CSV lib and not commas) - commit screen diff --git a/src/db/index.ts b/src/db/index.ts index 67b306193..dc7e911b6 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,11 +1,19 @@ import BaseDexie, { Table } from "dexie"; import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon"; -import { accountsSchema, Account } from "./tables/accounts"; -import { contactsSchema, Contact } from "./tables/contacts"; +import { + Account, + AccountsSchema, + Contact, + ContactsSchema, + MASTER_SETTINGS, + Settings, + SettingsSchema, +} from "./tables"; type AllTables = { accounts: Table; contacts: Table; + settings: Table; }; /** @@ -18,7 +26,13 @@ type AllTables = { */ type DexieTables = AllTables; export type Dexie = BaseDexie & T; -export const db = new BaseDexie("kickStarter") as Dexie; +export const db = new BaseDexie("KickStart") as Dexie; +const AllSchemas = Object.assign( + {}, + AccountsSchema, + ContactsSchema, + SettingsSchema +); /** * Needed to enable a special webpack setting to allow *await* below: @@ -32,7 +46,13 @@ const secret = if (localStorage.getItem("secret") == null) { localStorage.setItem("secret", secret); } -console.log("DB encryption secretKey:", secret); + +//console.log("IndexedDB Encryption Secret:", secret); encrypted(db, { secretKey: secret }); -db.version(1).stores(accountsSchema); -db.version(2).stores(contactsSchema); +db.version(1).stores(AllSchemas); + +// initialize, a la https://dexie.org/docs/Tutorial/Design#the-populate-event +db.on("populate", function () { + // ensure there's an initial entry for settings + db.settings.add({ id: MASTER_SETTINGS }); +}); diff --git a/src/db/tables/accounts.ts b/src/db/tables/accounts.ts deleted file mode 100644 index b78982f29..000000000 --- a/src/db/tables/accounts.ts +++ /dev/null @@ -1,12 +0,0 @@ -export type Account = { - id?: number; - publicKey: string; - mnemonic: string; - identity: string; - dateCreated: number; -}; - -// mark encrypted field by starting with a $ character -export const accountsSchema = { - accounts: "++id, publicKey, $mnemonic, $identity, dateCreated", -}; diff --git a/src/db/tables/contacts.ts b/src/db/tables/contacts.ts deleted file mode 100644 index a19790236..000000000 --- a/src/db/tables/contacts.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface Contact { - did: string; - name?: string; - publicKeyBase64?: string; - seesMe?: boolean; - registered?: boolean; -} - -// mark encrypted field by starting with a $ character -export const contactsSchema = { - contacts: "++did, name, publicKeyBase64, seesMe, registered", -}; diff --git a/src/db/tables/index.ts b/src/db/tables/index.ts new file mode 100644 index 000000000..6b7b62fec --- /dev/null +++ b/src/db/tables/index.ts @@ -0,0 +1,41 @@ +export type Account = { + id?: number; // auto-generated by Dexie + dateCreated: string; + derivationPath: string; + identity: string; + publicKeyHex: string; + mnemonic: string; +}; + +// mark encrypted field by starting with a $ character +// see https://github.com/PVermeer/dexie-addon-suite-monorepo/tree/master/packages/dexie-encrypted-addon +export const AccountsSchema = { + accounts: + "++id, dateCreated, derivationPath, $identity, $mnemonic, publicKeyHex", +}; + +export interface Contact { + did: string; + name?: string; + publicKeyBase64?: string; + seesMe?: boolean; + registered?: boolean; +} + +export const ContactsSchema = { + contacts: "++did, name, publicKeyBase64, registered, seesMe", +}; + +// a singleton +export type Settings = { + id: number; + firstName?: string; + lastName?: string; + showContactGivesInline?: boolean; +}; + +export const SettingsSchema = { + settings: "id", +}; + +export const MASTER_SETTINGS = 1; diff --git a/src/libs/crypto/index.ts b/src/libs/crypto/index.ts index a760295d4..bec075e3a 100644 --- a/src/libs/crypto/index.ts +++ b/src/libs/crypto/index.ts @@ -65,7 +65,7 @@ export const deriveAddress = ( * * @return {*} {string} */ -export const createIdentifier = (): string => { +export const generateSeed = (): string => { const entropy: Uint8Array = getRandomBytesSync(32); const mnemonic = entropyToMnemonic(entropy, wordlist); @@ -87,9 +87,9 @@ export const accessToken = async (identifier: IIdentifier) => { const nowEpoch = Math.floor(Date.now() / 1000); const endEpoch = nowEpoch + 60; // add one minute - const uportTokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; + const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R - const jwt: string = await didJwt.createJWT(uportTokenPayload, { + const jwt: string = await didJwt.createJWT(tokenPayload, { alg, issuer: did, signer, diff --git a/src/router/index.ts b/src/router/index.ts index 3147ab42d..376cfd7df 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,5 +1,5 @@ import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router"; -import { useAppStore } from "../store/app"; +import { db } from "@/db"; const routes: Array = [ { @@ -7,10 +7,10 @@ const routes: Array = [ name: "home", component: () => import(/* webpackChunkName: "start" */ "../views/DiscoverView.vue"), - beforeEnter: (to, from, next) => { - const appStore = useAppStore(); - const isAuthenticated = appStore.condition === "registered"; - if (isAuthenticated) { + beforeEnter: async (to, from, next) => { + await db.open(); + const num_accounts = await db.accounts.count(); + if (num_accounts > 0) { next(); } else { next({ name: "start" }); diff --git a/src/store/account.ts b/src/store/account.ts deleted file mode 100644 index 79c83407a..000000000 --- a/src/store/account.ts +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-check -import { defineStore } from "pinia"; - -export const useAccountStore = defineStore({ - id: "account", - state: () => ({ - account: JSON.parse( - typeof localStorage["account"] == "undefined" - ? null - : localStorage["account"] - ), - }), - getters: { - firstName: (state) => state.account.firstName, - lastName: (state) => state.account.lastName, - }, - actions: { - reset() { - localStorage.removeItem("account"); - }, - }, -}); diff --git a/src/store/app.ts b/src/store/app.ts index 0aefd7e09..0ed6c46b2 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -4,30 +4,15 @@ import { defineStore } from "pinia"; export const useAppStore = defineStore({ id: "app", state: () => ({ - _condition: - typeof localStorage["condition"] == "undefined" - ? "uninitialized" - : localStorage["condition"], - _lastView: - typeof localStorage["lastView"] == "undefined" - ? "/start" - : localStorage["lastView"], _projectId: typeof localStorage.getItem("projectId") === "undefined" ? "" : localStorage.getItem("projectId"), }), getters: { - condition: (state) => state._condition, projectId: (state): string => state._projectId as string, }, actions: { - reset() { - localStorage.removeItem("condition"); - }, - setCondition(newCondition: string) { - localStorage.setItem("condition", newCondition); - }, async setProjectId(newProjectId: string) { localStorage.setItem("projectId", newProjectId); }, diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index d67e3a25f..01bdf4906 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -111,8 +111,8 @@
Derivation Path
{{ UPORT_ROOT_DERIVATION_PATH }} - @@ -168,86 +168,158 @@ + +

Advanced

+ +
+ +
+ +
+ +

{{ alertTitle }}

+

{{ alertMessage }}

+
diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index 34fcb2b85..4d89c7aaa 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -141,7 +141,7 @@ import { AppString } from "@/constants/app"; import { accessToken, SimpleSigner } from "@/libs/crypto"; import { IIdentifier } from "@veramo/core"; import { db } from "../db"; -import { Contact } from "../db/tables/contacts"; +import { Contact } from "../db/tables"; export interface GiveVerifiableCredential { "@context": string; diff --git a/src/views/ImportAccountView.vue b/src/views/ImportAccountView.vue index d16db3194..73a7359b4 100644 --- a/src/views/ImportAccountView.vue +++ b/src/views/ImportAccountView.vue @@ -46,7 +46,6 @@ import { Options, Vue } from "vue-class-component"; import { deriveAddress, newIdentifier } from "../libs/crypto"; import { db } from "@/db"; -import { useAppStore } from "@/store/app"; @Options({ components: {}, @@ -56,7 +55,7 @@ export default class ImportAccountView extends Vue { address = ""; privateHex = ""; publicHex = ""; - UPORT_ROOT_DERIVATION_PATH = ""; + derivationPath = ""; public onCancelClick() { this.$router.back(); @@ -65,33 +64,28 @@ export default class ImportAccountView extends Vue { public async from_mnemonic() { const mne: string = this.mnemonic.trim().toLowerCase(); if (this.mnemonic.trim().length > 0) { - [ - this.address, - this.privateHex, - this.publicHex, - this.UPORT_ROOT_DERIVATION_PATH, - ] = deriveAddress(mne); + [this.address, this.privateHex, this.publicHex, this.derivationPath] = + deriveAddress(mne); const newId = newIdentifier( this.address, this.publicHex, this.privateHex, - this.UPORT_ROOT_DERIVATION_PATH + this.derivationPath ); try { await db.open(); const num_accounts = await db.accounts.count(); if (num_accounts === 0) { - console.log("..."); await db.accounts.add({ - publicKey: newId.keys[0].publicKeyHex, - mnemonic: mne, + dateCreated: new Date().toISOString(), + derivationPath: this.derivationPath, identity: JSON.stringify(newId), - dateCreated: new Date().getTime(), + mnemonic: mne, + publicKeyHex: newId.keys[0].publicKeyHex, }); } - useAppStore().setCondition("registered"); this.$router.push({ name: "account" }); } catch (err) { console.log("Error!"); diff --git a/src/views/NewEditAccountView.vue b/src/views/NewEditAccountView.vue index 55545b3e7..d63d401c1 100644 --- a/src/views/NewEditAccountView.vue +++ b/src/views/NewEditAccountView.vue @@ -50,6 +50,8 @@