allow use of custom derivation path, and add way to increment derivation for existing #56
Merged
anomalist
merged 1 commits from increment-derived
into master
1 year ago
8 changed files with 244 additions and 13 deletions
@ -0,0 +1,163 @@ |
|||||
|
<template> |
||||
|
<section id="Content" class="p-6 pb-24"> |
||||
|
<!-- 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"; |
||||
|
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 = {}; |
||||
|
accounts.forEach((account) => { |
||||
|
const prevDids = 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> |
Loading…
Reference in new issue