summaryrefslogtreecommitdiff
path: root/spec/frontend/authentication/webauthn/register_spec.js
blob: 0f8ea2b635f7417c061d0f7f252442f06966f890 (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 $ from 'jquery';
import setWindowLocation from 'helpers/set_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import WebAuthnRegister from '~/authentication/webauthn/register';
import MockWebAuthnDevice from './mock_webauthn_device';
import { useMockNavigatorCredentials } from './util';

describe('WebAuthnRegister', () => {
  useMockNavigatorCredentials();

  const mockResponse = {
    type: 'public-key',
    id: '',
    rawId: '',
    response: {
      clientDataJSON: '',
      attestationObject: '',
    },
    getClientExtensionResults: () => {},
  };
  let webAuthnDevice;
  let container;
  let component;

  beforeEach(() => {
    loadFixtures('webauthn/register.html');
    webAuthnDevice = new MockWebAuthnDevice();
    container = $('#js-register-token-2fa');
    component = new WebAuthnRegister(container, {
      options: {
        rp: '',
        user: {
          id: '',
          name: '',
          displayName: '',
        },
        challenge: '',
        pubKeyCredParams: '',
      },
    });
    component.start();
  });

  const findSetupButton = () => container.find('#js-setup-token-2fa-device');
  const findMessage = () => container.find('p');
  const findDeviceResponse = () => container.find('#js-device-response');
  const findRetryButton = () => container.find('#js-token-2fa-try-again');

  it('shows setup button', () => {
    expect(findSetupButton().text()).toBe('Set up new device');
  });

  describe('when unsupported', () => {
    const { PublicKeyCredential } = window;

    beforeEach(() => {
      delete window.credentials;
      window.PublicKeyCredential = undefined;
    });

    afterEach(() => {
      window.PublicKeyCredential = PublicKeyCredential;
    });

    it.each`
      httpsEnabled | expectedText
      ${false}     | ${'WebAuthn only works with HTTPS-enabled websites'}
      ${true}      | ${'Please use a supported browser, e.g. Chrome (67+) or Firefox'}
    `('when https is $httpsEnabled', ({ httpsEnabled, expectedText }) => {
      setWindowLocation(`${httpsEnabled ? 'https:' : 'http:'}//localhost`);
      component.start();

      expect(findMessage().text()).toContain(expectedText);
    });
  });

  describe('when setup', () => {
    beforeEach(() => {
      findSetupButton().trigger('click');
    });

    it('shows in progress message', () => {
      expect(findMessage().text()).toContain('Trying to communicate with your device');
    });

    it('registers device', () => {
      webAuthnDevice.respondToRegisterRequest(mockResponse);

      return waitForPromises().then(() => {
        expect(findMessage().text()).toContain('Your device was successfully set up!');
        expect(findDeviceResponse().val()).toBe(JSON.stringify(mockResponse));
      });
    });

    it.each`
      errorName              | expectedText
      ${'NotSupportedError'} | ${'Your device is not compatible with GitLab'}
      ${'NotAllowedError'}   | ${'There was a problem communicating with your device'}
    `('when fails with $errorName', ({ errorName, expectedText }) => {
      webAuthnDevice.rejectRegisterRequest(new DOMException('', errorName));

      return waitForPromises().then(() => {
        expect(findMessage().text()).toContain(expectedText);
        expect(findRetryButton().length).toBe(1);
      });
    });

    it('can retry', () => {
      webAuthnDevice.respondToRegisterRequest({
        errorCode: 'error!',
      });

      return waitForPromises()
        .then(() => {
          findRetryButton().click();

          expect(findMessage().text()).toContain('Trying to communicate with your device');

          webAuthnDevice.respondToRegisterRequest(mockResponse);
          return waitForPromises();
        })
        .then(() => {
          expect(findMessage().text()).toContain('Your device was successfully set up!');
          expect(findDeviceResponse().val()).toBe(JSON.stringify(mockResponse));
        });
    });
  });
});