/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ const { getPrefsGUIDForTest } = ChromeUtils.importESModule( "resource://services-sync/engines/prefs.sys.mjs" ); const PREFS_GUID = getPrefsGUIDForTest(); const { Service } = ChromeUtils.importESModule( "resource://services-sync/service.sys.mjs" ); async function cleanup(engine, server) { await engine._tracker.stop(); await engine.wipeClient(); Svc.Prefs.resetBranch(""); Service.recordManager.clearCache(); await promiseStopServer(server); } add_task(async function test_modified_after_fail() { let engine = Service.engineManager.get("prefs"); let server = await serverForFoo(engine); await SyncTestingInfrastructure(server); try { // The homepage pref is synced by default. _("Set homepage before first sync"); Services.prefs.setStringPref("browser.startup.homepage", "about:welcome"); _("First sync; create collection and pref record on server"); await sync_engine_and_validate_telem(engine, false); let collection = server.user("foo").collection("prefs"); equal( collection.cleartext(PREFS_GUID).value["browser.startup.homepage"], "about:welcome", "Should upload homepage in pref record" ); ok( !engine._tracker.modified, "Tracker shouldn't be modified after first sync" ); // Our tracker only has a `modified` flag that's reset after a // successful upload. Force it to remain set by failing the // upload. _("Second sync; flag tracker as modified and throw on upload"); Services.prefs.setStringPref("browser.startup.homepage", "about:robots"); engine._tracker.modified = true; let oldPost = collection.post; collection.post = () => { throw new Error("Sync this!"); }; await Assert.rejects( sync_engine_and_validate_telem(engine, true), ex => ex.success === false ); ok( engine._tracker.modified, "Tracker should remain modified after failed sync" ); _("Third sync"); collection.post = oldPost; await sync_engine_and_validate_telem(engine, false); equal( collection.cleartext(PREFS_GUID).value["browser.startup.homepage"], "about:robots", "Should upload new homepage on third sync" ); ok( !engine._tracker.modified, "Tracker shouldn't be modified again after third sync" ); } finally { await cleanup(engine, server); } }); add_task(async function test_allow_arbitrary() { let engine = Service.engineManager.get("prefs"); let server = await serverForFoo(engine); await SyncTestingInfrastructure(server); try { _("Create collection and pref record on server"); await sync_engine_and_validate_telem(engine, false); let collection = server.user("foo").collection("prefs"); _("Insert arbitrary pref into remote record"); let cleartext1 = collection.cleartext(PREFS_GUID); cleartext1.value.let_viruses_take_over = true; collection.insert( PREFS_GUID, encryptPayload(cleartext1), new_timestamp() + 5 ); _("Sync again; client shouldn't allow pref"); await sync_engine_and_validate_telem(engine, false); ok( !Services.prefs.getBoolPref("let_viruses_take_over", false), "Shouldn't allow arbitrary remote prefs without control pref" ); _("Sync with control pref set; client should set new pref"); Services.prefs.setBoolPref( "services.sync.prefs.sync.let_viruses_take_over_take_two", true ); let cleartext2 = collection.cleartext(PREFS_GUID); cleartext2.value.let_viruses_take_over_take_two = true; collection.insert( PREFS_GUID, encryptPayload(cleartext2), new_timestamp() + 5 ); // Reset the last sync time so that the engine fetches the record again. await engine.setLastSync(0); await sync_engine_and_validate_telem(engine, false); ok( Services.prefs.getBoolPref("let_viruses_take_over_take_two"), "Should set arbitrary remote pref with control pref" ); } finally { await cleanup(engine, server); } });