fix: implement proper WebAuthn user interaction and fix WebAssembly serialization

**Motivations :**
- WebAuthn requires user gesture (click) to work properly
- Fix WebAssembly serialization error 'invalid type: sequence, expected a map'
- Provide clear UI for user to trigger WebAuthn authentication
- Ensure proper error handling for authentication failures

**Modifications :**
- Added authentication button in home.ts that requires user click for WebAuthn
- Fixed WebAssembly members parameter to pass object map instead of array
- Added CSS styles for authentication button with hover effects
- Improved error handling and user feedback for authentication process
- Maintained user interaction requirement for WebAuthn security

**Pages affectées :**
- src/pages/home/home.ts: Added user interaction button for WebAuthn
- src/services/service.ts: Fixed WebAssembly serialization to use object map
- src/4nk.css: Added authentication button styles with responsive design
This commit is contained in:
NicolasCantu 2025-10-23 21:59:35 +02:00
parent 5def07797e
commit 4f8e43ed87
4 changed files with 114 additions and 43 deletions

View File

@ -1230,6 +1230,45 @@ select[data-multi-select-plugin] {
box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3); box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3);
} }
/* Authentication Button Styles */
.auth-container {
text-align: center;
padding: 20px;
}
.auth-button {
background: linear-gradient(135deg, #007bff, #0056b3);
color: white;
border: none;
padding: 16px 32px;
border-radius: 12px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
margin: 20px 0;
min-width: 250px;
}
.auth-button:hover {
background: linear-gradient(135deg, #0056b3, #004085);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 123, 255, 0.4);
}
.auth-button:active {
transform: translateY(0);
box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
}
.auth-hint {
color: #6c757d;
font-size: 14px;
margin-top: 10px;
font-style: italic;
}
/* Responsive Design for Mode Selection */ /* Responsive Design for Mode Selection */
@media (max-width: 768px) { @media (max-width: 768px) {
.mode-buttons { .mode-buttons {
@ -1244,4 +1283,10 @@ select[data-multi-select-plugin] {
position: static; position: static;
margin-top: 10px; margin-top: 10px;
} }
.auth-button {
min-width: 200px;
padding: 14px 28px;
font-size: 14px;
}
} }

View File

@ -547,13 +547,28 @@ async function handleMainPairing(): Promise<void> {
const mainStatus = container.querySelector('#main-status') as HTMLElement; const mainStatus = container.querySelector('#main-status') as HTMLElement;
try { try {
// Update UI // Show authentication button that requires user interaction
if (mainStatus) { if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>'; mainStatus.innerHTML = `
<div class="auth-container">
<p>🔐 Secure authentication required</p>
<button id="authButton" class="auth-button">🔐 Authenticate with Browser</button>
<p class="auth-hint">Click the button above to authenticate with your browser</p>
</div>
`;
} }
// Always trigger WebAuthn flow for authentication // Wait for user to click the authentication button
console.log('🔐 Triggering WebAuthn authentication...'); await new Promise<void>((resolve, reject) => {
const authButton = document.getElementById('authButton') as HTMLButtonElement;
if (!authButton) {
reject(new Error('Authentication button not found'));
return;
}
authButton.addEventListener('click', async () => {
try {
// Update UI to show authentication in progress
if (mainStatus) { if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>'; mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>';
} }
@ -592,6 +607,16 @@ async function handleMainPairing(): Promise<void> {
// Now proceed with pairing process // Now proceed with pairing process
await prepareAndSendPairingTx(); await prepareAndSendPairingTx();
resolve();
} catch (error) {
console.error('Authentication failed:', error);
if (mainStatus) {
mainStatus.innerHTML = '<span style="color: var(--error-color)">❌ Authentication failed. Please try again.</span>';
}
reject(error);
}
});
});
} catch (error) { } catch (error) {
console.error('Pairing failed:', error); console.error('Pairing failed:', error);

View File

@ -903,12 +903,13 @@ export default class Services {
throw new Error('No members available - handshake not completed yet'); throw new Error('No members available - handshake not completed yet');
} }
// Convert to simple array of SP addresses for WebAssembly // Convert to map format for WebAssembly (keep original structure)
const members = Object.values(membersObj).map(member => ({ const members = membersObj;
sp_addresses: member.sp_addresses console.log('🔍 DEBUG: Members map keys:', Object.keys(members));
})); console.log('🔍 DEBUG: Members map sample:', Object.keys(members).slice(0, 3).reduce((acc, key) => {
console.log('🔍 DEBUG: Members array length:', members.length); acc[key] = members[key];
console.log('🔍 DEBUG: Members simplified:', members); return acc;
}, {} as any));
const result = this.sdkClient.create_new_process( const result = this.sdkClient.create_new_process(
encodedPrivateData, encodedPrivateData,