refactor: Simplify pairing interface with direct WebAuthn flow
**Motivations :** - Simplify user experience with single authentication flow - Remove confusing mode selection interface - Hide 4 words display (will be used later in interface) - Direct WebAuthn authentication for both new and existing pairings **Modifications :** - Replaced mode selection with single pairing interface - Added logic to detect existing credentials vs new pairing - Removed 4 words display from pairing process - Simplified HTML structure with single main interface - Updated JavaScript logic for direct WebAuthn flow **Pages affectées :** - src/pages/home/home.html - Simplified to single interface - src/pages/home/home.ts - Added direct WebAuthn flow logic - src/utils/sp-address.utils.ts - Removed 4 words display
This commit is contained in:
parent
82b3b27ab6
commit
802a77b568
@ -1,85 +1,21 @@
|
||||
<div class="pairing-container">
|
||||
<!-- Mode Selection -->
|
||||
<div id="mode-selection" class="card pairing-card">
|
||||
<!-- Main Pairing Interface -->
|
||||
<div id="main-pairing" class="card pairing-card">
|
||||
<div class="card-header">
|
||||
<h2>🔐 4NK Pairing</h2>
|
||||
<p class="card-description">Choose your role in the pairing process</p>
|
||||
</div>
|
||||
|
||||
<div class="mode-buttons">
|
||||
<button id="creator-mode-btn" class="mode-btn primary-btn">
|
||||
<div class="mode-icon">🔐</div>
|
||||
<div class="mode-content">
|
||||
<h3>Create New Pairing</h3>
|
||||
<p>Generate 4 words to share with another device</p>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button id="joiner-mode-btn" class="mode-btn secondary-btn">
|
||||
<div class="mode-icon">🔗</div>
|
||||
<div class="mode-content">
|
||||
<h3>Join Existing Pairing</h3>
|
||||
<p>Enter 4 words from another device</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Creator Flow -->
|
||||
<div id="creator-flow" class="card pairing-card" style="display: none">
|
||||
<div class="card-header">
|
||||
<h2>🔐 Create New Pairing</h2>
|
||||
<button id="back-to-mode-creator" class="back-btn">← Back to Mode Selection</button>
|
||||
<p class="card-description">Secure device pairing with WebAuthn authentication</p>
|
||||
</div>
|
||||
|
||||
<div class="pairing-request"></div>
|
||||
|
||||
<div class="words-display-container">
|
||||
<div class="words-label">Share these 4 words with the other device:</div>
|
||||
<div class="words-content" id="creator-words"></div>
|
||||
<button class="copy-btn" id="copyWordsBtn">📋 Copy Words</button>
|
||||
</div>
|
||||
|
||||
<div class="status-container">
|
||||
<div class="status-indicator" id="creator-status">
|
||||
<div class="status-indicator" id="main-status">
|
||||
<div class="spinner"></div>
|
||||
<span>Creating pairing process...</span>
|
||||
<span>Initializing secure pairing...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="createButton" class="primary-btn">Create Pairing</button>
|
||||
</div>
|
||||
|
||||
<!-- Joiner Flow -->
|
||||
<div id="joiner-flow" class="card pairing-card" style="display: none">
|
||||
<div class="card-header">
|
||||
<h2>🔗 Join Existing Pairing</h2>
|
||||
<p class="card-description">Enter the 4 words from the creator device</p>
|
||||
<button id="back-to-mode-joiner" class="back-btn">← Back to Mode Selection</button>
|
||||
</div>
|
||||
|
||||
<div class="input-container">
|
||||
<label for="wordsInput" class="input-label">4 Words:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="wordsInput"
|
||||
placeholder="Enter 4 words (e.g., abandon ability able about)"
|
||||
class="words-input"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
/>
|
||||
<div class="input-hint">Separate words with spaces</div>
|
||||
</div>
|
||||
|
||||
<div class="words-display" id="words-display-2"></div>
|
||||
|
||||
<div class="status-container">
|
||||
<div class="status-indicator" id="joiner-status">
|
||||
<span>Ready to join</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="joinButton" class="primary-btn" disabled>Join Pairing</button>
|
||||
<button id="mainPairingButton" class="primary-btn">Authenticate with Browser</button>
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Routing from '../../services/modal.service';
|
||||
import Services from '../../services/service';
|
||||
import { addSubscription } from '../../utils/subscription.utils';
|
||||
import { displayEmojis, generateCreateBtn, addressToEmoji } from '../../utils/sp-address.utils';
|
||||
import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairingTx } from '../../utils/sp-address.utils';
|
||||
import { getCorrectDOM } from '../../utils/html.utils';
|
||||
// import { navigate, registerAllListeners } from '../../router'; // Unused imports
|
||||
import { IframePairingComponent } from '../../components/iframe-pairing/iframe-pairing';
|
||||
@ -118,8 +118,8 @@ export async function initHomePage(): Promise<void> {
|
||||
// Set up iframe pairing button listeners
|
||||
setupIframePairingButtons();
|
||||
|
||||
// Set up mode selection
|
||||
setupModeSelection();
|
||||
// Set up main pairing interface
|
||||
setupMainPairing();
|
||||
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
container.querySelectorAll('.tab').forEach(tab => {
|
||||
@ -517,65 +517,83 @@ export function setupIframePairingButtons() {
|
||||
}
|
||||
}
|
||||
|
||||
// Mode Selection Functions
|
||||
export function setupModeSelection(): void {
|
||||
// Main Pairing Interface
|
||||
export function setupMainPairing(): void {
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
|
||||
// Mode selection buttons
|
||||
const creatorModeBtn = container.querySelector('#creator-mode-btn') as HTMLButtonElement;
|
||||
const joinerModeBtn = container.querySelector('#joiner-mode-btn') as HTMLButtonElement;
|
||||
const mainPairingButton = container.querySelector('#mainPairingButton') as HTMLButtonElement;
|
||||
const mainStatus = container.querySelector('#main-status') as HTMLElement;
|
||||
|
||||
// Back buttons
|
||||
const backToModeCreator = container.querySelector('#back-to-mode-creator') as HTMLButtonElement;
|
||||
const backToModeJoiner = container.querySelector('#back-to-mode-joiner') as HTMLButtonElement;
|
||||
|
||||
if (creatorModeBtn) {
|
||||
creatorModeBtn.addEventListener('click', () => {
|
||||
showMode('creator');
|
||||
});
|
||||
}
|
||||
|
||||
if (joinerModeBtn) {
|
||||
joinerModeBtn.addEventListener('click', () => {
|
||||
showMode('joiner');
|
||||
});
|
||||
}
|
||||
|
||||
if (backToModeCreator) {
|
||||
backToModeCreator.addEventListener('click', () => {
|
||||
showMode('selection');
|
||||
});
|
||||
}
|
||||
|
||||
if (backToModeJoiner) {
|
||||
backToModeJoiner.addEventListener('click', () => {
|
||||
showMode('selection');
|
||||
if (mainPairingButton) {
|
||||
mainPairingButton.addEventListener('click', async () => {
|
||||
await handleMainPairing();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showMode(mode: 'selection' | 'creator' | 'joiner'): void {
|
||||
async function handleMainPairing(): Promise<void> {
|
||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||
const mainStatus = container.querySelector('#main-status') as HTMLElement;
|
||||
const mainPairingButton = container.querySelector('#mainPairingButton') as HTMLButtonElement;
|
||||
|
||||
const modeSelection = container.querySelector('#mode-selection') as HTMLElement;
|
||||
const creatorFlow = container.querySelector('#creator-flow') as HTMLElement;
|
||||
const joinerFlow = container.querySelector('#joiner-flow') as HTMLElement;
|
||||
|
||||
// Hide all flows
|
||||
if (modeSelection) modeSelection.style.display = 'none';
|
||||
if (creatorFlow) creatorFlow.style.display = 'none';
|
||||
if (joinerFlow) joinerFlow.style.display = 'none';
|
||||
|
||||
// Show selected flow
|
||||
switch (mode) {
|
||||
case 'selection':
|
||||
if (modeSelection) modeSelection.style.display = 'block';
|
||||
break;
|
||||
case 'creator':
|
||||
if (creatorFlow) creatorFlow.style.display = 'block';
|
||||
break;
|
||||
case 'joiner':
|
||||
if (joinerFlow) joinerFlow.style.display = 'block';
|
||||
break;
|
||||
try {
|
||||
// Update UI
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>';
|
||||
}
|
||||
if (mainPairingButton) {
|
||||
mainPairingButton.disabled = true;
|
||||
mainPairingButton.textContent = 'Authenticating...';
|
||||
}
|
||||
|
||||
// Check if we have existing credentials
|
||||
const service = await Services.getInstance();
|
||||
const { secureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (hasCredentials) {
|
||||
// Existing pairing - decrypt credentials
|
||||
console.log('🔓 Existing credentials found, decrypting...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Decrypting existing credentials...</span>';
|
||||
}
|
||||
|
||||
await secureCredentialsService.retrieveCredentials(''); // Empty password for WebAuthn
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Credentials decrypted successfully</span>';
|
||||
}
|
||||
} else {
|
||||
// No existing pairing - create new one
|
||||
console.log('🔐 No existing credentials, creating new pairing...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Creating new secure pairing...</span>';
|
||||
}
|
||||
|
||||
// This will trigger the WebAuthn flow and create new credentials
|
||||
await prepareAndSendPairingTx();
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ New pairing created successfully</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// Re-enable button
|
||||
if (mainPairingButton) {
|
||||
mainPairingButton.disabled = false;
|
||||
mainPairingButton.textContent = 'Authenticate with Browser';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Pairing failed:', error);
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Authentication failed</span>';
|
||||
}
|
||||
|
||||
if (mainPairingButton) {
|
||||
mainPairingButton.disabled = false;
|
||||
mainPairingButton.textContent = 'Authenticate with Browser';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2743,10 +2743,6 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
// Update UI with creator address
|
||||
updateCreatorStatus(`Creator address: ${creatorAddress}`);
|
||||
|
||||
// Generate 4 words representation for the joiner immediately
|
||||
console.log(`🔍 DEBUG: Generating 4 words representation for joiner...`);
|
||||
await generateWordsDisplay(creatorAddress);
|
||||
|
||||
// Secure credentials already initialized in the click handler
|
||||
|
||||
// Create pairing process with creator's address
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user