You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
6.6 KiB
223 lines
6.6 KiB
<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>
|
|
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"
|
|
v-model="mnemonic"
|
|
type="text"
|
|
placeholder="Seed Phrase"
|
|
class="block w-full rounded border border-slate-400 mb-4 px-3 py-2"
|
|
/>
|
|
|
|
<h3
|
|
class="text-blue-500 text-sm font-semibold mb-3"
|
|
@click="showAdvanced = !showAdvanced"
|
|
>
|
|
Advanced
|
|
</h3>
|
|
<div v-if="showAdvanced">
|
|
Enter a custom derivation path
|
|
<input
|
|
v-model="derivationPath"
|
|
type="text"
|
|
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2"
|
|
/>
|
|
<span class="ml-4">
|
|
For previous uPort or Endorser users,
|
|
<a
|
|
class="text-blue-500"
|
|
@click="derivationPath = UPORT_DERIVATION_PATH"
|
|
>
|
|
click here to use that value.
|
|
</a>
|
|
</span>
|
|
|
|
<div v-if="numAccounts == 1" class="mt-4">
|
|
<input v-model="shouldErase" type="checkbox" class="mr-2" />
|
|
<label>Erase previous identifiers.</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
|
|
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="fromMnemonic()"
|
|
>
|
|
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 } from "vue-router";
|
|
|
|
import { AppString, NotificationIface } from "../constants/app";
|
|
import { DEFAULT_ROOT_DERIVATION_PATH } from "../libs/crypto";
|
|
import { retrieveAccountCount, importFromMnemonic } from "../libs/util";
|
|
import { logger } from "../utils/logger";
|
|
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
|
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
|
|
|
/**
|
|
* Import Account View Component
|
|
*
|
|
* Allows users to import existing identifiers using seed phrases:
|
|
* - Secure mnemonic phrase input with validation
|
|
* - Advanced options for custom derivation paths
|
|
* - Legacy uPort compatibility support
|
|
* - Test environment utilities for development
|
|
*
|
|
* Features:
|
|
* - Secure seed phrase import functionality
|
|
* - Custom derivation path configuration
|
|
* - Account erasure options for fresh imports
|
|
* - Development mode test utilities
|
|
* - Comprehensive error handling and validation
|
|
*
|
|
* Security Considerations:
|
|
* - Seed phrases are handled securely and not logged
|
|
* - Import process includes validation and error recovery
|
|
* - Advanced options are hidden by default
|
|
*
|
|
* @author Matthew Raymer
|
|
*/
|
|
@Component({
|
|
components: {},
|
|
mixins: [PlatformServiceMixin],
|
|
})
|
|
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;
|
|
$router!: Router;
|
|
|
|
notify!: ReturnType<typeof createNotifyHelpers>;
|
|
|
|
apiServer = "";
|
|
derivationPath = DEFAULT_ROOT_DERIVATION_PATH;
|
|
mnemonic = "";
|
|
numAccounts = 0;
|
|
showAdvanced = false;
|
|
shouldErase = false;
|
|
|
|
/**
|
|
* Initializes notification helpers
|
|
*/
|
|
created() {
|
|
this.notify = createNotifyHelpers(this.$notify);
|
|
}
|
|
|
|
/**
|
|
* Component initialization
|
|
*
|
|
* Loads account count and server settings for import configuration
|
|
* Uses PlatformServiceMixin for secure database access
|
|
*/
|
|
async mounted() {
|
|
await this.initializeSettings();
|
|
}
|
|
|
|
/**
|
|
* Initializes component settings and account information
|
|
*/
|
|
private async initializeSettings() {
|
|
this.numAccounts = await retrieveAccountCount();
|
|
const settings = await this.$accountSettings();
|
|
this.apiServer = settings.apiServer || "";
|
|
}
|
|
|
|
/**
|
|
* Handles cancel button click
|
|
*
|
|
* Navigates back to previous view
|
|
*/
|
|
public onCancelClick() {
|
|
this.$router.back();
|
|
}
|
|
|
|
/**
|
|
* Checks if running on production server
|
|
*
|
|
* @returns True if not on production server (enables test utilities)
|
|
*/
|
|
public isNotProdServer() {
|
|
return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER;
|
|
}
|
|
|
|
/**
|
|
* Imports identifier from mnemonic phrase
|
|
*
|
|
* Processes the mnemonic phrase with optional custom derivation path
|
|
* and account erasure options. Handles validation and error scenarios
|
|
* with appropriate user feedback.
|
|
*
|
|
* Error Handling:
|
|
* - Invalid mnemonic format validation
|
|
* - Import process failure recovery
|
|
* - User-friendly error messaging
|
|
*/
|
|
public async fromMnemonic() {
|
|
try {
|
|
await importFromMnemonic(
|
|
this.mnemonic,
|
|
this.derivationPath,
|
|
this.shouldErase,
|
|
);
|
|
this.$router.push({ name: "account" });
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} catch (err: any) {
|
|
logger.error("Error importing from mnemonic:", err);
|
|
if (err == "Error: invalid mnemonic") {
|
|
this.notify.error(
|
|
"Please check your mnemonic and try again.",
|
|
TIMEOUTS.LONG
|
|
);
|
|
} else {
|
|
this.notify.error(
|
|
"Got an error creating that identifier.",
|
|
TIMEOUTS.LONG
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|