tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

otpcredential-helper.js (3601B)


      1 // These tests rely on the User Agent providing an implementation of
      2 // MockWebOTPService.
      3 //
      4 // In Chromium-based browsers this implementation is provided by a polyfill
      5 // in order to reduce the amount of test-only code shipped to users. To enable
      6 // these tests the browser must be run with these options:
      7 // //   --enable-blink-features=MojoJS,MojoJSTest
      8 
      9 import {isChromiumBased} from '/resources/test-only-api.m.js';
     10 
     11 /**
     12 * This enumeration is used by WebOTP WPTs to control mock backend behavior.
     13 * See MockWebOTPService below.
     14 */
     15 export const Status = {
     16  SUCCESS: 0,
     17  UNHANDLED_REQUEST: 1,
     18  CANCELLED: 2,
     19  ABORTED: 3,
     20 };
     21 
     22 /**
     23 * A interface which must be implemented by browsers to support WebOTP WPTs.
     24 */
     25 export class MockWebOTPService {
     26  /**
     27   * Accepts a function to be invoked in response to the next OTP request
     28   * received by the mock. The (optionally async) function, when executed, must
     29   * return an object with a `status` field holding one of the `Status` values
     30   * defined above, and -- if successful -- an `otp` field containing a
     31   * simulated OTP string.
     32   *
     33   * Tests will call this method directly to inject specific response behavior
     34   * into the browser-specific mock implementation.
     35   */
     36  async handleNextOTPRequest(responseFunc) {}
     37 }
     38 
     39 /**
     40 * Returns a Promise resolving to a browser-specific MockWebOTPService subclass
     41 * instance if one is available.
     42 */
     43 async function createBrowserSpecificMockImpl() {
     44  if (isChromiumBased) {
     45    return await createChromiumMockImpl();
     46  }
     47  throw new Error('Unsupported browser.');
     48 }
     49 
     50 const asyncMock = createBrowserSpecificMockImpl();
     51 
     52 export function expectOTPRequest() {
     53  return {
     54    async andReturn(callback) {
     55      const mock = await asyncMock;
     56      mock.handleNextOTPRequest(callback);
     57    }
     58  }
     59 }
     60 
     61 /**
     62 * Instantiates a Chromium-specific subclass of MockWebOTPService.
     63 */
     64 async function createChromiumMockImpl() {
     65  const {SmsStatus, WebOTPService, WebOTPServiceReceiver} = await import(
     66      '/gen/third_party/blink/public/mojom/sms/webotp_service.mojom.m.js');
     67  const MockWebOTPServiceChromium = class extends MockWebOTPService {
     68    constructor() {
     69      super();
     70      this.mojoReceiver_ = new WebOTPServiceReceiver(this);
     71      this.interceptor_ =
     72          new MojoInterfaceInterceptor(WebOTPService.$interfaceName);
     73      this.interceptor_.oninterfacerequest = (e) => {
     74        this.mojoReceiver_.$.bindHandle(e.handle);
     75      };
     76      this.interceptor_.start();
     77      this.requestHandlers_ = [];
     78      Object.freeze(this);
     79    }
     80 
     81    handleNextOTPRequest(responseFunc) {
     82      this.requestHandlers_.push(responseFunc);
     83    }
     84 
     85    async receive() {
     86      if (this.requestHandlers_.length == 0) {
     87        throw new Error('Mock received unexpected OTP request.');
     88      }
     89 
     90      const responseFunc = this.requestHandlers_.shift();
     91      const response = await responseFunc();
     92      switch (response.status) {
     93        case Status.SUCCESS:
     94          if (typeof response.otp != 'string') {
     95            throw new Error('Mock success results require an OTP string.');
     96          }
     97          return {status: SmsStatus.kSuccess, otp: response.otp};
     98        case Status.UNHANDLED_REQUEST:
     99          return {status: SmsStatus.kUnhandledRequest};
    100        case Status.CANCELLED:
    101          return {status: SmsStatus.kCancelled};
    102        case Status.ABORTED:
    103          return {status: SmsStatus.kAborted};
    104        default:
    105          throw new Error(
    106              `Mock result contains unknown status: ${response.status}`);
    107      }
    108    }
    109 
    110    async abort() {}
    111  };
    112  return new MockWebOTPServiceChromium();
    113 }