Code snippets

This is an archived page. It's not actively maintained.

This page documents how to perform custom actions with Firefox Sync via JavaScript.

All of the in this page must be executed in a chrome-privileged console. To access a chrome-privileged console, open an about page (like about:about) then open a Web Console via the Web Developer menu.

Tabs from Other Computers

This snippet shows how to load all tabs from other computers.

Components.utils.import("resource://services-sync/main.js");

// Obtain a reference to the main Firefox window.
let mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                       .getInterface(Components.interfaces.nsIWebNavigation)
                       .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                       .rootTreeItem
                       .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                       .getInterface(Components.interfaces.nsIDOMWindow);  

// Obtain a reference to Sync's Tabs "engine."
let tabsEngine = Weave.Service.engineManager.get("tabs");

// Iterate over each client having data.
for each (let client in tabsEngine.getAllClients()) {
  for each (let tab in client.tabs) {
    let url = tab.urlHistory[0];

    // Load the tab via the tabbed browser API.
    mainWindow.gBrowser.addTab(url);
  }
}

Partially corrupt a server

Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");

function deletePath(path) {
  let resource = new Resource(Weave.Service.storageURL + path);
  resource.setHeader("X-Confirm-Delete", "1");
  return resource.delete();
}

// Delete meta/global:
deletePath("meta/global");

// Delete keys:
deletePath("crypto/keys");

// Delete server:
deletePath("");

Corrupt a single engine on the server

let ENGINE = "bookmarks";
Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");
Components.utils.import("resource://services-sync/util.js");
let r = new Resource(Weave.Service.storageURL + "meta/global");
let g = r.get();
let envelope = JSON.parse(g);
let payload  = JSON.parse(envelope.payload);
payload.engines[ENGINE].syncID = Weave.Utils.makeGUID(); // Or any other GUID you like.
payload.engines[ENGINE].version = 0; // Or any other version number you like.
envelope.payload = JSON.stringify(payload);
r.put(JSON.stringify(envelope));

Generate new keys

// Clients always wipe the server when they generate new keys.
Components.utils.import("resource://services-sync/main.js");
Weave.Service._freshStart();

// If you want to do it without wiping the server (which will cause corruption!):
Weave.Service.generateNewSymmetricKeys();
// Change '1000' as appropriate.
Components.utils.import("resource://services-sync/engines.js");
Components.utils.import("resource://services-sync/engines/bookmarks.js");
let bme = Weave.Service.engineManager.get("bookmarks");

let ids = Object.keys(bme._store.getAllIDs());
for each (let id in ids) {
  let record = bme._store.createRecord(id, "bookmarks");
  let len = record.toString().length;
  if (len > 1000) {
    console.log("ID: " + id + ", len = " + len + ", " + record.title);
  }
}
Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");

let ids = JSON.parse(new Resource(Weave.Service.storageURL + "bookmarks").get());
for each (let id in ids.sort()) {
  console.log("  " + id);
}

Get a count of the number of members of a collection on the server

let collection = "passwords";
Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");
JSON.parse(new Resource(Weave.Service.storageURL + collection).get()).length;

Dump the cleartext of each record in a collection to the console.

let collection = "forms";

Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/record.js");

let recordType = Weave.Engines.get(collection)._recordObj;
let coll = new Collection(Weave.Service.storageURL + collection, recordType);
coll.full = true;
coll.recordHandler = function(item) {
  item.collection = collection;
  item.decrypt();
  console.log(item.cleartext);
};
coll.get();
let collection = "history";
let id = "GUID_GOES_HERE";

Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/record.js");

let recordType = Weave.Engines.get(collection)._recordObj;
let coll = new Collection(Weave.Service.storageURL + collection, recordType);
coll.full = true;
coll.ids = [id];
coll.recordHandler = function(item) {
  item.collection = collection;
  item.decrypt();
  console.log(item.cleartext);
};

coll.get();

Count types of bookmark records

  Components.utils.import("resource://services-sync/main.js");
  Components.utils.import("resource://services-sync/record.js");

  let deleted = 0;
  let items   = {};

  let collection = "bookmarks";
  let recordType = Weave.Engines.get(collection)._recordObj;
  let coll = new Collection(Weave.Service.storageURL + collection, recordType);

  coll.full = true;
  coll.limit = null;

  coll.recordHandler = function(item) {
    item.collection = collection;
    item.decrypt();
    if (item.deleted) {
      deleted++;
    } else {
      items[item.type] = 1 + (items[item.type] || 0);
    }
  };
  coll.get();
  console.log("Deleted: " + deleted + ", " + JSON.stringify(items));

Get a log from XUL Fennec

  • View about:sync-log.
  • Long-tap the log in question. Choose "Save Link".
  • Open a mail client. Click Attach.
  • Choose "File Manager" as the handler.
  • Navigate to "Downloads", pick correct file.

Watch live Sync logs

  • Set services.sync.log.appender.console to Trace.

Bump meta/global's modified time

Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");

function getPath(path) {
  let r = new Resource(Weave.Service.storageURL + path);
  let g = r.get();
  return [g, r];
};

let [g, r] = getPath("meta/global");
r.put(g);

Delete and restore a record

Components.utils.import("resource://services-sync/main.js");
Components.utils.import("resource://services-sync/resource.js");
Components.utils.import("resource://services-sync/record.js");

// For example:
let id = "iASOkUOZpIxZ"
let collection = "bookmarks";

let resource = new Resource(Weave.Service.storageURL + collection + "/" + id);
let del = new CryptoWrapper(collection, id);

del.deleted = true;
del.encrypt();

// Save the old value.
let old = resource.get();

// Delete.
resource.put(del);

// Restore the old value.
resource.put(old);