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.
271 lines
9.0 KiB
271 lines
9.0 KiB
<template>
|
|
<section
|
|
id="Content"
|
|
class="p-6 pb-24 min-h-screen flex flex-col justify-center"
|
|
>
|
|
<!-- Breadcrumb -->
|
|
<div>
|
|
<!-- Back -->
|
|
<div class="text-lg text-center font-light relative px-7">
|
|
<h1
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
@click="goBack"
|
|
>
|
|
<font-awesome icon="chevron-left" class="fa-fw"></font-awesome>
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- Heading -->
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
|
Generate an Identity
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- id used by puppeteer test script -->
|
|
<div id="start-question" class="mt-8">
|
|
<div class="max-w-3xl mx-auto">
|
|
<p class="text-center text-xl font-light">
|
|
How do you want to create this identifier?
|
|
</p>
|
|
<p v-if="PASSKEYS_ENABLED" class="text-center font-light mt-6">
|
|
A <strong>passkey</strong> is easy to manage, though it is less
|
|
interoperable with other systems for advanced uses.
|
|
<a
|
|
href="https://www.perplexity.ai/search/what-are-passkeys-v2SHV3yLQlyA2CYH6.Nvhg"
|
|
target="_blank"
|
|
>
|
|
<font-awesome icon="info-circle" class="fa-fw text-blue-500" />
|
|
</a>
|
|
</p>
|
|
<p class="text-center font-light mt-4">
|
|
A <strong>new seed</strong> allows you full control over the keys,
|
|
though you are responsible for backups.
|
|
<a
|
|
href="https://www.perplexity.ai/search/what-is-a-seed-phrase-OqiP9foVRXidr_2le5OFKA"
|
|
target="_blank"
|
|
>
|
|
<font-awesome icon="info-circle" class="fa-fw text-blue-500" />
|
|
</a>
|
|
</p>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2 mt-4">
|
|
<a
|
|
v-if="PASSKEYS_ENABLED"
|
|
:class="primaryButtonClass"
|
|
@click="onClickNewPasskey()"
|
|
>
|
|
Generate one with a passkey
|
|
</a>
|
|
<a
|
|
:class="primaryButtonClass"
|
|
data-testId="newSeed"
|
|
@click="onClickNewSeed()"
|
|
>
|
|
Generate one with a new seed
|
|
</a>
|
|
</div>
|
|
<p class="text-center font-light mt-4">
|
|
You can also import an existing seed or derive a new address from an
|
|
existing seed.
|
|
</p>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2 mt-2">
|
|
<a :class="secondaryButtonClass" @click="onClickNo()">
|
|
You have a seed
|
|
</a>
|
|
<a
|
|
v-if="numAccounts > 0"
|
|
:class="secondaryButtonClass"
|
|
@click="onClickDerive()"
|
|
>
|
|
Derive new address from existing seed
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Database Migration Section -->
|
|
<div class="mt-8 pt-6 border-t border-gray-200">
|
|
<div class="flex justify-center">
|
|
<router-link
|
|
:to="{ name: 'database-migration' }"
|
|
:class="migrationButtonClass"
|
|
>
|
|
Migrate My Old Data
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
/**
|
|
* @fileoverview StartView - Identity Generation Selection Component
|
|
*
|
|
* This component serves as the primary entry point for users to create their
|
|
* cryptographic identity. It provides multiple options for identity generation
|
|
* including modern passkeys, traditional seed phrases, and import/derivation
|
|
* capabilities while maintaining security and user experience standards.
|
|
*
|
|
* Key Features:
|
|
* - Multiple identity generation methods (passkey, seed, import, derive)
|
|
* - User preference and account information loading
|
|
* - Secure navigation to specialized identity creation flows
|
|
* - Database migration access for legacy data handling
|
|
* - Educational links for user guidance on identity methods
|
|
*
|
|
* Enhanced Triple Migration Pattern Status:
|
|
* ✅ Phase 1: Database Migration - PlatformServiceMixin integration
|
|
* ✅ Phase 2: SQL Abstraction - No raw SQL queries to migrate
|
|
* ✅ Phase 3: Notification Migration - No notifications to migrate
|
|
* ✅ Phase 4: Template Streamlining - Method extraction and styling
|
|
*
|
|
* Security: This component handles foundational identity generation selection
|
|
* with proper security context preservation for all downstream flows.
|
|
*
|
|
* @component StartView
|
|
* @requires PlatformServiceMixin - Database operations
|
|
* @requires PasskeyUtilities - Passkey-based identity creation
|
|
* @requires AccountUtilities - Account management functions
|
|
* @author TimeSafari Development Team
|
|
* @since 2024-01-01
|
|
* @version 1.0.0
|
|
* @migrated 2025-07-09 (Enhanced Triple Migration Pattern)
|
|
*/
|
|
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { Router } from "vue-router";
|
|
|
|
import { AppString, PASSKEYS_ENABLED } from "../constants/app";
|
|
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
|
|
import { logger } from "../utils/logger";
|
|
|
|
import {
|
|
registerSaveAndActivatePasskey,
|
|
retrieveAccountCount,
|
|
} from "../libs/util";
|
|
|
|
@Component({
|
|
components: {},
|
|
mixins: [PlatformServiceMixin],
|
|
})
|
|
export default class StartView extends Vue {
|
|
$router!: Router;
|
|
|
|
// Feature flags and application constants
|
|
PASSKEYS_ENABLED = PASSKEYS_ENABLED;
|
|
|
|
// Component state for identity generation
|
|
givenName = "";
|
|
numAccounts = 0;
|
|
|
|
/**
|
|
* Computed property for primary action button styling
|
|
* Provides consistent classes for main identity generation buttons
|
|
*/
|
|
get primaryButtonClass() {
|
|
return "block w-full text-center text-lg 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 mb-2 cursor-pointer";
|
|
}
|
|
|
|
/**
|
|
* Computed property for secondary action button styling
|
|
* Provides consistent classes for secondary identity generation buttons
|
|
*/
|
|
get secondaryButtonClass() {
|
|
return "block w-full text-center text-md 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-1.5 py-2 rounded-md cursor-pointer";
|
|
}
|
|
|
|
/**
|
|
* Computed property for migration button styling
|
|
* Provides consistent classes for database migration button
|
|
*/
|
|
get migrationButtonClass() {
|
|
return "block w-fit text-center text-md 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-4 py-2 rounded-md";
|
|
}
|
|
|
|
/**
|
|
* Navigate back to previous page
|
|
* Extracted from template for better maintainability
|
|
*/
|
|
goBack() {
|
|
this.$router.back();
|
|
}
|
|
|
|
/**
|
|
* Component lifecycle hook - Initialize identity generation options
|
|
* Loads user settings and account information to present appropriate
|
|
* identity creation options based on user preferences and existing accounts
|
|
*/
|
|
async mounted() {
|
|
try {
|
|
// Load user settings using platform service
|
|
const settings = await this.$accountSettings();
|
|
this.givenName = settings.firstName || "";
|
|
|
|
// Load account count for display logic
|
|
this.numAccounts = await retrieveAccountCount();
|
|
|
|
logger.info("[StartView] Component mounted", {
|
|
hasGivenName: !!this.givenName,
|
|
accountCount: this.numAccounts,
|
|
passkeysEnabled: this.PASSKEYS_ENABLED,
|
|
});
|
|
} catch (error) {
|
|
logger.error("[StartView] Failed to load initialization data", error);
|
|
// Continue with default behavior if settings load fails
|
|
this.givenName = "";
|
|
this.numAccounts = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle new seed identity generation selection
|
|
* Routes user to new identifier creation flow with seed-based approach
|
|
*/
|
|
public onClickNewSeed() {
|
|
logger.info("[StartView] User selected new seed generation");
|
|
this.$router.push({ name: "new-identifier" });
|
|
}
|
|
|
|
/**
|
|
* Handle new passkey identity generation selection
|
|
* Creates passkey-based identity using user's given name and activates it
|
|
* Routes to account view upon successful creation
|
|
*/
|
|
public async onClickNewPasskey() {
|
|
try {
|
|
const keyName =
|
|
AppString.APP_NAME + (this.givenName ? " - " + this.givenName : "");
|
|
|
|
logger.info("[StartView] Initiating passkey registration", {
|
|
keyName,
|
|
hasGivenName: !!this.givenName,
|
|
});
|
|
|
|
await registerSaveAndActivatePasskey(keyName);
|
|
|
|
logger.info("[StartView] Passkey registration successful");
|
|
this.$router.push({ name: "account" });
|
|
} catch (error) {
|
|
logger.error("[StartView] Passkey registration failed", error);
|
|
// Error handling will be managed by the passkey utilities
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle existing seed import selection
|
|
* Routes user to account import flow for existing seed phrase
|
|
*/
|
|
public onClickNo() {
|
|
logger.info("[StartView] User selected existing seed import");
|
|
this.$router.push({ name: "import-account" });
|
|
}
|
|
|
|
/**
|
|
* Handle derive new address selection
|
|
* Routes user to address derivation flow for existing seed
|
|
*/
|
|
public onClickDerive() {
|
|
logger.info("[StartView] User selected address derivation");
|
|
this.$router.push({ name: "import-derive" });
|
|
}
|
|
}
|
|
</script>
|
|
|