summaryrefslogtreecommitdiffhomepage
path: root/packages/browser/src/methods/startAssertion.test.ts
blob: 2287b498271e686421fa8adc9d9e9122f865bb0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import base64js from 'base64-js';

import {
  AssertionCredential,
  PublicKeyCredentialRequestOptionsJSON,
} from '@webauthntine/typescript-types';

import toUint8Array from '../helpers/toUint8Array';
import supportsWebauthn from '../helpers/supportsWebauthn';
import toBase64String from '../helpers/toBase64String';

import startAssertion from './startAssertion';

jest.mock('../helpers/supportsWebauthn');

const mockNavigatorGet = window.navigator.credentials.get as jest.Mock;
const mockSupportsWebauthn = supportsWebauthn as jest.Mock;

const mockAuthenticatorData = toBase64String(toUint8Array('mockAuthenticatorData'));
const mockClientDataJSON = toBase64String(toUint8Array('mockClientDataJSON'));
const mockSignature = toBase64String(toUint8Array('mockSignature'));
const mockUserHandle = toBase64String(toUint8Array('mockUserHandle'));

const goodOpts1: PublicKeyCredentialRequestOptionsJSON = {
  publicKey: {
    challenge: 'fizz',
    allowCredentials: [
      {
        id: 'abcdefgfdnsdfunguisdfgs',
        type: 'public-key',
        transports: ['nfc'],
      },
    ],
    timeout: 1,
  },
};

beforeEach(() => {
  mockNavigatorGet.mockReset();
  mockSupportsWebauthn.mockReset();
});

test('should convert options before passing to navigator.credentials.get(...)', async done => {
  mockSupportsWebauthn.mockReturnValue(true);

  // Stub out a response so the method won't throw
  mockNavigatorGet.mockImplementation(
    (): Promise<any> => {
      return new Promise(resolve => {
        resolve({ response: {} });
      });
    },
  );

  await startAssertion(goodOpts1);

  const argsPublicKey = mockNavigatorGet.mock.calls[0][0].publicKey;
  const credId = base64js.fromByteArray(argsPublicKey.allowCredentials[0].id);

  expect(argsPublicKey.challenge).toEqual(toUint8Array(goodOpts1.publicKey.challenge));
  // Make sure the credential ID is a proper base64 with a length that's a multiple of 4
  expect(credId.length % 4).toEqual(0);

  done();
});

test('should return base64-encoded response values', async done => {
  mockSupportsWebauthn.mockReturnValue(true);

  const credentialID = 'foobar';

  mockNavigatorGet.mockImplementation(
    (): Promise<AssertionCredential> => {
      return new Promise(resolve => {
        resolve({
          id: 'foobar',
          rawId: toUint8Array('foobar'),
          response: {
            authenticatorData: base64js.toByteArray(mockAuthenticatorData),
            clientDataJSON: base64js.toByteArray(mockClientDataJSON),
            signature: base64js.toByteArray(mockSignature),
            userHandle: base64js.toByteArray(mockUserHandle),
          },
          getClientExtensionResults: () => ({}),
          type: 'webauthn.get',
        });
      });
    },
  );

  const response = await startAssertion(goodOpts1);

  expect(response).toEqual({
    base64CredentialID: credentialID,
    base64AuthenticatorData: mockAuthenticatorData,
    base64ClientDataJSON: mockClientDataJSON,
    base64Signature: mockSignature,
    base64UserHandle: mockUserHandle,
  });

  done();
});

test("should throw error if WebAuthn isn't supported", async done => {
  mockSupportsWebauthn.mockReturnValue(false);

  await expect(startAssertion(goodOpts1)).rejects.toThrow(
    'WebAuthn is not supported in this browser',
  );

  done();
});

test('should throw error if assertion is cancelled for some reason', async done => {
  mockSupportsWebauthn.mockReturnValue(true);

  mockNavigatorGet.mockImplementation(
    (): Promise<null> => {
      return new Promise(resolve => {
        resolve(null);
      });
    },
  );

  await expect(startAssertion(goodOpts1)).rejects.toThrow('Assertion was not completed');

  done();
});