summaryrefslogtreecommitdiffstats
path: root/dom/u2f/tests/browser/browser_abort_visibility.js
blob: 1eb915fc769eae4af34d0b819c8af41598035cdf (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
129
130
131
132
133
134
135
136
137
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const TEST_URL =
  "https://example.com/browser/dom/u2f/tests/browser/tab_u2f_result.html";

async function assertStatus(tab, expected) {
  let actual = await SpecialPowers.spawn(
    tab.linkedBrowser,
    [],
    async function() {
      return content.document.getElementById("status").value;
    }
  );
  is(actual, expected, "u2f request " + expected);
}

async function waitForStatus(tab, expected) {
  /* eslint-disable no-shadow */
  await SpecialPowers.spawn(tab.linkedBrowser, [[expected]], async function(
    expected
  ) {
    return ContentTaskUtils.waitForCondition(() => {
      return content.document.getElementById("status").value == expected;
    });
  });
  /* eslint-enable no-shadow */

  await assertStatus(tab, expected);
}

function startMakeCredentialRequest(tab) {
  let challenge = crypto.getRandomValues(new Uint8Array(16));
  challenge = bytesToBase64UrlSafe(challenge);

  /* eslint-disable no-shadow */
  return SpecialPowers.spawn(tab.linkedBrowser, [[challenge]], async function([
    challenge,
  ]) {
    let appId = content.location.origin;
    let request = { version: "U2F_V2", challenge };

    let status = content.document.getElementById("status");

    content.u2f.register(appId, [request], [], result => {
      status.value = result.errorCode ? "aborted" : completed;
    });

    status.value = "pending";
  });
  /* eslint-enable no-shadow */
}

function startGetAssertionRequest(tab) {
  let challenge = crypto.getRandomValues(new Uint8Array(16));
  challenge = bytesToBase64UrlSafe(challenge);

  let keyHandle = crypto.getRandomValues(new Uint8Array(16));
  keyHandle = bytesToBase64UrlSafe(keyHandle);

  /* eslint-disable no-shadow */
  return SpecialPowers.spawn(
    tab.linkedBrowser,
    [[challenge, keyHandle]],
    async function([challenge, keyHandle]) {
      let appId = content.location.origin;
      let key = { version: "U2F_V2", keyHandle };

      let status = content.document.getElementById("status");

      content.u2f.sign(appId, challenge, [key], result => {
        status.value = result.errorCode ? "aborted" : completed;
      });

      status.value = "pending";
    }
  );
  /* eslint-enable no-shadow */
}

// Test that MakeCredential() and GetAssertion() requests
// are aborted when the current tab loses its focus.
add_task(async function test_abort() {
  // Enable the USB token.
  Services.prefs.setBoolPref("security.webauth.u2f", true);
  Services.prefs.setBoolPref(
    "security.webauth.webauthn_enable_softtoken",
    false
  );
  Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", true);
  Services.prefs.setBoolPref(
    "security.webauth.webauthn_enable_android_fido2",
    false
  );

  // Create a new tab for the MakeCredential() request.
  let tab_create = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    TEST_URL
  );

  // Start the request.
  await startMakeCredentialRequest(tab_create);
  await assertStatus(tab_create, "pending");

  // Open another tab and switch to it. The first will lose focus.
  let tab_get = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);

  // Start a GetAssertion() request in the second tab. That will abort the first.
  await startGetAssertionRequest(tab_get);
  await waitForStatus(tab_get, "pending");
  await waitForStatus(tab_create, "aborted");

  // Start a second request in the second tab. It should remain pending.
  await startGetAssertionRequest(tab_get);
  await waitForStatus(tab_get, "pending");

  // Switch back to the first tab. The second should still be pending
  await BrowserTestUtils.switchTab(gBrowser, tab_create);
  await assertStatus(tab_get, "pending");

  // Switch back to the get tab. The second should remain pending
  await BrowserTestUtils.switchTab(gBrowser, tab_get);
  await assertStatus(tab_get, "pending");

  // Close tabs.
  BrowserTestUtils.removeTab(tab_create);
  BrowserTestUtils.removeTab(tab_get);

  // Cleanup.
  Services.prefs.clearUserPref("security.webauth.u2f");
  Services.prefs.clearUserPref("security.webauth.webauthn_enable_softtoken");
  Services.prefs.clearUserPref("security.webauth.webauthn_enable_usbtoken");
});