test/helpers/passkey-browser-fixture.js
Rama main · réplica de lectura del repositorio original.
// Test-only WebAuthn device: signs real assertions without touching a user's keychain.
var createAuthenticator = require('./passkey-authenticator').createAuthenticator;
function shim() {
function encode(value) {
var binary = ''; new Uint8Array(value).forEach(function (byte) { binary += String.fromCharCode(byte); });
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
function decode(value) { return Uint8Array.from(atob(value.replace(/-/g, '+').replace(/_/g, '/')), function (char) { return char.charCodeAt(0); }).buffer; }
async function invoke(action, input) {
var options = Object.assign({}, input.publicKey, { challenge: encode(input.publicKey.challenge) });
if (options.user) options.user = Object.assign({}, options.user, { id: encode(options.user.id) });
var res = await fetch('/fixture/webauthn/' + action, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(options) });
var credential = await res.json();
if (!res.ok) throw new DOMException('No fixture passkey', 'NotAllowedError');
credential.rawId = decode(credential.rawId);
['clientDataJSON', 'attestationObject', 'authenticatorData', 'signature', 'userHandle'].forEach(function (field) {
if (credential.response[field]) credential.response[field] = decode(credential.response[field]);
});
credential.response.getTransports = function () { return ['internal']; };
credential.getClientExtensionResults = function () { return {}; };
return credential;
}
Object.defineProperty(window, 'PublicKeyCredential', { value: function () {}, configurable: true });
Object.defineProperty(navigator, 'credentials', { value: {
create: function (input) { return invoke('create', input); },
get: function (input) { return invoke('get', input); },
}, configurable: true });
}
function attach() {
var device = null; var counter = 0;
function handle(req, res, url) {
if (url === '/fixture/passkey-shim.js') {
res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.end('(' + shim.toString() + ')();'); return true;
}
if (url !== '/fixture/webauthn/create' && url !== '/fixture/webauthn/get') return false;
var body = '';
req.on('data', function (chunk) { body += chunk; });
req.on('end', function () {
try {
var options = JSON.parse(body); var response;
if (url.endsWith('/create')) { device = createAuthenticator(); counter = 0; response = device.register(options, req.headers.origin); }
else { if (!device) throw new Error('No fixture passkey'); response = device.authenticate(options, req.headers.origin, { counter: ++counter }); }
res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(response));
} catch (error) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end('{}'); }
});
return true;
}
return { handle: handle };
}
module.exports = { attach: attach };