Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 this.EXPORTED_SYMBOLS = ["FirefoxAccounts"];
9 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
11 Cu.import("resource://gre/modules/Log.jsm");
12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
13 Cu.import("resource://gre/modules/Services.jsm");
14 Cu.import("resource://gre/modules/identity/LogUtils.jsm");
16 XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
17 "resource://gre/modules/identity/IdentityUtils.jsm");
19 XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject",
20 "resource://gre/modules/identity/IdentityUtils.jsm");
22 // loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO",
23 // "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by
24 // default.
25 const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel";
26 try {
27 this.LOG_LEVEL =
28 Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING
29 && Services.prefs.getCharPref(PREF_LOG_LEVEL);
30 } catch (e) {
31 this.LOG_LEVEL = Log.Level.Error;
32 }
34 let log = Log.repository.getLogger("Identity.FxAccounts");
35 log.level = LOG_LEVEL;
36 log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
38 #ifdef MOZ_B2G
39 XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsManager",
40 "resource://gre/modules/FxAccountsManager.jsm",
41 "FxAccountsManager");
42 #else
43 log.warn("The FxAccountsManager is only functional in B2G at this time.");
44 var FxAccountsManager = null;
45 #endif
47 function FxAccountsService() {
48 Services.obs.addObserver(this, "quit-application-granted", false);
50 // Maintain interface parity with Identity.jsm and MinimalIdentity.jsm
51 this.RP = this;
53 this._rpFlows = new Map();
55 // Enable us to mock FxAccountsManager service in testing
56 this.fxAccountsManager = FxAccountsManager;
57 }
59 FxAccountsService.prototype = {
60 QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
62 observe: function observe(aSubject, aTopic, aData) {
63 switch (aTopic) {
64 case "quit-application-granted":
65 Services.obs.removeObserver(this, "quit-application-granted");
66 break;
67 }
68 },
70 /**
71 * Register a listener for a given windowID as a result of a call to
72 * navigator.id.watch().
73 *
74 * @param aCaller
75 * (Object) an object that represents the caller document, and
76 * is expected to have properties:
77 * - id (unique, e.g. uuid)
78 * - origin (string)
79 *
80 * and a bunch of callbacks
81 * - doReady()
82 * - doLogin()
83 * - doLogout()
84 * - doError()
85 * - doCancel()
86 *
87 */
88 watch: function watch(aRpCaller) {
89 this._rpFlows.set(aRpCaller.id, aRpCaller);
90 log.debug("watch: " + aRpCaller.id);
91 log.debug("Current rp flows: " + this._rpFlows.size);
93 // Log the user in, if possible, and then call ready().
94 let runnable = {
95 run: () => {
96 this.fxAccountsManager.getAssertion(aRpCaller.audience, {silent:true}).then(
97 data => {
98 if (data) {
99 this.doLogin(aRpCaller.id, data);
100 } else {
101 this.doLogout(aRpCaller.id);
102 }
103 this.doReady(aRpCaller.id);
104 },
105 error => {
106 log.error("get silent assertion failed: " + JSON.stringify(error));
107 this.doError(aRpCaller.id, error);
108 }
109 );
110 }
111 };
112 Services.tm.currentThread.dispatch(runnable,
113 Ci.nsIThread.DISPATCH_NORMAL);
114 },
116 /**
117 * Delete the flow when the screen is unloaded
118 */
119 unwatch: function(aRpCallerId, aTargetMM) {
120 log.debug("unwatching: " + aRpCallerId);
121 this._rpFlows.delete(aRpCallerId);
122 },
124 /**
125 * Initiate a login with user interaction as a result of a call to
126 * navigator.id.request().
127 *
128 * @param aRPId
129 * (integer) the id of the doc object obtained in .watch()
130 *
131 * @param aOptions
132 * (Object) options including privacyPolicy, termsOfService
133 */
134 request: function request(aRPId, aOptions) {
135 aOptions = aOptions || {};
136 let rp = this._rpFlows.get(aRPId);
137 if (!rp) {
138 log.error("request() called before watch()");
139 return;
140 }
142 let options = makeMessageObject(rp);
143 objectCopy(aOptions, options);
145 log.debug("get assertion for " + rp.audience);
147 this.fxAccountsManager.getAssertion(rp.audience, options).then(
148 data => {
149 log.debug("got assertion for " + rp.audience + ": " + data);
150 this.doLogin(aRPId, data);
151 },
152 error => {
153 log.error("get assertion failed: " + JSON.stringify(error));
154 this.doError(aRPId, error);
155 }
156 );
157 },
159 /**
160 * Invoked when a user wishes to logout of a site (for instance, when clicking
161 * on an in-content logout button).
162 *
163 * @param aRpCallerId
164 * (integer) the id of the doc object obtained in .watch()
165 *
166 */
167 logout: function logout(aRpCallerId) {
168 // XXX Bug 945363 - Resolve the SSO story for FXA and implement
169 // logout accordingly.
170 //
171 // For now, it makes no sense to logout from a specific RP in
172 // Firefox Accounts, so just directly call the logout callback.
173 if (!this._rpFlows.has(aRpCallerId)) {
174 log.error("logout() called before watch()");
175 return;
176 }
178 // Call logout() on the next tick
179 let runnable = {
180 run: () => {
181 this.fxAccountsManager.signOut().then(() => {
182 this.doLogout(aRpCallerId);
183 });
184 }
185 };
186 Services.tm.currentThread.dispatch(runnable,
187 Ci.nsIThread.DISPATCH_NORMAL);
188 },
190 childProcessShutdown: function childProcessShutdown(messageManager) {
191 for (let [key,] of this._rpFlows) {
192 if (this._rpFlows.get(key)._mm === messageManager) {
193 this._rpFlows.delete(key);
194 }
195 }
196 },
198 doLogin: function doLogin(aRpCallerId, aAssertion) {
199 let rp = this._rpFlows.get(aRpCallerId);
200 if (!rp) {
201 log.warn("doLogin found no rp to go with callerId " + aRpCallerId + "\n");
202 return;
203 }
205 rp.doLogin(aAssertion);
206 },
208 doLogout: function doLogout(aRpCallerId) {
209 let rp = this._rpFlows.get(aRpCallerId);
210 if (!rp) {
211 log.warn("doLogout found no rp to go with callerId " + aRpCallerId + "\n");
212 return;
213 }
215 rp.doLogout();
216 },
218 doReady: function doReady(aRpCallerId) {
219 let rp = this._rpFlows.get(aRpCallerId);
220 if (!rp) {
221 log.warn("doReady found no rp to go with callerId " + aRpCallerId + "\n");
222 return;
223 }
225 rp.doReady();
226 },
228 doCancel: function doCancel(aRpCallerId) {
229 let rp = this._rpFlows.get(aRpCallerId);
230 if (!rp) {
231 log.warn("doCancel found no rp to go with callerId " + aRpCallerId + "\n");
232 return;
233 }
235 rp.doCancel();
236 },
238 doError: function doError(aRpCallerId, aError) {
239 let rp = this._rpFlows.get(aRpCallerId);
240 if (!rp) {
241 log.warn("doCancel found no rp to go with callerId " + aRpCallerId + "\n");
242 return;
243 }
245 rp.doError(aError);
246 }
247 };
249 this.FirefoxAccounts = new FxAccountsService();