chromium/chrome/test/data/extensions/api_test/web_authentication_proxy/main/test.js

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as util from '/_test_resources/api_test/web_authentication_proxy/util.js';

const ERROR_INVALID_SENDER = 'Error: Invalid sender';
const ERROR_INVALID_REQUEST_ID = 'Error: Invalid requestId';

let availableTests = [
  async function attachDetach() {
    await chrome.webAuthenticationProxy.attach();
    // Attaching the same extension again should be a no-op. (Attaching a
    // *different* extension would fail. This is tested in
    // WebAuthenticationProxyApiTest.AttachSecondExtension)
    await chrome.webAuthenticationProxy.attach();
    await chrome.webAuthenticationProxy.detach();
    // Similarly, detaching an unattached extension does nothing.
    await chrome.webAuthenticationProxy.detach();
    chrome.test.succeed();
  },
  async function attachReload() {
    // This test will be run twice by reloading the extension.
    await chrome.webAuthenticationProxy.attach();
    chrome.test.succeed();
  },
  async function attachSecondExtension() {
    // The first attempt to attach should succeed.
    await chrome.webAuthenticationProxy.attach();
    await chrome.test.sendMessage('attached');
    // The browser loaded a second extension. Detach so that it can attach.
    await chrome.webAuthenticationProxy.detach();
    await chrome.test.sendMessage('detached');
    // Browser unloaded the second extension. Reattaching should
    // succeed.
    await chrome.webAuthenticationProxy.attach();
    chrome.test.succeed();
  },
  async function isUvpaa() {
    let receivedRequests = 0;
    chrome.webAuthenticationProxy.onIsUvpaaRequest.addListener(
        async (requestInfo) => {
          receivedRequests++;
          chrome.test.assertTrue(receivedRequests <= 2);
          // We set the first request to false, and the second to true.
          let isUvpaa = receivedRequests == 2;
          await chrome.webAuthenticationProxy.completeIsUvpaaRequest(
              {requestId: requestInfo.requestId, isUvpaa});
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function isUvpaaNotAttached() {
    let eventHandlerCalled = false;
    chrome.webAuthenticationProxy.onIsUvpaaRequest.addListener(
        (requestInfo) => {
          eventHandlerCalled = true;
        });
    await chrome.test.sendMessage('ready');
    chrome.test.assertFalse(eventHandlerCalled);
    chrome.test.succeed();
  },
  async function isUvpaaResolvesOnDetach() {
    chrome.webAuthenticationProxy.onIsUvpaaRequest.addListener(
        async (request) => {
          await chrome.webAuthenticationProxy.detach();
          await chrome.test.assertPromiseRejects(
              chrome.webAuthenticationProxy.completeIsUvpaaRequest(
                  {requestId: request.requestId, isUvpaa: true}),
              ERROR_INVALID_SENDER);
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });

    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function makeCredential() {
    chrome.webAuthenticationProxy.onCreateRequest.addListener(
        async (request) => {
          await util.completeCreateRequest(request.requestId);
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function makeCredentialError() {
    let nextError;
    chrome.webAuthenticationProxy.onCreateRequest.addListener(
        async (request) => {
          chrome.test.assertTrue(nextError.length > 0);
          // The C++ side verifies that the passed in errorName matches the
          // error that  the WebAuthn client-side JS receives.
          await util.completeCreateRequest(request.requestId, nextError);
          chrome.test.assertNoLastError();
          nextError = await chrome.test.sendMessage('nextError');
          if (!nextError) {
            chrome.test.succeed();
          } else {
            chrome.test.sendMessage('nextRequest');
          }
        });
    await chrome.webAuthenticationProxy.attach();
    // The C++ side passes error names to be used in completeCreateRequest().
    nextError = await chrome.test.sendMessage('nextError');
    chrome.test.sendMessage('nextRequest');
  },
  async function makeCredentialResolvesOnDetach() {
    chrome.webAuthenticationProxy.onCreateRequest.addListener(
        async (request) => {
          await chrome.webAuthenticationProxy.detach();
          await chrome.test.assertPromiseRejects(
              util.completeCreateRequest(request.requestId),
              ERROR_INVALID_SENDER);
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function makeCredentialCancel() {
    let canceled = false;
    let requestId;
    chrome.webAuthenticationProxy.onRequestCanceled.addListener(
        (canceledRequestId) => {
          chrome.test.assertFalse(canceled);
          canceled = true;
          chrome.test.assertTrue(canceledRequestId == requestId);
        });
    chrome.webAuthenticationProxy.onCreateRequest.addListener(
        async (request) => {
          chrome.test.assertFalse(canceled);
          requestId = request.requestId;
          await chrome.test.sendMessage('request');
          // Browser indicates the request completed, which means the cancel
          // handler should have been invoked.
          chrome.test.assertTrue(canceled);

          // Completing the canceled request should fail.
          await chrome.test.assertPromiseRejects(
              util.completeCreateRequest(request.requestId),
              ERROR_INVALID_REQUEST_ID);
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function getAssertion() {
    chrome.webAuthenticationProxy.onGetRequest.addListener(async (request) => {
      await util.completeGetRequest(request.requestId);
      chrome.test.assertNoLastError();
      chrome.test.succeed();
    });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function getAssertionError() {
    let nextError;
    chrome.webAuthenticationProxy.onGetRequest.addListener(async (request) => {
      chrome.test.assertTrue(nextError.length > 0);
      // The C++ side verifies that the passed in errorName matches the
      // error that  the WebAuthn client-side JS receives.
      await util.completeGetRequest(request.requestId, nextError);
      chrome.test.assertNoLastError();
      nextError = await chrome.test.sendMessage('nextError');
      if (!nextError) {
        chrome.test.succeed();
      } else {
        chrome.test.sendMessage('nextRequest');
      }
    });
    await chrome.webAuthenticationProxy.attach();
    // The C++ side passes error names to be used in completeGetRequest().
    nextError = await chrome.test.sendMessage('nextError');
    chrome.test.sendMessage('nextRequest');
  },
  async function getAssertionResolvesOnDetach() {
    chrome.webAuthenticationProxy.onGetRequest.addListener(async (request) => {
      await chrome.webAuthenticationProxy.detach();
      await chrome.test.assertPromiseRejects(
          util.completeGetRequest(request.requestId), ERROR_INVALID_SENDER);
      chrome.test.assertNoLastError();
      chrome.test.succeed();
    });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function getAssertionCancel() {
    let canceled = false;
    let requestId;
    chrome.webAuthenticationProxy.onRequestCanceled.addListener(
        (canceledRequestId) => {
          chrome.test.assertFalse(canceled);
          canceled = true;
          chrome.test.assertTrue(canceledRequestId == requestId);
        });
    chrome.webAuthenticationProxy.onGetRequest.addListener(async (request) => {
      chrome.test.assertFalse(canceled);
      requestId = request.requestId;
      await chrome.test.sendMessage('request');
      // Browser indicates the request completed, which means the cancel
      // handler should have been invoked.
      chrome.test.assertTrue(canceled);

      // Completing the canceled request should fail.
      await chrome.test.assertPromiseRejects(
          util.completeGetRequest(request.requestId), ERROR_INVALID_REQUEST_ID);
      chrome.test.assertNoLastError();
      chrome.test.succeed();
    });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function incognitoSpanning() {
    chrome.webAuthenticationProxy.onCreateRequest.addListener(
        async (request) => {
          await util.completeCreateRequest(request.requestId);
          chrome.test.assertNoLastError();
          chrome.test.succeed();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
  async function policyBlockedHosts() {
    chrome.webAuthenticationProxy.onIsUvpaaRequest.addListener(
        async (requestInfo) => {
          await chrome.webAuthenticationProxy.completeIsUvpaaRequest(
              {requestId: requestInfo.requestId, isUvpaa: true});
          chrome.test.assertNoLastError();
        });
    await chrome.webAuthenticationProxy.attach();
    chrome.test.sendMessage('ready');
  },
];

chrome.test.getConfig((config) => {
  const tests = availableTests.filter((t) => {
    return config.customArg == t.name;
  });
  if (tests.length == 0) {
    // Log because the C++ side might stall rather than notice the call to
    // notifyFail.
    console.error('No test found');
    chrome.test.notifyFail('No test found');
    return;
  }
  chrome.test.runTests(tests);
});