tor-browser

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

nfc-helpers.js (7933B)


      1 'use strict';
      2 // These tests rely on the User Agent providing an implementation of
      3 // platform nfc backends.
      4 //
      5 // In Chromium-based browsers this implementation is provided by a polyfill
      6 // in order to reduce the amount of test-only code shipped to users. To enable
      7 // these tests the browser must be run with these options:
      8 //
      9 //   --enable-blink-features=MojoJS,MojoJSTest
     10 
     11 async function loadChromiumResources() {
     12  await loadScript('/resources/testdriver.js');
     13  await loadScript('/resources/testdriver-vendor.js');
     14  await import('/resources/chromium/nfc-mock.js');
     15 }
     16 
     17 async function initialize_nfc_tests() {
     18  if (typeof WebNFCTest === 'undefined') {
     19    const script = document.createElement('script');
     20    script.src = '/resources/test-only-api.js';
     21    script.async = false;
     22    const p = new Promise((resolve, reject) => {
     23      script.onload = () => { resolve(); };
     24      script.onerror = e => { reject(e); };
     25    })
     26    document.head.appendChild(script);
     27    await p;
     28 
     29    if (isChromiumBased) {
     30      await loadChromiumResources();
     31    }
     32  }
     33  assert_implements( WebNFCTest, 'WebNFC testing interface is unavailable.');
     34  let NFCTest = new WebNFCTest();
     35  await NFCTest.initialize();
     36  return NFCTest;
     37 }
     38 
     39 function nfc_test(func, name, properties) {
     40  promise_test(async t => {
     41    let NFCTest = await initialize_nfc_tests();
     42    t.add_cleanup(async () => {
     43      await NFCTest.reset();
     44    });
     45    await func(t, NFCTest.getMockNFC());
     46  }, name, properties);
     47 }
     48 
     49 const test_text_data = 'Test text data.';
     50 const test_text_byte_array = new TextEncoder().encode(test_text_data);
     51 const test_number_data = 42;
     52 const test_json_data = {level: 1, score: 100, label: 'Game'};
     53 const test_url_data = 'https://w3c.github.io/web-nfc/';
     54 const test_message_origin = 'https://127.0.0.1:8443';
     55 const test_buffer_data = new ArrayBuffer(test_text_byte_array.length);
     56 const test_buffer_view = new Uint8Array(test_buffer_data);
     57 test_buffer_view.set(test_text_byte_array);
     58 const fake_tag_serial_number = 'c0:45:00:02';
     59 const test_record_id = '/test_path/test_id';
     60 
     61 const NFCHWStatus = {};
     62 // OS-level NFC setting is ON
     63 NFCHWStatus.ENABLED = 1;
     64 // no NFC chip
     65 NFCHWStatus.NOT_SUPPORTED = NFCHWStatus.ENABLED + 1;
     66 // OS-level NFC setting OFF
     67 NFCHWStatus.DISABLED = NFCHWStatus.NOT_SUPPORTED + 1;
     68 
     69 function encodeTextToArrayBuffer(string, encoding) {
     70  // Only support 'utf-8', 'utf-16', 'utf-16be', and 'utf-16le'.
     71  assert_true(
     72      encoding === 'utf-8' || encoding === 'utf-16' ||
     73      encoding === 'utf-16be' || encoding === 'utf-16le');
     74 
     75  if (encoding === 'utf-8') {
     76    return new TextEncoder().encode(string).buffer;
     77  }
     78 
     79  if (encoding === 'utf-16') {
     80    let uint16array = new Uint16Array(string.length);
     81    for (let i = 0; i < string.length; i++) {
     82      uint16array[i] = string.codePointAt(i);
     83    }
     84    return uint16array.buffer;
     85  }
     86 
     87  const littleEndian = encoding === 'utf-16le';
     88  const buffer = new ArrayBuffer(string.length * 2);
     89  const view = new DataView(buffer);
     90  for (let i = 0; i < string.length; i++) {
     91    view.setUint16(i * 2, string.codePointAt(i), littleEndian);
     92  }
     93  return buffer;
     94 }
     95 
     96 function createMessage(records) {
     97  if (records !== undefined) {
     98    let message = {};
     99    message.records = records;
    100    return message;
    101  }
    102 }
    103 
    104 function createRecord(recordType, data, id, mediaType, encoding, lang) {
    105  let record = {};
    106  if (recordType !== undefined)
    107    record.recordType = recordType;
    108  if (id !== undefined)
    109    record.id = id;
    110  if (mediaType !== undefined)
    111    record.mediaType = mediaType;
    112  if (encoding !== undefined)
    113    record.encoding = encoding;
    114  if (lang !== undefined)
    115    record.lang = lang;
    116  if (data !== undefined)
    117    record.data = data;
    118  return record;
    119 }
    120 
    121 function createTextRecord(data, encoding, lang) {
    122  return createRecord('text', data, test_record_id, undefined, encoding, lang);
    123 }
    124 
    125 function createMimeRecordFromJson(json) {
    126  return createRecord(
    127      'mime', new TextEncoder().encode(JSON.stringify(json)),
    128      test_record_id, 'application/json');
    129 }
    130 
    131 function createMimeRecord(buffer) {
    132  return createRecord(
    133      'mime', buffer, test_record_id, 'application/octet-stream');
    134 }
    135 
    136 function createUnknownRecord(buffer) {
    137  return createRecord('unknown', buffer, test_record_id);
    138 }
    139 
    140 function createUrlRecord(url, isAbsUrl) {
    141  if (isAbsUrl) {
    142    return createRecord('absolute-url', url, test_record_id);
    143  }
    144  return createRecord('url', url, test_record_id);
    145 }
    146 
    147 // Compares NDEFMessageSource that was provided to the API
    148 // (e.g. NDEFReader.write), and NDEFMessage that was received by the
    149 // mock NFC service.
    150 function assertNDEFMessagesEqual(providedMessage, receivedMessage) {
    151  // If simple data type is passed, e.g. String or ArrayBuffer or
    152  // ArrayBufferView, convert it to NDEFMessage before comparing.
    153  // https://w3c.github.io/web-nfc/#dom-ndefmessagesource
    154  let provided = providedMessage;
    155  if (providedMessage instanceof ArrayBuffer ||
    156      ArrayBuffer.isView(providedMessage))
    157    provided = createMessage([createRecord(
    158        'mime', providedMessage, undefined /* id */,
    159        'application/octet-stream')]);
    160  else if (typeof providedMessage === 'string')
    161    provided = createMessage([createRecord('text', providedMessage)]);
    162 
    163  assert_equals(provided.records.length, receivedMessage.data.length,
    164      'NDEFMessages must have same number of NDEFRecords');
    165 
    166  // Compare contents of each individual NDEFRecord
    167  for (let i = 0; i < provided.records.length; ++i)
    168    compareNDEFRecords(provided.records[i], receivedMessage.data[i]);
    169 }
    170 
    171 // Used to compare two NDEFMessage, one that is received from
    172 // NDEFReader.onreading() EventHandler and another that is provided to mock NFC
    173 // service.
    174 function assertWebNDEFMessagesEqual(message, expectedMessage) {
    175  assert_equals(message.records.length, expectedMessage.records.length);
    176 
    177  for(let i in message.records) {
    178    let record = message.records[i];
    179    let expectedRecord = expectedMessage.records[i];
    180    assert_equals(record.recordType, expectedRecord.recordType);
    181    assert_equals(record.mediaType, expectedRecord.mediaType);
    182    assert_equals(record.id, expectedRecord.id);
    183    assert_equals(record.encoding, expectedRecord.encoding);
    184    assert_equals(record.lang, expectedRecord.lang);
    185    // Compares record data
    186    assert_array_equals(new Uint8Array(record.data),
    187          new Uint8Array(expectedRecord.data));
    188  }
    189 }
    190 
    191 function testMultiScanOptions(message, scanOptions, unmatchedScanOptions, desc) {
    192  nfc_test(async (t, mockNFC) => {
    193    const ndef1 = new NDEFReader();
    194    const ndef2 = new NDEFReader();
    195    const controller = new AbortController();
    196 
    197    // Reading from unmatched ndef will not be triggered
    198    ndef1.onreading = t.unreached_func("reading event should not be fired.");
    199    unmatchedScanOptions.signal = controller.signal;
    200    await ndef1.scan(unmatchedScanOptions);
    201 
    202    const ndefWatcher = new EventWatcher(t, ndef2, ["reading", "readingerror"]);
    203    const promise = ndefWatcher.wait_for("reading").then(event => {
    204      controller.abort();
    205      assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
    206    });
    207    scanOptions.signal = controller.signal;
    208    await ndef2.scan(scanOptions);
    209 
    210    mockNFC.setReadingMessage(message);
    211    await promise;
    212  }, desc);
    213 }
    214 
    215 function testMultiMessages(message, scanOptions, unmatchedMessage, desc) {
    216  nfc_test(async (t, mockNFC) => {
    217    const ndef = new NDEFReader();
    218    const controller = new AbortController();
    219    const ndefWatcher = new EventWatcher(t, ndef, ["reading", "readingerror"]);
    220    const promise = ndefWatcher.wait_for("reading").then(event => {
    221      controller.abort();
    222      assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
    223    });
    224    scanOptions.signal = controller.signal;
    225    await ndef.scan(scanOptions);
    226 
    227    // Unmatched message will not be read
    228    mockNFC.setReadingMessage(unmatchedMessage);
    229    mockNFC.setReadingMessage(message);
    230    await promise;
    231  }, desc);
    232 }