tor-browser

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

test_service_login.js (6925B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 const { Service } = ChromeUtils.importESModule(
      5  "resource://services-sync/service.sys.mjs"
      6 );
      7 
      8 Log.repository.rootLogger.addAppender(new Log.DumpAppender());
      9 
     10 function login_handling(handler) {
     11  return function (request, response) {
     12    if (has_hawk_header(request)) {
     13      handler(request, response);
     14    } else {
     15      let body = "Unauthorized";
     16      response.setStatusLine(request.httpVersion, 401, "Unauthorized");
     17      response.setHeader("Content-Type", "text/plain");
     18      response.bodyOutputStream.write(body, body.length);
     19    }
     20  };
     21 }
     22 
     23 add_task(async function test_offline() {
     24  try {
     25    _("The right bits are set when we're offline.");
     26    Services.io.offline = true;
     27    Assert.ok(!(await Service.login()));
     28    Assert.equal(Service.status.login, LOGIN_FAILED_NETWORK_ERROR);
     29    Services.io.offline = false;
     30  } finally {
     31    for (const pref of Svc.PrefBranch.getChildList("")) {
     32      Svc.PrefBranch.clearUserPref(pref);
     33    }
     34  }
     35 });
     36 
     37 function setup() {
     38  let janeHelper = track_collections_helper();
     39  let janeU = janeHelper.with_updated_collection;
     40  let johnHelper = track_collections_helper();
     41  let johnU = johnHelper.with_updated_collection;
     42 
     43  let server = httpd_setup({
     44    "/1.1/johndoe/info/collections": login_handling(johnHelper.handler),
     45    "/1.1/janedoe/info/collections": login_handling(janeHelper.handler),
     46 
     47    // We need these handlers because we test login, and login
     48    // is where keys are generated or fetched.
     49    // TODO: have Jane fetch her keys, not generate them...
     50    "/1.1/johndoe/storage/crypto/keys": johnU(
     51      "crypto",
     52      new ServerWBO("keys").handler()
     53    ),
     54    "/1.1/johndoe/storage/meta/global": johnU(
     55      "meta",
     56      new ServerWBO("global").handler()
     57    ),
     58    "/1.1/janedoe/storage/crypto/keys": janeU(
     59      "crypto",
     60      new ServerWBO("keys").handler()
     61    ),
     62    "/1.1/janedoe/storage/meta/global": janeU(
     63      "meta",
     64      new ServerWBO("global").handler()
     65    ),
     66  });
     67 
     68  return server;
     69 }
     70 
     71 add_task(async function test_not_logged_in() {
     72  let server = setup();
     73  try {
     74    await Service.login();
     75    Assert.ok(!Service.isLoggedIn, "no user configured, so can't be logged in");
     76    Assert.equal(Service._checkSync(), kSyncNotConfigured);
     77  } finally {
     78    for (const pref of Svc.PrefBranch.getChildList("")) {
     79      Svc.PrefBranch.clearUserPref(pref);
     80    }
     81    await promiseStopServer(server);
     82  }
     83 });
     84 
     85 add_task(async function test_login_logout() {
     86  enableValidationPrefs();
     87 
     88  let server = setup();
     89 
     90  try {
     91    _("Force the initial state.");
     92    Service.status.service = STATUS_OK;
     93    Assert.equal(Service.status.service, STATUS_OK);
     94 
     95    _("Try logging in. It won't work because we're not configured yet.");
     96    await Service.login();
     97    Assert.equal(Service.status.service, CLIENT_NOT_CONFIGURED);
     98    Assert.equal(Service.status.login, LOGIN_FAILED_NO_USERNAME);
     99    Assert.ok(!Service.isLoggedIn);
    100 
    101    _("Try again with a configured account");
    102    await configureIdentity({ username: "johndoe" }, server);
    103    await Service.login();
    104    Assert.equal(Service.status.service, STATUS_OK);
    105    Assert.equal(Service.status.login, LOGIN_SUCCEEDED);
    106    Assert.ok(Service.isLoggedIn);
    107 
    108    _("Logout.");
    109    Service.logout();
    110    Assert.ok(!Service.isLoggedIn);
    111 
    112    _("Logging out again won't do any harm.");
    113    Service.logout();
    114    Assert.ok(!Service.isLoggedIn);
    115  } finally {
    116    for (const pref of Svc.PrefBranch.getChildList("")) {
    117      Svc.PrefBranch.clearUserPref(pref);
    118    }
    119    await promiseStopServer(server);
    120  }
    121 });
    122 
    123 add_task(async function test_login_on_sync() {
    124  enableValidationPrefs();
    125 
    126  let server = setup();
    127  await configureIdentity({ username: "johndoe" }, server);
    128 
    129  try {
    130    _("Sync calls login.");
    131    let oldLogin = Service.login;
    132    let loginCalled = false;
    133    Service.login = async function () {
    134      loginCalled = true;
    135      Service.status.login = LOGIN_SUCCEEDED;
    136      this._loggedIn = false; // So that sync aborts.
    137      return true;
    138    };
    139 
    140    await Service.sync();
    141 
    142    Assert.ok(loginCalled);
    143    Service.login = oldLogin;
    144 
    145    // Stub mpLocked.
    146    let mpLocked = true;
    147    Utils.mpLocked = () => mpLocked;
    148 
    149    // Stub scheduleNextSync. This gets called within checkSyncStatus if we're
    150    // ready to sync, so use it as an indicator.
    151    let scheduleNextSyncF = Service.scheduler.scheduleNextSync;
    152    let scheduleCalled = false;
    153    Service.scheduler.scheduleNextSync = function (wait) {
    154      scheduleCalled = true;
    155      scheduleNextSyncF.call(this, wait);
    156    };
    157 
    158    // Autoconnect still tries to connect in the background (useful behavior:
    159    // for non-MP users and unlocked MPs, this will detect version expiry
    160    // earlier).
    161    //
    162    // Consequently, non-MP users will be logged in as in the pre-Bug 543784 world,
    163    // and checkSyncStatus reflects that by waiting for login.
    164    //
    165    // This process doesn't apply if your MP is still locked, so we make
    166    // checkSyncStatus accept a locked MP in place of being logged in.
    167    //
    168    // This test exercises these two branches.
    169 
    170    _("We're ready to sync if locked.");
    171    Service.enabled = true;
    172    Services.io.offline = false;
    173    Service.scheduler.checkSyncStatus();
    174    Assert.ok(scheduleCalled);
    175 
    176    _("... and also if we're not locked.");
    177    scheduleCalled = false;
    178    mpLocked = false;
    179    Service.scheduler.checkSyncStatus();
    180    Assert.ok(scheduleCalled);
    181    Service.scheduler.scheduleNextSync = scheduleNextSyncF;
    182 
    183    // TODO: need better tests around master password prompting. See Bug 620583.
    184 
    185    mpLocked = true;
    186 
    187    // Testing exception handling if master password dialog is canceled.
    188    // Do this by monkeypatching.
    189    Service.identity.unlockAndVerifyAuthState = () =>
    190      Promise.resolve(MASTER_PASSWORD_LOCKED);
    191 
    192    let cSTCalled = false;
    193    let lockedSyncCalled = false;
    194 
    195    Service.scheduler.clearSyncTriggers = function () {
    196      cSTCalled = true;
    197    };
    198    Service._lockedSync = async function () {
    199      lockedSyncCalled = true;
    200    };
    201 
    202    _("If master password is canceled, login fails and we report lockage.");
    203    Assert.ok(!(await Service.login()));
    204    Assert.equal(Service.status.login, MASTER_PASSWORD_LOCKED);
    205    Assert.equal(Service.status.service, LOGIN_FAILED);
    206    _("Locked? " + Utils.mpLocked());
    207    _("checkSync reports the correct term.");
    208    Assert.equal(Service._checkSync(), kSyncMasterPasswordLocked);
    209 
    210    _("Sync doesn't proceed and clears triggers if MP is still locked.");
    211    await Service.sync();
    212 
    213    Assert.ok(cSTCalled);
    214    Assert.ok(!lockedSyncCalled);
    215 
    216    // N.B., a bunch of methods are stubbed at this point. Be careful putting
    217    // new tests after this point!
    218  } finally {
    219    for (const pref of Svc.PrefBranch.getChildList("")) {
    220      Svc.PrefBranch.clearUserPref(pref);
    221    }
    222    await promiseStopServer(server);
    223  }
    224 });