fix: resolve multiple critical issues
**Motivations :** - Fix WebAuthn authentication regression (button reappeared instead of auto-trigger) - Resolve infinite loop of 'process.states is not an array' logs - Fix WebAssembly serialization error 'invalid type: map, expected a sequence' - Improve WebAuthn error handling and timeout management **Modifications :** - Restored automatic WebAuthn triggering in home.ts initHomePage() - Fixed handshake deduplication logic in service.ts using content-based keys - Added membersList validation before WebAssembly calls to prevent empty object errors - Enhanced WebAuthn error handling with specific error messages and increased timeout to 2 minutes - Improved error messages for NotAllowedError, NotSupportedError, and SecurityError **Pages affectées :** - src/pages/home/home.ts: Restored auto WebAuthn trigger, removed manual button - src/services/service.ts: Fixed handshake deduplication and added membersList validation - src/services/secure-credentials.service.ts: Enhanced WebAuthn error handling and timeout
This commit is contained in:
parent
8af1fd055d
commit
e393a4f615
@ -524,9 +524,21 @@ export function setupIframePairingButtons() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main Pairing Interface - Auto-triggered, no button needed
|
// Main Pairing Interface - Automatic WebAuthn trigger
|
||||||
export function setupMainPairing(): void {
|
export function setupMainPairing(): void {
|
||||||
// No button setup needed since authentication is automatic
|
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
||||||
|
const mainStatus = container.querySelector('#main-status') as HTMLElement;
|
||||||
|
|
||||||
|
if (mainStatus) {
|
||||||
|
mainStatus.innerHTML = `
|
||||||
|
<div class="auth-container">
|
||||||
|
<p>🔐 Secure authentication required</p>
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<span>Initializing secure authentication...</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('🔐 Main pairing setup - authentication will be automatic');
|
console.log('🔐 Main pairing setup - authentication will be automatic');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -99,16 +99,32 @@ export class SecureCredentialsService {
|
|||||||
authenticatorAttachment: "platform", // Force l'authentificateur intégré
|
authenticatorAttachment: "platform", // Force l'authentificateur intégré
|
||||||
userVerification: "required"
|
userVerification: "required"
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 120000, // 2 minutes timeout
|
||||||
attestation: "direct"
|
attestation: "direct"
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('🔐 Requesting WebAuthn credential creation for encryption key...');
|
console.log('🔐 Requesting WebAuthn credential creation for encryption key...');
|
||||||
|
|
||||||
// Créer le credential WebAuthn
|
// Créer le credential WebAuthn avec gestion d'erreur robuste
|
||||||
const credential = await navigator.credentials.create({
|
let credential: PublicKeyCredential;
|
||||||
publicKey: publicKeyCredentialCreationOptions
|
try {
|
||||||
}) as PublicKeyCredential;
|
credential = await navigator.credentials.create({
|
||||||
|
publicKey: publicKeyCredentialCreationOptions
|
||||||
|
}) as PublicKeyCredential;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
if (error.name === 'NotAllowedError') {
|
||||||
|
throw new Error('WebAuthn authentication was cancelled or timed out. Please try again and complete the authentication when prompted.');
|
||||||
|
} else if (error.name === 'NotSupportedError') {
|
||||||
|
throw new Error('WebAuthn is not supported in this browser. Please use a modern browser with WebAuthn support.');
|
||||||
|
} else if (error.name === 'SecurityError') {
|
||||||
|
throw new Error('WebAuthn security error. Please ensure you are using HTTPS and try again.');
|
||||||
|
} else {
|
||||||
|
throw new Error(`WebAuthn error: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!credential) {
|
if (!credential) {
|
||||||
throw new Error('WebAuthn credential creation failed');
|
throw new Error('WebAuthn credential creation failed');
|
||||||
@ -283,18 +299,34 @@ export class SecureCredentialsService {
|
|||||||
throw new Error('WebAuthn not supported for decryption');
|
throw new Error('WebAuthn not supported for decryption');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demander l'authentification WebAuthn
|
// Demander l'authentification WebAuthn avec gestion d'erreur robuste
|
||||||
const credential = await navigator.credentials.get({
|
let credential: PublicKeyCredential;
|
||||||
publicKey: {
|
try {
|
||||||
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
credential = await navigator.credentials.get({
|
||||||
allowCredentials: [{
|
publicKey: {
|
||||||
id: new TextEncoder().encode(credentialId),
|
challenge: crypto.getRandomValues(new Uint8Array(32)),
|
||||||
type: 'public-key'
|
allowCredentials: [{
|
||||||
}],
|
id: new TextEncoder().encode(credentialId),
|
||||||
userVerification: 'required',
|
type: 'public-key'
|
||||||
timeout: 60000
|
}],
|
||||||
|
userVerification: 'required',
|
||||||
|
timeout: 120000 // 2 minutes timeout
|
||||||
|
}
|
||||||
|
}) as PublicKeyCredential;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
if (error.name === 'NotAllowedError') {
|
||||||
|
throw new Error('WebAuthn authentication was cancelled or timed out. Please try again and complete the authentication when prompted.');
|
||||||
|
} else if (error.name === 'NotSupportedError') {
|
||||||
|
throw new Error('WebAuthn is not supported in this browser. Please use a modern browser with WebAuthn support.');
|
||||||
|
} else if (error.name === 'SecurityError') {
|
||||||
|
throw new Error('WebAuthn security error. Please ensure you are using HTTPS and try again.');
|
||||||
|
} else {
|
||||||
|
throw new Error(`WebAuthn decryption error: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}) as PublicKeyCredential;
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!credential) {
|
if (!credential) {
|
||||||
throw new Error('WebAuthn authentication failed');
|
throw new Error('WebAuthn authentication failed');
|
||||||
|
|||||||
@ -897,9 +897,18 @@ export default class Services {
|
|||||||
console.log('🔍 DEBUG: Members type:', typeof membersObj);
|
console.log('🔍 DEBUG: Members type:', typeof membersObj);
|
||||||
console.log('🔍 DEBUG: Members keys:', Object.keys(membersObj));
|
console.log('🔍 DEBUG: Members keys:', Object.keys(membersObj));
|
||||||
|
|
||||||
// Convert object to array for WebAssembly
|
// Check if membersList is empty
|
||||||
const members = Object.values(membersObj);
|
if (!membersObj || Object.keys(membersObj).length === 0) {
|
||||||
|
console.warn('⚠️ No members available for create_new_process, waiting for handshake...');
|
||||||
|
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 array length:', members.length);
|
||||||
|
console.log('🔍 DEBUG: Members simplified:', members);
|
||||||
|
|
||||||
const result = this.sdkClient.create_new_process(
|
const result = this.sdkClient.create_new_process(
|
||||||
encodedPrivateData,
|
encodedPrivateData,
|
||||||
@ -943,12 +952,15 @@ export default class Services {
|
|||||||
...this.sdkClient.encode_binary(publicSplitData.binaryData),
|
...this.sdkClient.encode_binary(publicSplitData.binaryData),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
|
const members = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
const result = this.sdkClient.update_process(
|
const result = this.sdkClient.update_process(
|
||||||
process,
|
process,
|
||||||
encodedPrivateData,
|
encodedPrivateData,
|
||||||
roles,
|
roles,
|
||||||
encodedPublicData,
|
encodedPublicData,
|
||||||
Object.values(this.getAllMembers())
|
members
|
||||||
);
|
);
|
||||||
if (result.updated_process) {
|
if (result.updated_process) {
|
||||||
await this.checkConnections(result.updated_process.current_process);
|
await this.checkConnections(result.updated_process.current_process);
|
||||||
@ -969,7 +981,10 @@ export default class Services {
|
|||||||
await this.checkConnections(process);
|
await this.checkConnections(process);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.create_update_message(process, stateId, Object.values(this.getAllMembers()));
|
const members = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
|
return this.sdkClient.create_update_message(process, stateId, members);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Failed to create prd update: ${e}`);
|
throw new Error(`Failed to create prd update: ${e}`);
|
||||||
}
|
}
|
||||||
@ -981,7 +996,10 @@ export default class Services {
|
|||||||
throw new Error('Unknown process');
|
throw new Error('Unknown process');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.create_response_prd(process, stateId, Object.values(this.getAllMembers()));
|
const members = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
|
return this.sdkClient.create_response_prd(process, stateId, members);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Failed to create response prd: ${e}`);
|
throw new Error(`Failed to create response prd: ${e}`);
|
||||||
}
|
}
|
||||||
@ -993,7 +1011,10 @@ export default class Services {
|
|||||||
throw new Error('Failed to get process from db');
|
throw new Error('Failed to get process from db');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const result = this.sdkClient.validate_state(process, stateId, Object.values(this.getAllMembers()));
|
const members = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
|
const result = this.sdkClient.validate_state(process, stateId, members);
|
||||||
if (result.updated_process) {
|
if (result.updated_process) {
|
||||||
await this.checkConnections(result.updated_process.current_process);
|
await this.checkConnections(result.updated_process.current_process);
|
||||||
return result;
|
return result;
|
||||||
@ -1049,7 +1070,9 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async parseCipher(message: string) {
|
async parseCipher(message: string) {
|
||||||
const membersList = Object.values(this.getAllMembers());
|
const membersList = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
const processes = await this.getProcesses();
|
const processes = await this.getProcesses();
|
||||||
try {
|
try {
|
||||||
// console.log('parsing new cipher');
|
// console.log('parsing new cipher');
|
||||||
@ -1080,7 +1103,9 @@ export default class Services {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const membersList = Object.values(this.getAllMembers());
|
const membersList = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
try {
|
try {
|
||||||
// Does the transaction spend the tip of a process?
|
// Does the transaction spend the tip of a process?
|
||||||
const prevouts = this.sdkClient.get_prevouts(parsedMsg.transaction);
|
const prevouts = this.sdkClient.get_prevouts(parsedMsg.transaction);
|
||||||
@ -2178,7 +2203,7 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a flag to prevent processing the same handshake multiple times
|
// Add a flag to prevent processing the same handshake multiple times
|
||||||
const handshakeKey = `${url}_${Date.now()}`;
|
const handshakeKey = `${url}_${JSON.stringify(handshakeMsg.processes_list)}`;
|
||||||
if (this.processedHandshakes && this.processedHandshakes.has(handshakeKey)) {
|
if (this.processedHandshakes && this.processedHandshakes.has(handshakeKey)) {
|
||||||
console.debug('Handshake already processed for', url);
|
console.debug('Handshake already processed for', url);
|
||||||
return;
|
return;
|
||||||
@ -2479,7 +2504,9 @@ export default class Services {
|
|||||||
roles: Record<string, RoleDefinition>[]
|
roles: Record<string, RoleDefinition>[]
|
||||||
) {
|
) {
|
||||||
console.log('Requesting data from peers');
|
console.log('Requesting data from peers');
|
||||||
const membersList = Object.values(this.getAllMembers());
|
const membersList = Object.values(this.getAllMembers()).map(member => ({
|
||||||
|
sp_addresses: member.sp_addresses
|
||||||
|
}));
|
||||||
try {
|
try {
|
||||||
// Convert objects to strings for WASM compatibility
|
// Convert objects to strings for WASM compatibility
|
||||||
const rolesString = JSON.stringify(roles);
|
const rolesString = JSON.stringify(roles);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user