Bug 1047133 - Persist FxA OAuth token between browser sessions. r=MattN

This commit is contained in:
Jared Wein 2014-10-08 20:49:47 -04:00
Родитель e186ad154f
Коммит 7543d4da50
12 изменённых файлов: 272 добавлений и 69 удалений

Просмотреть файл

@ -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.