app/javascript/packages/webauthn/verify-webauthn-device.spec.ts
import { TextEncoder } from 'util';
import { useSandbox, useDefineProperty } from '@18f/identity-test-helpers';
import verifyWebauthnDevice from './verify-webauthn-device';
describe('verifyWebauthnDevice', () => {
const sandbox = useSandbox();
const defineProperty = useDefineProperty();
const userChallenge = '[1, 2, 3, 4, 5, 6, 7, 8]';
const credentials = [
{ id: btoa('credential123'), transports: ['usb'] as AuthenticatorTransport[] },
{ id: btoa('credential456'), transports: ['internal', 'hybrid'] as AuthenticatorTransport[] },
];
context('webauthn api resolves credential', () => {
beforeEach(() => {
defineProperty(navigator, 'credentials', {
configurable: true,
value: {
get: sandbox.stub().resolves({
rawId: Buffer.from('123', 'utf-8'),
response: {
authenticatorData: Buffer.from('auth', 'utf-8'),
clientDataJSON: Buffer.from('json', 'utf-8'),
signature: Buffer.from('sig', 'utf-8'),
},
}),
},
});
});
it('resolves to credential', async () => {
const expectedGetOptions = {
publicKey: {
challenge: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]),
rpId: 'example.test',
allowCredentials: [
{
id: new TextEncoder().encode('credential123').buffer,
type: 'public-key',
transports: ['usb'],
},
{
id: new TextEncoder().encode('credential456').buffer,
type: 'public-key',
transports: ['internal', 'hybrid'],
},
],
timeout: 800000,
},
};
const result = await verifyWebauthnDevice({
userChallenge,
credentials,
});
expect(navigator.credentials.get).to.have.been.calledWith(expectedGetOptions);
expect(result).to.deep.equal({
credentialId: btoa('123'),
authenticatorData: btoa('auth'),
clientDataJSON: btoa('json'),
signature: btoa('sig'),
});
});
});
context('webauthn rejects with an error', () => {
const authError = new Error();
beforeEach(() => {
defineProperty(navigator, 'credentials', {
configurable: true,
value: {
get: sandbox.stub().rejects(authError),
},
});
});
it('forwards errors', async () => {
let didCatch;
try {
await verifyWebauthnDevice({
userChallenge,
credentials,
});
} catch (error) {
expect(error).to.equal(error);
didCatch = true;
}
expect(didCatch).to.be.true();
});
});
});