forked from trent_larson/crowd-funder-for-time-pwa
Changes: - Move v-model directives before other attributes - Move v-bind directives before event handlers - Reorder attributes for better readability - Fix template attribute ordering across components - Improve eslint rules - add default vite config for testing (handles nostr error too) This follows Vue.js style guide recommendations for attribute ordering and improves template consistency.
164 lines
5.3 KiB
Vue
164 lines
5.3 KiB
Vue
<template>
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
|
<!-- Breadcrumb -->
|
|
<div id="ViewBreadcrumb" class="mb-8">
|
|
<h1 class="text-lg text-center font-light relative px-7">
|
|
<!-- Cancel -->
|
|
<button
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
@click="$router.go(-1)"
|
|
>
|
|
<font-awesome icon="chevron-left"></font-awesome>
|
|
</button>
|
|
Derive from Existing Identity
|
|
</h1>
|
|
</div>
|
|
<!-- Import Account Form -->
|
|
|
|
<div>
|
|
<p class="text-center text-xl mb-4 font-light">
|
|
Will increment the maximum known derivation path from the existing seed.
|
|
</p>
|
|
|
|
<p v-if="didArrays.length > 1">
|
|
Choose existing DIDs from same seed phrase to compute derivation.
|
|
</p>
|
|
<ul class="mb-4">
|
|
<li
|
|
v-for="dids in didArrays"
|
|
:key="dids[0]"
|
|
class="block bg-slate-100 rounded-md flex items-center px-4 py-3 mb-2"
|
|
@click="switchAccount(dids[0])"
|
|
>
|
|
<font-awesome
|
|
v-if="dids[0] == selectedArrayFirstDid"
|
|
icon="circle"
|
|
class="fa-fw text-blue-500 text-xl mr-3"
|
|
></font-awesome>
|
|
<font-awesome
|
|
v-else
|
|
icon="circle"
|
|
class="fa-fw text-slate-400 text-xl mr-3"
|
|
></font-awesome>
|
|
<span class="overflow-hidden">
|
|
<div class="text-sm text-slate-500 truncate">
|
|
<code>{{ dids.join(",") }}</code>
|
|
</div>
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="mt-8">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
|
<button
|
|
class="block w-full text-center text-lg font-bold uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md"
|
|
@click="incrementDerivation()"
|
|
>
|
|
Increment and Import
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="block w-full text-center text-md uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md"
|
|
@click="onCancelClick()"
|
|
>
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { Router, RouteLocationNormalizedLoaded } from "vue-router";
|
|
|
|
import {
|
|
DEFAULT_ROOT_DERIVATION_PATH,
|
|
deriveAddress,
|
|
newIdentifier,
|
|
nextDerivationPath,
|
|
} from "../libs/crypto";
|
|
import { accountsDBPromise, db } from "../db/index";
|
|
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
|
import { retrieveAllFullyDecryptedAccounts } from "../libs/util";
|
|
|
|
@Component({
|
|
components: {},
|
|
})
|
|
export default class ImportAccountView extends Vue {
|
|
$route!: RouteLocationNormalizedLoaded;
|
|
$router!: Router;
|
|
|
|
derivationPath = DEFAULT_ROOT_DERIVATION_PATH;
|
|
didArrays: Array<Array<string>> = [];
|
|
selectedArrayFirstDid = "";
|
|
|
|
async mounted() {
|
|
const accounts = await retrieveAllFullyDecryptedAccounts(); // let's match derived accounts differently so we don't need the private info
|
|
const seedDids: Record<string, Array<string>> = {};
|
|
accounts.forEach((account) => {
|
|
const prevDids: Array<string> = seedDids[account.mnemonic] || [];
|
|
seedDids[account.mnemonic] = prevDids.concat([account.did]);
|
|
});
|
|
this.didArrays = Object.values(seedDids);
|
|
this.selectedArrayFirstDid = this.didArrays[0][0];
|
|
}
|
|
|
|
public onCancelClick() {
|
|
this.$router.back();
|
|
}
|
|
|
|
public switchAccount(did: string) {
|
|
this.selectedArrayFirstDid = did;
|
|
}
|
|
|
|
public async incrementDerivation() {
|
|
// find the maximum derivation path for the selected DIDs
|
|
const selectedArray: Array<string> =
|
|
this.didArrays.find((dids) => dids[0] === this.selectedArrayFirstDid) ||
|
|
[];
|
|
const accountsDB = await accountsDBPromise; // let's match derived accounts differently so we don't need the private info
|
|
const allMatchingAccounts = await accountsDB.accounts
|
|
.where("did")
|
|
.anyOf(...selectedArray)
|
|
.toArray();
|
|
const accountWithMaxDeriv = allMatchingAccounts[0];
|
|
allMatchingAccounts.slice(1).forEach((account) => {
|
|
if (account.derivationPath > accountWithMaxDeriv.derivationPath) {
|
|
accountWithMaxDeriv.derivationPath = account.derivationPath;
|
|
}
|
|
});
|
|
// increment the last number in that max derivation path
|
|
const newDerivPath = nextDerivationPath(
|
|
accountWithMaxDeriv.derivationPath as string,
|
|
);
|
|
|
|
const mne: string = accountWithMaxDeriv.mnemonic as string;
|
|
|
|
const [address, privateHex, publicHex] = deriveAddress(mne, newDerivPath);
|
|
|
|
const newId = newIdentifier(address, publicHex, privateHex, newDerivPath);
|
|
|
|
try {
|
|
await accountsDB.accounts.add({
|
|
dateCreated: new Date().toISOString(),
|
|
derivationPath: newDerivPath,
|
|
did: newId.did,
|
|
identity: JSON.stringify(newId),
|
|
mnemonic: mne,
|
|
publicKeyHex: newId.keys[0].publicKeyHex,
|
|
});
|
|
|
|
// record that as the active DID
|
|
await db.open();
|
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
|
activeDid: newId.did,
|
|
});
|
|
this.$router.push({ name: "account" });
|
|
} catch (err) {
|
|
console.error("Error saving mnemonic & updating settings:", err);
|
|
}
|
|
}
|
|
}
|
|
</script>
|