|
|
|
<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
|
|
|
|
@click="$router.go(-1)"
|
|
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
|
|
>
|
|
|
|
<fa icon="chevron-left"></fa>
|
|
|
|
</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 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
|
|
|
|
class="block bg-slate-100 rounded-md flex items-center px-4 py-3 mb-2"
|
|
|
|
v-for="dids in didArrays"
|
|
|
|
:key="dids[0]"
|
|
|
|
@click="switchAccount(dids[0])"
|
|
|
|
>
|
|
|
|
<fa
|
|
|
|
v-if="dids[0] == selectedArrayFirstDid"
|
|
|
|
icon="circle"
|
|
|
|
class="fa-fw text-blue-400 text-xl mr-3"
|
|
|
|
></fa>
|
|
|
|
<fa
|
|
|
|
v-else
|
|
|
|
icon="circle"
|
|
|
|
class="fa-fw text-slate-400 text-xl mr-3"
|
|
|
|
></fa>
|
|
|
|
<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">
|
|
|
|
<button
|
|
|
|
@click="incrementDerivation()"
|
|
|
|
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
|
|
|
>
|
|
|
|
Increment and Import
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
@click="onCancelClick()"
|
|
|
|
type="button"
|
|
|
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
|
|
|
>
|
|
|
|
Cancel
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
|
|
import {
|
|
|
|
DEFAULT_ROOT_DERIVATION_PATH,
|
|
|
|
deriveAddress,
|
|
|
|
newIdentifier,
|
|
|
|
} from "../libs/crypto";
|
|
|
|
import { accountsDB, db } from "@/db/index";
|
|
|
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
components: {},
|
|
|
|
})
|
|
|
|
export default class ImportAccountView extends Vue {
|
|
|
|
derivationPath = DEFAULT_ROOT_DERIVATION_PATH;
|
|
|
|
didArrays: Array<Array<string>> = [];
|
|
|
|
selectedArrayFirstDid = "";
|
|
|
|
|
|
|
|
async mounted() {
|
|
|
|
await accountsDB.open();
|
|
|
|
const accounts = await accountsDB.accounts.toArray();
|
|
|
|
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() {
|
|
|
|
await accountsDB.open();
|
|
|
|
// find the maximum derivation path for the selected DIDs
|
|
|
|
const selectedArray: Array<string> =
|
|
|
|
this.didArrays.find((dids) => dids[0] === this.selectedArrayFirstDid) ||
|
|
|
|
[];
|
|
|
|
const 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
|
|
|
|
let lastStr = accountWithMaxDeriv.derivationPath.split("/").slice(-1)[0];
|
|
|
|
if (lastStr.endsWith("'")) {
|
|
|
|
lastStr = lastStr.slice(0, -1);
|
|
|
|
}
|
|
|
|
const lastNum = parseInt(lastStr, 10);
|
|
|
|
const newLastNum = lastNum + 1;
|
|
|
|
const newDerivPath = accountWithMaxDeriv.derivationPath
|
|
|
|
.split("/")
|
|
|
|
.slice(0, -1)
|
|
|
|
.concat([newLastNum.toString() + "'"])
|
|
|
|
.join("/");
|
|
|
|
|
|
|
|
const mne: string = accountWithMaxDeriv.mnemonic;
|
|
|
|
|
|
|
|
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();
|
|
|
|
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>
|