services/sync/tests/unit/test_service_detect_upgrade.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/sync/tests/unit/test_service_detect_upgrade.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,297 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +Cu.import("resource://gre/modules/Log.jsm");
     1.8 +Cu.import("resource://services-sync/constants.js");
     1.9 +Cu.import("resource://services-sync/keys.js");
    1.10 +Cu.import("resource://services-sync/engines/tabs.js");
    1.11 +Cu.import("resource://services-sync/engines.js");
    1.12 +Cu.import("resource://services-sync/record.js");
    1.13 +Cu.import("resource://services-sync/service.js");
    1.14 +Cu.import("resource://services-sync/util.js");
    1.15 +Cu.import("resource://testing-common/services/sync/utils.js");
    1.16 +
    1.17 +Service.engineManager.register(TabEngine);
    1.18 +
    1.19 +add_test(function v4_upgrade() {
    1.20 +  let passphrase = "abcdeabcdeabcdeabcdeabcdea";
    1.21 +
    1.22 +  let clients = new ServerCollection();
    1.23 +  let meta_global = new ServerWBO('global');
    1.24 +
    1.25 +  // Tracking info/collections.
    1.26 +  let collectionsHelper = track_collections_helper();
    1.27 +  let upd = collectionsHelper.with_updated_collection;
    1.28 +  let collections = collectionsHelper.collections;
    1.29 +
    1.30 +  let keysWBO = new ServerWBO("keys");
    1.31 +  let server = httpd_setup({
    1.32 +    // Special.
    1.33 +    "/1.1/johndoe/info/collections": collectionsHelper.handler,
    1.34 +    "/1.1/johndoe/storage/crypto/keys": upd("crypto", keysWBO.handler()),
    1.35 +    "/1.1/johndoe/storage/meta/global": upd("meta", meta_global.handler()),
    1.36 +
    1.37 +    // Track modified times.
    1.38 +    "/1.1/johndoe/storage/clients": upd("clients", clients.handler()),
    1.39 +    "/1.1/johndoe/storage/tabs": upd("tabs", new ServerCollection().handler()),
    1.40 +
    1.41 +    // Just so we don't get 404s in the logs.
    1.42 +    "/1.1/johndoe/storage/bookmarks": new ServerCollection().handler(),
    1.43 +    "/1.1/johndoe/storage/forms": new ServerCollection().handler(),
    1.44 +    "/1.1/johndoe/storage/history": new ServerCollection().handler(),
    1.45 +    "/1.1/johndoe/storage/passwords": new ServerCollection().handler(),
    1.46 +    "/1.1/johndoe/storage/prefs": new ServerCollection().handler()
    1.47 +  });
    1.48 +
    1.49 +  ensureLegacyIdentityManager();
    1.50 +
    1.51 +  try {
    1.52 +
    1.53 +    _("Set up some tabs.");
    1.54 +    let myTabs =
    1.55 +      {windows: [{tabs: [{index: 1,
    1.56 +                          entries: [{
    1.57 +                            url: "http://foo.com/",
    1.58 +                            title: "Title"
    1.59 +                          }],
    1.60 +                          attributes: {
    1.61 +                            image: "image"
    1.62 +                          }
    1.63 +                          }]}]};
    1.64 +    delete Svc.Session;
    1.65 +    Svc.Session = {
    1.66 +      getBrowserState: function () JSON.stringify(myTabs)
    1.67 +    };
    1.68 +
    1.69 +    Service.status.resetSync();
    1.70 +
    1.71 +    _("Logging in.");
    1.72 +    Service.serverURL = server.baseURI;
    1.73 +
    1.74 +    Service.login("johndoe", "ilovejane", passphrase);
    1.75 +    do_check_true(Service.isLoggedIn);
    1.76 +    Service.verifyAndFetchSymmetricKeys();
    1.77 +    do_check_true(Service._remoteSetup());
    1.78 +
    1.79 +    function test_out_of_date() {
    1.80 +      _("Old meta/global: " + JSON.stringify(meta_global));
    1.81 +      meta_global.payload = JSON.stringify({"syncID": "foooooooooooooooooooooooooo",
    1.82 +                                            "storageVersion": STORAGE_VERSION + 1});
    1.83 +      collections.meta = Date.now() / 1000;
    1.84 +      _("New meta/global: " + JSON.stringify(meta_global));
    1.85 +      Service.recordManager.set(Service.metaURL, meta_global);
    1.86 +      try {
    1.87 +        Service.sync();
    1.88 +      }
    1.89 +      catch (ex) {
    1.90 +      }
    1.91 +      do_check_eq(Service.status.sync, VERSION_OUT_OF_DATE);
    1.92 +    }
    1.93 +
    1.94 +    // See what happens when we bump the storage version.
    1.95 +    _("Syncing after server has been upgraded.");
    1.96 +    test_out_of_date();
    1.97 +
    1.98 +    // Same should happen after a wipe.
    1.99 +    _("Syncing after server has been upgraded and wiped.");
   1.100 +    Service.wipeServer();
   1.101 +    test_out_of_date();
   1.102 +
   1.103 +    // Now's a great time to test what happens when keys get replaced.
   1.104 +    _("Syncing afresh...");
   1.105 +    Service.logout();
   1.106 +    Service.collectionKeys.clear();
   1.107 +    Service.serverURL = server.baseURI;
   1.108 +    meta_global.payload = JSON.stringify({"syncID": "foooooooooooooobbbbbbbbbbbb",
   1.109 +                                          "storageVersion": STORAGE_VERSION});
   1.110 +    collections.meta = Date.now() / 1000;
   1.111 +    Service.recordManager.set(Service.metaURL, meta_global);
   1.112 +    Service.login("johndoe", "ilovejane", passphrase);
   1.113 +    do_check_true(Service.isLoggedIn);
   1.114 +    Service.sync();
   1.115 +    do_check_true(Service.isLoggedIn);
   1.116 +
   1.117 +    let serverDecrypted;
   1.118 +    let serverKeys;
   1.119 +    let serverResp;
   1.120 +
   1.121 +
   1.122 +    function retrieve_server_default() {
   1.123 +      serverKeys = serverResp = serverDecrypted = null;
   1.124 +
   1.125 +      serverKeys = new CryptoWrapper("crypto", "keys");
   1.126 +      serverResp = serverKeys.fetch(Service.resource(Service.cryptoKeysURL)).response;
   1.127 +      do_check_true(serverResp.success);
   1.128 +
   1.129 +      serverDecrypted = serverKeys.decrypt(Service.identity.syncKeyBundle);
   1.130 +      _("Retrieved WBO:       " + JSON.stringify(serverDecrypted));
   1.131 +      _("serverKeys:          " + JSON.stringify(serverKeys));
   1.132 +
   1.133 +      return serverDecrypted.default;
   1.134 +    }
   1.135 +
   1.136 +    function retrieve_and_compare_default(should_succeed) {
   1.137 +      let serverDefault = retrieve_server_default();
   1.138 +      let localDefault = Service.collectionKeys.keyForCollection().keyPairB64;
   1.139 +
   1.140 +      _("Retrieved keyBundle: " + JSON.stringify(serverDefault));
   1.141 +      _("Local keyBundle:     " + JSON.stringify(localDefault));
   1.142 +
   1.143 +      if (should_succeed)
   1.144 +        do_check_eq(JSON.stringify(serverDefault), JSON.stringify(localDefault));
   1.145 +      else
   1.146 +        do_check_neq(JSON.stringify(serverDefault), JSON.stringify(localDefault));
   1.147 +    }
   1.148 +
   1.149 +    // Uses the objects set above.
   1.150 +    function set_server_keys(pair) {
   1.151 +      serverDecrypted.default = pair;
   1.152 +      serverKeys.cleartext = serverDecrypted;
   1.153 +      serverKeys.encrypt(Service.identity.syncKeyBundle);
   1.154 +      serverKeys.upload(Service.resource(Service.cryptoKeysURL));
   1.155 +    }
   1.156 +
   1.157 +    _("Checking we have the latest keys.");
   1.158 +    retrieve_and_compare_default(true);
   1.159 +
   1.160 +    _("Update keys on server.");
   1.161 +    set_server_keys(["KaaaaaaaaaaaHAtfmuRY0XEJ7LXfFuqvF7opFdBD/MY=",
   1.162 +                     "aaaaaaaaaaaapxMO6TEWtLIOv9dj6kBAJdzhWDkkkis="]);
   1.163 +
   1.164 +    _("Checking that we no longer have the latest keys.");
   1.165 +    retrieve_and_compare_default(false);
   1.166 +
   1.167 +    _("Indeed, they're what we set them to...");
   1.168 +    do_check_eq("KaaaaaaaaaaaHAtfmuRY0XEJ7LXfFuqvF7opFdBD/MY=",
   1.169 +                retrieve_server_default()[0]);
   1.170 +
   1.171 +    _("Sync. Should download changed keys automatically.");
   1.172 +    let oldClientsModified = collections.clients;
   1.173 +    let oldTabsModified = collections.tabs;
   1.174 +
   1.175 +    Service.login("johndoe", "ilovejane", passphrase);
   1.176 +    Service.sync();
   1.177 +    _("New key should have forced upload of data.");
   1.178 +    _("Tabs: " + oldTabsModified + " < " + collections.tabs);
   1.179 +    _("Clients: " + oldClientsModified + " < " + collections.clients);
   1.180 +    do_check_true(collections.clients > oldClientsModified);
   1.181 +    do_check_true(collections.tabs    > oldTabsModified);
   1.182 +
   1.183 +    _("... and keys will now match.");
   1.184 +    retrieve_and_compare_default(true);
   1.185 +
   1.186 +    // Clean up.
   1.187 +    Service.startOver();
   1.188 +
   1.189 +  } finally {
   1.190 +    Svc.Prefs.resetBranch("");
   1.191 +    server.stop(run_next_test);
   1.192 +  }
   1.193 +});
   1.194 +
   1.195 +add_test(function v5_upgrade() {
   1.196 +  let passphrase = "abcdeabcdeabcdeabcdeabcdea";
   1.197 +
   1.198 +  // Tracking info/collections.
   1.199 +  let collectionsHelper = track_collections_helper();
   1.200 +  let upd = collectionsHelper.with_updated_collection;
   1.201 +  let collections = collectionsHelper.collections;
   1.202 +
   1.203 +  let keysWBO = new ServerWBO("keys");
   1.204 +  let bulkWBO = new ServerWBO("bulk");
   1.205 +  let clients = new ServerCollection();
   1.206 +  let meta_global = new ServerWBO('global');
   1.207 +
   1.208 +  let server = httpd_setup({
   1.209 +    // Special.
   1.210 +    "/1.1/johndoe/storage/meta/global": upd("meta", meta_global.handler()),
   1.211 +    "/1.1/johndoe/info/collections": collectionsHelper.handler,
   1.212 +    "/1.1/johndoe/storage/crypto/keys": upd("crypto", keysWBO.handler()),
   1.213 +    "/1.1/johndoe/storage/crypto/bulk": upd("crypto", bulkWBO.handler()),
   1.214 +
   1.215 +    // Track modified times.
   1.216 +    "/1.1/johndoe/storage/clients": upd("clients", clients.handler()),
   1.217 +    "/1.1/johndoe/storage/tabs": upd("tabs", new ServerCollection().handler()),
   1.218 +  });
   1.219 +
   1.220 +  try {
   1.221 +
   1.222 +    _("Set up some tabs.");
   1.223 +    let myTabs =
   1.224 +      {windows: [{tabs: [{index: 1,
   1.225 +                          entries: [{
   1.226 +                            url: "http://foo.com/",
   1.227 +                            title: "Title"
   1.228 +                          }],
   1.229 +                          attributes: {
   1.230 +                            image: "image"
   1.231 +                          }
   1.232 +                          }]}]};
   1.233 +    delete Svc.Session;
   1.234 +    Svc.Session = {
   1.235 +      getBrowserState: function () JSON.stringify(myTabs)
   1.236 +    };
   1.237 +
   1.238 +    Service.status.resetSync();
   1.239 +
   1.240 +    setBasicCredentials("johndoe", "ilovejane", passphrase);
   1.241 +    Service.serverURL = server.baseURI + "/";
   1.242 +    Service.clusterURL = server.baseURI + "/";
   1.243 +
   1.244 +    // Test an upgrade where the contents of the server would cause us to error
   1.245 +    // -- keys decrypted with a different sync key, for example.
   1.246 +    _("Testing v4 -> v5 (or similar) upgrade.");
   1.247 +    function update_server_keys(syncKeyBundle, wboName, collWBO) {
   1.248 +      generateNewKeys(Service.collectionKeys);
   1.249 +      serverKeys = Service.collectionKeys.asWBO("crypto", wboName);
   1.250 +      serverKeys.encrypt(syncKeyBundle);
   1.251 +      let res = Service.resource(Service.storageURL + collWBO);
   1.252 +      do_check_true(serverKeys.upload(res).success);
   1.253 +    }
   1.254 +
   1.255 +    _("Bumping version.");
   1.256 +    // Bump version on the server.
   1.257 +    let m = new WBORecord("meta", "global");
   1.258 +    m.payload = {"syncID": "foooooooooooooooooooooooooo",
   1.259 +                 "storageVersion": STORAGE_VERSION + 1};
   1.260 +    m.upload(Service.resource(Service.metaURL));
   1.261 +
   1.262 +    _("New meta/global: " + JSON.stringify(meta_global));
   1.263 +
   1.264 +    // Fill the keys with bad data.
   1.265 +    let badKeys = new SyncKeyBundle("foobar", "aaaaaaaaaaaaaaaaaaaaaaaaaa");
   1.266 +    update_server_keys(badKeys, "keys", "crypto/keys");  // v4
   1.267 +    update_server_keys(badKeys, "bulk", "crypto/bulk");  // v5
   1.268 +
   1.269 +    _("Generating new keys.");
   1.270 +    generateNewKeys(Service.collectionKeys);
   1.271 +
   1.272 +    // Now sync and see what happens. It should be a version fail, not a crypto
   1.273 +    // fail.
   1.274 +
   1.275 +    _("Logging in.");
   1.276 +    try {
   1.277 +      Service.login("johndoe", "ilovejane", passphrase);
   1.278 +    }
   1.279 +    catch (e) {
   1.280 +      _("Exception: " + e);
   1.281 +    }
   1.282 +    _("Status: " + Service.status);
   1.283 +    do_check_false(Service.isLoggedIn);
   1.284 +    do_check_eq(VERSION_OUT_OF_DATE, Service.status.sync);
   1.285 +
   1.286 +    // Clean up.
   1.287 +    Service.startOver();
   1.288 +
   1.289 +  } finally {
   1.290 +    Svc.Prefs.resetBranch("");
   1.291 +    server.stop(run_next_test);
   1.292 +  }
   1.293 +});
   1.294 +
   1.295 +function run_test() {
   1.296 +  let logger = Log.repository.rootLogger;
   1.297 +  Log.repository.rootLogger.addAppender(new Log.DumpAppender());
   1.298 +
   1.299 +  run_next_test();
   1.300 +}

mercurial