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:
parent
5def07797e
commit
4f8e43ed87
45
src/4nk.css
45
src/4nk.css
@ -1230,6 +1230,45 @@ select[data-multi-select-plugin] {
|
||||
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 */
|
||||
@media (max-width: 768px) {
|
||||
.mode-buttons {
|
||||
@ -1244,4 +1283,10 @@ select[data-multi-select-plugin] {
|
||||
position: static;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.auth-button {
|
||||
min-width: 200px;
|
||||
padding: 14px 28px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,51 +547,76 @@ async function handleMainPairing(): Promise<void> {
|
||||
const mainStatus = container.querySelector('#main-status') as HTMLElement;
|
||||
|
||||
try {
|
||||
// Update UI
|
||||
// Show authentication button that requires user interaction
|
||||
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
|
||||
console.log('🔐 Triggering WebAuthn authentication...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>';
|
||||
}
|
||||
|
||||
// Import and trigger WebAuthn directly
|
||||
const { secureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
|
||||
// Check if we have existing credentials
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (hasCredentials) {
|
||||
console.log('🔓 Existing credentials found, decrypting...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Decrypting existing credentials...</span>';
|
||||
// Wait for user to click the authentication button
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const authButton = document.getElementById('authButton') as HTMLButtonElement;
|
||||
if (!authButton) {
|
||||
reject(new Error('Authentication button not found'));
|
||||
return;
|
||||
}
|
||||
|
||||
// This will trigger WebAuthn for decryption
|
||||
await secureCredentialsService.retrieveCredentials('');
|
||||
authButton.addEventListener('click', async () => {
|
||||
try {
|
||||
// Update UI to show authentication in progress
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Authenticating with browser...</span>';
|
||||
}
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Credentials decrypted successfully</span>';
|
||||
}
|
||||
} else {
|
||||
console.log('🔐 No existing credentials, creating new ones...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Creating new credentials...</span>';
|
||||
}
|
||||
// Import and trigger WebAuthn directly
|
||||
const { secureCredentialsService } = await import('../../services/secure-credentials.service');
|
||||
|
||||
// This will trigger WebAuthn for creation
|
||||
await secureCredentialsService.generateSecureCredentials('');
|
||||
// Check if we have existing credentials
|
||||
const hasCredentials = await secureCredentialsService.hasCredentials();
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ New credentials created successfully</span>';
|
||||
}
|
||||
}
|
||||
if (hasCredentials) {
|
||||
console.log('🔓 Existing credentials found, decrypting...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Decrypting existing credentials...</span>';
|
||||
}
|
||||
|
||||
// Now proceed with pairing process
|
||||
await prepareAndSendPairingTx();
|
||||
// This will trigger WebAuthn for decryption
|
||||
await secureCredentialsService.retrieveCredentials('');
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Credentials decrypted successfully</span>';
|
||||
}
|
||||
} else {
|
||||
console.log('🔐 No existing credentials, creating new ones...');
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<div class="spinner"></div><span>Creating new credentials...</span>';
|
||||
}
|
||||
|
||||
// This will trigger WebAuthn for creation
|
||||
await secureCredentialsService.generateSecureCredentials('');
|
||||
|
||||
if (mainStatus) {
|
||||
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ New credentials created successfully</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// Now proceed with pairing process
|
||||
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) {
|
||||
console.error('Pairing failed:', error);
|
||||
|
||||
@ -903,12 +903,13 @@ export default class Services {
|
||||
throw new Error('No members available - handshake not completed yet');
|
||||
}
|
||||
|
||||
// Convert to simple array of SP addresses for WebAssembly
|
||||
const members = Object.values(membersObj).map(member => ({
|
||||
sp_addresses: member.sp_addresses
|
||||
}));
|
||||
console.log('🔍 DEBUG: Members array length:', members.length);
|
||||
console.log('🔍 DEBUG: Members simplified:', members);
|
||||
// Convert to map format for WebAssembly (keep original structure)
|
||||
const members = membersObj;
|
||||
console.log('🔍 DEBUG: Members map keys:', Object.keys(members));
|
||||
console.log('🔍 DEBUG: Members map sample:', Object.keys(members).slice(0, 3).reduce((acc, key) => {
|
||||
acc[key] = members[key];
|
||||
return acc;
|
||||
}, {} as any));
|
||||
|
||||
const result = this.sdkClient.create_new_process(
|
||||
encodedPrivateData,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user