forked from mirrors/gecko-dev
Bug 1888019 - Use a different client ID, scope and keys for Sync in Thunderbird. r=teshaq,sync-reviewers a=RyanVM
Differential Revision: https://phabricator.services.mozilla.com/D205783
This commit is contained in:
parent
d26cf26a79
commit
a6ee611db1
21 changed files with 215 additions and 184 deletions
|
|
@ -19,7 +19,7 @@ import {
|
||||||
FXA_PWDMGR_PLAINTEXT_FIELDS,
|
FXA_PWDMGR_PLAINTEXT_FIELDS,
|
||||||
FXA_PWDMGR_REAUTH_ALLOWLIST,
|
FXA_PWDMGR_REAUTH_ALLOWLIST,
|
||||||
FXA_PWDMGR_SECURE_FIELDS,
|
FXA_PWDMGR_SECURE_FIELDS,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
ON_ACCOUNT_STATE_CHANGE_NOTIFICATION,
|
ON_ACCOUNT_STATE_CHANGE_NOTIFICATION,
|
||||||
ONLOGIN_NOTIFICATION,
|
ONLOGIN_NOTIFICATION,
|
||||||
ONLOGOUT_NOTIFICATION,
|
ONLOGOUT_NOTIFICATION,
|
||||||
|
|
@ -1089,10 +1089,7 @@ FxAccountsInternal.prototype = {
|
||||||
* @param { Object } tokenData: The token's data, with `tokenData.token` being the token itself
|
* @param { Object } tokenData: The token's data, with `tokenData.token` being the token itself
|
||||||
**/
|
**/
|
||||||
destroyOAuthToken(tokenData) {
|
destroyOAuthToken(tokenData) {
|
||||||
return this.fxAccountsClient.oauthDestroy(
|
return this.fxAccountsClient.oauthDestroy(OAUTH_CLIENT_ID, tokenData.token);
|
||||||
FX_OAUTH_CLIENT_ID,
|
|
||||||
tokenData.token
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_destroyAllOAuthTokens(tokenInfos) {
|
_destroyAllOAuthTokens(tokenInfos) {
|
||||||
|
|
@ -1378,7 +1375,7 @@ FxAccountsInternal.prototype = {
|
||||||
async _doTokenFetchWithSessionToken(sessionToken, scopeString, ttl) {
|
async _doTokenFetchWithSessionToken(sessionToken, scopeString, ttl) {
|
||||||
const result = await this.fxAccountsClient.accessTokenWithSessionToken(
|
const result = await this.fxAccountsClient.accessTokenWithSessionToken(
|
||||||
sessionToken,
|
sessionToken,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
scopeString,
|
scopeString,
|
||||||
ttl
|
ttl
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
CLIENT_IS_THUNDERBIRD,
|
||||||
COMMAND_SENDTAB,
|
COMMAND_SENDTAB,
|
||||||
COMMAND_SENDTAB_TAIL,
|
COMMAND_SENDTAB_TAIL,
|
||||||
COMMAND_CLOSETAB,
|
COMMAND_CLOSETAB,
|
||||||
|
|
@ -45,26 +46,30 @@ export class FxAccountsCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
async availableCommands() {
|
async availableCommands() {
|
||||||
// Invalid keys usually means the account is not verified yet.
|
|
||||||
const encryptedSendTabKeys = await this.sendTab.getEncryptedSendTabKeys();
|
|
||||||
let commands = {};
|
let commands = {};
|
||||||
|
|
||||||
if (encryptedSendTabKeys) {
|
if (!CLIENT_IS_THUNDERBIRD) {
|
||||||
commands[COMMAND_SENDTAB] = encryptedSendTabKeys;
|
// Invalid keys usually means the account is not verified yet.
|
||||||
}
|
const encryptedSendTabKeys = await this.sendTab.getEncryptedSendTabKeys();
|
||||||
|
|
||||||
// Close Tab is still a worked-on feature, so we should not broadcast it widely yet
|
if (encryptedSendTabKeys) {
|
||||||
let closeTabEnabled = Services.prefs.getBoolPref(
|
commands[COMMAND_SENDTAB] = encryptedSendTabKeys;
|
||||||
"identity.fxaccounts.commands.remoteTabManagement.enabled",
|
}
|
||||||
false
|
|
||||||
);
|
// Close Tab is still a worked-on feature, so we should not broadcast it widely yet
|
||||||
if (closeTabEnabled) {
|
let closeTabEnabled = Services.prefs.getBoolPref(
|
||||||
const encryptedCloseTabKeys =
|
"identity.fxaccounts.commands.remoteTabManagement.enabled",
|
||||||
await this.closeTab.getEncryptedCloseTabKeys();
|
false
|
||||||
if (encryptedCloseTabKeys) {
|
);
|
||||||
commands[COMMAND_CLOSETAB] = encryptedCloseTabKeys;
|
if (closeTabEnabled) {
|
||||||
|
const encryptedCloseTabKeys =
|
||||||
|
await this.closeTab.getEncryptedCloseTabKeys();
|
||||||
|
if (encryptedCloseTabKeys) {
|
||||||
|
commands[COMMAND_CLOSETAB] = encryptedCloseTabKeys;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
||||||
import { Log } from "resource://gre/modules/Log.sys.mjs";
|
import { Log } from "resource://gre/modules/Log.sys.mjs";
|
||||||
import { LogManager } from "resource://gre/modules/LogManager.sys.mjs";
|
import { LogManager } from "resource://gre/modules/LogManager.sys.mjs";
|
||||||
|
|
||||||
|
|
@ -88,10 +89,22 @@ export let COMMAND_CLOSETAB_TAIL = "close-uri/v1";
|
||||||
export let COMMAND_CLOSETAB = COMMAND_PREFIX + COMMAND_CLOSETAB_TAIL;
|
export let COMMAND_CLOSETAB = COMMAND_PREFIX + COMMAND_CLOSETAB_TAIL;
|
||||||
|
|
||||||
// OAuth
|
// OAuth
|
||||||
export let FX_OAUTH_CLIENT_ID = "5882386c6d801776";
|
export let CLIENT_IS_THUNDERBIRD = AppConstants.MOZ_APP_NAME == "thunderbird";
|
||||||
|
let FX_OAUTH_CLIENT_ID = "5882386c6d801776";
|
||||||
|
let TB_OAUTH_CLIENT_ID = "8269bacd7bbc7f80";
|
||||||
|
export let OAUTH_CLIENT_ID = CLIENT_IS_THUNDERBIRD
|
||||||
|
? TB_OAUTH_CLIENT_ID
|
||||||
|
: FX_OAUTH_CLIENT_ID;
|
||||||
export let SCOPE_PROFILE = "profile";
|
export let SCOPE_PROFILE = "profile";
|
||||||
export let SCOPE_PROFILE_WRITE = "profile:write";
|
export let SCOPE_PROFILE_WRITE = "profile:write";
|
||||||
|
// Sync scope in Firefox.
|
||||||
export let SCOPE_OLD_SYNC = "https://identity.mozilla.com/apps/oldsync";
|
export let SCOPE_OLD_SYNC = "https://identity.mozilla.com/apps/oldsync";
|
||||||
|
// Sync scope in Thunderbird.
|
||||||
|
let SCOPE_THUNDERBIRD_SYNC = "https://identity.thunderbird.net/apps/sync";
|
||||||
|
// The scope to use for sync, depending on the current application.
|
||||||
|
export let SCOPE_APP_SYNC = CLIENT_IS_THUNDERBIRD
|
||||||
|
? SCOPE_THUNDERBIRD_SYNC
|
||||||
|
: SCOPE_OLD_SYNC;
|
||||||
|
|
||||||
// This scope was previously used to calculate a telemetry tracking identifier for
|
// This scope was previously used to calculate a telemetry tracking identifier for
|
||||||
// the account, but that system has since been decommissioned. It's here entirely
|
// the account, but that system has since been decommissioned. It's here entirely
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { RESTRequest } from "resource://services-common/rest.sys.mjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
log,
|
log,
|
||||||
SCOPE_OLD_SYNC,
|
SCOPE_APP_SYNC,
|
||||||
SCOPE_PROFILE,
|
SCOPE_PROFILE,
|
||||||
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
||||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||||
|
|
@ -344,7 +344,7 @@ export var FxAccountsConfig = {
|
||||||
|
|
||||||
async _getAuthParams() {
|
async _getAuthParams() {
|
||||||
if (this._isOAuthFlow()) {
|
if (this._isOAuthFlow()) {
|
||||||
const scopes = [SCOPE_OLD_SYNC, SCOPE_PROFILE];
|
const scopes = [SCOPE_APP_SYNC, SCOPE_PROFILE];
|
||||||
return lazy.fxAccounts._internal.beginOAuthFlow(scopes);
|
return lazy.fxAccounts._internal.beginOAuthFlow(scopes);
|
||||||
}
|
}
|
||||||
return { service: SYNC_PARAM };
|
return { service: SYNC_PARAM };
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import { CommonUtils } from "resource://services-common/utils.sys.mjs";
|
||||||
import { CryptoUtils } from "resource://services-crypto/utils.sys.mjs";
|
import { CryptoUtils } from "resource://services-crypto/utils.sys.mjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SCOPE_OLD_SYNC,
|
SCOPE_APP_SYNC,
|
||||||
DEPRECATED_SCOPE_ECOSYSTEM_TELEMETRY,
|
DEPRECATED_SCOPE_ECOSYSTEM_TELEMETRY,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
log,
|
log,
|
||||||
logPII,
|
logPII,
|
||||||
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
||||||
|
|
@ -35,7 +35,7 @@ const DEPRECATED_SCOPE_WEBEXT_SYNC = "sync:addon_storage";
|
||||||
// These are the scopes that correspond to new storage for the `LEGACY_DERIVED_KEYS_NAMES`.
|
// These are the scopes that correspond to new storage for the `LEGACY_DERIVED_KEYS_NAMES`.
|
||||||
// We will, if necessary, migrate storage for those keys so that it's associated with
|
// We will, if necessary, migrate storage for those keys so that it's associated with
|
||||||
// these scopes.
|
// these scopes.
|
||||||
const LEGACY_DERIVED_KEY_SCOPES = [SCOPE_OLD_SYNC];
|
const LEGACY_DERIVED_KEY_SCOPES = [SCOPE_APP_SYNC];
|
||||||
|
|
||||||
// These are scopes that we used to store, but are no longer using,
|
// These are scopes that we used to store, but are no longer using,
|
||||||
// and hence should be deleted from storage if present.
|
// and hence should be deleted from storage if present.
|
||||||
|
|
@ -474,23 +474,21 @@ export class FxAccountsKeys {
|
||||||
async _fetchScopedKeysMetadata(sessionToken) {
|
async _fetchScopedKeysMetadata(sessionToken) {
|
||||||
// Hard-coded list of scopes that we know about.
|
// Hard-coded list of scopes that we know about.
|
||||||
// This list will probably grow in future.
|
// This list will probably grow in future.
|
||||||
const scopes = [SCOPE_OLD_SYNC].join(" ");
|
const scopes = [SCOPE_APP_SYNC].join(" ");
|
||||||
const scopedKeysMetadata =
|
const scopedKeysMetadata =
|
||||||
await this._fxai.fxAccountsClient.getScopedKeyData(
|
await this._fxai.fxAccountsClient.getScopedKeyData(
|
||||||
sessionToken,
|
sessionToken,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
scopes
|
scopes
|
||||||
);
|
);
|
||||||
// The server may decline us permission for some of those scopes, although it really shouldn't.
|
// The server may decline us permission for some of those scopes, although it really shouldn't.
|
||||||
// We can live without them...except for the OLDSYNC scope, whose absence would be catastrophic.
|
// We can live without them...except for the sync scope, whose absence would be catastrophic.
|
||||||
if (!scopedKeysMetadata.hasOwnProperty(SCOPE_OLD_SYNC)) {
|
if (!scopedKeysMetadata.hasOwnProperty(SCOPE_APP_SYNC)) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"The FxA server did not grant Firefox the `oldsync` scope; this is most unexpected!" +
|
"The FxA server did not grant Firefox the sync scope; this is most unexpected!" +
|
||||||
` scopes were: ${Object.keys(scopedKeysMetadata)}`
|
` scopes were: ${Object.keys(scopedKeysMetadata)}`
|
||||||
);
|
);
|
||||||
throw new Error(
|
throw new Error("The FxA server did not grant Firefox the sync scope");
|
||||||
"The FxA server did not grant Firefox the `oldsync` scope"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return scopedKeysMetadata;
|
return scopedKeysMetadata;
|
||||||
}
|
}
|
||||||
|
|
@ -645,7 +643,7 @@ export class FxAccountsKeys {
|
||||||
*/
|
*/
|
||||||
async _deriveLegacyScopedKey(uid, kBbytes, scope, scopedKeyMetadata) {
|
async _deriveLegacyScopedKey(uid, kBbytes, scope, scopedKeyMetadata) {
|
||||||
let kid, key;
|
let kid, key;
|
||||||
if (scope == SCOPE_OLD_SYNC) {
|
if (scope == SCOPE_APP_SYNC) {
|
||||||
kid = await this._deriveXClientState(kBbytes);
|
kid = await this._deriveXClientState(kBbytes);
|
||||||
key = await this._deriveSyncKey(kBbytes);
|
key = await this._deriveSyncKey(kBbytes);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
});
|
});
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
SCOPE_PROFILE,
|
SCOPE_PROFILE,
|
||||||
SCOPE_PROFILE_WRITE,
|
SCOPE_PROFILE_WRITE,
|
||||||
SCOPE_OLD_SYNC,
|
SCOPE_APP_SYNC,
|
||||||
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
} from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
||||||
|
|
||||||
const VALID_SCOPES = [SCOPE_PROFILE, SCOPE_PROFILE_WRITE, SCOPE_OLD_SYNC];
|
const VALID_SCOPES = [SCOPE_PROFILE, SCOPE_PROFILE_WRITE, SCOPE_APP_SYNC];
|
||||||
|
|
||||||
export const ERROR_INVALID_SCOPES = "INVALID_SCOPES";
|
export const ERROR_INVALID_SCOPES = "INVALID_SCOPES";
|
||||||
export const ERROR_INVALID_STATE = "INVALID_STATE";
|
export const ERROR_INVALID_STATE = "INVALID_STATE";
|
||||||
|
|
@ -116,7 +116,7 @@ export class FxAccountsOAuth {
|
||||||
throw new Error(ERROR_INVALID_SCOPES);
|
throw new Error(ERROR_INVALID_SCOPES);
|
||||||
}
|
}
|
||||||
const queryParams = {
|
const queryParams = {
|
||||||
client_id: FX_OAUTH_CLIENT_ID,
|
client_id: OAUTH_CLIENT_ID,
|
||||||
action: "email",
|
action: "email",
|
||||||
response_type: "code",
|
response_type: "code",
|
||||||
access_type: "offline",
|
access_type: "offline",
|
||||||
|
|
@ -194,15 +194,15 @@ export class FxAccountsOAuth {
|
||||||
sessionTokenHex,
|
sessionTokenHex,
|
||||||
code,
|
code,
|
||||||
verifier,
|
verifier,
|
||||||
FX_OAUTH_CLIENT_ID
|
OAUTH_CLIENT_ID
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
requestedScopes.includes(SCOPE_OLD_SYNC) &&
|
requestedScopes.includes(SCOPE_APP_SYNC) &&
|
||||||
!scope.includes(SCOPE_OLD_SYNC)
|
!scope.includes(SCOPE_APP_SYNC)
|
||||||
) {
|
) {
|
||||||
throw new Error(ERROR_SYNC_SCOPE_NOT_GRANTED);
|
throw new Error(ERROR_SYNC_SCOPE_NOT_GRANTED);
|
||||||
}
|
}
|
||||||
if (scope.includes(SCOPE_OLD_SYNC) && !keys_jwe) {
|
if (scope.includes(SCOPE_APP_SYNC) && !keys_jwe) {
|
||||||
throw new Error(ERROR_NO_KEYS_JWE);
|
throw new Error(ERROR_NO_KEYS_JWE);
|
||||||
}
|
}
|
||||||
let scopedKeys;
|
let scopedKeys;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import {
|
||||||
COMMAND_PAIR_COMPLETE,
|
COMMAND_PAIR_COMPLETE,
|
||||||
COMMAND_PAIR_PREFERENCES,
|
COMMAND_PAIR_PREFERENCES,
|
||||||
COMMAND_FIREFOX_VIEW,
|
COMMAND_FIREFOX_VIEW,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
ON_PROFILE_CHANGE_NOTIFICATION,
|
ON_PROFILE_CHANGE_NOTIFICATION,
|
||||||
PREF_LAST_FXA_USER,
|
PREF_LAST_FXA_USER,
|
||||||
WEBCHANNEL_ID,
|
WEBCHANNEL_ID,
|
||||||
|
|
@ -647,7 +647,7 @@ FxAccountsWebChannelHelpers.prototype = {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
signedInUser,
|
signedInUser,
|
||||||
clientId: FX_OAUTH_CLIENT_ID,
|
clientId: OAUTH_CLIENT_ID,
|
||||||
capabilities,
|
capabilities,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@ const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||||
const { sinon } = ChromeUtils.importESModule(
|
const { sinon } = ChromeUtils.importESModule(
|
||||||
"resource://testing-common/Sinon.sys.mjs"
|
"resource://testing-common/Sinon.sys.mjs"
|
||||||
);
|
);
|
||||||
const { SCOPE_OLD_SYNC } = ChromeUtils.importESModule(
|
const { SCOPE_APP_SYNC, SCOPE_OLD_SYNC } = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Some mock key data, in both scoped-key and legacy field formats.
|
// Some mock key data, in both scoped-key and legacy field formats.
|
||||||
const MOCK_ACCOUNT_KEYS = {
|
const MOCK_ACCOUNT_KEYS = {
|
||||||
scopedKeys: {
|
scopedKeys: {
|
||||||
[SCOPE_OLD_SYNC]: {
|
[SCOPE_APP_SYNC]: {
|
||||||
kid: "1234567890123-u7u7u7u7u7u7u7u7u7u7uw",
|
kid: "1234567890123-u7u7u7u7u7u7u7u7u7u7uw",
|
||||||
k: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg",
|
k: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg",
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@ const { FxAccountsClient } = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/FxAccountsClient.sys.mjs"
|
"resource://gre/modules/FxAccountsClient.sys.mjs"
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
|
CLIENT_IS_THUNDERBIRD,
|
||||||
ERRNO_INVALID_AUTH_TOKEN,
|
ERRNO_INVALID_AUTH_TOKEN,
|
||||||
ERROR_NO_ACCOUNT,
|
ERROR_NO_ACCOUNT,
|
||||||
FX_OAUTH_CLIENT_ID,
|
OAUTH_CLIENT_ID,
|
||||||
ONLOGIN_NOTIFICATION,
|
ONLOGIN_NOTIFICATION,
|
||||||
ONLOGOUT_NOTIFICATION,
|
ONLOGOUT_NOTIFICATION,
|
||||||
ONVERIFIED_NOTIFICATION,
|
ONVERIFIED_NOTIFICATION,
|
||||||
|
|
@ -34,7 +35,7 @@ const MOCK_TOKEN_RESPONSE = {
|
||||||
access_token:
|
access_token:
|
||||||
"43793fdfffec22eb39fc3c44ed09193a6fde4c24e5d6a73f73178597b268af69",
|
"43793fdfffec22eb39fc3c44ed09193a6fde4c24e5d6a73f73178597b268af69",
|
||||||
token_type: "bearer",
|
token_type: "bearer",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
expires_in: 21600,
|
expires_in: 21600,
|
||||||
auth_at: 1589579900,
|
auth_at: 1589579900,
|
||||||
};
|
};
|
||||||
|
|
@ -152,13 +153,13 @@ function MockFxAccountsClient() {
|
||||||
|
|
||||||
this.getScopedKeyData = function (sessionToken, client_id, scopes) {
|
this.getScopedKeyData = function (sessionToken, client_id, scopes) {
|
||||||
Assert.ok(sessionToken);
|
Assert.ok(sessionToken);
|
||||||
Assert.equal(client_id, FX_OAUTH_CLIENT_ID);
|
Assert.equal(client_id, OAUTH_CLIENT_ID);
|
||||||
Assert.equal(scopes, SCOPE_OLD_SYNC);
|
Assert.equal(scopes, SCOPE_APP_SYNC);
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
do_timeout(50, () => {
|
do_timeout(50, () => {
|
||||||
resolve({
|
resolve({
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
keyRotationTimestamp: 1234567890123,
|
keyRotationTimestamp: 1234567890123,
|
||||||
|
|
@ -678,7 +679,7 @@ add_test(function test_getKeyForScope() {
|
||||||
Assert.equal(!!user2.keyFetchToken, true);
|
Assert.equal(!!user2.keyFetchToken, true);
|
||||||
Assert.equal(!!user2.unwrapBKey, true);
|
Assert.equal(!!user2.unwrapBKey, true);
|
||||||
|
|
||||||
fxa.keys.getKeyForScope(SCOPE_OLD_SYNC).then(() => {
|
fxa.keys.getKeyForScope(SCOPE_APP_SYNC).then(() => {
|
||||||
fxa._internal.getUserAccountData().then(user3 => {
|
fxa._internal.getUserAccountData().then(user3 => {
|
||||||
// Now we should have keys
|
// Now we should have keys
|
||||||
Assert.equal(fxa._internal.isUserEmailVerified(user3), true);
|
Assert.equal(fxa._internal.isUserEmailVerified(user3), true);
|
||||||
|
|
@ -712,7 +713,7 @@ add_task(
|
||||||
|
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
// getKeyForScope will run the migration
|
// getKeyForScope will run the migration
|
||||||
await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
let newUser = await fxa._internal.getUserAccountData();
|
let newUser = await fxa._internal.getUserAccountData();
|
||||||
// Then, the deprecated keys will be removed
|
// Then, the deprecated keys will be removed
|
||||||
Assert.strictEqual(newUser.kExtSync, undefined);
|
Assert.strictEqual(newUser.kExtSync, undefined);
|
||||||
|
|
@ -732,21 +733,21 @@ add_task(
|
||||||
user.scopedKeys = {
|
user.scopedKeys = {
|
||||||
...MOCK_ACCOUNT_KEYS.scopedKeys,
|
...MOCK_ACCOUNT_KEYS.scopedKeys,
|
||||||
[DEPRECATED_SCOPE_ECOSYSTEM_TELEMETRY]:
|
[DEPRECATED_SCOPE_ECOSYSTEM_TELEMETRY]:
|
||||||
MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
[DEPRECATED_SCOPE_WEBEXT_SYNC]:
|
[DEPRECATED_SCOPE_WEBEXT_SYNC]:
|
||||||
MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
[EXTRA_SCOPE]: MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
[EXTRA_SCOPE]: MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
};
|
};
|
||||||
|
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
let newUser = await fxa._internal.getUserAccountData();
|
let newUser = await fxa._internal.getUserAccountData();
|
||||||
// It should have removed the deprecated ecosystem_telemetry key,
|
// It should have removed the deprecated ecosystem_telemetry key,
|
||||||
// and the old kinto extension sync key
|
// and the old kinto extension sync key
|
||||||
// but left the other keys intact.
|
// but left the other keys intact.
|
||||||
const expectedScopedKeys = {
|
const expectedScopedKeys = {
|
||||||
...MOCK_ACCOUNT_KEYS.scopedKeys,
|
...MOCK_ACCOUNT_KEYS.scopedKeys,
|
||||||
[EXTRA_SCOPE]: MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
[EXTRA_SCOPE]: MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
};
|
};
|
||||||
Assert.deepEqual(newUser.scopedKeys, expectedScopedKeys);
|
Assert.deepEqual(newUser.scopedKeys, expectedScopedKeys);
|
||||||
Assert.equal(newUser.ecosystemUserId, null);
|
Assert.equal(newUser.ecosystemUserId, null);
|
||||||
|
|
@ -777,7 +778,7 @@ add_task(async function test_getKeyForScope_nonexistent_account() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await Assert.rejects(fxa.keys.getKeyForScope(SCOPE_OLD_SYNC), err => {
|
await Assert.rejects(fxa.keys.getKeyForScope(SCOPE_APP_SYNC), err => {
|
||||||
Assert.equal(err.message, ERROR_INVALID_ACCOUNT_STATE);
|
Assert.equal(err.message, ERROR_INVALID_ACCOUNT_STATE);
|
||||||
return true; // expected error
|
return true; // expected error
|
||||||
});
|
});
|
||||||
|
|
@ -808,7 +809,7 @@ add_task(async function test_getKeyForScope_invalid_token() {
|
||||||
Assert.notEqual(user.encryptedSendTabKeys, null);
|
Assert.notEqual(user.encryptedSendTabKeys, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
Assert.ok(false);
|
Assert.ok(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Assert.equal(err.code, 401);
|
Assert.equal(err.code, 401);
|
||||||
|
|
@ -831,8 +832,8 @@ add_task(async function test_getKeyForScope_oldsync() {
|
||||||
let client = fxa._internal.fxAccountsClient;
|
let client = fxa._internal.fxAccountsClient;
|
||||||
client.getScopedKeyData = () =>
|
client.getScopedKeyData = () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
keyRotationTimestamp: 1510726317123,
|
keyRotationTimestamp: 1510726317123,
|
||||||
|
|
@ -862,7 +863,7 @@ add_task(async function test_getKeyForScope_oldsync() {
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
|
|
||||||
// We derive, persist and return the sync key
|
// We derive, persist and return the sync key
|
||||||
const key = await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
const key = await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
|
|
||||||
// We verify the key returned matches what we would expect from the test vectors
|
// We verify the key returned matches what we would expect from the test vectors
|
||||||
// kb = 2ee722fdd8ccaa721bdeb2d1b76560efef705b04349d9357c3e592cf4906e075 (from test vectors)
|
// kb = 2ee722fdd8ccaa721bdeb2d1b76560efef705b04349d9357c3e592cf4906e075 (from test vectors)
|
||||||
|
|
@ -871,7 +872,7 @@ add_task(async function test_getKeyForScope_oldsync() {
|
||||||
//
|
//
|
||||||
// k can be verified by HKDF(kb, undefined, "identity.mozilla.com/picl/v1/oldsync", 64)
|
// k can be verified by HKDF(kb, undefined, "identity.mozilla.com/picl/v1/oldsync", 64)
|
||||||
Assert.deepEqual(key, {
|
Assert.deepEqual(key, {
|
||||||
scope: SCOPE_OLD_SYNC,
|
scope: SCOPE_APP_SYNC,
|
||||||
kid: "1510726317123-BAik7hEOdpGnPZnPBSdaTg",
|
kid: "1510726317123-BAik7hEOdpGnPZnPBSdaTg",
|
||||||
k: "fwM5VZu0Spf5XcFRZYX2zk6MrqZP7zvovCBcvuKwgYMif3hz98FHmIVa3qjKjrW0J244Zj-P5oWaOcQbvypmpw",
|
k: "fwM5VZu0Spf5XcFRZYX2zk6MrqZP7zvovCBcvuKwgYMif3hz98FHmIVa3qjKjrW0J244Zj-P5oWaOcQbvypmpw",
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
|
|
@ -888,10 +889,10 @@ add_task(async function test_getScopedKeys_cached_key() {
|
||||||
};
|
};
|
||||||
|
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
let key = await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
let key = await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
Assert.deepEqual(key, {
|
Assert.deepEqual(key, {
|
||||||
scope: SCOPE_OLD_SYNC,
|
scope: SCOPE_APP_SYNC,
|
||||||
...MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
...MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -934,8 +935,8 @@ add_task(async function test_getScopedKeys_misconfigured_fxa_server() {
|
||||||
};
|
};
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
await Assert.rejects(
|
await Assert.rejects(
|
||||||
fxa.keys.getKeyForScope(SCOPE_OLD_SYNC),
|
fxa.keys.getKeyForScope(SCOPE_APP_SYNC),
|
||||||
/The FxA server did not grant Firefox the `oldsync` scope/
|
/The FxA server did not grant Firefox the sync scope/
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -947,10 +948,10 @@ add_task(async function test_setScopedKeys() {
|
||||||
};
|
};
|
||||||
await fxa.setSignedInUser(user);
|
await fxa.setSignedInUser(user);
|
||||||
await fxa.keys.setScopedKeys(MOCK_ACCOUNT_KEYS.scopedKeys);
|
await fxa.keys.setScopedKeys(MOCK_ACCOUNT_KEYS.scopedKeys);
|
||||||
const key = await fxa.keys.getKeyForScope(SCOPE_OLD_SYNC);
|
const key = await fxa.keys.getKeyForScope(SCOPE_APP_SYNC);
|
||||||
Assert.deepEqual(key, {
|
Assert.deepEqual(key, {
|
||||||
scope: SCOPE_OLD_SYNC,
|
scope: SCOPE_APP_SYNC,
|
||||||
...MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_OLD_SYNC],
|
...MOCK_ACCOUNT_KEYS.scopedKeys[SCOPE_APP_SYNC],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1166,7 +1167,10 @@ add_test(async function test_getOAuthTokenWithSessionToken() {
|
||||||
) => {
|
) => {
|
||||||
oauthTokenCalled = true;
|
oauthTokenCalled = true;
|
||||||
Assert.equal(sessionTokenHex, "alice's session token");
|
Assert.equal(sessionTokenHex, "alice's session token");
|
||||||
Assert.equal(clientId, "5882386c6d801776");
|
Assert.equal(
|
||||||
|
clientId,
|
||||||
|
CLIENT_IS_THUNDERBIRD ? "a958794159236f76" : "5882386c6d801776"
|
||||||
|
);
|
||||||
Assert.equal(scope, "profile");
|
Assert.equal(scope, "profile");
|
||||||
Assert.equal(ttl, undefined);
|
Assert.equal(ttl, undefined);
|
||||||
return MOCK_TOKEN_RESPONSE;
|
return MOCK_TOKEN_RESPONSE;
|
||||||
|
|
@ -1445,7 +1449,7 @@ add_task(async function test_listAttachedOAuthClients() {
|
||||||
deviceId: "deadbeef",
|
deviceId: "deadbeef",
|
||||||
sessionTokenId: null,
|
sessionTokenId: null,
|
||||||
name: "Firefox Preview (no session token)",
|
name: "Firefox Preview (no session token)",
|
||||||
scope: ["profile", "https://identity.mozilla.com/apps/oldsync"],
|
scope: ["profile", SCOPE_APP_SYNC],
|
||||||
lastAccessTime: Date.now(),
|
lastAccessTime: Date.now(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const { FxAccounts } = ChromeUtils.importESModule(
|
||||||
|
|
||||||
add_task(
|
add_task(
|
||||||
async function test_non_https_remote_server_uri_with_requireHttps_false() {
|
async function test_non_https_remote_server_uri_with_requireHttps_false() {
|
||||||
|
Services.prefs.setStringPref("identity.fxaccounts.autoconfig.uri", "");
|
||||||
Services.prefs.setBoolPref("identity.fxaccounts.allowHttp", true);
|
Services.prefs.setBoolPref("identity.fxaccounts.allowHttp", true);
|
||||||
Services.prefs.setStringPref(
|
Services.prefs.setStringPref(
|
||||||
"identity.fxaccounts.remote.root",
|
"identity.fxaccounts.remote.root",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const { FxAccountsDevice } = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/FxAccountsDevice.sys.mjs"
|
"resource://gre/modules/FxAccountsDevice.sys.mjs"
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
|
CLIENT_IS_THUNDERBIRD,
|
||||||
ERRNO_DEVICE_SESSION_CONFLICT,
|
ERRNO_DEVICE_SESSION_CONFLICT,
|
||||||
ERRNO_TOO_MANY_CLIENT_REQUESTS,
|
ERRNO_TOO_MANY_CLIENT_REQUESTS,
|
||||||
ERRNO_UNKNOWN_DEVICE,
|
ERRNO_UNKNOWN_DEVICE,
|
||||||
|
|
@ -625,48 +626,50 @@ add_task(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
add_task(async function test_verification_updates_registration() {
|
add_task(
|
||||||
const deviceName = "foo";
|
{ skip_if: () => CLIENT_IS_THUNDERBIRD },
|
||||||
|
async function test_verification_updates_registration() {
|
||||||
|
const deviceName = "foo";
|
||||||
|
|
||||||
const credentials = getTestUser("baz");
|
const credentials = getTestUser("baz");
|
||||||
const fxa = await MockFxAccounts(credentials, {
|
const fxa = await MockFxAccounts(credentials, {
|
||||||
id: "device-id",
|
id: "device-id",
|
||||||
name: deviceName,
|
name: deviceName,
|
||||||
});
|
});
|
||||||
|
|
||||||
// We should already have a device registration, but without send-tab due to
|
// We should already have a device registration, but without send-tab due to
|
||||||
// our inability to fetch keys for an unverified users.
|
// our inability to fetch keys for an unverified users.
|
||||||
const state = fxa._internal.currentAccountState;
|
const state = fxa._internal.currentAccountState;
|
||||||
const { device } = await state.getUserAccountData();
|
const { device } = await state.getUserAccountData();
|
||||||
Assert.equal(device.registeredCommandsKeys.length, 0);
|
Assert.equal(device.registeredCommandsKeys.length, 0);
|
||||||
|
|
||||||
let updatePromise = new Promise(resolve => {
|
let updatePromise = new Promise(resolve => {
|
||||||
const old_registerOrUpdateDevice = fxa.device._registerOrUpdateDevice.bind(
|
const old_registerOrUpdateDevice =
|
||||||
fxa.device
|
fxa.device._registerOrUpdateDevice.bind(fxa.device);
|
||||||
);
|
fxa.device._registerOrUpdateDevice = async function (
|
||||||
fxa.device._registerOrUpdateDevice = async function (
|
currentState,
|
||||||
currentState,
|
signedInUser
|
||||||
signedInUser
|
) {
|
||||||
) {
|
await old_registerOrUpdateDevice(currentState, signedInUser);
|
||||||
await old_registerOrUpdateDevice(currentState, signedInUser);
|
fxa.device._registerOrUpdateDevice = old_registerOrUpdateDevice;
|
||||||
fxa.device._registerOrUpdateDevice = old_registerOrUpdateDevice;
|
resolve();
|
||||||
resolve();
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fxa._internal.checkEmailStatus = async function () {
|
||||||
|
credentials.verified = true;
|
||||||
|
return credentials;
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
|
||||||
fxa._internal.checkEmailStatus = async function () {
|
await updatePromise;
|
||||||
credentials.verified = true;
|
|
||||||
return credentials;
|
|
||||||
};
|
|
||||||
|
|
||||||
await updatePromise;
|
const { device: newDevice, encryptedSendTabKeys } =
|
||||||
|
await state.getUserAccountData();
|
||||||
const { device: newDevice, encryptedSendTabKeys } =
|
Assert.equal(newDevice.registeredCommandsKeys.length, 1);
|
||||||
await state.getUserAccountData();
|
Assert.notEqual(encryptedSendTabKeys, null);
|
||||||
Assert.equal(newDevice.registeredCommandsKeys.length, 1);
|
await fxa.signOut(true);
|
||||||
Assert.notEqual(encryptedSendTabKeys, null);
|
}
|
||||||
await fxa.signOut(true);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_devicelist_pushendpointexpired() {
|
add_task(async function test_devicelist_pushendpointexpired() {
|
||||||
const deviceId = "mydeviceid";
|
const deviceId = "mydeviceid";
|
||||||
|
|
|
||||||
|
|
@ -620,7 +620,7 @@ add_task(async function test_accessTokenWithSessionToken() {
|
||||||
access_token:
|
access_token:
|
||||||
"43793fdfffec22eb39fc3c44ed09193a6fde4c24e5d6a73f73178597b268af69",
|
"43793fdfffec22eb39fc3c44ed09193a6fde4c24e5d6a73f73178597b268af69",
|
||||||
token_type: "bearer",
|
token_type: "bearer",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
expires_in: 21600,
|
expires_in: 21600,
|
||||||
auth_at: 1589579900,
|
auth_at: 1589579900,
|
||||||
});
|
});
|
||||||
|
|
@ -634,7 +634,7 @@ add_task(async function test_accessTokenWithSessionToken() {
|
||||||
let sessionTokenHex =
|
let sessionTokenHex =
|
||||||
"0599c36ebb5cad6feb9285b9547b65342b5434d55c07b33bffd4307ab8f82dc4";
|
"0599c36ebb5cad6feb9285b9547b65342b5434d55c07b33bffd4307ab8f82dc4";
|
||||||
let clientId = "5882386c6d801776";
|
let clientId = "5882386c6d801776";
|
||||||
let scope = "https://identity.mozilla.com/apps/oldsync";
|
let scope = SCOPE_APP_SYNC;
|
||||||
let ttl = 100;
|
let ttl = 100;
|
||||||
let result = await client.accessTokenWithSessionToken(
|
let result = await client.accessTokenWithSessionToken(
|
||||||
sessionTokenHex,
|
sessionTokenHex,
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,12 @@ const { getFxAccountsSingleton } = ChromeUtils.importESModule(
|
||||||
);
|
);
|
||||||
const fxAccounts = getFxAccountsSingleton();
|
const fxAccounts = getFxAccountsSingleton();
|
||||||
|
|
||||||
const { ON_NEW_DEVICE_ID, PREF_ACCOUNT_ROOT } = ChromeUtils.importESModule(
|
const { CLIENT_IS_THUNDERBIRD, ON_NEW_DEVICE_ID, PREF_ACCOUNT_ROOT } =
|
||||||
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
ChromeUtils.importESModule("resource://gre/modules/FxAccountsCommon.sys.mjs");
|
||||||
|
const { TestUtils } = ChromeUtils.importESModule(
|
||||||
|
"resource://testing-common/TestUtils.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
function promiseObserved(topic) {
|
|
||||||
return new Promise(res => {
|
|
||||||
Services.obs.addObserver(res, topic);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_("Misc tests for FxAccounts.device");
|
_("Misc tests for FxAccounts.device");
|
||||||
|
|
||||||
fxAccounts.device._checkRemoteCommandsUpdateNeeded = async () => false;
|
fxAccounts.device._checkRemoteCommandsUpdateNeeded = async () => false;
|
||||||
|
|
@ -90,9 +86,16 @@ add_task(async function test_reset() {
|
||||||
.callsFake(async () => {
|
.callsFake(async () => {
|
||||||
return { id: "foo" };
|
return { id: "foo" };
|
||||||
});
|
});
|
||||||
|
const notifyPromise = TestUtils.topicObserved(ON_NEW_DEVICE_ID);
|
||||||
await fxAccounts._internal.setSignedInUser(credentials);
|
await fxAccounts._internal.setSignedInUser(credentials);
|
||||||
// wait for device registration to complete.
|
await notifyPromise;
|
||||||
await promiseObserved(ON_NEW_DEVICE_ID);
|
if (!CLIENT_IS_THUNDERBIRD) {
|
||||||
|
// Firefox fires the notification twice - once during `setSignedInUser` and
|
||||||
|
// once after it returns. It's the second notification we need to wait for.
|
||||||
|
// Thunderbird, OTOH, fires only once during `setSignedInUser` and that's
|
||||||
|
// what we need to wait for.
|
||||||
|
await TestUtils.topicObserved(ON_NEW_DEVICE_ID);
|
||||||
|
}
|
||||||
ok(!Services.prefs.prefHasUserValue(testPref));
|
ok(!Services.prefs.prefHasUserValue(testPref));
|
||||||
// signing the user out should reset the name pref.
|
// signing the user out should reset the name pref.
|
||||||
const namePref = PREF_ACCOUNT_ROOT + "device.name";
|
const namePref = PREF_ACCOUNT_ROOT + "device.name";
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ add_task(async function test_derive_legacy_sync_key_test_vector() {
|
||||||
const uid = "aeaa1725c7a24ff983c6295725d5fc9b";
|
const uid = "aeaa1725c7a24ff983c6295725d5fc9b";
|
||||||
const kB = "eaf9570b7219a4187d3d6bf3cec2770c2e0719b7cc0dfbb38243d6f1881675e9";
|
const kB = "eaf9570b7219a4187d3d6bf3cec2770c2e0719b7cc0dfbb38243d6f1881675e9";
|
||||||
const scopedKeyMetadata = {
|
const scopedKeyMetadata = {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationTimestamp: 1510726317123,
|
keyRotationTimestamp: 1510726317123,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|
@ -49,7 +49,7 @@ add_task(async function test_derive_legacy_sync_key_test_vector() {
|
||||||
const scopedKey = await keys._deriveLegacyScopedKey(
|
const scopedKey = await keys._deriveLegacyScopedKey(
|
||||||
uid,
|
uid,
|
||||||
CommonUtils.hexToBytes(kB),
|
CommonUtils.hexToBytes(kB),
|
||||||
"https://identity.mozilla.com/apps/oldsync",
|
SCOPE_APP_SYNC,
|
||||||
scopedKeyMetadata
|
scopedKeyMetadata
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -71,8 +71,8 @@ add_task(async function test_derive_multiple_keys_at_once() {
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"517d478cb4f994aa69930416648a416fdaa1762c5abf401a2acf11a0f185e98d",
|
"517d478cb4f994aa69930416648a416fdaa1762c5abf401a2acf11a0f185e98d",
|
||||||
},
|
},
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationTimestamp: 1510726318123,
|
keyRotationTimestamp: 1510726318123,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|
@ -91,7 +91,7 @@ add_task(async function test_derive_multiple_keys_at_once() {
|
||||||
kid: "1510726317-tUkxiR1lTlFrTgkF0tJidA",
|
kid: "1510726317-tUkxiR1lTlFrTgkF0tJidA",
|
||||||
k: "TYK6Hmj86PfKiqsk9DZmX61nxk9VsExGrwo94HP-0wU",
|
k: "TYK6Hmj86PfKiqsk9DZmX61nxk9VsExGrwo94HP-0wU",
|
||||||
},
|
},
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
|
|
@ -103,17 +103,17 @@ add_task(function test_check_valid_scoped_keys() {
|
||||||
const keys = new FxAccountsKeys(null);
|
const keys = new FxAccountsKeys(null);
|
||||||
add_task(function test_missing_key_data() {
|
add_task(function test_missing_key_data() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
});
|
});
|
||||||
add_task(function test_unexpected_scope() {
|
add_task(function test_unexpected_scope() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
|
|
@ -124,59 +124,59 @@ add_task(function test_check_valid_scoped_keys() {
|
||||||
});
|
});
|
||||||
add_task(function test_not_oct_key() {
|
add_task(function test_not_oct_key() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
// Should be "oct"!
|
// Should be "oct"!
|
||||||
kty: "EC",
|
kty: "EC",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
});
|
});
|
||||||
add_task(function test_invalid_kid_not_timestamp() {
|
add_task(function test_invalid_kid_not_timestamp() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
// Does not have the timestamp!
|
// Does not have the timestamp!
|
||||||
kid: "IqQv4onc7VcVE1kTQkyyOw",
|
kid: "IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
});
|
});
|
||||||
add_task(function test_invalid_kid_not_valid_timestamp() {
|
add_task(function test_invalid_kid_not_valid_timestamp() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
// foo is not a valid timestamp!
|
// foo is not a valid timestamp!
|
||||||
kid: "foo-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "foo-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
});
|
});
|
||||||
add_task(function test_invalid_kid_not_b64_fingerprint() {
|
add_task(function test_invalid_kid_not_b64_fingerprint() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
// fingerprint not a valid base64 encoded string.
|
// fingerprint not a valid base64 encoded string.
|
||||||
kid: "1510726318123-notvalidb64][",
|
kid: "1510726318123-notvalidb64][",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
});
|
});
|
||||||
add_task(function test_invalid_k_not_base64() {
|
add_task(function test_invalid_k_not_base64() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "notavalidb64[]",
|
k: "notavalidb64[]",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
|
|
@ -192,11 +192,11 @@ add_task(function test_check_valid_scoped_keys() {
|
||||||
scope: "https://identity.mozilla.com/apps/otherscope",
|
scope: "https://identity.mozilla.com/apps/otherscope",
|
||||||
},
|
},
|
||||||
// Invalid
|
// Invalid
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "notavalidb64[]",
|
k: "notavalidb64[]",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
Assert.equal(keys.validScopedKeys(scopedKeys), false);
|
||||||
|
|
@ -204,11 +204,11 @@ add_task(function test_check_valid_scoped_keys() {
|
||||||
|
|
||||||
add_task(function test_valid_scopedkeys() {
|
add_task(function test_valid_scopedkeys() {
|
||||||
const scopedKeys = {
|
const scopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
"https://identity.mozilla.com/apps/otherscope": {
|
"https://identity.mozilla.com/apps/otherscope": {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const {
|
||||||
"resource://gre/modules/FxAccountsOAuth.sys.mjs"
|
"resource://gre/modules/FxAccountsOAuth.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
const { SCOPE_PROFILE, FX_OAUTH_CLIENT_ID } = ChromeUtils.importESModule(
|
const { SCOPE_PROFILE, OAUTH_CLIENT_ID } = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -45,15 +45,15 @@ add_task(function test_begin_oauth_flow() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
add_task(async function test_begin_oauth_flow_ok() {
|
add_task(async function test_begin_oauth_flow_ok() {
|
||||||
const scopes = [SCOPE_PROFILE, SCOPE_OLD_SYNC];
|
const scopes = [SCOPE_PROFILE, SCOPE_APP_SYNC];
|
||||||
const queryParams = await oauth.beginOAuthFlow(scopes);
|
const queryParams = await oauth.beginOAuthFlow(scopes);
|
||||||
|
|
||||||
// First verify default query parameters
|
// First verify default query parameters
|
||||||
Assert.equal(queryParams.client_id, FX_OAUTH_CLIENT_ID);
|
Assert.equal(queryParams.client_id, OAUTH_CLIENT_ID);
|
||||||
Assert.equal(queryParams.action, "email");
|
Assert.equal(queryParams.action, "email");
|
||||||
Assert.equal(queryParams.response_type, "code");
|
Assert.equal(queryParams.response_type, "code");
|
||||||
Assert.equal(queryParams.access_type, "offline");
|
Assert.equal(queryParams.access_type, "offline");
|
||||||
Assert.equal(queryParams.scope, [SCOPE_PROFILE, SCOPE_OLD_SYNC].join(" "));
|
Assert.equal(queryParams.scope, [SCOPE_PROFILE, SCOPE_APP_SYNC].join(" "));
|
||||||
|
|
||||||
// Then, we verify that the state is a valid Base64 value
|
// Then, we verify that the state is a valid Base64 value
|
||||||
const state = queryParams.state;
|
const state = queryParams.state;
|
||||||
|
|
@ -120,7 +120,7 @@ add_task(function test_complete_oauth_flow() {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const oauth = new FxAccountsOAuth(fxaClient);
|
const oauth = new FxAccountsOAuth(fxaClient);
|
||||||
const scopes = [SCOPE_PROFILE, SCOPE_OLD_SYNC];
|
const scopes = [SCOPE_PROFILE, SCOPE_APP_SYNC];
|
||||||
const sessionToken = "01abcef12";
|
const sessionToken = "01abcef12";
|
||||||
const queryParams = await oauth.beginOAuthFlow(scopes);
|
const queryParams = await oauth.beginOAuthFlow(scopes);
|
||||||
try {
|
try {
|
||||||
|
|
@ -133,7 +133,7 @@ add_task(function test_complete_oauth_flow() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
add_task(async function test_jwe_not_returned() {
|
add_task(async function test_jwe_not_returned() {
|
||||||
const scopes = [SCOPE_PROFILE, SCOPE_OLD_SYNC];
|
const scopes = [SCOPE_PROFILE, SCOPE_APP_SYNC];
|
||||||
const fxaClient = {
|
const fxaClient = {
|
||||||
oauthToken: () =>
|
oauthToken: () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
|
@ -157,15 +157,15 @@ add_task(function test_complete_oauth_flow() {
|
||||||
add_task(async function test_complete_oauth_ok() {
|
add_task(async function test_complete_oauth_ok() {
|
||||||
// First, we initialize some fake values we would typically get
|
// First, we initialize some fake values we would typically get
|
||||||
// from outside our system
|
// from outside our system
|
||||||
const scopes = [SCOPE_PROFILE, SCOPE_OLD_SYNC];
|
const scopes = [SCOPE_PROFILE, SCOPE_APP_SYNC];
|
||||||
const oauthCode = "fake oauth code";
|
const oauthCode = "fake oauth code";
|
||||||
const sessionToken = "01abcef12";
|
const sessionToken = "01abcef12";
|
||||||
const plainTextScopedKeys = {
|
const plainTextScopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const fakeAccessToken = "fake access token";
|
const fakeAccessToken = "fake access token";
|
||||||
|
|
@ -280,16 +280,16 @@ add_task(function test_complete_oauth_flow() {
|
||||||
add_task(async function test_complete_oauth_invalid_scoped_keys() {
|
add_task(async function test_complete_oauth_invalid_scoped_keys() {
|
||||||
// First, we initialize some fake values we would typically get
|
// First, we initialize some fake values we would typically get
|
||||||
// from outside our system
|
// from outside our system
|
||||||
const scopes = [SCOPE_PROFILE, SCOPE_OLD_SYNC];
|
const scopes = [SCOPE_PROFILE, SCOPE_APP_SYNC];
|
||||||
const oauthCode = "fake oauth code";
|
const oauthCode = "fake oauth code";
|
||||||
const sessionToken = "01abcef12";
|
const sessionToken = "01abcef12";
|
||||||
const invalidScopedKeys = {
|
const invalidScopedKeys = {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
// ====== This is an invalid key type! Should be "oct", so we will raise an error once we realize
|
// ====== This is an invalid key type! Should be "oct", so we will raise an error once we realize
|
||||||
kty: "EC",
|
kty: "EC",
|
||||||
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
kid: "1510726318123-IqQv4onc7VcVE1kTQkyyOw",
|
||||||
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
k: "DW_ll5GwX6SJ5GPqJVAuMUP2t6kDqhUulc2cbt26xbTcaKGQl-9l29FHAQ7kUiJETma4s9fIpEHrt909zgFang",
|
||||||
scope: "https://identity.mozilla.com/apps/oldsync",
|
scope: SCOPE_APP_SYNC,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const fakeAccessToken = "fake access token";
|
const fakeAccessToken = "fake access token";
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ const fxAccounts = {
|
||||||
fxAccountsClient: {
|
fxAccountsClient: {
|
||||||
async getScopedKeyData() {
|
async getScopedKeyData() {
|
||||||
return {
|
return {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationTimestamp: 12345678,
|
keyRotationTimestamp: 12345678,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -151,7 +151,7 @@ add_task(async function testFullFlow() {
|
||||||
new TextEncoder().encode(JSON.stringify(epk.publicJWK)),
|
new TextEncoder().encode(JSON.stringify(epk.publicJWK)),
|
||||||
{ pad: false }
|
{ pad: false }
|
||||||
),
|
),
|
||||||
scope: "profile https://identity.mozilla.com/apps/oldsync",
|
scope: `profile ${SCOPE_APP_SYNC}`,
|
||||||
code_challenge: "chal",
|
code_challenge: "chal",
|
||||||
code_challenge_method: "S256",
|
code_challenge_method: "S256",
|
||||||
},
|
},
|
||||||
|
|
@ -169,7 +169,9 @@ add_task(async function testFullFlow() {
|
||||||
const oauthUrl = await promiseSwitchToWebContent;
|
const oauthUrl = await promiseSwitchToWebContent;
|
||||||
Assert.equal(
|
Assert.equal(
|
||||||
oauthUrl,
|
oauthUrl,
|
||||||
`${OAUTH_URI}?client_id=client_id_1&scope=profile+https%3A%2F%2Fidentity.mozilla.com%2Fapps%2Foldsync&email=foo%40bar.com&uid=abcd&channel_id=${CHANNEL_ID}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob%3Apair-auth-webchannel`
|
`${OAUTH_URI}?client_id=client_id_1&scope=profile+${encodeURIComponent(
|
||||||
|
SCOPE_APP_SYNC
|
||||||
|
)}&email=foo%40bar.com&uid=abcd&channel_id=${CHANNEL_ID}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob%3Apair-auth-webchannel`
|
||||||
);
|
);
|
||||||
|
|
||||||
let pairSuppMetadata = await simulateIncomingWebChannel(
|
let pairSuppMetadata = await simulateIncomingWebChannel(
|
||||||
|
|
@ -199,7 +201,7 @@ add_task(async function testFullFlow() {
|
||||||
const generateArgs = generateJWE.firstCall.args;
|
const generateArgs = generateJWE.firstCall.args;
|
||||||
Assert.deepEqual(generateArgs[0], epk.publicJWK);
|
Assert.deepEqual(generateArgs[0], epk.publicJWK);
|
||||||
Assert.deepEqual(JSON.parse(new TextDecoder().decode(generateArgs[1])), {
|
Assert.deepEqual(JSON.parse(new TextDecoder().decode(generateArgs[1])), {
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
kid: "123456",
|
kid: "123456",
|
||||||
k: KSYNC,
|
k: KSYNC,
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
|
|
@ -217,10 +219,7 @@ add_task(async function testFullFlow() {
|
||||||
Assert.equal(oauthCodeArgs.client_id, "client_id_1");
|
Assert.equal(oauthCodeArgs.client_id, "client_id_1");
|
||||||
Assert.equal(oauthCodeArgs.access_type, "offline");
|
Assert.equal(oauthCodeArgs.access_type, "offline");
|
||||||
Assert.equal(oauthCodeArgs.state, "mystate");
|
Assert.equal(oauthCodeArgs.state, "mystate");
|
||||||
Assert.equal(
|
Assert.equal(oauthCodeArgs.scope, `profile ${SCOPE_APP_SYNC}`);
|
||||||
oauthCodeArgs.scope,
|
|
||||||
"profile https://identity.mozilla.com/apps/oldsync"
|
|
||||||
);
|
|
||||||
Assert.equal(oauthCodeArgs.code_challenge, "chal");
|
Assert.equal(oauthCodeArgs.code_challenge, "chal");
|
||||||
Assert.equal(oauthCodeArgs.code_challenge_method, "S256");
|
Assert.equal(oauthCodeArgs.code_challenge_method, "S256");
|
||||||
|
|
||||||
|
|
@ -318,7 +317,7 @@ add_task(async function testPairingChannelFailure() {
|
||||||
data: {
|
data: {
|
||||||
client_id: "client_id_1",
|
client_id: "client_id_1",
|
||||||
state: "mystate",
|
state: "mystate",
|
||||||
scope: "profile https://identity.mozilla.com/apps/oldsync",
|
scope: `profile ${SCOPE_APP_SYNC}`,
|
||||||
code_challenge: "chal",
|
code_challenge: "chal",
|
||||||
code_challenge_method: "S256",
|
code_challenge_method: "S256",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,14 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { ON_PROFILE_CHANGE_NOTIFICATION, WEBCHANNEL_ID, log } =
|
const {
|
||||||
ChromeUtils.importESModule("resource://gre/modules/FxAccountsCommon.sys.mjs");
|
CLIENT_IS_THUNDERBIRD,
|
||||||
|
ON_PROFILE_CHANGE_NOTIFICATION,
|
||||||
|
WEBCHANNEL_ID,
|
||||||
|
log,
|
||||||
|
} = ChromeUtils.importESModule(
|
||||||
|
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
||||||
|
);
|
||||||
const { CryptoUtils } = ChromeUtils.importESModule(
|
const { CryptoUtils } = ChromeUtils.importESModule(
|
||||||
"resource://services-crypto/utils.sys.mjs"
|
"resource://services-crypto/utils.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
@ -684,6 +690,7 @@ add_task(async function test_helpers_login_with_customize_sync() {
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(
|
add_task(
|
||||||
|
{ skip_if: () => CLIENT_IS_THUNDERBIRD },
|
||||||
async function test_helpers_login_with_customize_sync_and_declined_engines() {
|
async function test_helpers_login_with_customize_sync_and_declined_engines() {
|
||||||
let configured = false;
|
let configured = false;
|
||||||
let helpers = new FxAccountsWebChannelHelpers({
|
let helpers = new FxAccountsWebChannelHelpers({
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ head = "head.js ../../../common/tests/unit/head_helpers.js ../../../common/tests
|
||||||
firefox-appdir = "browser"
|
firefox-appdir = "browser"
|
||||||
skip-if = [
|
skip-if = [
|
||||||
"os == 'android'",
|
"os == 'android'",
|
||||||
"appname == 'thunderbird'",
|
"appname == 'thunderbird' && !nightly_build"
|
||||||
]
|
]
|
||||||
support-files = [
|
support-files = [
|
||||||
"!/services/common/tests/unit/head_helpers.js",
|
"!/services/common/tests/unit/head_helpers.js",
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import {
|
||||||
} from "resource://gre/modules/FxAccounts.sys.mjs";
|
} from "resource://gre/modules/FxAccounts.sys.mjs";
|
||||||
import { FxAccountsClient } from "resource://gre/modules/FxAccountsClient.sys.mjs";
|
import { FxAccountsClient } from "resource://gre/modules/FxAccountsClient.sys.mjs";
|
||||||
|
|
||||||
import { SCOPE_OLD_SYNC } from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
import { SCOPE_APP_SYNC } from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
||||||
|
|
||||||
// A mock "storage manager" for FxAccounts that doesn't actually write anywhere.
|
// A mock "storage manager" for FxAccounts that doesn't actually write anywhere.
|
||||||
export function MockFxaStorageManager() {}
|
export function MockFxaStorageManager() {}
|
||||||
|
|
@ -119,7 +119,7 @@ export var makeIdentityConfig = function (overrides) {
|
||||||
user: {
|
user: {
|
||||||
email: "foo",
|
email: "foo",
|
||||||
scopedKeys: {
|
scopedKeys: {
|
||||||
[SCOPE_OLD_SYNC]: {
|
[SCOPE_APP_SYNC]: {
|
||||||
kid: "1234567890123-u7u7u7u7u7u7u7u7u7u7uw",
|
kid: "1234567890123-u7u7u7u7u7u7u7u7u7u7uw",
|
||||||
k: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg",
|
k: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg",
|
||||||
kty: "oct",
|
kty: "oct",
|
||||||
|
|
@ -174,8 +174,8 @@ export var makeFxAccountsInternalMock = function (config) {
|
||||||
keys: {
|
keys: {
|
||||||
getScopedKeys: () =>
|
getScopedKeys: () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
keyRotationTimestamp: 1510726317123,
|
keyRotationTimestamp: 1510726317123,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
// FxAccountsCommon.js doesn't use a "namespace", so create one here.
|
// FxAccountsCommon.js doesn't use a "namespace", so create one here.
|
||||||
import * as fxAccountsCommon from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
import * as fxAccountsCommon from "resource://gre/modules/FxAccountsCommon.sys.mjs";
|
||||||
|
|
||||||
const SCOPE_OLD_SYNC = fxAccountsCommon.SCOPE_OLD_SYNC;
|
const SCOPE_APP_SYNC = fxAccountsCommon.SCOPE_APP_SYNC;
|
||||||
|
|
||||||
const OBSERVER_TOPICS = [
|
const OBSERVER_TOPICS = [
|
||||||
fxAccountsCommon.ONLOGIN_NOTIFICATION,
|
fxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||||
|
|
@ -305,7 +305,7 @@ SyncAuthManager.prototype = {
|
||||||
lazy.log.debug("unlockAndVerifyAuthState has an unverified user");
|
lazy.log.debug("unlockAndVerifyAuthState has an unverified user");
|
||||||
return LOGIN_FAILED_LOGIN_REJECTED;
|
return LOGIN_FAILED_LOGIN_REJECTED;
|
||||||
}
|
}
|
||||||
if (await fxa.keys.canGetKeyForScope(SCOPE_OLD_SYNC)) {
|
if (await fxa.keys.canGetKeyForScope(SCOPE_APP_SYNC)) {
|
||||||
lazy.log.debug(
|
lazy.log.debug(
|
||||||
"unlockAndVerifyAuthState already has (or can fetch) sync keys"
|
"unlockAndVerifyAuthState already has (or can fetch) sync keys"
|
||||||
);
|
);
|
||||||
|
|
@ -323,7 +323,7 @@ SyncAuthManager.prototype = {
|
||||||
// without unlocking the MP or cleared the saved logins, so we've now
|
// without unlocking the MP or cleared the saved logins, so we've now
|
||||||
// lost them - the user will need to reauth before continuing.
|
// lost them - the user will need to reauth before continuing.
|
||||||
let result;
|
let result;
|
||||||
if (await fxa.keys.canGetKeyForScope(SCOPE_OLD_SYNC)) {
|
if (await fxa.keys.canGetKeyForScope(SCOPE_APP_SYNC)) {
|
||||||
result = STATUS_OK;
|
result = STATUS_OK;
|
||||||
} else {
|
} else {
|
||||||
result = LOGIN_FAILED_LOGIN_REJECTED;
|
result = LOGIN_FAILED_LOGIN_REJECTED;
|
||||||
|
|
@ -377,7 +377,7 @@ SyncAuthManager.prototype = {
|
||||||
// We need keys for things to work. If we don't have them, just
|
// We need keys for things to work. If we don't have them, just
|
||||||
// return null for the token - sync calling unlockAndVerifyAuthState()
|
// return null for the token - sync calling unlockAndVerifyAuthState()
|
||||||
// before actually syncing will setup the error states if necessary.
|
// before actually syncing will setup the error states if necessary.
|
||||||
if (!(await fxa.keys.canGetKeyForScope(SCOPE_OLD_SYNC))) {
|
if (!(await fxa.keys.canGetKeyForScope(SCOPE_APP_SYNC))) {
|
||||||
this._log.info(
|
this._log.info(
|
||||||
"Unable to fetch keys (master-password locked?), so aborting token fetch"
|
"Unable to fetch keys (master-password locked?), so aborting token fetch"
|
||||||
);
|
);
|
||||||
|
|
@ -400,7 +400,7 @@ SyncAuthManager.prototype = {
|
||||||
try {
|
try {
|
||||||
this._log.info("Getting sync key");
|
this._log.info("Getting sync key");
|
||||||
const tokenAndKey = await fxa.getOAuthTokenAndKey({
|
const tokenAndKey = await fxa.getOAuthTokenAndKey({
|
||||||
scope: SCOPE_OLD_SYNC,
|
scope: SCOPE_APP_SYNC,
|
||||||
ttl,
|
ttl,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -419,7 +419,7 @@ SyncAuthManager.prototype = {
|
||||||
"Token server returned 401, retrying token fetch with fresh credentials"
|
"Token server returned 401, retrying token fetch with fresh credentials"
|
||||||
);
|
);
|
||||||
const tokenAndKey = await fxa.getOAuthTokenAndKey({
|
const tokenAndKey = await fxa.getOAuthTokenAndKey({
|
||||||
scope: SCOPE_OLD_SYNC,
|
scope: SCOPE_APP_SYNC,
|
||||||
ttl,
|
ttl,
|
||||||
});
|
});
|
||||||
token = await getToken(tokenAndKey.key, tokenAndKey.token);
|
token = await getToken(tokenAndKey.key, tokenAndKey.token);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const {
|
||||||
ERRNO_INVALID_AUTH_TOKEN,
|
ERRNO_INVALID_AUTH_TOKEN,
|
||||||
ONLOGIN_NOTIFICATION,
|
ONLOGIN_NOTIFICATION,
|
||||||
ONVERIFIED_NOTIFICATION,
|
ONVERIFIED_NOTIFICATION,
|
||||||
|
SCOPE_APP_SYNC,
|
||||||
} = ChromeUtils.importESModule(
|
} = ChromeUtils.importESModule(
|
||||||
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
||||||
);
|
);
|
||||||
|
|
@ -66,8 +67,8 @@ MockFxAccountsClient.prototype = {
|
||||||
},
|
},
|
||||||
getScopedKeyData() {
|
getScopedKeyData() {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"https://identity.mozilla.com/apps/oldsync": {
|
[SCOPE_APP_SYNC]: {
|
||||||
identifier: "https://identity.mozilla.com/apps/oldsync",
|
identifier: SCOPE_APP_SYNC,
|
||||||
keyRotationSecret:
|
keyRotationSecret:
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
keyRotationTimestamp: 1234567890123,
|
keyRotationTimestamp: 1234567890123,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue