Refactor Passkey Registration to utilize native WebAuthn API
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 44s

Update the test-smartphone.html to replace the use of @simplewebauthn/browser with the native WebAuthn API for Passkey registration. Enhance user feedback with additional messages regarding the use of the native API and improve the handling of user ID formats. Include detailed logging of credential creation options and ensure proper serialization of credential data for better debugging and compliance.
This commit is contained in:
Torsten Schulz (local)
2026-01-08 16:11:30 +01:00
parent 04f38cda69
commit 73ae8599c3

View File

@@ -328,34 +328,77 @@
throw new Error('Invalid options response'); throw new Error('Invalid options response');
} }
resultEl.textContent = 'Options erhalten. Starte WebAuthn startRegistration...\n\n'; resultEl.textContent = 'Options erhalten. Starte WebAuthn Registrierung...\n\n';
resultEl.textContent += `Challenge: ${optionsData.options.challenge?.substring(0, 20)}...\n`; resultEl.textContent += `Challenge: ${optionsData.options.challenge?.substring(0, 20)}...\n`;
resultEl.textContent += `RP ID: ${optionsData.options.rp?.id}\n`; resultEl.textContent += `RP ID: ${optionsData.options.rp?.id}\n`;
resultEl.textContent += `Timeout: ${optionsData.options.timeout}ms\n\n`; resultEl.textContent += `Timeout: ${optionsData.options.timeout}ms\n\n`;
resultEl.textContent += 'Warte auf Passkey-Authentifizierung...\n'; resultEl.textContent += 'Warte auf Passkey-Authentifizierung...\n';
resultEl.textContent += '(Scanne QR-Code oder verwende lokalen Authenticator)\n'; resultEl.textContent += '(Scanne QR-Code oder verwende lokalen Authenticator)\n\n';
resultEl.textContent += 'HINWEIS: Diese Test-Seite verwendet die native WebAuthn-API.\n';
resultEl.textContent += 'Die eigentliche App verwendet @simplewebauthn/browser (ist im Build enthalten).\n\n';
// WebAuthn startRegistration // Verwende native WebAuthn-API (navigator.credentials.create)
// Versuche, das Modul zu laden (kann fehlschlagen auf Smartphone) // Dies ist die Basis-API, die @simplewebauthn/browser verwendet
let startRegistration; const startTime = Date.now();
try {
const mod = await import('https://unpkg.com/@simplewebauthn/browser@13.2.2/dist/bundle/index.umd.min.js'); // Konvertiere user.id von Base64URL zu Uint8Array (falls nötig)
startRegistration = mod.startRegistration; let userId;
} catch (importError) { if (typeof optionsData.options.user?.id === 'string') {
// Fallback: Versuche, es lokal zu laden (wenn auf der Seite verfügbar) // Base64URL decode
resultEl.textContent += '\n\nWARNUNG: Konnte @simplewebauthn/browser nicht laden.\n'; const base64Url = optionsData.options.user.id;
resultEl.textContent += 'Dies ist normal, wenn die Bibliothek nicht verfügbar ist.\n'; const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
resultEl.textContent += 'Die Options wurden aber erfolgreich vom Server erhalten.\n\n'; const binaryString = atob(base64);
resultEl.textContent += 'Options-Struktur:\n'; userId = new Uint8Array(binaryString.length);
resultEl.textContent += JSON.stringify(optionsData.options, null, 2); for (let i = 0; i < binaryString.length; i++) {
resultEl.className = 'result warn'; userId[i] = binaryString.charCodeAt(i);
return; }
} else if (optionsData.options.user?.id instanceof Uint8Array) {
userId = optionsData.options.user.id;
} else {
throw new Error('Invalid user.id format');
} }
const startTime = Date.now(); // Erstelle PublicKeyCredentialCreationOptions
const credential = await startRegistration(optionsData.options); const publicKeyCredentialCreationOptions = {
challenge: Uint8Array.from(atob(optionsData.options.challenge.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)),
rp: optionsData.options.rp,
user: {
id: userId,
name: optionsData.options.user.name,
displayName: optionsData.options.user.displayName
},
pubKeyCredParams: optionsData.options.pubKeyCredParams,
timeout: optionsData.options.timeout,
attestation: optionsData.options.attestation,
excludeCredentials: optionsData.options.excludeCredentials?.map(cred => ({
id: Uint8Array.from(atob(cred.id.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)),
type: cred.type,
transports: cred.transports
})) || [],
authenticatorSelection: optionsData.options.authenticatorSelection,
extensions: optionsData.options.extensions
};
console.log('[DEBUG] Calling navigator.credentials.create with options:', publicKeyCredentialCreationOptions);
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
// Konvertiere Credential zu einem serialisierbaren Format
const credentialData = {
id: credential.id,
rawId: Array.from(new Uint8Array(credential.rawId)),
type: credential.type,
response: {
clientDataJSON: Array.from(new Uint8Array(credential.response.clientDataJSON)),
attestationObject: Array.from(new Uint8Array(credential.response.attestationObject))
},
transports: credential.response.getTransports?.() || []
};
const result = { const result = {
'Status': 'SUCCESS ✓', 'Status': 'SUCCESS ✓',
'Duration': `${duration}ms`, 'Duration': `${duration}ms`,
@@ -364,9 +407,10 @@
'Type': credential.type, 'Type': credential.type,
'Raw ID': credential.rawId ? 'present' : 'missing', 'Raw ID': credential.rawId ? 'present' : 'missing',
'Response': credential.response ? 'present' : 'missing', 'Response': credential.response ? 'present' : 'missing',
'Transports': credential.transports || [] 'Transports': credentialData.transports || []
}, },
'Full Credential': credential 'Note': 'Dies ist die native WebAuthn-API. Die eigentliche App verwendet @simplewebauthn/browser.',
'Credential Data': credentialData
}; };
resultEl.className = 'result success'; resultEl.className = 'result success';