tor-browser

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

test_hawkrequest.js (6894B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { HAWKAuthenticatedRESTRequest, deriveHawkCredentials } =
      7  ChromeUtils.importESModule("resource://services-common/hawkrequest.sys.mjs");
      8 const { Async } = ChromeUtils.importESModule(
      9  "resource://services-common/async.sys.mjs"
     10 );
     11 
     12 // https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-use-session-certificatesign-etc
     13 var SESSION_KEYS = {
     14  sessionToken: h(
     15    // eslint-disable-next-line no-useless-concat
     16    "a0a1a2a3a4a5a6a7 a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7 b8b9babbbcbdbebf"
     17  ),
     18 
     19  tokenID: h(
     20    // eslint-disable-next-line no-useless-concat
     21    "c0a29dcf46174973 da1378696e4c82ae" + "10f723cf4f4d9f75 e39f4ae3851595ab"
     22  ),
     23 
     24  reqHMACkey: h(
     25    // eslint-disable-next-line no-useless-concat
     26    "9d8f22998ee7f579 8b887042466b72d5" + "3e56ab0c094388bf 65831f702d2febc0"
     27  ),
     28 };
     29 
     30 function do_register_cleanup() {
     31  Services.prefs.clearUserPref("intl.accept_languages");
     32  Services.prefs.clearUserPref("services.common.log.logger.rest.request");
     33 
     34  // remove the pref change listener
     35  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
     36  hawk._intl.uninit();
     37 }
     38 
     39 function run_test() {
     40  registerCleanupFunction(do_register_cleanup);
     41 
     42  Services.prefs.setStringPref(
     43    "services.common.log.logger.rest.request",
     44    "Trace"
     45  );
     46  initTestLogging("Trace");
     47 
     48  run_next_test();
     49 }
     50 
     51 add_test(function test_intl_accept_language() {
     52  let testCount = 0;
     53  let languages = [
     54    "zu-NP;vo", // Nepalese dialect of Zulu, defaulting to Volapük
     55    "fa-CG;ik", // Congolese dialect of Farsei, defaulting to Inupiaq
     56  ];
     57 
     58  function setLanguagePref(lang) {
     59    Services.prefs.setStringPref("intl.accept_languages", lang);
     60  }
     61 
     62  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
     63 
     64  Services.prefs.addObserver("intl.accept_languages", checkLanguagePref);
     65  setLanguagePref(languages[testCount]);
     66 
     67  function checkLanguagePref() {
     68    CommonUtils.nextTick(function () {
     69      // Ensure we're only called for the number of entries in languages[].
     70      Assert.less(testCount, languages.length);
     71 
     72      Assert.equal(hawk._intl.accept_languages, languages[testCount]);
     73 
     74      testCount++;
     75      if (testCount < languages.length) {
     76        // Set next language in prefs; Pref service will call checkNextLanguage.
     77        setLanguagePref(languages[testCount]);
     78        return;
     79      }
     80 
     81      // We've checked all the entries in languages[]. Cleanup and move on.
     82      info(
     83        "Checked " +
     84          testCount +
     85          " languages. Removing checkLanguagePref as pref observer."
     86      );
     87      Services.prefs.removeObserver("intl.accept_languages", checkLanguagePref);
     88      run_next_test();
     89    });
     90  }
     91 });
     92 
     93 add_task(async function test_hawk_authenticated_request() {
     94  let postData = { your: "data" };
     95 
     96  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
     97  // computation with the hawk timestamp easier, since hawk throws away the
     98  // millisecond values.
     99  let then = 34329600000;
    100 
    101  let clockSkew = 120000;
    102  let timeOffset = -1 * clockSkew;
    103  let localTime = then + clockSkew;
    104 
    105  // Set the accept-languages pref to the Nepalese dialect of Zulu.
    106  let acceptLanguage = "zu-NP"; // omit trailing ';', which our HTTP libs snip
    107  Services.prefs.setStringPref("intl.accept_languages", acceptLanguage);
    108 
    109  let credentials = {
    110    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    111    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    112    algorithm: "sha256",
    113  };
    114 
    115  let server = httpd_setup({
    116    "/elysium": function (request, response) {
    117      Assert.ok(request.hasHeader("Authorization"));
    118 
    119      // check that the header timestamp is our arbitrary system date, not
    120      // today's date.  Note that hawk header timestamps are in seconds, not
    121      // milliseconds.
    122      let authorization = request.getHeader("Authorization");
    123      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
    124      Assert.equal(tsMS, then);
    125 
    126      // This testing can be a little wonky. In an environment where
    127      //   pref("intl.accept_languages") === 'en-US, en'
    128      // the header is sent as:
    129      //   'en-US,en;q=0.5'
    130      // hence our fake value for acceptLanguage.
    131      let lang = request.getHeader("Accept-Language");
    132      Assert.equal(lang, acceptLanguage);
    133 
    134      let message = "yay";
    135      response.setStatusLine(request.httpVersion, 200, "OK");
    136      response.bodyOutputStream.write(message, message.length);
    137    },
    138  });
    139 
    140  let url = server.baseURI + "/elysium";
    141  let extra = {
    142    now: localTime,
    143    localtimeOffsetMsec: timeOffset,
    144  };
    145 
    146  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
    147 
    148  // Allow hawk._intl to respond to the language pref change
    149  await Async.promiseYield();
    150 
    151  await request.post(postData);
    152  Assert.equal(200, request.response.status);
    153  Assert.equal(request.response.body, "yay");
    154 
    155  Services.prefs.clearUserPref("intl.accept_languages");
    156  let pref = Services.locale.acceptLanguages;
    157  Assert.notEqual(acceptLanguage, pref);
    158 
    159  await promiseStopServer(server);
    160 });
    161 
    162 add_task(async function test_hawk_language_pref_changed() {
    163  let languages = [
    164    "zu-NP", // Nepalese dialect of Zulu
    165    "fa-CG", // Congolese dialect of Farsi
    166  ];
    167 
    168  let credentials = {
    169    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    170    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    171    algorithm: "sha256",
    172  };
    173 
    174  function setLanguage(lang) {
    175    Services.prefs.setStringPref("intl.accept_languages", lang);
    176  }
    177 
    178  let server = httpd_setup({
    179    "/foo": function (request, response) {
    180      Assert.equal(languages[1], request.getHeader("Accept-Language"));
    181 
    182      response.setStatusLine(request.httpVersion, 200, "OK");
    183    },
    184  });
    185 
    186  let url = server.baseURI + "/foo";
    187  let request;
    188 
    189  setLanguage(languages[0]);
    190 
    191  // A new request should create the stateful object for tracking the current
    192  // language.
    193  request = new HAWKAuthenticatedRESTRequest(url, credentials);
    194 
    195  // Wait for change to propagate
    196  await Async.promiseYield();
    197  Assert.equal(languages[0], request._intl.accept_languages);
    198 
    199  // Change the language pref ...
    200  setLanguage(languages[1]);
    201 
    202  await Async.promiseYield();
    203 
    204  request = new HAWKAuthenticatedRESTRequest(url, credentials);
    205  let response = await request.post({});
    206 
    207  Assert.equal(200, response.status);
    208  Services.prefs.clearUserPref("intl.accept_languages");
    209 
    210  await promiseStopServer(server);
    211 });
    212 
    213 add_task(async function test_deriveHawkCredentials() {
    214  let credentials = await deriveHawkCredentials(
    215    SESSION_KEYS.sessionToken,
    216    "sessionToken"
    217  );
    218  Assert.equal(credentials.id, SESSION_KEYS.tokenID);
    219  Assert.equal(
    220    CommonUtils.bytesAsHex(credentials.key),
    221    SESSION_KEYS.reqHMACkey
    222  );
    223 });
    224 
    225 // turn formatted test vectors into normal hex strings
    226 function h(hexStr) {
    227  return hexStr.replace(/\s+/g, "");
    228 }