Browse Source

separate account from other data for backup/restore

kb/add-usage-guide
Trent Larson 2 years ago
parent
commit
45b54db01e
  1. 4
      README.md
  2. 41
      src/db/index.ts
  3. 26
      src/db/tables/accounts.ts
  4. 11
      src/db/tables/contacts.ts
  5. 13
      src/db/tables/settings.ts
  6. 6
      src/router/index.ts
  7. 6
      src/test/index.ts
  8. 33
      src/views/AccountViewView.vue
  9. 10
      src/views/ContactsView.vue
  10. 8
      src/views/ImportAccountView.vue
  11. 6
      src/views/NewEditAccountView.vue
  12. 14
      src/views/NewEditProjectView.vue
  13. 8
      src/views/ProjectViewView.vue
  14. 8
      src/views/ProjectsView.vue

4
README.md

@ -48,9 +48,9 @@ On the test server, User #0 has rights to register others, so you can start play
- Register someone else under User #0 on the `/account` page:
* Edit the `src/views/AccountViewView.vue` file and uncomment the lines referring to "test".
* Edit the `src/views/AccountViewView.vue` file and uncomment the lines referring to "testServerRegisterUser".
* Use the [Vue Devtools browser extension](https://devtools.vuejs.org/) and type this into the console: `$vm.ctx.testRegisterUser()`
* Visit the `/account` page, open the [Vue Devtools browser extension](https://devtools.vuejs.org/), select a component, then type this into the console: `$vm.ctx.testRegisterUser()`

41
src/db/index.ts

@ -1,17 +1,19 @@
import BaseDexie, { Table } from "dexie";
import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon";
import { Account, AccountsSchema } from "./tables/accounts";
import { Contact, ContactsSchema } from "./tables/contacts";
import {
Account,
AccountsSchema,
Contact,
ContactsSchema,
MASTER_SETTINGS,
MASTER_SETTINGS_KEY,
Settings,
SettingsSchema,
} from "./tables";
} from "./tables/settings";
type AllTables = {
// a separate DB because the seed is super-sensitive data
type SensitiveTables = {
accounts: Table<Account>;
};
type NonsensitiveTables = {
contacts: Table<Contact>;
settings: Table<Settings>;
};
@ -24,15 +26,14 @@ type AllTables = {
*
* https://9to5answer.com/how-to-bypass-warning-unexpected-any-specify-a-different-type-typescript-eslint-no-explicit-any
*/
type DexieTables = AllTables;
export type Dexie<T extends unknown = DexieTables> = BaseDexie & T;
export const db = new BaseDexie("KickStart") as Dexie;
const AllSchemas = Object.assign(
{},
AccountsSchema,
ContactsSchema,
SettingsSchema
);
export type SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
export const accountsDB = new BaseDexie("KickStartSensitive") as SensitiveDexie;
const SensitiveSchemas = Object.assign({}, AccountsSchema);
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
BaseDexie & T;
export const db = new BaseDexie("KickStart") as NonsensitiveDexie;
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);
/**
* Needed to enable a special webpack setting to allow *await* below:
@ -48,11 +49,13 @@ if (localStorage.getItem("secret") == null) {
}
//console.log("IndexedDB Encryption Secret:", secret);
encrypted(db, { secretKey: secret });
db.version(1).stores(AllSchemas);
encrypted(accountsDB, { secretKey: secret });
accountsDB.version(1).stores(SensitiveSchemas);
db.version(1).stores(NonsensitiveSchemas);
// 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 });
db.settings.add({ id: MASTER_SETTINGS_KEY });
});

26
src/db/tables/index.ts → src/db/tables/accounts.ts

@ -13,29 +13,3 @@ 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;

11
src/db/tables/contacts.ts

@ -0,0 +1,11 @@
export interface Contact {
did: string;
name?: string;
publicKeyBase64?: string;
seesMe?: boolean;
registered?: boolean;
}
export const ContactsSchema = {
contacts: "++did, name, publicKeyBase64, registered, seesMe",
};

13
src/db/tables/settings.ts

@ -0,0 +1,13 @@
// a singleton
export type Settings = {
id: number;
firstName?: string;
lastName?: string;
showContactGivesInline?: boolean;
};
export const SettingsSchema = {
settings: "id",
};
export const MASTER_SETTINGS_KEY = 1;

6
src/router/index.ts

@ -1,5 +1,5 @@
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { db } from "@/db";
import { accountsDB } from "@/db";
const routes: Array<RouteRecordRaw> = [
{
@ -8,8 +8,8 @@ const routes: Array<RouteRecordRaw> = [
component: () =>
import(/* webpackChunkName: "start" */ "../views/DiscoverView.vue"),
beforeEnter: async (to, from, next) => {
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts > 0) {
next();
} else {

6
src/test/index.ts

@ -1,7 +1,7 @@
import axios from "axios";
import * as didJwt from "did-jwt";
import { AppString } from "@/constants/app";
import { db } from "../db";
import { accountsDB } from "../db";
import { SERVICE_ID } from "../libs/veramo/setup";
import { deriveAddress, newIdentifier } from "../libs/crypto";
@ -13,8 +13,8 @@ export async function testServerRegisterUser() {
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
await db.open();
const accounts = await db.accounts.toArray();
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const thisIdentity = JSON.parse(accounts[0].identity);
// Make a claim

33
src/views/AccountViewView.vue

@ -200,17 +200,17 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { useClipboard } from "@vueuse/core";
import { db } from "@/db";
import { MASTER_SETTINGS } from "@/db/tables";
import { db, accountsDB } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
//import { testServerRegisterUser } from "../test";
import { testServerRegisterUser } from "../test";
@Options({
components: {},
})
export default class AccountViewView extends Vue {
// This registers current user in vue plugin with: $vm.ctx.testRegisterUser()
//testRegisterUser = testServerRegisterUser;
testRegisterUser = testServerRegisterUser;
address = "";
firstName = "";
@ -224,16 +224,17 @@ export default class AccountViewView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
await db.open();
try {
const settings = await db.settings.get(MASTER_SETTINGS);
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
if (settings) {
this.firstName = settings.firstName || "";
this.lastName = settings.lastName || "";
this.showContactGives = !!settings.showContactGivesInline;
}
const numAccounts = await db.accounts.count();
await accountsDB.open();
const numAccounts = await accountsDB.accounts.count();
if (numAccounts === 0) {
let privateHex = "";
this.mnemonic = generateSeed();
@ -246,7 +247,7 @@ export default class AccountViewView extends Vue {
privateHex,
this.derivationPath
);
await db.accounts.add({
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: this.derivationPath,
identity: JSON.stringify(newId),
@ -254,6 +255,12 @@ export default class AccountViewView extends Vue {
publicKeyHex: newId.keys[0].publicKeyHex,
});
}
const accounts = await accountsDB.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.address = identity.did;
this.publicHex = identity.keys[0].publicKeyHex;
this.derivationPath = identity.keys[0].meta.derivationPath;
} catch (err) {
this.alertMessage =
"Clear your cache and start over (after data backup). See console log for more info.";
@ -261,21 +268,15 @@ export default class AccountViewView extends Vue {
this.alertTitle = "Error Creating Account";
this.isAlertVisible = true;
}
const accounts = await db.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.address = identity.did;
this.publicHex = identity.keys[0].publicKeyHex;
this.derivationPath = identity.keys[0].meta.derivationPath;
}
public async toggleShowContactAmounts() {
this.showContactGives = !this.showContactGives;
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS);
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
if (settings) {
db.settings.update(MASTER_SETTINGS, {
db.settings.update(MASTER_SETTINGS_KEY, {
showContactGivesInline: this.showContactGives,
});
}

10
src/views/ContactsView.vue

@ -140,8 +140,8 @@ import { Options, Vue } from "vue-class-component";
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";
import { accountsDB, db } from "../db";
import { Contact } from "../db/tables/contacts";
export interface GiveVerifiableCredential {
"@context": string;
@ -169,9 +169,11 @@ export default class ContactsView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
await db.open();
const accounts = await db.accounts.toArray();
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
this.identity = JSON.parse(accounts[0].identity);
await db.open();
this.contacts = await db.contacts.toArray();
const params = new URLSearchParams(window.location.search);

8
src/views/ImportAccountView.vue

@ -45,7 +45,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { deriveAddress, newIdentifier } from "../libs/crypto";
import { db } from "@/db";
import { accountsDB } from "@/db";
@Options({
components: {},
@ -75,10 +75,10 @@ export default class ImportAccountView extends Vue {
);
try {
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts === 0) {
await db.accounts.add({
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: this.derivationPath,
identity: JSON.stringify(newId),

6
src/views/NewEditAccountView.vue

@ -51,7 +51,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { db } from "@/db";
import { MASTER_SETTINGS } from "@/db/tables";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
@Options({
components: {},
@ -69,7 +69,7 @@ export default class NewEditAccountView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS);
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
if (settings) {
this.firstName = settings.firstName || "";
this.lastName = settings.lastName || "";
@ -77,7 +77,7 @@ export default class NewEditAccountView extends Vue {
}
onClickSaveChanges() {
db.settings.update(MASTER_SETTINGS, {
db.settings.update(MASTER_SETTINGS_KEY, {
firstName: this.firstName,
lastName: this.lastName,
});

14
src/views/NewEditProjectView.vue

@ -78,7 +78,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { AppString } from "@/constants/app";
import { db } from "../db";
import { accountsDB } from "../db";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import * as didJwt from "did-jwt";
import { IIdentifier } from "@veramo/core";
@ -112,12 +112,12 @@ export default class NewEditProjectView extends Vue {
if (this.projectId === "") {
console.log("This is a new project");
} else {
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts === 0) {
console.log("Problem! Should have a profile!");
} else {
const accounts = await db.accounts.toArray();
const accounts = await accountsDB.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.LoadProject(identity);
}
@ -254,12 +254,12 @@ export default class NewEditProjectView extends Vue {
public async onSaveProjectClick() {
this.isHiddenSave = true;
this.isHiddenSpinner = false;
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts === 0) {
console.log("Problem! Should have a profile!");
} else {
const accounts = await db.accounts.toArray();
const accounts = await accountsDB.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.SaveProject(identity);
}

8
src/views/ProjectViewView.vue

@ -146,7 +146,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { accessToken } from "@/libs/crypto";
import { db } from "../db";
import { accountsDB } from "../db";
import { IIdentifier } from "@veramo/core";
import { AppString } from "@/constants/app";
import * as moment from "moment";
@ -224,12 +224,12 @@ export default class ProjectViewView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts === 0) {
console.log("Problem! Should have a profile!");
} else {
const accounts = await db.accounts.toArray();
const accounts = await accountsDB.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.LoadProject(identity);
}

8
src/views/ProjectsView.vue

@ -103,7 +103,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { accessToken } from "@/libs/crypto";
import { db } from "../db";
import { accountsDB } from "../db";
import { IIdentifier } from "@veramo/core";
import { AppString } from "@/constants/app";
@ -155,12 +155,12 @@ export default class ProjectsView extends Vue {
// 'created' hook runs when the Vue instance is first created
async created() {
await db.open();
const num_accounts = await db.accounts.count();
await accountsDB.open();
const num_accounts = await accountsDB.accounts.count();
if (num_accounts === 0) {
console.log("Problem! Should have a profile!");
} else {
const accounts = await db.accounts.toArray();
const accounts = await accountsDB.accounts.toArray();
const identity = JSON.parse(accounts[0].identity);
this.LoadProjects(identity);
}

Loading…
Cancel
Save