зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1047133 - Persist FxA OAuth token between browser sessions. r=MattN
This commit is contained in:
Родитель
e186ad154f
Коммит
7543d4da50
|
@ -1624,6 +1624,8 @@ pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data:
|
|||
pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
|
||||
pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
|
||||
pref("loop.rooms.enabled", false);
|
||||
pref("loop.fxa_oauth.tokendata", "");
|
||||
pref("loop.fxa_oauth.profile", "");
|
||||
|
||||
// serverURL to be assigned by services team
|
||||
pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||
|
|
|
@ -77,19 +77,27 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
return new ConsoleAPI(consoleOptions);
|
||||
});
|
||||
|
||||
function setJSONPref(aName, aValue) {
|
||||
let value = !!aValue ? JSON.stringify(aValue) : "";
|
||||
Services.prefs.setCharPref(aName, value);
|
||||
}
|
||||
|
||||
function getJSONPref(aName) {
|
||||
let value = Services.prefs.getCharPref(aName);
|
||||
return !!value ? JSON.parse(value) : null;
|
||||
}
|
||||
|
||||
// The current deferred for the registration process. This is set if in progress
|
||||
// or the registration was successful. This is null if a registration attempt was
|
||||
// unsuccessful.
|
||||
let gRegisteredDeferred = null;
|
||||
let gPushHandler = null;
|
||||
let gHawkClient = null;
|
||||
let gLocalizedStrings = null;
|
||||
let gLocalizedStrings = null;
|
||||
let gInitializeTimer = null;
|
||||
let gFxAEnabled = true;
|
||||
let gFxAOAuthClientPromise = null;
|
||||
let gFxAOAuthClient = null;
|
||||
let gFxAOAuthTokenData = null;
|
||||
let gFxAOAuthProfile = null;
|
||||
let gErrors = new Map();
|
||||
|
||||
/**
|
||||
|
@ -306,6 +314,38 @@ let MozLoopServiceInternal = {
|
|||
return this.expiryTimeSeconds * 1000 > Date.now();
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves MozLoopService Firefox Accounts OAuth token.
|
||||
*
|
||||
* @return {Object} OAuth token
|
||||
*/
|
||||
get fxAOAuthTokenData() {
|
||||
return getJSONPref("loop.fxa_oauth.tokendata");
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets MozLoopService Firefox Accounts OAuth token.
|
||||
* If the tokenData is being cleared, will also clear the
|
||||
* profile since the profile is dependent on the token data.
|
||||
*
|
||||
* @param {Object} aTokenData OAuth token
|
||||
*/
|
||||
set fxAOAuthTokenData(aTokenData) {
|
||||
setJSONPref("loop.fxa_oauth.tokendata", aTokenData);
|
||||
if (!aTokenData) {
|
||||
this.fxAOAuthProfile = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets MozLoopService Firefox Accounts Profile data.
|
||||
*
|
||||
* @param {Object} aProfileData Profile data
|
||||
*/
|
||||
set fxAOAuthProfile(aProfileData) {
|
||||
setJSONPref("loop.fxa_oauth.profile", aProfileData);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves MozLoopService "do not disturb" pref value.
|
||||
*
|
||||
|
@ -420,9 +460,8 @@ let MozLoopServiceInternal = {
|
|||
let result = gRegisteredDeferred.promise;
|
||||
|
||||
gPushHandler = mockPushHandler || MozLoopPushHandler;
|
||||
|
||||
gPushHandler.initialize(this.onPushRegistered.bind(this),
|
||||
this.onHandleNotification.bind(this));
|
||||
this.onHandleNotification.bind(this));
|
||||
|
||||
return result;
|
||||
},
|
||||
|
@ -575,12 +614,15 @@ let MozLoopServiceInternal = {
|
|||
if (!gRegisteredDeferred) {
|
||||
return;
|
||||
}
|
||||
gRegisteredDeferred.resolve();
|
||||
gRegisteredDeferred.resolve("registered to guest status");
|
||||
// No need to clear the promise here, everything was good, so we don't need
|
||||
// to re-register.
|
||||
}, (error) => {
|
||||
}, error => {
|
||||
log.error("Failed to register with Loop server: ", error);
|
||||
gRegisteredDeferred.reject(error.errno);
|
||||
// registerWithLoopServer may have already made this null.
|
||||
if (gRegisteredDeferred) {
|
||||
gRegisteredDeferred.reject(error);
|
||||
}
|
||||
gRegisteredDeferred = null;
|
||||
});
|
||||
},
|
||||
|
@ -616,6 +658,8 @@ let MozLoopServiceInternal = {
|
|||
|
||||
log.error("Failed to register with the loop server. Error: ", error);
|
||||
this.setError("registration", error);
|
||||
gRegisteredDeferred.reject(error);
|
||||
gRegisteredDeferred = null;
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
|
@ -1069,15 +1113,36 @@ let MozLoopServiceInternal = {
|
|||
};
|
||||
Object.freeze(MozLoopServiceInternal);
|
||||
|
||||
let gInitializeTimerFunc = () => {
|
||||
// Kick off the push notification service into registering after a timeout
|
||||
// this ensures we're not doing too much straight after the browser's finished
|
||||
let gInitializeTimerFunc = (deferredInitialization, mockPushHandler, mockWebSocket) => {
|
||||
// Kick off the push notification service into registering after a timeout.
|
||||
// This ensures we're not doing too much straight after the browser's finished
|
||||
// starting up.
|
||||
gInitializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
gInitializeTimer.initWithCallback(() => {
|
||||
MozLoopService.register();
|
||||
gInitializeTimer.initWithCallback(Task.async(function* initializationCallback() {
|
||||
yield MozLoopService.register(mockPushHandler, mockWebSocket).then(Task.async(function*() {
|
||||
if (!MozLoopServiceInternal.fxAOAuthTokenData) {
|
||||
log.debug("MozLoopService: Initialized without an already logged-in account");
|
||||
deferredInitialization.resolve("initialized to guest status");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("MozLoopService: Initializing with already logged-in account");
|
||||
let registeredPromise =
|
||||
MozLoopServiceInternal.registerWithLoopServer(LOOP_SESSION_TYPE.FXA,
|
||||
gPushHandler.pushUrl);
|
||||
registeredPromise.then(() => {
|
||||
deferredInitialization.resolve("initialized to logged-in status");
|
||||
}, error => {
|
||||
log.debug("MozLoopService: error logging in using cached auth token");
|
||||
MozLoopServiceInternal.setError("login", error);
|
||||
deferredInitialization.reject("error logging in using cached auth token");
|
||||
});
|
||||
}), error => {
|
||||
log.debug("MozLoopService: Failure of initial registration", error);
|
||||
deferredInitialization.reject(error);
|
||||
});
|
||||
gInitializeTimer = null;
|
||||
},
|
||||
}),
|
||||
MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
};
|
||||
|
||||
|
@ -1094,9 +1159,10 @@ this.MozLoopService = {
|
|||
/**
|
||||
* Initialized the loop service, and starts registration with the
|
||||
* push and loop servers.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
initialize: function() {
|
||||
|
||||
initialize: Task.async(function*(mockPushHandler, mockWebSocket) {
|
||||
// Do this here, rather than immediately after definition, so that we can
|
||||
// stub out API functions for unit testing
|
||||
Object.freeze(this);
|
||||
|
@ -1104,21 +1170,34 @@ this.MozLoopService = {
|
|||
// Don't do anything if loop is not enabled.
|
||||
if (!Services.prefs.getBoolPref("loop.enabled") ||
|
||||
Services.prefs.getBoolPref("loop.throttled")) {
|
||||
return;
|
||||
return Promise.reject("loop is not enabled");
|
||||
}
|
||||
|
||||
if (Services.prefs.getPrefType("loop.fxa.enabled") == Services.prefs.PREF_BOOL) {
|
||||
gFxAEnabled = Services.prefs.getBoolPref("loop.fxa.enabled");
|
||||
if (!gFxAEnabled) {
|
||||
this.logOutFromFxA();
|
||||
yield this.logOutFromFxA();
|
||||
}
|
||||
}
|
||||
|
||||
// If expiresTime is in the future then kick-off registration.
|
||||
if (MozLoopServiceInternal.urlExpiryTimeIsInFuture()) {
|
||||
gInitializeTimerFunc();
|
||||
// If expiresTime is not in the future and the user hasn't
|
||||
// previously authenticated then skip registration.
|
||||
if (!MozLoopServiceInternal.urlExpiryTimeIsInFuture() &&
|
||||
!MozLoopServiceInternal.fxAOAuthTokenData) {
|
||||
return Promise.resolve("registration not needed");
|
||||
}
|
||||
},
|
||||
|
||||
let deferredInitialization = Promise.defer();
|
||||
gInitializeTimerFunc(deferredInitialization, mockPushHandler, mockWebSocket);
|
||||
|
||||
return deferredInitialization.promise.catch(error => {
|
||||
if (typeof(error) == "object") {
|
||||
// This never gets cleared since there is no UI to recover. Only restarting will work.
|
||||
MozLoopServiceInternal.setError("initialization", error);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}),
|
||||
|
||||
/**
|
||||
* If we're operating the service in "soft start" mode, and this browser
|
||||
|
@ -1248,7 +1327,7 @@ this.MozLoopService = {
|
|||
* sooner, this function is a no-op; this ensures we always have the latest
|
||||
* expiry time for a url.
|
||||
*
|
||||
* This is used to deterimine whether or not we should be registering with the
|
||||
* This is used to determine whether or not we should be registering with the
|
||||
* push server on start.
|
||||
*
|
||||
* @param {Integer} expiryTimeSeconds The seconds since epoch of the expiry time
|
||||
|
@ -1305,8 +1384,16 @@ this.MozLoopService = {
|
|||
return gFxAEnabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the user profile, but only if there is
|
||||
* tokenData present. Without tokenData, the
|
||||
* profile is meaningless.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
get userProfile() {
|
||||
return gFxAOAuthProfile;
|
||||
return getJSONPref("loop.fxa_oauth.tokendata") &&
|
||||
getJSONPref("loop.fxa_oauth.profile");
|
||||
},
|
||||
|
||||
get errors() {
|
||||
|
@ -1435,15 +1522,15 @@ this.MozLoopService = {
|
|||
* @return {Promise} that resolves when the FxA login flow is complete.
|
||||
*/
|
||||
logInToFxA: function() {
|
||||
log.debug("logInToFxA with gFxAOAuthTokenData:", !!gFxAOAuthTokenData);
|
||||
if (gFxAOAuthTokenData) {
|
||||
return Promise.resolve(gFxAOAuthTokenData);
|
||||
log.debug("logInToFxA with fxAOAuthTokenData:", !!MozLoopServiceInternal.fxAOAuthTokenData);
|
||||
if (MozLoopServiceInternal.fxAOAuthTokenData) {
|
||||
return Promise.resolve(MozLoopServiceInternal.fxAOAuthTokenData);
|
||||
}
|
||||
|
||||
return MozLoopServiceInternal.promiseFxAOAuthAuthorization().then(response => {
|
||||
return MozLoopServiceInternal.promiseFxAOAuthToken(response.code, response.state);
|
||||
}).then(tokenData => {
|
||||
gFxAOAuthTokenData = tokenData;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = tokenData;
|
||||
return tokenData;
|
||||
}).then(tokenData => {
|
||||
return gRegisteredDeferred.promise.then(Task.async(function*() {
|
||||
|
@ -1454,7 +1541,7 @@ this.MozLoopService = {
|
|||
}
|
||||
MozLoopServiceInternal.clearError("login");
|
||||
MozLoopServiceInternal.clearError("profile");
|
||||
return gFxAOAuthTokenData;
|
||||
return MozLoopServiceInternal.fxAOAuthTokenData;
|
||||
}));
|
||||
}).then(tokenData => {
|
||||
let client = new FxAccountsProfileClient({
|
||||
|
@ -1462,18 +1549,18 @@ this.MozLoopService = {
|
|||
token: tokenData.access_token
|
||||
});
|
||||
client.fetchProfile().then(result => {
|
||||
gFxAOAuthProfile = result;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = result;
|
||||
MozLoopServiceInternal.notifyStatusChanged("login");
|
||||
}, error => {
|
||||
log.error("Failed to retrieve profile", error);
|
||||
this.setError("profile", error);
|
||||
gFxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.notifyStatusChanged();
|
||||
});
|
||||
return tokenData;
|
||||
}).catch(error => {
|
||||
gFxAOAuthTokenData = null;
|
||||
gFxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
throw error;
|
||||
}).catch((error) => {
|
||||
MozLoopServiceInternal.setError("login", error);
|
||||
|
@ -1498,8 +1585,8 @@ this.MozLoopService = {
|
|||
MozLoopServiceInternal.clearSessionToken(LOOP_SESSION_TYPE.FXA);
|
||||
}
|
||||
|
||||
gFxAOAuthTokenData = null;
|
||||
gFxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
|
||||
// Reset the client since the initial promiseFxAOAuthParameters() call is
|
||||
// what creates a new session.
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
gFxAOAuthTokenData,
|
||||
gFxAOAuthProfile,
|
||||
} = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
|
||||
const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
|
||||
|
||||
function* checkFxA401() {
|
||||
|
@ -211,6 +206,8 @@ add_task(function* registrationWithInvalidState() {
|
|||
},
|
||||
error => {
|
||||
is(error.code, 400, "Check error code");
|
||||
checkFxAOAuthTokenData(null);
|
||||
is(MozLoopService.userProfile, null, "Profile should be empty after invalid login");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -232,6 +229,8 @@ add_task(function* registrationWith401() {
|
|||
},
|
||||
error => {
|
||||
is(error.code, 401, "Check error code");
|
||||
checkFxAOAuthTokenData(null);
|
||||
is(MozLoopService.userProfile, null, "Profile should be empty after invalid login");
|
||||
});
|
||||
|
||||
yield checkFxA401();
|
||||
|
@ -321,7 +320,7 @@ add_task(function* loginWithParams401() {
|
|||
},
|
||||
error => {
|
||||
ise(error.code, 401, "Check error code");
|
||||
ise(gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
checkFxAOAuthTokenData(null);
|
||||
});
|
||||
|
||||
yield checkFxA401();
|
||||
|
@ -387,7 +386,7 @@ add_task(function* loginWithRegistration401() {
|
|||
},
|
||||
error => {
|
||||
ise(error.code, 401, "Check error code");
|
||||
ise(gFxAOAuthTokenData, null, "Check there is no saved token data");
|
||||
checkFxAOAuthTokenData(null);
|
||||
});
|
||||
|
||||
yield checkFxA401();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
registerCleanupFunction(function*() {
|
||||
MozLoopService.doNotDisturb = false;
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", null);
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
yield MozLoopServiceInternal.clearError("testing");
|
||||
});
|
||||
|
||||
|
@ -25,7 +25,8 @@ add_task(function* test_doNotDisturb_with_login() {
|
|||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
yield MozLoopService.doNotDisturb = true;
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is in disabled state");
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", {email: "test@example.com", uid: "abcd1234"});
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = {token_type:"bearer",access_token:"1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",scope:"profile"};
|
||||
MozLoopServiceInternal.fxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
|
||||
yield MozLoopServiceInternal.notifyStatusChanged("login");
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state");
|
||||
yield loadLoopPanel();
|
||||
|
@ -34,7 +35,7 @@ add_task(function* test_doNotDisturb_with_login() {
|
|||
loopPanel.hidePopup();
|
||||
yield MozLoopService.doNotDisturb = false;
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", null);
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
yield MozLoopServiceInternal.notifyStatusChanged();
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
});
|
||||
|
@ -51,26 +52,27 @@ add_task(function* test_error_with_login() {
|
|||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
yield MozLoopServiceInternal.setError("testing", {});
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "error", "Check button is in error state");
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", {email: "test@example.com", uid: "abcd1234"});
|
||||
MozLoopServiceInternal.fxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
|
||||
MozLoopServiceInternal.notifyStatusChanged("login");
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "error", "Check button is in error state");
|
||||
yield MozLoopServiceInternal.clearError("testing");
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", null);
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.notifyStatusChanged();
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
});
|
||||
|
||||
add_task(function* test_active() {
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", {email: "test@example.com", uid: "abcd1234"});
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = {token_type:"bearer",access_token:"1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",scope:"profile"};
|
||||
MozLoopServiceInternal.fxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
|
||||
yield MozLoopServiceInternal.notifyStatusChanged("login");
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state");
|
||||
yield loadLoopPanel();
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state after opening panel");
|
||||
let loopPanel = document.getElementById("loop-notification-panel");
|
||||
loopPanel.hidePopup();
|
||||
setInternalLoopGlobal("gFxAOAuthProfile", null);
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
MozLoopServiceInternal.notifyStatusChanged();
|
||||
Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state");
|
||||
});
|
||||
|
|
|
@ -120,8 +120,8 @@ function* resetFxA() {
|
|||
global.gHawkClient = null;
|
||||
global.gFxAOAuthClientPromise = null;
|
||||
global.gFxAOAuthClient = null;
|
||||
global.gFxAOAuthTokenData = null;
|
||||
global.gFxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
|
||||
Services.prefs.clearUserPref(fxASessionPref);
|
||||
MozLoopService.errors.clear();
|
||||
|
@ -130,17 +130,16 @@ function* resetFxA() {
|
|||
yield notified;
|
||||
}
|
||||
|
||||
function setInternalLoopGlobal(aName, aValue) {
|
||||
let global = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
global[aName] = aValue;
|
||||
function checkFxAOAuthTokenData(aValue) {
|
||||
ise(MozLoopServiceInternal.fxAOAuthTokenData, aValue, "fxAOAuthTokenData should be " + aValue);
|
||||
}
|
||||
|
||||
function checkLoggedOutState() {
|
||||
let global = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
ise(global.gFxAOAuthClientPromise, null, "gFxAOAuthClientPromise should be cleared");
|
||||
ise(global.gFxAOAuthProfile, null, "gFxAOAuthProfile should be cleared");
|
||||
ise(MozLoopService.userProfile, null, "fxAOAuthProfile should be cleared");
|
||||
ise(global.gFxAOAuthClient, null, "gFxAOAuthClient should be cleared");
|
||||
ise(global.gFxAOAuthTokenData, null, "gFxAOAuthTokenData should be cleared");
|
||||
checkFxAOAuthTokenData(null);
|
||||
const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
|
||||
ise(Services.prefs.getPrefType(fxASessionPref), Services.prefs.PREF_INVALID,
|
||||
"FxA hawk session should be cleared anyways");
|
||||
|
|
|
@ -52,9 +52,10 @@ function run_test()
|
|||
{
|
||||
setupFakeLoopServer();
|
||||
|
||||
// Setup fake login (profile) state so we get FxA requests.
|
||||
const serviceGlobal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
|
||||
serviceGlobal.gFxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
|
||||
// Setup fake login state so we get FxA requests.
|
||||
const MozLoopServiceInternal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).MozLoopServiceInternal;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = {token_type:"bearer",access_token:"1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",scope:"profile"};
|
||||
MozLoopServiceInternal.fxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
|
||||
|
||||
// For each notification received from the PushServer, MozLoopService will first query
|
||||
// for any pending calls on the FxA hawk session and then again using the guest session.
|
||||
|
@ -102,7 +103,7 @@ function run_test()
|
|||
Chat.open = openChatOrig;
|
||||
|
||||
// Revert fake login state
|
||||
serviceGlobal.gFxAOAuthProfile = null;
|
||||
MozLoopServiceInternal.fxAOAuthTokenData = null;
|
||||
|
||||
// clear test pref
|
||||
Services.prefs.clearUserPref("loop.seenToS");
|
||||
|
|
|
@ -10,8 +10,9 @@ var startTimerCalled = false;
|
|||
add_task(function test_initialize_no_expiry() {
|
||||
startTimerCalled = false;
|
||||
|
||||
MozLoopService.initialize();
|
||||
|
||||
let initializedPromise = yield MozLoopService.initialize();
|
||||
Assert.equal(initializedPromise, "registration not needed",
|
||||
"Promise should be fulfilled");
|
||||
Assert.equal(startTimerCalled, false,
|
||||
"should not register when no expiry time is set");
|
||||
});
|
||||
|
|
|
@ -40,7 +40,7 @@ add_test(function test_register_websocket_success_loop_server_fail() {
|
|||
}, err => {
|
||||
// 404 is an expected failure indicated by the lack of route being set
|
||||
// up on the Loop server mock. This is added in the next test.
|
||||
Assert.equal(err, 404, "Expected no errors in websocket registration");
|
||||
Assert.equal(err.errno, 404, "Expected no errors in websocket registration");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const FAKE_FXA_TOKEN_DATA = JSON.stringify({
|
||||
"token_type": "bearer",
|
||||
"access_token": "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
|
||||
"scope": "profile"
|
||||
});
|
||||
const FAKE_FXA_PROFILE = JSON.stringify({
|
||||
"email": "test@example.com",
|
||||
"uid": "999999994d9f4b08a2cbfc0999999999",
|
||||
"avatar": null
|
||||
});
|
||||
const LOOP_FXA_TOKEN_PREF = "loop.fxa_oauth.tokendata";
|
||||
const LOOP_FXA_PROFILE_PREF = "loop.fxa_oauth.profile";
|
||||
const LOOP_URL_EXPIRY_PREF = "loop.urlsExpiryTimeSeconds";
|
||||
const LOOP_INITIAL_DELAY_PREF = "loop.initialDelay";
|
||||
|
||||
/**
|
||||
* This file is to test restart+reauth.
|
||||
*/
|
||||
|
||||
add_task(function test_initialize_with_expired_urls_and_no_auth_token() {
|
||||
// Set time to be 2 seconds in the past.
|
||||
var nowSeconds = Date.now() / 1000;
|
||||
Services.prefs.setIntPref(LOOP_URL_EXPIRY_PREF, nowSeconds - 2);
|
||||
Services.prefs.clearUserPref(LOOP_FXA_TOKEN_PREF);
|
||||
|
||||
yield MozLoopService.initialize(mockPushHandler).then((msg) => {
|
||||
Assert.equal(msg, "registration not needed", "Initialize should not register when the " +
|
||||
"URLs are expired and there are no auth tokens");
|
||||
}, (error) => {
|
||||
Assert.ok(false, error, "should have resolved the promise that initialize returned");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_initialize_with_urls_and_no_auth_token() {
|
||||
Services.prefs.setIntPref(LOOP_URL_EXPIRY_PREF, Date.now() / 1000 + 10);
|
||||
Services.prefs.clearUserPref(LOOP_FXA_TOKEN_PREF);
|
||||
|
||||
loopServer.registerPathHandler("/registration", (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
});
|
||||
|
||||
yield MozLoopService.initialize(mockPushHandler).then((msg) => {
|
||||
Assert.equal(msg, "initialized to guest status", "Initialize should register as a " +
|
||||
"guest when no auth tokens but expired URLs");
|
||||
}, (error) => {
|
||||
Assert.ok(false, error, "should have resolved the promise that initialize returned");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_initialize_with_invalid_fxa_token() {
|
||||
Services.prefs.setCharPref(LOOP_FXA_PROFILE_PREF, FAKE_FXA_PROFILE);
|
||||
Services.prefs.setCharPref(LOOP_FXA_TOKEN_PREF, FAKE_FXA_TOKEN_DATA);
|
||||
|
||||
// Only need to implement the FxA registration because the previous
|
||||
// test registered as a guest.
|
||||
loopServer.registerPathHandler("/registration", (request, response) => {
|
||||
response.setStatusLine(null, 401, "Unauthorized");
|
||||
response.write(JSON.stringify({
|
||||
code: 401,
|
||||
errno: 110,
|
||||
error: "Unauthorized",
|
||||
message: "Unknown credentials",
|
||||
}));
|
||||
});
|
||||
|
||||
yield MozLoopService.initialize(mockPushHandler).then(() => {
|
||||
Assert.ok(false, "Initializing with an invalid token should reject the promise");
|
||||
},
|
||||
(error) => {
|
||||
let pushHandler = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).gPushHandler;
|
||||
Assert.equal(pushHandler.pushUrl, kEndPointUrl, "Push URL should match");
|
||||
Assert.equal(Services.prefs.getCharPref(LOOP_FXA_TOKEN_PREF), "",
|
||||
"FXA pref should be cleared if token was invalid");
|
||||
Assert.equal(Services.prefs.getCharPref(LOOP_FXA_PROFILE_PREF), "",
|
||||
"FXA profile pref should be cleared if token was invalid");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_initialize_with_fxa_token() {
|
||||
Services.prefs.setCharPref(LOOP_FXA_PROFILE_PREF, FAKE_FXA_PROFILE);
|
||||
Services.prefs.setCharPref(LOOP_FXA_TOKEN_PREF, FAKE_FXA_TOKEN_DATA);
|
||||
loopServer.registerPathHandler("/registration", (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
});
|
||||
|
||||
yield MozLoopService.initialize(mockPushHandler).then(() => {
|
||||
Assert.equal(Services.prefs.getCharPref(LOOP_FXA_TOKEN_PREF), FAKE_FXA_TOKEN_DATA,
|
||||
"FXA pref should still be set after initialization");
|
||||
Assert.equal(Services.prefs.getCharPref(LOOP_FXA_PROFILE_PREF), FAKE_FXA_PROFILE,
|
||||
"FXA profile should still be set after initialization");
|
||||
});
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
setupFakeLoopServer();
|
||||
// Note, this is just used to speed up the test.
|
||||
Services.prefs.setIntPref(LOOP_INITIAL_DELAY_PREF, 0);
|
||||
mockPushHandler.pushUrl = kEndPointUrl;
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.clearUserPref(LOOP_INITIAL_DELAY_PREF);
|
||||
Services.prefs.clearUserPref(LOOP_FXA_TOKEN_PREF);
|
||||
Services.prefs.clearUserPref(LOOP_FXA_PROFILE_PREF);
|
||||
Services.prefs.clearUserPref(LOOP_URL_EXPIRY_PREF);
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
};
|
|
@ -18,11 +18,8 @@ add_test(function test_registration_invalid_token() {
|
|||
response.write(JSON.stringify({
|
||||
code: 401,
|
||||
errno: 110,
|
||||
error: {
|
||||
error: "Unauthorized",
|
||||
message: "Unknown credentials",
|
||||
statusCode: 401
|
||||
}
|
||||
error: "Unauthorized",
|
||||
message: "Unknown credentials",
|
||||
}));
|
||||
} else {
|
||||
// We didn't have an authorization header, so check the pref has been cleared.
|
||||
|
|
|
@ -15,6 +15,7 @@ skip-if = toolkit == 'gonk'
|
|||
[test_loopservice_locales.js]
|
||||
[test_loopservice_notification.js]
|
||||
[test_loopservice_registration.js]
|
||||
[test_loopservice_restart.js]
|
||||
[test_loopservice_token_invalid.js]
|
||||
[test_loopservice_token_save.js]
|
||||
[test_loopservice_token_send.js]
|
||||
|
|
|
@ -743,7 +743,10 @@ BrowserGlue.prototype = {
|
|||
|
||||
// XXX: Temporary hack to allow Loop FxA login after a restart to work.
|
||||
// Remove this once bug 1071247 is deployed.
|
||||
Services.prefs.clearUserPref("loop.hawk-session-token.fxa");
|
||||
if (Services.prefs.getPrefType("loop.autologin-after-restart") != Ci.nsIPrefBranch.PREF_BOOL ||
|
||||
!Services.prefs.getBoolPref("loop.autologin-after-restart")) {
|
||||
Services.prefs.clearUserPref("loop.hawk-session-token.fxa");
|
||||
}
|
||||
},
|
||||
|
||||
// All initial windows have opened.
|
||||
|
|
Загрузка…
Ссылка в новой задаче