Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
2 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * This alternate implementation of IdentityService provides just the
9 * channels for navigator.id, leaving the certificate storage to a
10 * server-provided app.
11 *
12 * On b2g, the messages identity-controller-watch, -request, and
13 * -logout, are observed by the component SignInToWebsite.jsm.
14 */
16 "use strict";
18 this.EXPORTED_SYMBOLS = ["IdentityService"];
20 const Cu = Components.utils;
21 const Ci = Components.interfaces;
22 const Cc = Components.classes;
23 const Cr = Components.results;
25 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
26 Cu.import("resource://gre/modules/Services.jsm");
27 Cu.import("resource://gre/modules/identity/LogUtils.jsm");
29 XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
30 "resource://gre/modules/identity/IdentityUtils.jsm");
32 XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject",
33 "resource://gre/modules/identity/IdentityUtils.jsm");
35 function log(...aMessageArgs) {
36 Logger.log.apply(Logger, ["minimal core"].concat(aMessageArgs));
37 }
38 function reportError(...aMessageArgs) {
39 Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs));
40 }
42 function IDService() {
43 Services.obs.addObserver(this, "quit-application-granted", false);
45 // simplify, it's one object
46 this.RP = this;
47 this.IDP = this;
49 // keep track of flows
50 this._rpFlows = {};
51 this._authFlows = {};
52 this._provFlows = {};
53 }
55 IDService.prototype = {
56 QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
58 observe: function observe(aSubject, aTopic, aData) {
59 switch (aTopic) {
60 case "quit-application-granted":
61 this.shutdown();
62 break;
63 }
64 },
66 shutdown: function() {
67 Services.obs.removeObserver(this, "quit-application-granted");
68 },
70 /**
71 * Parse an email into username and domain if it is valid, else return null
72 */
73 parseEmail: function parseEmail(email) {
74 var match = email.match(/^([^@]+)@([^@^/]+.[a-z]+)$/);
75 if (match) {
76 return {
77 username: match[1],
78 domain: match[2]
79 };
80 }
81 return null;
82 },
84 /**
85 * Register a listener for a given windowID as a result of a call to
86 * navigator.id.watch().
87 *
88 * @param aCaller
89 * (Object) an object that represents the caller document, and
90 * is expected to have properties:
91 * - id (unique, e.g. uuid)
92 * - loggedInUser (string or null)
93 * - origin (string)
94 *
95 * and a bunch of callbacks
96 * - doReady()
97 * - doLogin()
98 * - doLogout()
99 * - doError()
100 * - doCancel()
101 *
102 */
103 watch: function watch(aRpCaller) {
104 // store the caller structure and notify the UI observers
105 this._rpFlows[aRpCaller.id] = aRpCaller;
107 log("flows:", Object.keys(this._rpFlows).join(', '));
109 let options = makeMessageObject(aRpCaller);
110 log("sending identity-controller-watch:", options);
111 Services.obs.notifyObservers({wrappedJSObject: options},"identity-controller-watch", null);
112 },
114 /*
115 * The RP has gone away; remove handles to the hidden iframe.
116 * It's probable that the frame will already have been cleaned up.
117 */
118 unwatch: function unwatch(aRpId, aTargetMM) {
119 let rp = this._rpFlows[aRpId];
120 if (!rp) {
121 return;
122 }
124 let options = makeMessageObject({
125 id: aRpId,
126 origin: rp.origin,
127 messageManager: aTargetMM
128 });
129 log("sending identity-controller-unwatch for id", options.id, options.origin);
130 Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-unwatch", null);
132 // Stop sending messages to this window
133 delete this._rpFlows[aRpId];
134 },
136 /**
137 * Initiate a login with user interaction as a result of a call to
138 * navigator.id.request().
139 *
140 * @param aRPId
141 * (integer) the id of the doc object obtained in .watch()
142 *
143 * @param aOptions
144 * (Object) options including privacyPolicy, termsOfService
145 */
146 request: function request(aRPId, aOptions) {
147 let rp = this._rpFlows[aRPId];
148 if (!rp) {
149 reportError("request() called before watch()");
150 return;
151 }
153 // Notify UX to display identity picker.
154 // Pass the doc id to UX so it can pass it back to us later.
155 let options = makeMessageObject(rp);
156 objectCopy(aOptions, options);
157 Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-request", null);
158 },
160 /**
161 * Invoked when a user wishes to logout of a site (for instance, when clicking
162 * on an in-content logout button).
163 *
164 * @param aRpCallerId
165 * (integer) the id of the doc object obtained in .watch()
166 *
167 */
168 logout: function logout(aRpCallerId) {
169 let rp = this._rpFlows[aRpCallerId];
170 if (!rp) {
171 reportError("logout() called before watch()");
172 return;
173 }
175 let options = makeMessageObject(rp);
176 Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-logout", null);
177 },
179 childProcessShutdown: function childProcessShutdown(messageManager) {
180 Object.keys(this._rpFlows).forEach(function(key) {
181 if (this._rpFlows[key]._mm === messageManager) {
182 log("child process shutdown for rp", key, "- deleting flow");
183 delete this._rpFlows[key];
184 }
185 }, this);
186 },
188 /*
189 * once the UI-and-display-logic components have received
190 * notifications, they call back with direct invocation of the
191 * following functions (doLogin, doLogout, or doReady)
192 */
194 doLogin: function doLogin(aRpCallerId, aAssertion, aInternalParams) {
195 let rp = this._rpFlows[aRpCallerId];
196 if (!rp) {
197 log("WARNING: doLogin found no rp to go with callerId " + aRpCallerId);
198 return;
199 }
201 rp.doLogin(aAssertion, aInternalParams);
202 },
204 doLogout: function doLogout(aRpCallerId) {
205 let rp = this._rpFlows[aRpCallerId];
206 if (!rp) {
207 log("WARNING: doLogout found no rp to go with callerId " + aRpCallerId);
208 return;
209 }
211 // Logout from every site with the same origin
212 let origin = rp.origin;
213 Object.keys(this._rpFlows).forEach(function(key) {
214 let rp = this._rpFlows[key];
215 if (rp.origin === origin) {
216 rp.doLogout();
217 }
218 }.bind(this));
219 },
221 doReady: function doReady(aRpCallerId) {
222 let rp = this._rpFlows[aRpCallerId];
223 if (!rp) {
224 log("WARNING: doReady found no rp to go with callerId " + aRpCallerId);
225 return;
226 }
228 rp.doReady();
229 },
231 doCancel: function doCancel(aRpCallerId) {
232 let rp = this._rpFlows[aRpCallerId];
233 if (!rp) {
234 log("WARNING: doCancel found no rp to go with callerId " + aRpCallerId);
235 return;
236 }
238 rp.doCancel();
239 }
240 };
242 this.IdentityService = new IDService();