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/. */
7 this.EXPORTED_SYMBOLS = ["SignInToWebsiteUX"];
9 const Cc = Components.classes;
10 const Ci = Components.interfaces;
11 const Cu = Components.utils;
13 Cu.import("resource://gre/modules/Services.jsm");
14 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
16 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
17 "resource://gre/modules/identity/Identity.jsm");
19 XPCOMUtils.defineLazyModuleGetter(this, "Logger",
20 "resource://gre/modules/identity/LogUtils.jsm");
22 function log(...aMessageArgs) {
23 Logger.log.apply(Logger, ["SignInToWebsiteUX"].concat(aMessageArgs));
26 this.SignInToWebsiteUX = {
28 init: function SignInToWebsiteUX_init() {
31 * bug 793906 - temporarily disabling desktop UI so we can
32 * focus on b2g without worrying about desktop as well
34 Services.obs.addObserver(this, "identity-request", false);
35 Services.obs.addObserver(this, "identity-auth", false);
36 Services.obs.addObserver(this, "identity-auth-complete", false);
37 Services.obs.addObserver(this, "identity-login-state-changed", false);
41 uninit: function SignInToWebsiteUX_uninit() {
44 * bug 793906 - temporarily disabling desktop UI so we can
45 * focus on b2g without worrying about desktop as well
47 Services.obs.removeObserver(this, "identity-request");
48 Services.obs.removeObserver(this, "identity-auth");
49 Services.obs.removeObserver(this, "identity-auth-complete");
50 Services.obs.removeObserver(this, "identity-login-state-changed");
54 observe: function SignInToWebsiteUX_observe(aSubject, aTopic, aData) {
55 log("observe: received", aTopic, "with", aData, "for", aSubject);
58 options = aSubject.wrappedJSObject;
61 case "identity-request":
62 this.requestLogin(options);
65 this._openAuthenticationUI(aData, options);
67 case "identity-auth-complete":
68 this._closeAuthenticationUI(aData);
70 case "identity-login-state-changed":
71 let emailAddress = aData;
73 this._removeRequestUI(options);
74 this._showLoggedInUI(emailAddress, options);
76 this._removeLoggedInUI(options);
80 Logger.reportError("SignInToWebsiteUX", "Unknown observer notification:", aTopic);
86 * The website is requesting login so the user must choose an identity to use.
88 requestLogin: function SignInToWebsiteUX_requestLogin(aOptions) {
89 let windowID = aOptions.rpId;
90 log("requestLogin", aOptions);
91 let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
93 // message is not shown in the UI but is required
94 let message = aOptions.origin;
96 label: chromeWin.gNavigatorBundle.getString("identity.next.label"),
97 accessKey: chromeWin.gNavigatorBundle.getString("identity.next.accessKey"),
98 callback: function() {}, // required
102 origin: aOptions.origin,
105 let secondaryActions = [];
107 // add some extra properties to the notification to store some identity-related state
108 for (let opt in aOptions) {
109 options.identity[opt] = aOptions[opt];
111 log("requestLogin: rpId: ", options.identity.rpId);
113 chromeWin.PopupNotifications.show(browserEl, "identity-request", message,
114 "identity-notification-icon", mainAction,
119 * Get the list of possible identities to login to the given origin.
121 getIdentitiesForSite: function SignInToWebsiteUX_getIdentitiesForSite(aOrigin) {
122 return IdentityService.RP.getIdentitiesForSite(aOrigin);
126 * User chose a new or existing identity from the doorhanger after a request() call
128 selectIdentity: function SignInToWebsiteUX_selectIdentity(aRpId, aIdentity) {
129 log("selectIdentity: rpId: ", aRpId, " identity: ", aIdentity);
130 IdentityService.selectIdentity(aRpId, aIdentity);
136 * Return the chrome window and <browser> for the given outer window ID.
138 _getUIForWindowID: function(aWindowID) {
139 let someWindow = Services.wm.getMostRecentWindow("navigator:browser");
141 Logger.reportError("SignInToWebsiteUX", "no window");
145 let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
146 .getInterface(Ci.nsIDOMWindowUtils);
147 let content = windowUtils.getOuterWindowWithId(aWindowID);
150 let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
151 .getInterface(Ci.nsIWebNavigation)
152 .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
153 let chromeWin = browser.ownerDocument.defaultView;
154 return [chromeWin, browser];
156 Logger.reportError("SignInToWebsiteUX", "no content");
162 * Open UI with a content frame displaying aAuthURI so that the user can authenticate with their
163 * IDP. Then tell Identity.jsm the identifier for the window so that it knows that the DOM API
164 * calls are for this authentication flow.
166 _openAuthenticationUI: function _openAuthenticationUI(aAuthURI, aContext) {
167 // Open a tab/window with aAuthURI with an identifier (aID) attached so that the DOM APIs know this is an auth. window.
168 let chromeWin = Services.wm.getMostRecentWindow('navigator:browser');
169 let features = "chrome=false,width=640,height=480,centerscreen,location=yes,resizable=yes,scrollbars=yes,status=yes";
170 log("aAuthURI: ", aAuthURI);
171 let authWin = Services.ww.openWindow(chromeWin, "about:blank", "", features, null);
172 let windowID = authWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
173 log("authWin outer id: ", windowID);
175 let provId = aContext.provId;
176 // Tell the ID service about the id before loading the url
177 IdentityService.IDP.setAuthenticationFlow(windowID, provId);
179 authWin.location = aAuthURI;
182 _closeAuthenticationUI: function _closeAuthenticationUI(aAuthId) {
183 log("_closeAuthenticationUI:", aAuthId);
184 let [chromeWin, browserEl] = this._getUIForWindowID(aAuthId);
188 Logger.reportError("SignInToWebsite", "Could not close window with ID", aAuthId);
192 * Show a doorhanger indicating the currently logged-in user.
194 _showLoggedInUI: function _showLoggedInUI(aIdentity, aContext) {
195 let windowID = aContext.rpId;
196 log("_showLoggedInUI for ", windowID);
197 let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
199 let message = chromeWin.gNavigatorBundle.getFormattedString("identity.loggedIn.description",
202 label: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.label"),
203 accessKey: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.accessKey"),
204 callback: function() {
205 log("sign out callback fired");
206 IdentityService.RP.logout(windowID);
209 let secondaryActions = [];
213 let loggedInNot = chromeWin.PopupNotifications.show(browserEl, "identity-logged-in", message,
214 "identity-notification-icon", mainAction,
215 secondaryActions, options);
216 loggedInNot.rpId = windowID;
220 * Remove the doorhanger indicating the currently logged-in user.
222 _removeLoggedInUI: function _removeLoggedInUI(aContext) {
223 let windowID = aContext.rpId;
224 log("_removeLoggedInUI for ", windowID);
226 throw "_removeLoggedInUI: Invalid RP ID";
227 let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
229 let loggedInNot = chromeWin.PopupNotifications.getNotification("identity-logged-in", browserEl);
231 chromeWin.PopupNotifications.remove(loggedInNot);
235 * Remove the doorhanger indicating the currently logged-in user.
237 _removeRequestUI: function _removeRequestUI(aContext) {
238 let windowID = aContext.rpId;
239 log("_removeRequestUI for ", windowID);
240 let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
242 let requestNot = chromeWin.PopupNotifications.getNotification("identity-request", browserEl);
244 chromeWin.PopupNotifications.remove(requestNot);