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