tor-browser

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

test_remote_settings_startup_bundle.js (4198B)


      1 const { Database } = ChromeUtils.importESModule(
      2  "resource://services-settings/Database.sys.mjs"
      3 );
      4 const { RemoteSettings } = ChromeUtils.importESModule(
      5  "resource://services-settings/remote-settings.sys.mjs"
      6 );
      7 
      8 let server;
      9 let startupClients;
     10 
     11 add_setup(async () => {
     12  // Disable signature verification of collections listed in test startup.json.mzlz4
     13  // since their metadata will eventually expire.
     14  startupClients = [
     15    "message-groups",
     16    "nimbus-desktop-experiments",
     17    "search-categorization",
     18    "tracking-protection-lists",
     19    "query-stripping",
     20    "cfr",
     21  ].map(id => {
     22    const c = RemoteSettings(id);
     23    c.verifySignature = false;
     24    return c;
     25  });
     26 
     27  // Setup an HTTP server to serve the 'startup.json.mzlz4' bundle.
     28  server = new HttpServer();
     29  server.start(-1);
     30  server.registerDirectory(
     31    "/cdn/bundles/",
     32    do_get_file("test_remote_settings_startup_bundle")
     33  );
     34  server.registerPathHandler("/v1/", (request, response) => {
     35    response.write(
     36      JSON.stringify({
     37        capabilities: {
     38          attachments: {
     39            base_url: `http://localhost:${server.identity.primaryPort}/cdn/`,
     40          },
     41        },
     42      })
     43    );
     44    response.setHeader("Content-Type", "application/json; charset=UTF-8");
     45    response.setStatusLine(null, 200, "OK");
     46  });
     47  Services.prefs.setStringPref(
     48    "services.settings.server",
     49    `http://localhost:${server.identity.primaryPort}/v1`
     50  );
     51  registerCleanupFunction(() => {
     52    server.stop(() => {});
     53    Services.prefs.clearUserPref("services.settings.loglevel");
     54  });
     55 });
     56 
     57 async function clear_state() {
     58  await Database.destroy();
     59  RemoteSettings._ongoingExtractBundlePromise = null;
     60 }
     61 
     62 add_task(async function test_bundle_is_pulled_when_get_needs_sync() {
     63  const client = startupClients[0];
     64 
     65  Assert.ok(
     66    !(await Utils.hasLocalDump(client.bucketName, client.collectionName)),
     67    "Client has no packaged dump"
     68  );
     69 
     70  const records = await client.get();
     71 
     72  Assert.equal(records.length, 6, "Records were read from startup bundle");
     73 });
     74 add_task(clear_state);
     75 
     76 add_task(
     77  async function test_signature_of_extracted_data_from_bundle_is_verified() {
     78    const c = RemoteSettings("tracking-protection-lists"); // part of startup.json.mzlz4
     79    c.verifySignature = true;
     80 
     81    let called = null;
     82    c.validateCollectionSignature = (records, timestamp, metadata) => {
     83      called = { records, timestamp, metadata };
     84    };
     85 
     86    await c.get();
     87 
     88    Assert.ok(!!called.records.length);
     89    Assert.greaterOrEqual(called.timestamp, 1694684362860);
     90    Assert.ok(called.metadata.flags.includes("startup"));
     91  }
     92 );
     93 add_task(clear_state);
     94 
     95 add_task(async function test_bundle_is_not_importent_when_signature_fails() {
     96  const c = RemoteSettings("tracking-protection-lists"); // part of startup.json.mzlz4
     97  c.verifySignature = true;
     98 
     99  let called = false;
    100  c.validateCollectionSignature = () => {
    101    called = true;
    102    throw new Error("boom!");
    103  };
    104 
    105  let error;
    106  try {
    107    await c.get({ emptyListFallback: false });
    108    Assert.ok(false, ".get() should fail without network");
    109  } catch (e) {
    110    error = e;
    111  }
    112  Assert.ok(called, "Signature was verified");
    113  Assert.equal(
    114    error.name,
    115    "UnknownCollectionError",
    116    ".get() fails without network and with bad startup bundle"
    117  );
    118 });
    119 add_task(clear_state);
    120 
    121 add_task(async function test_sync_occurs_if_collection_not_part_of_bundle() {
    122  const c = RemoteSettings("foo");
    123 
    124  let error;
    125  try {
    126    await c.get({ emptyListFallback: false });
    127    Assert.ok(false, ".get() should fail when bundle disabled");
    128  } catch (e) {
    129    error = e;
    130  }
    131  Assert.equal(
    132    error.name,
    133    "UnknownCollectionError",
    134    ".get() fails to sync data"
    135  );
    136 });
    137 add_task(clear_state);
    138 
    139 add_task(async function test_several_clients_wait_for_bundle() {
    140  // several clients calling .get() in parallel will all take content from bundle.
    141  const results = await Promise.allSettled(
    142    startupClients.map(c => c.get({ emptyListFallback: false }))
    143  );
    144 
    145  Assert.deepEqual(
    146    [6, 70, 5, "UnknownCollectionError", 3, 11],
    147    results.map(({ status, value, reason }) =>
    148      status == "fulfilled" ? value.length : reason.name
    149    )
    150  );
    151 });
    152 add_task(clear_state);