mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1191064 - Part 1: Add Fennec version of FxAccountsWebChannel. r=markh
This ticket does the following things: * register early. If the first page that Gecko loads is about:accounts, the channel needs to be in place. If we delay this, we can and do miss content server messages. * listen to the following messages: CAN_LINK_ACCOUNT: 'fxaccounts:can_link_account' CHANGE_PASSWORD: 'fxaccounts:change_password' DELETE_ACCOUNT: 'fxaccounts:delete_account' LOADED: 'fxaccounts:loaded' LOGIN: 'fxaccounts:login' The list of messages is from2a78a14daf/app/scripts/models/auth_brokers/fx-desktop-v2.js (L24)
via2a78a14daf/app/scripts/models/auth_brokers/fx-fennec-v1.js
This patch implements only LOADED, LOGIN, and CHANGE_PASSWORD. The messages have the following behaviour: A LOADED message is ferried to the individual XUL <browser> element it originated from. In general, WebChannel is a global listener: it does not matter where a message originates. We want to have fine-grained control over when an embedding <iframe> is displayed (as opposed to loaded, in the Gecko sense of loaded). The fxa-content-server participates in this exchange via the LOADED message; we complete the loop by specially handling LOADED. A LOGIN or CHANGE_PASSWORD message either creates a new Android Account in the Engaged state, or moves an existing Android Account to the Engaged state. An Android sync is not yet requested -- we'll arrange that from the Java side.
This commit is contained in:
parent
9720b8dd9b
commit
d6b4d9e981
@ -22,7 +22,6 @@ import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.GeneralSecurityException;
|
||||
@ -109,7 +108,7 @@ public class AccountsHelper implements NativeEventListener {
|
||||
final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
|
||||
if (account == null) {
|
||||
if (callback != null) {
|
||||
callback.sendError("Could not update Firefox Account since non exists");
|
||||
callback.sendError("Could not update Firefox Account since none exists");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -117,6 +116,17 @@ public class AccountsHelper implements NativeEventListener {
|
||||
final NativeJSObject json = message.getObject("json");
|
||||
final String email = json.getString("email");
|
||||
final String uid = json.getString("uid");
|
||||
|
||||
// Protect against cross-connecting accounts.
|
||||
if (account.name == null || !account.name.equals(email)) {
|
||||
final String errorMessage = "Cannot update Firefox Account from JSON: datum has different email address!";
|
||||
Log.e(LOGTAG, errorMessage);
|
||||
if (callback != null) {
|
||||
callback.sendError(errorMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean verified = json.optBoolean("verified", false);
|
||||
final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey"));
|
||||
final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken"));
|
||||
@ -129,7 +139,7 @@ public class AccountsHelper implements NativeEventListener {
|
||||
if (callback != null) {
|
||||
callback.sendSuccess(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (NativeJSObject.InvalidPropertyException e) {
|
||||
Log.w(LOGTAG, "Got exception updating Firefox Account from JSON; ignoring.", e);
|
||||
if (callback != null) {
|
||||
callback.sendError("Could not update Firefox Account from JSON: " + e.toString());
|
||||
|
@ -546,6 +546,16 @@ var BrowserApp = {
|
||||
InitLater(() => AccessFu.attach(window), window, "AccessFu");
|
||||
}
|
||||
|
||||
if (!AppConstants.MOZ_ANDROID_NATIVE_ACCOUNT_UI) {
|
||||
// We can't delay registering WebChannel listeners: if the first page is
|
||||
// about:accounts, which can happen when starting the Firefox Account flow
|
||||
// from the first run experience, or via the Firefox Account Status
|
||||
// Activity, we can and do miss messages from the fxa-content-server.
|
||||
console.log("browser.js: loading Firefox Accounts WebChannel");
|
||||
Cu.import("resource://gre/modules/FxAccountsWebChannel.jsm");
|
||||
EnsureFxAccountsWebChannel();
|
||||
}
|
||||
|
||||
// Notify Java that Gecko has loaded.
|
||||
Messaging.sendRequest({ type: "Gecko:Ready" });
|
||||
|
||||
|
235
mobile/android/modules/FxAccountsWebChannel.jsm
Normal file
235
mobile/android/modules/FxAccountsWebChannel.jsm
Normal file
@ -0,0 +1,235 @@
|
||||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Firefox Accounts Web Channel.
|
||||
*
|
||||
* Use the WebChannel component to receive messages about account
|
||||
* state changes.
|
||||
*/
|
||||
this.EXPORTED_SYMBOLS = ["EnsureFxAccountsWebChannel"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; /*global Components */
|
||||
|
||||
Cu.import("resource://gre/modules/Accounts.jsm"); /*global Accounts */
|
||||
Cu.import("resource://gre/modules/Notifications.jsm"); /*global Notifications */
|
||||
Cu.import("resource://gre/modules/Prompt.jsm"); /*global Prompt */
|
||||
Cu.import("resource://gre/modules/Services.jsm"); /*global Services */
|
||||
Cu.import("resource://gre/modules/WebChannel.jsm"); /*global WebChannel */
|
||||
|
||||
const log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.bind("FxAccounts");
|
||||
|
||||
const WEBCHANNEL_ID = "account_updates";
|
||||
|
||||
const COMMAND_LOADED = "fxaccounts:loaded";
|
||||
const COMMAND_CAN_LINK_ACCOUNT = "fxaccounts:can_link_account";
|
||||
const COMMAND_LOGIN = "fxaccounts:login";
|
||||
const COMMAND_CHANGE_PASSWORD = "fxaccounts:change_password";
|
||||
|
||||
/**
|
||||
* Create a new FxAccountsWebChannel to listen for account updates.
|
||||
*
|
||||
* @param {Object} options Options
|
||||
* @param {Object} options
|
||||
* @param {String} options.content_uri
|
||||
* The FxA Content server uri
|
||||
* @param {String} options.channel_id
|
||||
* The ID of the WebChannel
|
||||
* @param {String} options.helpers
|
||||
* Helpers functions. Should only be passed in for testing.
|
||||
* @constructor
|
||||
*/
|
||||
this.FxAccountsWebChannel = function(options) {
|
||||
if (!options) {
|
||||
throw new Error("Missing configuration options");
|
||||
}
|
||||
if (!options["content_uri"]) {
|
||||
throw new Error("Missing 'content_uri' option");
|
||||
}
|
||||
this._contentUri = options.content_uri;
|
||||
|
||||
if (!options["channel_id"]) {
|
||||
throw new Error("Missing 'channel_id' option");
|
||||
}
|
||||
this._webChannelId = options.channel_id;
|
||||
|
||||
this._setupChannel();
|
||||
};
|
||||
|
||||
this.FxAccountsWebChannel.prototype = {
|
||||
/**
|
||||
* WebChannel that is used to communicate with content page
|
||||
*/
|
||||
_channel: null,
|
||||
|
||||
/**
|
||||
* WebChannel ID.
|
||||
*/
|
||||
_webChannelId: null,
|
||||
/**
|
||||
* WebChannel origin, used to validate origin of messages
|
||||
*/
|
||||
_webChannelOrigin: null,
|
||||
|
||||
/**
|
||||
* Release all resources that are in use.
|
||||
*/
|
||||
tearDown() {
|
||||
this._channel.stopListening();
|
||||
this._channel = null;
|
||||
this._channelCallback = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures and registers a new WebChannel
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_setupChannel() {
|
||||
// if this.contentUri is present but not a valid URI, then this will throw an error.
|
||||
try {
|
||||
this._webChannelOrigin = Services.io.newURI(this._contentUri, null, null);
|
||||
this._registerChannel();
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new channel with the WebChannelBroker, setup a callback listener
|
||||
* @private
|
||||
*/
|
||||
_registerChannel() {
|
||||
/**
|
||||
* Processes messages that are called back from the FxAccountsChannel
|
||||
*
|
||||
* @param webChannelId {String}
|
||||
* Command webChannelId
|
||||
* @param message {Object}
|
||||
* Command message
|
||||
* @param sendingContext {Object}
|
||||
* Message sending context.
|
||||
* @param sendingContext.browser {browser}
|
||||
* The <browser> object that captured the
|
||||
* WebChannelMessageToChrome.
|
||||
* @param sendingContext.eventTarget {EventTarget}
|
||||
* The <EventTarget> where the message was sent.
|
||||
* @param sendingContext.principal {Principal}
|
||||
* The <Principal> of the EventTarget where the message was sent.
|
||||
* @private
|
||||
*
|
||||
*/
|
||||
let listener = (webChannelId, message, sendingContext) => {
|
||||
if (message) {
|
||||
let command = message.command;
|
||||
let data = message.data;
|
||||
log.d("FxAccountsWebChannel message received, command: " + command);
|
||||
|
||||
// Respond to the message with true or false.
|
||||
let respond = (data) => {
|
||||
let response = {
|
||||
command: command,
|
||||
messageId: message.messageId,
|
||||
data: data
|
||||
};
|
||||
log.d("Sending response to command: " + command);
|
||||
this._channel.send(response, sendingContext);
|
||||
};
|
||||
|
||||
switch (command) {
|
||||
case COMMAND_LOADED:
|
||||
let mm = sendingContext.browser.docShell
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
mm.sendAsyncMessage(COMMAND_LOADED);
|
||||
break;
|
||||
|
||||
case COMMAND_CAN_LINK_ACCOUNT:
|
||||
// Temporarily accept any login.
|
||||
respond({ ok: true });
|
||||
break;
|
||||
|
||||
case COMMAND_LOGIN:
|
||||
// Either create a new Android Account or re-connect an existing
|
||||
// Android Account here. There's not much to be done if we don't
|
||||
// succeed or get an error.
|
||||
Accounts.getFirefoxAccount().then(account => {
|
||||
if (!account) {
|
||||
return Accounts.createFirefoxAccountFromJSON(data).then(success => {
|
||||
if (!success) {
|
||||
throw new Error("Could not create Firefox Account!");
|
||||
}
|
||||
return success;
|
||||
});
|
||||
} else {
|
||||
return Accounts.updateFirefoxAccountFromJSON(data).then(success => {
|
||||
if (!success) {
|
||||
throw new Error("Could not update Firefox Account!");
|
||||
}
|
||||
return success;
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(success => {
|
||||
if (!success) {
|
||||
throw new Error("Could not create or update Firefox Account!");
|
||||
}
|
||||
log.i("Created or updated Firefox Account.");
|
||||
})
|
||||
.catch(e => {
|
||||
log.e(e.toString());
|
||||
});
|
||||
break;
|
||||
|
||||
case COMMAND_CHANGE_PASSWORD:
|
||||
// Only update an existing Android Account.
|
||||
Accounts.getFirefoxAccount().then(account => {
|
||||
if (!account) {
|
||||
throw new Error("Can't change password of non-existent Firefox Account!");
|
||||
}
|
||||
return Accounts.updateFirefoxAccountFromJSON(data);
|
||||
})
|
||||
.then(success => {
|
||||
if (!success) {
|
||||
throw new Error("Could not change Firefox Account password!");
|
||||
}
|
||||
log.i("Changed Firefox Account password.");
|
||||
})
|
||||
.catch(e => {
|
||||
log.e(e.toString());
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
log.w("Ignoring unrecognized FxAccountsWebChannel command: " + JSON.stringify(command));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this._channelCallback = listener;
|
||||
this._channel = new WebChannel(this._webChannelId, this._webChannelOrigin);
|
||||
this._channel.listen(listener);
|
||||
|
||||
log.d("FxAccountsWebChannel registered: " + this._webChannelId + " with origin " + this._webChannelOrigin.prePath);
|
||||
}
|
||||
};
|
||||
|
||||
let singleton;
|
||||
// The entry-point for this module, which ensures only one of our channels is
|
||||
// ever created - we require this because the WebChannel is global in scope and
|
||||
// allowing multiple channels would cause such notifications to be sent multiple
|
||||
// times.
|
||||
this.EnsureFxAccountsWebChannel = function() {
|
||||
if (!singleton) {
|
||||
let contentUri = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.webchannel.uri");
|
||||
// The FxAccountsWebChannel listens for events and updates the Java layer.
|
||||
singleton = new this.FxAccountsWebChannel({
|
||||
content_uri: contentUri,
|
||||
channel_id: WEBCHANNEL_ID,
|
||||
});
|
||||
}
|
||||
};
|
@ -11,6 +11,7 @@ EXTRA_JS_MODULES += [
|
||||
'dbg-browser-actors.js',
|
||||
'DelayedInit.jsm',
|
||||
'DownloadNotifications.jsm',
|
||||
'FxAccountsWebChannel.jsm',
|
||||
'HelperApps.jsm',
|
||||
'Home.jsm',
|
||||
'HomeProvider.jsm',
|
||||
|
Loading…
Reference in New Issue
Block a user