<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> Import Existing Identifier </h1> </div> <!-- Import Account Form --> <p class="text-center text-xl mb-4 font-light"> Enter your seed phrase below to import your identifier on this device. </p> <!-- id used by puppeteer test script --> <textarea id="seed-input" type="text" placeholder="Seed Phrase" class="block w-full rounded border border-slate-400 mb-4 px-3 py-2" v-model="mnemonic" /> <h3 class="text-sm uppercase font-semibold mb-3" @click="showAdvanced = !showAdvanced" > Advanced </h3> <div v-if="showAdvanced"> Enter a custom derivation path <input type="text" class="block w-full rounded border border-slate-400 mb-2 px-3 py-2" v-model="derivationPath" /> <span class="ml-4"> For previous uPort or Endorser users, <a @click="derivationPath = UPORT_DERIVATION_PATH" class="text-blue-500" > click here to use that value. </a> </span> <div class="mt-4" v-if="numAccounts == 1"> <input type="checkbox" class="mr-2" v-model="shouldErase" /> <label>Erase the previous identifier.</label> </div> <div v-if="isNotProdServer()" class="mt-4 text-blue-500"> <!-- if they click this, fill in the mnemonic seed-input with the test mnemonic --> <button @click="mnemonic = TEST_USER_0_MNEMONIC"> Use mnemonic for Test User #0 </button> </div> </div> <div class="mt-8"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-2"> <button @click="fromMnemonic()" 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" > Import </button> <button @click="onCancelClick()" 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" > Cancel </button> </div> </div> </section> </template> <script lang="ts"> import { Component, Vue } from "vue-facing-decorator"; import { Router } from "vue-router"; import { AppString, NotificationIface } from "@/constants/app"; import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { DEFAULT_ROOT_DERIVATION_PATH, deriveAddress, newIdentifier, } from "@/libs/crypto"; @Component({ components: {}, }) export default class ImportAccountView extends Vue { TEST_USER_0_MNEMONIC = "rigid shrug mobile smart veteran half all pond toilet brave review universe ship congress found yard skate elite apology jar uniform subway slender luggage"; UPORT_DERIVATION_PATH = "m/7696500'/0'/0'/0'"; // for legacy imports, likely never used AppString = AppString; $notify!: (notification: NotificationIface, timeout?: number) => void; apiServer = ""; address = ""; derivationPath = DEFAULT_ROOT_DERIVATION_PATH; mnemonic = ""; numAccounts = 0; privateHex = ""; publicHex = ""; showAdvanced = false; shouldErase = false; async created() { await accountsDB.open(); this.numAccounts = await accountsDB.accounts.count(); // get the server, to help with import on the test server const settings = await retrieveSettingsForActiveAccount(); this.apiServer = settings.apiServer || ""; } public onCancelClick() { (this.$router as Router).back(); } public isNotProdServer() { return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER; } public async fromMnemonic() { const mne: string = this.mnemonic.trim().toLowerCase(); try { [this.address, this.privateHex, this.publicHex] = deriveAddress( mne, this.derivationPath, ); const newId = newIdentifier( this.address, this.publicHex, this.privateHex, this.derivationPath, ); await accountsDB.open(); if (this.shouldErase) { await accountsDB.accounts.clear(); } await accountsDB.accounts.add({ dateCreated: new Date().toISOString(), derivationPath: this.derivationPath, 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 as Router).push({ name: "account" }); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { console.error("Error saving mnemonic & updating settings:", err); if (err == "Error: invalid mnemonic") { this.$notify( { group: "alert", type: "danger", title: "Invalid Mnemonic", text: "Please check your mnemonic and try again.", }, -1, ); } else { this.$notify( { group: "alert", type: "danger", title: "Error", text: "Got an error creating that identifier.", }, -1, ); } } } } </script>