|
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/. */ |
|
4 |
|
5 const Cc = Components.classes; |
|
6 const Ci = Components.interfaces; |
|
7 const Cu = Components.utils; |
|
8 |
|
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"); |
|
14 |
|
15 const SYNC_PREFS_BRANCH = "services.sync."; |
|
16 |
|
17 |
|
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; |
|
67 } |
|
68 WeaveService.prototype = { |
|
69 classID: Components.ID("{74b89fb0-f200-4ae8-a3ec-dd164117f6de}"), |
|
70 |
|
71 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, |
|
72 Ci.nsISupportsWeakReference]), |
|
73 |
|
74 ensureLoaded: function () { |
|
75 Components.utils.import("resource://services-sync/main.js"); |
|
76 |
|
77 // Side-effect of accessing the service is that it is instantiated. |
|
78 Weave.Service; |
|
79 }, |
|
80 |
|
81 whenLoaded: function() { |
|
82 if (this.ready) { |
|
83 return Promise.resolve(); |
|
84 } |
|
85 let deferred = Promise.defer(); |
|
86 |
|
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 }, |
|
94 |
|
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 }, |
|
110 |
|
111 /** |
|
112 * Returns whether the password engine is allowed. We explicitly disallow |
|
113 * the password engine when a master password is used to ensure those can't |
|
114 * be accessed without the master key. |
|
115 */ |
|
116 get allowPasswordsEngine() { |
|
117 // This doesn't apply to old-style sync, it's only an issue for FxA. |
|
118 return !this.fxAccountsEnabled || !Utils.mpEnabled(); |
|
119 }, |
|
120 |
|
121 /** |
|
122 * Whether Sync appears to be enabled. |
|
123 * |
|
124 * This returns true if all the Sync preferences for storing account |
|
125 * and server configuration are populated. |
|
126 * |
|
127 * It does *not* perform a robust check to see if the client is working. |
|
128 * For that, you'll want to check Weave.Status.checkSetup(). |
|
129 */ |
|
130 get enabled() { |
|
131 let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH); |
|
132 return prefs.prefHasUserValue("username") && |
|
133 prefs.prefHasUserValue("clusterURL"); |
|
134 }, |
|
135 |
|
136 observe: function (subject, topic, data) { |
|
137 switch (topic) { |
|
138 case "app-startup": |
|
139 let os = Cc["@mozilla.org/observer-service;1"]. |
|
140 getService(Ci.nsIObserverService); |
|
141 os.addObserver(this, "final-ui-startup", true); |
|
142 break; |
|
143 |
|
144 case "final-ui-startup": |
|
145 // Force Weave service to load if it hasn't triggered from overlays |
|
146 this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
|
147 this.timer.initWithCallback({ |
|
148 notify: function() { |
|
149 // We only load more if it looks like Sync is configured. |
|
150 let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH); |
|
151 if (!prefs.prefHasUserValue("username")) { |
|
152 return; |
|
153 } |
|
154 |
|
155 // We have a username. So, do a more thorough check. This will |
|
156 // import a number of modules and thus increase memory |
|
157 // accordingly. We could potentially copy code performed by |
|
158 // this check into this file if our above code is yielding too |
|
159 // many false positives. |
|
160 Components.utils.import("resource://services-sync/main.js"); |
|
161 if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) { |
|
162 this.ensureLoaded(); |
|
163 } |
|
164 }.bind(this) |
|
165 }, 10000, Ci.nsITimer.TYPE_ONE_SHOT); |
|
166 break; |
|
167 } |
|
168 } |
|
169 }; |
|
170 |
|
171 function AboutWeaveLog() {} |
|
172 AboutWeaveLog.prototype = { |
|
173 classID: Components.ID("{d28f8a0b-95da-48f4-b712-caf37097be41}"), |
|
174 |
|
175 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule, |
|
176 Ci.nsISupportsWeakReference]), |
|
177 |
|
178 getURIFlags: function(aURI) { |
|
179 return 0; |
|
180 }, |
|
181 |
|
182 newChannel: function(aURI) { |
|
183 let dir = FileUtils.getDir("ProfD", ["weave", "logs"], true); |
|
184 let uri = Services.io.newFileURI(dir); |
|
185 let channel = Services.io.newChannelFromURI(uri); |
|
186 channel.originalURI = aURI; |
|
187 |
|
188 // Ensure that the about page has the same privileges as a regular directory |
|
189 // view. That way links to files can be opened. |
|
190 let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] |
|
191 .getService(Ci.nsIScriptSecurityManager); |
|
192 let principal = ssm.getNoAppCodebasePrincipal(uri); |
|
193 channel.owner = principal; |
|
194 return channel; |
|
195 } |
|
196 }; |
|
197 |
|
198 const components = [WeaveService, AboutWeaveLog]; |
|
199 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); |