Bumping manifests a=b2g-bump
[gecko.git] / services / sync / Weave.js
blobd7befe15b9353c4385c0b45149fe2c34b73a6052
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Cc = Components.classes;
6 const Ci = Components.interfaces;
7 const Cu = Components.utils;
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
10 Cu.import("resource://gre/modules/Services.jsm");
11 Cu.import("resource://gre/modules/FileUtils.jsm");
12 Cu.import("resource://gre/modules/Promise.jsm");
13 Cu.import("resource://services-sync/util.js");
15 const SYNC_PREFS_BRANCH = "services.sync.";
18 /**
19  * Sync's XPCOM service.
20  *
21  * It is named "Weave" for historical reasons.
22  *
23  * It's worth noting how Sync is lazily loaded. We register a timer that
24  * loads Sync a few seconds after app startup. This is so Sync does not
25  * adversely affect application start time.
26  *
27  * If Sync is not configured, no extra Sync code is loaded. If an
28  * external component (say the UI) needs to interact with Sync, it
29  * should use the promise-base function whenLoaded() - something like the
30  * following:
31  *
32  * // 1. Grab a handle to the Sync XPCOM service.
33  * let service = Cc["@mozilla.org/weave/service;1"]
34  *                 .getService(Components.interfaces.nsISupports)
35  *                 .wrappedJSObject;
36  *
37  * // 2. Use the .then method of the promise.
38  * service.whenLoaded().then(() => {
39  *   // You are free to interact with "Weave." objects.
40  *   return;
41  * });
42  *
43  * And that's it!  However, if you really want to avoid promises and do it
44  * old-school, then
45  *
46  * // 1. Get a reference to the service as done in (1) above.
47  *
48  * // 2. Check if the service has been initialized.
49  * if (service.ready) {
50  *   // You are free to interact with "Weave." objects.
51  *   return;
52  * }
53  *
54  * // 3. Install "ready" listener.
55  * Services.obs.addObserver(function onReady() {
56  *   Services.obs.removeObserver(onReady, "weave:service:ready");
57  *
58  *   // You are free to interact with "Weave." objects.
59  * }, "weave:service:ready", false);
60  *
61  * // 4. Trigger loading of Sync.
62  * service.ensureLoaded();
63  */
64 function WeaveService() {
65   this.wrappedJSObject = this;
66   this.ready = false;
68 WeaveService.prototype = {
69   classID: Components.ID("{74b89fb0-f200-4ae8-a3ec-dd164117f6de}"),
71   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
72                                          Ci.nsISupportsWeakReference]),
74   ensureLoaded: function () {
75     Components.utils.import("resource://services-sync/main.js");
77     // Side-effect of accessing the service is that it is instantiated.
78     Weave.Service;
79   },
81   whenLoaded: function() {
82     if (this.ready) {
83       return Promise.resolve();
84     }
85     let deferred = Promise.defer();
87     Services.obs.addObserver(function onReady() {
88       Services.obs.removeObserver(onReady, "weave:service:ready");
89       deferred.resolve();
90     }, "weave:service:ready", false);
91     this.ensureLoaded();
92     return deferred.promise;
93   },
95   /**
96    * Whether Firefox Accounts is enabled.
97    *
98    * @return bool
99    */
100   get fxAccountsEnabled() {
101     try {
102       // Old sync guarantees '@' will never appear in the username while FxA
103       // uses the FxA email address - so '@' is the flag we use.
104       let username = Services.prefs.getCharPref(SYNC_PREFS_BRANCH + "username");
105       return !username || username.contains('@');
106     } catch (_) {
107       return true; // No username == only allow FxA to be configured.
108     }
109   },
111   /**
112    * Whether Sync appears to be enabled.
113    *
114    * This returns true if all the Sync preferences for storing account
115    * and server configuration are populated.
116    *
117    * It does *not* perform a robust check to see if the client is working.
118    * For that, you'll want to check Weave.Status.checkSetup().
119    */
120   get enabled() {
121     let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
122     return prefs.prefHasUserValue("username") &&
123            prefs.prefHasUserValue("clusterURL");
124   },
126   observe: function (subject, topic, data) {
127     switch (topic) {
128     case "app-startup":
129       let os = Cc["@mozilla.org/observer-service;1"].
130                getService(Ci.nsIObserverService);
131       os.addObserver(this, "final-ui-startup", true);
132       break;
134     case "final-ui-startup":
135       // Force Weave service to load if it hasn't triggered from overlays
136       this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
137       this.timer.initWithCallback({
138         notify: function() {
139           let isConfigured = false;
140           // We only load more if it looks like Sync is configured.
141           let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
142           if (prefs.prefHasUserValue("username")) {
143             // We have a username. So, do a more thorough check. This will
144             // import a number of modules and thus increase memory
145             // accordingly. We could potentially copy code performed by
146             // this check into this file if our above code is yielding too
147             // many false positives.
148             Components.utils.import("resource://services-sync/main.js");
149             isConfigured = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
150           }
151           let getHistogramById = Services.telemetry.getHistogramById;
152           getHistogramById("WEAVE_CONFIGURED").add(isConfigured);
153           if (isConfigured) {
154             getHistogramById("WEAVE_CONFIGURED_MASTER_PASSWORD").add(Utils.mpEnabled());
155             this.ensureLoaded();
156           }
157         }.bind(this)
158       }, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
159       break;
160     }
161   }
164 function AboutWeaveLog() {}
165 AboutWeaveLog.prototype = {
166   classID: Components.ID("{d28f8a0b-95da-48f4-b712-caf37097be41}"),
168   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule,
169                                          Ci.nsISupportsWeakReference]),
171   getURIFlags: function(aURI) {
172     return 0;
173   },
175   newChannel: function(aURI) {
176     let dir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
177     let uri = Services.io.newFileURI(dir);
178     let channel = Services.io.newChannelFromURI(uri);
179     channel.originalURI = aURI;
181     // Ensure that the about page has the same privileges as a regular directory
182     // view. That way links to files can be opened.
183     let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
184                 .getService(Ci.nsIScriptSecurityManager);
185     let principal = ssm.getNoAppCodebasePrincipal(uri);
186     channel.owner = principal;
187     return channel;
188   }
191 const components = [WeaveService, AboutWeaveLog];
192 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);