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 +}