diff --git a/browser/base/content/aboutaccounts/aboutaccounts.js b/browser/base/content/aboutaccounts/aboutaccounts.js index f43f0fc831bd..7dca88dc8c2b 100644 --- a/browser/base/content/aboutaccounts/aboutaccounts.js +++ b/browser/base/content/aboutaccounts/aboutaccounts.js @@ -16,8 +16,6 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon); // for master-password utilities Cu.import("resource://services-sync/util.js"); -const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash"; - const ACTION_URL_PARAM = "action"; const OBSERVER_TOPICS = [ @@ -29,65 +27,6 @@ function log(msg) { // dump("FXA: " + msg + "\n"); } -function getPreviousAccountNameHash() { - try { - return Services.prefs.getStringPref(PREF_LAST_FXA_USER); - } catch (_) { - return ""; - } -} - -function setPreviousAccountNameHash(acctName) { - Services.prefs.setStringPref(PREF_LAST_FXA_USER, sha256(acctName)); -} - -function needRelinkWarning(acctName) { - let prevAcctHash = getPreviousAccountNameHash(); - return prevAcctHash && prevAcctHash != sha256(acctName); -} - -// Given a string, returns the SHA265 hash in base64 -function sha256(str) { - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Data is an array of bytes. - let data = converter.convertToByteArray(str, {}); - let hasher = Cc["@mozilla.org/security/hash;1"] - .createInstance(Ci.nsICryptoHash); - hasher.init(hasher.SHA256); - hasher.update(data, data.length); - - return hasher.finish(true); -} - -function promptForRelink(acctName) { - let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); - let continueLabel = sb.GetStringFromName("continue.label"); - let title = sb.GetStringFromName("relinkVerify.title"); - let description = sb.formatStringFromName("relinkVerify.description", - [acctName], 1); - let body = sb.GetStringFromName("relinkVerify.heading") + - "\n\n" + description; - let ps = Services.prompt; - let buttonFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) + - (ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) + - ps.BUTTON_POS_1_DEFAULT; - let pressed = Services.prompt.confirmEx(window, title, body, buttonFlags, - continueLabel, null, null, null, - {}); - return pressed == 0; // 0 is the "continue" button -} - -// If the last fxa account used for sync isn't this account, we display -// a modal dialog checking they really really want to do this... -// (This is sync-specific, so ideally would be in sync's identity module, -// but it's a little more seamless to do here, and sync is currently the -// only fxa consumer, so... -function shouldAllowRelink(acctName) { - return !needRelinkWarning(acctName) || promptForRelink(acctName); -} - function updateDisplayedEmail(user) { let emailDiv = document.getElementById("email"); if (emailDiv && user) { @@ -112,7 +51,6 @@ var wrapper = { docShell.addProgressListener(this.iframeListener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT | Ci.nsIWebProgress.NOTIFY_LOCATION); - iframe.addEventListener("load", this); // Ideally we'd just merge urlParams with new URL(url).searchParams, but our // URLSearchParams implementation doesn't support iteration (bug 1085284). @@ -168,133 +106,7 @@ var wrapper = { setErrorPage("networkError"); } }, - }, - - handleEvent(evt) { - switch (evt.type) { - case "load": - this.iframe.contentWindow.addEventListener("FirefoxAccountsCommand", this); - this.iframe.removeEventListener("load", this); - break; - case "FirefoxAccountsCommand": - this.handleRemoteCommand(evt); - break; - } - }, - - /** - * onLogin handler receives user credentials from the jelly after a - * sucessful login and stores it in the fxaccounts service - * - * @param accountData the user's account data and credentials - */ - onLogin(accountData) { - log("Received: 'login'. Data:" + JSON.stringify(accountData)); - - // We don't act on customizeSync anymore, it used to open a dialog inside - // the browser to selecte the engines to sync but we do it on the web now. - delete accountData.customizeSync; - // sessionTokenContext is erroneously sent by the content server. - // https://github.com/mozilla/fxa-content-server/issues/2766 - // To avoid having the FxA storage manager not knowing what to do with - // it we delete it here. - delete accountData.sessionTokenContext; - - // We need to confirm a relink - see shouldAllowRelink for more - let newAccountEmail = accountData.email; - // The hosted code may have already checked for the relink situation - // by sending the can_link_account command. If it did, then - // it will indicate we don't need to ask twice. - if (!accountData.verifiedCanLinkAccount && !shouldAllowRelink(newAccountEmail)) { - // we need to tell the page we successfully received the message, but - // then bail without telling fxAccounts - this.injectData("message", { status: "login" }); - // after a successful login we return to preferences - openPrefs(); - return; - } - delete accountData.verifiedCanLinkAccount; - - // Remember who it was so we can log out next time. - setPreviousAccountNameHash(newAccountEmail); - - // A sync-specific hack - we want to ensure sync has been initialized - // before we set the signed-in user. - let xps = Cc["@mozilla.org/weave/service;1"] - .getService(Ci.nsISupports) - .wrappedJSObject; - xps.whenLoaded().then(() => { - updateDisplayedEmail(accountData); - return fxAccounts.setSignedInUser(accountData); - }).then(() => { - // If the user data is verified, we want it to immediately look like - // they are signed in without waiting for messages to bounce around. - if (accountData.verified) { - openPrefs(); - } - this.injectData("message", { status: "login" }); - // until we sort out a better UX, just leave the jelly page in place. - // If the account email is not yet verified, it will tell the user to - // go check their email, but then it will *not* change state after - // the verification completes (the browser will begin syncing, but - // won't notify the user). If the email has already been verified, - // the jelly will say "Welcome! You are successfully signed in as - // EMAIL", but it won't then say "syncing started". - }, (err) => this.injectData("message", { status: "error", error: err }) - ); - }, - - onCanLinkAccount(accountData) { - // We need to confirm a relink - see shouldAllowRelink for more - let ok = shouldAllowRelink(accountData.email); - this.injectData("message", { status: "can_link_account", data: { ok } }); - }, - - /** - * onSignOut handler erases the current user's session from the fxaccounts service - */ - onSignOut() { - log("Received: 'sign_out'."); - - fxAccounts.signOut().then( - () => this.injectData("message", { status: "sign_out" }), - (err) => this.injectData("message", { status: "error", error: err }) - ); - }, - - handleRemoteCommand(evt) { - log("command: " + evt.detail.command); - let data = evt.detail.data; - - switch (evt.detail.command) { - case "login": - this.onLogin(data); - break; - case "can_link_account": - this.onCanLinkAccount(data); - break; - case "sign_out": - this.onSignOut(data); - break; - default: - log("Unexpected remote command received: " + evt.detail.command + ". Ignoring command."); - break; - } - }, - - injectData(type, content) { - return fxAccounts.promiseAccountsSignUpURI().then(authUrl => { - let data = { - type, - content - }; - this.iframe.contentWindow.postMessage(data, authUrl); - }) - .catch(e => { - console.log("Failed to inject data", e); - setErrorPage("configError"); - }); - }, + } }; diff --git a/browser/base/content/test/sync/accounts_testRemoteCommands.html b/browser/base/content/test/sync/accounts_testRemoteCommands.html deleted file mode 100644 index 943e1f5fa3fb..000000000000 --- a/browser/base/content/test/sync/accounts_testRemoteCommands.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - diff --git a/browser/base/content/test/sync/browser.ini b/browser/base/content/test/sync/browser.ini index c0e418001e17..b269ffd28adc 100644 --- a/browser/base/content/test/sync/browser.ini +++ b/browser/base/content/test/sync/browser.ini @@ -13,4 +13,3 @@ support-files= skip-if = os == "linux" # Bug 958026 support-files = content_aboutAccounts.js - accounts_testRemoteCommands.html diff --git a/browser/base/content/test/sync/browser_aboutAccounts.js b/browser/base/content/test/sync/browser_aboutAccounts.js index 3f199f2cc10e..4b2757f7054e 100644 --- a/browser/base/content/test/sync/browser_aboutAccounts.js +++ b/browser/base/content/test/sync/browser_aboutAccounts.js @@ -26,44 +26,6 @@ registerCleanupFunction(function() { }); var gTests = [ -{ - desc: "Test the remote commands", - async teardown() { - gBrowser.removeCurrentTab(); - await signOut(); - }, - async run() { - setPref("identity.fxaccounts.remote.signup.uri", - "https://example.com/browser/browser/base/content/test/sync/accounts_testRemoteCommands.html"); - let tab = await promiseNewTabLoadEvent("about:accounts"); - let mm = tab.linkedBrowser.messageManager; - - let deferred = Promise.defer(); - - // We'll get a message when openPrefs() is called, which this test should - // arrange. - let promisePrefsOpened = promiseOneMessage(tab, "test:openPrefsCalled"); - let results = 0; - try { - mm.addMessageListener("test:response", function responseHandler(msg) { - let data = msg.data.data; - if (data.type == "testResult") { - ok(data.pass, data.info); - results++; - } else if (data.type == "testsComplete") { - is(results, data.count, "Checking number of results received matches the number of tests that should have run"); - mm.removeMessageListener("test:response", responseHandler); - deferred.resolve(); - } - }); - } catch (e) { - ok(false, "Failed to get all commands"); - deferred.reject(); - } - await deferred.promise; - await promisePrefsOpened; - } -}, { desc: "Test action=signin - no user logged in", teardown: () => gBrowser.removeCurrentTab(), diff --git a/browser/components/downloads/content/downloadsOverlay.xul b/browser/components/downloads/content/downloadsOverlay.xul index fb24f1b8ffaa..0224cd7ad996 100644 --- a/browser/components/downloads/content/downloadsOverlay.xul +++ b/browser/components/downloads/content/downloadsOverlay.xul @@ -153,7 +153,8 @@ label="&downloadsHistory.label;" accesskey="&downloadsHistory.accesskey;" flex="1" - oncommand="DownloadsPanel.showDownloadsHistory();"/> + oncommand="DownloadsPanel.showDownloadsHistory();" + pack="start"/> diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js index 7afa1dcb97f1..ae7489cf319a 100644 --- a/browser/components/preferences/in-content/sync.js +++ b/browser/components/preferences/in-content/sync.js @@ -319,13 +319,6 @@ var gSyncPane = { }).then(data => { let fxaLoginStatus = document.getElementById("fxaLoginStatus"); if (data) { - if (data.email) { - // A hack to handle that the user's email address may have changed. - // This can probably be removed as part of bug 1383663. - fxaEmailAddressLabels.forEach((label) => { - label.value = data.email; - }); - } if (data.displayName) { fxaLoginStatus.setAttribute("hasName", true); displayNameLabel.hidden = false; diff --git a/browser/themes/shared/customizableui/panelUI.inc.css b/browser/themes/shared/customizableui/panelUI.inc.css index 7818a8f7e3fe..f8ee1014807c 100644 --- a/browser/themes/shared/customizableui/panelUI.inc.css +++ b/browser/themes/shared/customizableui/panelUI.inc.css @@ -121,12 +121,11 @@ background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center; border-radius: 50%; box-shadow: none; - border: 2px solid -moz-dialog; /* "!important" is necessary to override the rule in toolbarbutton.css */ - margin: -9px 0 0 !important; - margin-inline-end: -6px !important; - min-width: 16px; - min-height: 16px; + margin: -7px 0 0 !important; + margin-inline-end: -4px !important; + min-width: 12px; + min-height: 12px; } .panel-banner-item[notificationid^=update]::after { @@ -223,12 +222,18 @@ panelview { .subviewbutton.panel-subview-footer { box-sizing: border-box; min-height: 41px; - padding: 11px 12px; } -.cui-widget-panelview .subviewbutton.panel-subview-footer { +.cui-widget-panelview menuitem.subviewbutton.panel-subview-footer { margin: 4px 0 0; - -moz-box-pack: center; +} + +.cui-widget-panelview .subviewbutton.panel-subview-footer > .menu-text { + -moz-box-flex: 1; +} + +.cui-widget-panelview .subviewbutton.panel-subview-footer .menu-accel-container { + -moz-box-pack: end; } #appMenu-popup > arrowscrollbox > autorepeatbutton, @@ -384,7 +389,8 @@ panelview[id^=PanelUI-webext-] { } panelview:not([mainview]) .toolbarbutton-text, -.cui-widget-panel toolbarbutton:not([wrap]) > .toolbarbutton-text { +.cui-widget-panel toolbarbutton:not([wrap]) > .toolbarbutton-text, +#overflowMenu-customize-button > .toolbarbutton-text { text-align: start; display: -moz-box; } @@ -1209,7 +1215,6 @@ panelview .toolbarbutton-1, .subviewbutton > .toolbarbutton-text { padding: 0; - padding-inline-start: 24px; /* This is 16px for the icon + 8px for the padding as defined above. */ } .subviewbutton > .menu-right, @@ -1985,12 +1990,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left { #PanelUI-panic-actionlist-newwindow { background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 128, 32, 96); } - - #PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, - #PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, - #PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { - border: 1px solid -moz-dialog; - } } /* START photon adjustments */ diff --git a/browser/themes/shared/downloads/downloads.inc.css b/browser/themes/shared/downloads/downloads.inc.css index 0a8ce216d0c7..3fd5c204d369 100644 --- a/browser/themes/shared/downloads/downloads.inc.css +++ b/browser/themes/shared/downloads/downloads.inc.css @@ -92,8 +92,8 @@ } #downloadsHistory { - padding-inline-start: 10px; - padding-inline-end: 10px; + padding-inline-start: 14px; + padding-inline-end: 14px; } @item@ > toolbarseparator { diff --git a/browser/themes/shared/icons/menu-badged.svg b/browser/themes/shared/icons/menu-badged.svg new file mode 100644 index 000000000000..58ad9a8ecfe0 --- /dev/null +++ b/browser/themes/shared/icons/menu-badged.svg @@ -0,0 +1,6 @@ + + + + diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index 6182de3ab577..6f82e83704e3 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -150,6 +150,7 @@ skin/classic/browser/link.svg (../shared/icons/link.svg) skin/classic/browser/mail.svg (../shared/icons/mail.svg) skin/classic/browser/menu.svg (../shared/icons/menu.svg) + skin/classic/browser/menu-badged.svg (../shared/icons/menu-badged.svg) skin/classic/browser/new-tab.svg (../shared/icons/new-tab.svg) skin/classic/browser/new-window.svg (../shared/icons/new-window.svg) skin/classic/browser/open.svg (../shared/icons/open.svg) diff --git a/browser/themes/shared/toolbarbutton-icons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css index 51e0b8e907eb..5c5c819dd596 100644 --- a/browser/themes/shared/toolbarbutton-icons.inc.css +++ b/browser/themes/shared/toolbarbutton-icons.inc.css @@ -275,6 +275,12 @@ toolbar[brighttext] { list-style-image: url("chrome://browser/skin/menu.svg"); } +#PanelUI-menu-button[badge-status="update-available"], +#PanelUI-menu-button[badge-status="update-manual"], +#PanelUI-menu-button[badge-status="update-restart"] { + list-style-image: url("chrome://browser/skin/menu-badged.svg"); +} + #cut-button { list-style-image: url("chrome://browser/skin/edit-cut.svg"); } diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index c929a6198390..6afcd06e7942 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -78,6 +78,14 @@ margin-top: var(--space-above-tabbar); } +/* Add 4px extra margin on top of the tabs toolbar on Windows 7. */ +@media (-moz-os-version: windows-win7) { + :root[sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar, + :root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar { + margin-top: calc(var(--space-above-tabbar) + 4px); + } +} + #navigator-toolbox, #navigator-toolbox > toolbar { -moz-appearance: none; diff --git a/config/check_macroassembler_style.py b/config/check_macroassembler_style.py index 77480903fc0e..6d00a44b3467 100644 --- a/config/check_macroassembler_style.py +++ b/config/check_macroassembler_style.py @@ -3,7 +3,7 @@ # 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/. -#---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- # This script checks that SpiderMonkey MacroAssembler methods are properly # annotated. # @@ -18,7 +18,7 @@ # MacroAssembler-inl.h for method definitions. The result of both scans are # uniformized, and compared, to determine if the MacroAssembler.h header as # proper methods annotations. -#---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- from __future__ import print_function @@ -30,10 +30,10 @@ import sys from mozversioncontrol import get_repository_from_env -architecture_independent = set([ 'generic' ]) -all_unsupported_architectures_names = set([ 'mips32', 'mips64', 'mips_shared' ]) -all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64' ]) -all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64' ]) +architecture_independent = set(['generic']) +all_unsupported_architectures_names = set(['mips32', 'mips64', 'mips_shared']) +all_architecture_names = set(['x86', 'x64', 'arm', 'arm64']) +all_shared_architecture_names = set(['x86_shared', 'arm', 'arm64']) reBeforeArg = "(?<=[(,\s])" reArgType = "(?P[\w\s:*&]+)" @@ -42,7 +42,8 @@ reArgDefault = "(?P(?:\s=[^,)]+)?)" reAfterArg = "(?=[,)])" reMatchArg = re.compile(reBeforeArg + reArgType + reArgName + reArgDefault + reAfterArg) -def get_normalized_signatures(signature, fileAnnot = None): + +def get_normalized_signatures(signature, fileAnnot=None): # Remove static signature = signature.replace('static', '') # Remove semicolon. @@ -88,18 +89,21 @@ def get_normalized_signatures(signature, fileAnnot = None): inlinePrefx = '' if inline: inlinePrefx = 'inline ' - signatures = [ - { 'arch': a, 'sig': inlinePrefx + signature } + signatures = [ + {'arch': a, 'sig': inlinePrefx + signature} for a in archs ] return signatures + file_suffixes = set([ a.replace('_', '-') for a in all_architecture_names.union(all_shared_architecture_names) .union(all_unsupported_architectures_names) ]) + + def get_file_annotation(filename): origFilename = filename filename = filename.split('/')[-1] @@ -124,6 +128,7 @@ def get_file_annotation(filename): 'arch': arch.replace('-', '_') } + def get_macroassembler_definitions(filename): try: fileAnnot = get_file_annotation(filename) @@ -147,7 +152,7 @@ def get_macroassembler_definitions(filename): if line.startswith('{') or line.strip() == "{}": if 'MacroAssembler::' in lines: signatures.extend(get_normalized_signatures(lines, fileAnnot)) - if line.strip() != "{}": # Empty declaration, no need to declare + if line.strip() != "{}": # Empty declaration, no need to declare # a new code section code_section = True continue @@ -172,6 +177,7 @@ def get_macroassembler_definitions(filename): return signatures + def get_macroassembler_declaration(filename): style_section = False lines = '' @@ -203,13 +209,15 @@ def get_macroassembler_declaration(filename): return signatures + def append_signatures(d, sigs): for s in sigs: if s['sig'] not in d: d[s['sig']] = [] - d[s['sig']].append(s['arch']); + d[s['sig']].append(s['arch']) return d + def generate_file_content(signatures): output = [] for s in sorted(signatures.keys()): @@ -237,6 +245,7 @@ def generate_file_content(signatures): output.append(' is defined in %s.cpp\n' % masm) return output + def check_style(): # We read from the header file the signature of each function. decls = dict() # type: dict(signature => ['x86', 'x64']) @@ -278,7 +287,7 @@ def main(): if ok: print('TEST-PASS | check_macroassembler_style.py | ok') else: - print('TEST-UNEXPECTED-FAIL | check_macroassembler_style.py | actual output does not match expected output; diff is above') + print('TEST-UNEXPECTED-FAIL | check_macroassembler_style.py | actual output does not match expected output; diff is above') # noqa: E501 sys.exit(0 if ok else 1) diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java index a2b297bd171d..b921bda24295 100644 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java +++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/BaseTest.java @@ -21,6 +21,7 @@ import org.mozilla.gecko.R; import org.mozilla.gecko.RobocopUtils; import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tabs; +import org.mozilla.gecko.toolbar.BrowserToolbar; import org.mozilla.gecko.util.GeckoBundle; import android.content.ContentValues; @@ -424,7 +425,8 @@ abstract class BaseTest extends BaseRobocopTest { public final void selectMenuItem(String menuItemName) { // build the item name ready to be used String itemName = "^" + menuItemName + "$"; - final View menuView = mSolo.getView(R.id.menu); + final BrowserToolbar toolbar = (BrowserToolbar) mSolo.getView(R.id.browser_toolbar); + final View menuView = toolbar.findViewById(R.id.menu); mAsserter.isnot(menuView, null, "Menu view is not null"); mSolo.clickOnView(menuView, true); mAsserter.ok(waitForEnabledText(itemName), "Waiting for menu item " + itemName, itemName + " is present and enabled"); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d907c12a7edb..717807745b38 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4,9 +4,9 @@ "lockfileVersion": 1, "dependencies": { "acorn": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", - "integrity": "sha1-U/4WERH5EquZnuiHqQoLxSgi/XU=" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==" }, "acorn-jsx": { "version": "3.0.1", @@ -79,9 +79,9 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, "babel-code-frame": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", - "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { "chalk": "1.1.3", "esutils": "2.0.2", @@ -128,9 +128,9 @@ } }, "circular-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", - "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=" + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" }, "cli-cursor": { "version": "1.0.2", @@ -141,9 +141,9 @@ } }, "cli-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", - "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, "co": { "version": "4.6.0", @@ -180,7 +180,7 @@ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "requires": { - "es5-ext": "0.10.24" + "es5-ext": "0.10.30" } }, "debug": { @@ -207,7 +207,7 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1", - "rimraf": "2.6.1" + "rimraf": "2.6.2" } }, "doctrine": { @@ -263,9 +263,9 @@ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" }, "es5-ext": { - "version": "0.10.24", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", - "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", + "version": "0.10.30", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", + "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", "requires": { "es6-iterator": "2.0.1", "es6-symbol": "3.1.1" @@ -277,7 +277,7 @@ "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24", + "es5-ext": "0.10.30", "es6-symbol": "3.1.1" } }, @@ -287,7 +287,7 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24", + "es5-ext": "0.10.30", "es6-iterator": "2.0.1", "es6-set": "0.1.5", "es6-symbol": "3.1.1", @@ -300,7 +300,7 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24", + "es5-ext": "0.10.30", "es6-iterator": "2.0.1", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" @@ -312,7 +312,7 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24" + "es5-ext": "0.10.30" } }, "es6-weak-map": { @@ -321,7 +321,7 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24", + "es5-ext": "0.10.30", "es6-iterator": "2.0.1", "es6-symbol": "3.1.1" } @@ -347,25 +347,25 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "requires": { - "babel-code-frame": "6.22.0", + "babel-code-frame": "6.26.0", "chalk": "1.1.3", "concat-stream": "1.6.0", "debug": "2.6.8", "doctrine": "2.0.0", "escope": "3.6.0", - "espree": "3.4.3", + "espree": "3.5.1", "esquery": "1.0.0", "estraverse": "4.2.0", "esutils": "2.0.2", "file-entry-cache": "2.0.0", "glob": "7.1.2", "globals": "9.18.0", - "ignore": "3.3.3", + "ignore": "3.3.5", "imurmurhash": "0.1.4", "inquirer": "0.12.0", - "is-my-json-valid": "2.16.0", + "is-my-json-valid": "2.16.1", "is-resolvable": "1.0.0", - "js-yaml": "3.9.0", + "js-yaml": "3.10.0", "json-stable-stringify": "1.0.1", "levn": "0.3.0", "lodash": "4.17.4", @@ -395,10 +395,6 @@ "eslint-plugin-mozilla": { "version": "file:tools/lint/eslint/eslint-plugin-mozilla", "requires": { - "escope": "3.6.0", - "espree": "3.4.3", - "estraverse": "4.2.0", - "globals": "9.18.0", "ini-parser": "0.0.2", "sax": "1.2.4" } @@ -425,11 +421,11 @@ "version": "file:tools/lint/eslint/eslint-plugin-spidermonkey-js" }, "espree": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", - "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz", + "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", "requires": { - "acorn": "5.1.1", + "acorn": "5.1.2", "acorn-jsx": "3.0.1" } }, @@ -471,7 +467,7 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "requires": { "d": "1.0.0", - "es5-ext": "0.10.24" + "es5-ext": "0.10.30" } }, "exit-hook": { @@ -507,7 +503,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", "requires": { - "circular-json": "0.3.1", + "circular-json": "0.3.3", "del": "2.2.2", "graceful-fs": "4.1.11", "write": "0.2.1" @@ -519,9 +515,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", - "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "generate-function": { "version": "2.0.0", @@ -539,7 +535,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -552,7 +548,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=" + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" }, "globby": { "version": "5.0.0", @@ -577,7 +573,7 @@ "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "requires": { - "function-bind": "1.1.0" + "function-bind": "1.1.1" } }, "has-ansi": { @@ -602,9 +598,9 @@ } }, "ignore": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", - "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=" + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==" }, "imurmurhash": { "version": "0.1.4", @@ -639,7 +635,7 @@ "ansi-regex": "2.1.1", "chalk": "1.1.3", "cli-cursor": "1.0.2", - "cli-width": "2.1.0", + "cli-width": "2.2.0", "figures": "1.7.0", "lodash": "4.17.4", "readline2": "1.0.1", @@ -651,9 +647,9 @@ } }, "interpret": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", - "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=" }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -664,9 +660,9 @@ } }, "is-my-json-valid": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", - "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", + "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", "requires": { "generate-function": "2.0.0", "generate-object-property": "1.2.0", @@ -719,9 +715,9 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-yaml": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz", - "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "requires": { "argparse": "1.0.9", "esprima": "4.0.0" @@ -767,7 +763,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "1.1.8" } @@ -897,7 +893,7 @@ "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -923,7 +919,7 @@ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "requires": { - "resolve": "1.3.3" + "resolve": "1.4.0" } }, "require-uncached": { @@ -936,9 +932,9 @@ } }, "resolve": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", - "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", "requires": { "path-parse": "1.0.5" } @@ -958,9 +954,9 @@ } }, "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "requires": { "glob": "7.1.2" } @@ -981,12 +977,12 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "shelljs": { "version": "0.7.8", @@ -994,7 +990,7 @@ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", "requires": { "glob": "7.1.2", - "interpret": "1.0.3", + "interpret": "1.0.4", "rechoir": "0.6.2" } }, @@ -1021,7 +1017,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "requires": { "safe-buffer": "5.1.1" } @@ -1059,7 +1055,7 @@ "chalk": "1.1.3", "lodash": "4.17.4", "slice-ansi": "0.0.4", - "string-width": "2.1.0" + "string-width": "2.1.1" }, "dependencies": { "ansi-regex": { @@ -1073,9 +1069,9 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", - "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" diff --git a/services/crypto/modules/utils.js b/services/crypto/modules/utils.js index 9a5d8e65072a..aa0be9de0150 100644 --- a/services/crypto/modules/utils.js +++ b/services/crypto/modules/utils.js @@ -113,6 +113,15 @@ this.CryptoUtils = { return CommonUtils.bytesAsHex(CryptoUtils.digestUTF8(message, hasher)); }, + sha256Base64(message) { + let data = this._utf8Converter.convertToByteArray(message, {}); + let hasher = Cc["@mozilla.org/security/hash;1"] + .createInstance(Ci.nsICryptoHash); + hasher.init(hasher.SHA256); + hasher.update(data, data.length); + return hasher.finish(true); + }, + /** * Produce an HMAC key object from a key string. */ diff --git a/services/fxaccounts/FxAccounts.jsm b/services/fxaccounts/FxAccounts.jsm index 8242b229a6bb..b9f1118292e4 100644 --- a/services/fxaccounts/FxAccounts.jsm +++ b/services/fxaccounts/FxAccounts.jsm @@ -51,8 +51,9 @@ var publicProperties = [ "getProfileCache", "getSignedInUser", "getSignedInUserProfile", - "handleDeviceDisconnection", "handleAccountDestroyed", + "handleDeviceDisconnection", + "handleEmailUpdated", "hasLocalSession", "invalidateCertificate", "loadAndPoll", @@ -593,7 +594,7 @@ FxAccountsInternal.prototype = { * * @param credentials * The credentials object containing the fields to be updated. - * This object must contain |email| and |uid| fields and they must + * This object must contain the |uid| field and it must * match the currently signed in user. */ updateUserAccountData(credentials) { @@ -603,15 +604,14 @@ FxAccountsInternal.prototype = { } let currentAccountState = this.currentAccountState; return currentAccountState.promiseInitialized.then(() => { - return currentAccountState.getUserAccountData(["email", "uid"]); + return currentAccountState.getUserAccountData(["uid"]); }).then(existing => { - if (existing.email != credentials.email || existing.uid != credentials.uid) { + if (existing.uid != credentials.uid) { throw new Error("The specified credentials aren't for the current user"); } - // We need to nuke email and uid as storage will complain if we try and - // update them (even when the value is the same) + // We need to nuke uid as storage will complain if we try and + // update it (even when the value is the same) credentials = Cu.cloneInto(credentials, {}); // clone it first - delete credentials.email; delete credentials.uid; return currentAccountState.updateUserAccountData(credentials); }); @@ -1607,6 +1607,11 @@ FxAccountsInternal.prototype = { return null; }, + handleEmailUpdated(newEmail) { + Services.prefs.setStringPref(PREF_LAST_FXA_USER, CryptoUtils.sha256Base64(newEmail)); + return this.currentAccountState.updateUserAccountData({ email: newEmail }); + }, + async handleAccountDestroyed(uid) { const accountData = await this.currentAccountState.getUserAccountData(); const localUid = accountData ? accountData.uid : null; diff --git a/services/fxaccounts/FxAccountsCommon.js b/services/fxaccounts/FxAccountsCommon.js index 464c1606e125..e07710037d65 100644 --- a/services/fxaccounts/FxAccountsCommon.js +++ b/services/fxaccounts/FxAccountsCommon.js @@ -113,6 +113,8 @@ exports.FX_OAUTH_CLIENT_ID = "5882386c6d801776"; // Firefox Accounts WebChannel ID exports.WEBCHANNEL_ID = "account_updates"; +exports.PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash"; + // Server errno. // From https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format exports.ERRNO_ACCOUNT_ALREADY_EXISTS = 101; diff --git a/services/fxaccounts/FxAccountsProfile.jsm b/services/fxaccounts/FxAccountsProfile.jsm index 2543540973c5..ca89eaa7f2e0 100644 --- a/services/fxaccounts/FxAccountsProfile.jsm +++ b/services/fxaccounts/FxAccountsProfile.jsm @@ -71,45 +71,40 @@ this.FxAccountsProfile.prototype = { }, // Cache fetched data and send out a notification so that UI can update. - _cacheProfile(response) { + async _cacheProfile(response) { + const profile = response.body; + const userData = await this.fxa.getSignedInUser(); + if (profile.uid != userData.uid) { + throw new Error("The fetched profile does not correspond with the current account.") + } let profileCache = { - profile: response.body, + profile, etag: response.etag }; - - return this.fxa.setProfileCache(profileCache) - .then(() => { - return this.fxa.getSignedInUser(); - }) - .then(userData => { - log.debug("notifying profile changed for user ${uid}", userData); - this._notifyProfileChange(userData.uid); - return response.body; - }); + await this.fxa.setProfileCache(profileCache); + if (profile.email != userData.email) { + await this.fxa.handleEmailUpdated(profile.email); + } + log.debug("notifying profile changed for user ${uid}", userData); + this._notifyProfileChange(userData.uid); + return profile; }, - _fetchAndCacheProfileInternal() { - let onFinally = () => { + async _fetchAndCacheProfileInternal() { + try { + const profileCache = await this.fxa.getProfileCache(); + const etag = profileCache ? profileCache.etag : null; + const response = await this.client.fetchProfile(etag); + + // response may be null if the profile was not modified (same ETag). + if (!response) { + return null; + } + return await this._cacheProfile(response); + } finally { this._cachedAt = Date.now(); this._currentFetchPromise = null; } - return this.fxa.getProfileCache() - .then(profileCache => { - const etag = profileCache ? profileCache.etag : null; - return this.client.fetchProfile(etag); - }) - .then(response => { - // response may be null if the profile was not modified (same ETag). - return response ? this._cacheProfile(response) : null; - }) - .then(body => { // finally block - onFinally(); - // body may be null if the profile was not modified - return body; - }, err => { - onFinally(); - throw err; - }); }, _fetchAndCacheProfile() { @@ -122,23 +117,21 @@ this.FxAccountsProfile.prototype = { // Returns cached data right away if available, then fetches the latest profile // data in the background. After data is fetched a notification will be sent // out if the profile has changed. - getProfile() { - return this.fxa.getProfileCache() - .then(profileCache => { - if (profileCache) { - if (Date.now() > this._cachedAt + this.PROFILE_FRESHNESS_THRESHOLD) { - // Note that _fetchAndCacheProfile isn't returned, so continues - // in the background. - this._fetchAndCacheProfile().catch(err => { - log.error("Background refresh of profile failed", err); - }); - } else { - log.trace("not checking freshness of profile as it remains recent"); - } - return profileCache.profile; - } - return this._fetchAndCacheProfile(); + async getProfile() { + const profileCache = await this.fxa.getProfileCache(); + if (!profileCache) { + return this._fetchAndCacheProfile(); + } + if (Date.now() > this._cachedAt + this.PROFILE_FRESHNESS_THRESHOLD) { + // Note that _fetchAndCacheProfile isn't returned, so continues + // in the background. + this._fetchAndCacheProfile().catch(err => { + log.error("Background refresh of profile failed", err); }); + } else { + log.trace("not checking freshness of profile as it remains recent"); + } + return profileCache.profile; }, QueryInterface: XPCOMUtils.generateQI([ diff --git a/services/fxaccounts/FxAccountsStorage.jsm b/services/fxaccounts/FxAccountsStorage.jsm index b4ea0a00280a..b7d0078df937 100644 --- a/services/fxaccounts/FxAccountsStorage.jsm +++ b/services/fxaccounts/FxAccountsStorage.jsm @@ -208,11 +208,8 @@ this.FxAccountsStorageManager.prototype = { // update fields. throw new Error("No user is logged in"); } - if (!newFields || "uid" in newFields || "email" in newFields) { - // Once we support - // user changing email address this may need to change, but it's not - // clear how we would be told of such a change anyway... - throw new Error("Can't change uid or email address"); + if (!newFields || "uid" in newFields) { + throw new Error("Can't change uid"); } log.debug("_updateAccountData with items", Object.keys(newFields)); // work out what bucket. diff --git a/services/fxaccounts/FxAccountsWebChannel.jsm b/services/fxaccounts/FxAccountsWebChannel.jsm index f5f594c16db9..c23a214fb963 100644 --- a/services/fxaccounts/FxAccountsWebChannel.jsm +++ b/services/fxaccounts/FxAccountsWebChannel.jsm @@ -29,6 +29,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Weave", "resource://services-sync/main.js"); +XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils", + "resource://services-crypto/utils.js"); const COMMAND_PROFILE_CHANGE = "profile:change"; const COMMAND_CAN_LINK_ACCOUNT = "fxaccounts:can_link_account"; @@ -39,8 +41,6 @@ const COMMAND_SYNC_PREFERENCES = "fxaccounts:sync_preferences"; const COMMAND_CHANGE_PASSWORD = "fxaccounts:change_password"; const COMMAND_FXA_STATUS = "fxaccounts:fxa_status"; -const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash"; - // These engines were added years after Sync had been introduced, they need // special handling since they are system add-ons and are un-available on // older versions of Firefox. @@ -459,24 +459,7 @@ this.FxAccountsWebChannelHelpers.prototype = { * @param acctName the account name of the user's account. */ setPreviousAccountNameHashPref(acctName) { - Services.prefs.setStringPref(PREF_LAST_FXA_USER, this.sha256(acctName)); - }, - - /** - * Given a string, returns the SHA265 hash in base64 - */ - sha256(str) { - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Data is an array of bytes. - let data = converter.convertToByteArray(str, {}); - let hasher = Cc["@mozilla.org/security/hash;1"] - .createInstance(Ci.nsICryptoHash); - hasher.init(hasher.SHA256); - hasher.update(data, data.length); - - return hasher.finish(true); + Services.prefs.setStringPref(PREF_LAST_FXA_USER, CryptoUtils.sha256Base64(acctName)); }, /** @@ -504,7 +487,7 @@ this.FxAccountsWebChannelHelpers.prototype = { */ _needRelinkWarning(acctName) { let prevAcctHash = this.getPreviousAccountNameHashPref(); - return prevAcctHash && prevAcctHash != this.sha256(acctName); + return prevAcctHash && prevAcctHash != CryptoUtils.sha256Base64(acctName); }, /** diff --git a/services/fxaccounts/tests/xpcshell/test_accounts.js b/services/fxaccounts/tests/xpcshell/test_accounts.js index d026a063de77..807b2f842871 100644 --- a/services/fxaccounts/tests/xpcshell/test_accounts.js +++ b/services/fxaccounts/tests/xpcshell/test_accounts.js @@ -299,13 +299,7 @@ add_task(async function test_update_account_data() { do_check_eq((await account.getSignedInUser()).assertion, "new_assertion", "new field value was saved"); - // but we should fail attempting to change email or uid. - newCreds = { - email: "someoneelse@example.com", - uid: credentials.uid, - assertion: "new_assertion", - } - await Assert.rejects(account.updateUserAccountData(newCreds)); + // but we should fail attempting to change the uid. newCreds = { email: credentials.email, uid: "another_uid", @@ -313,7 +307,7 @@ add_task(async function test_update_account_data() { } await Assert.rejects(account.updateUserAccountData(newCreds)); - // should fail without email or uid. + // should fail without the uid. newCreds = { assertion: "new_assertion", } diff --git a/services/fxaccounts/tests/xpcshell/test_profile.js b/services/fxaccounts/tests/xpcshell/test_profile.js index 1b7b19f870d0..31cc3ee43374 100644 --- a/services/fxaccounts/tests/xpcshell/test_profile.js +++ b/services/fxaccounts/tests/xpcshell/test_profile.js @@ -6,6 +6,7 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js"); Cu.import("resource://gre/modules/FxAccountsProfileClient.jsm"); Cu.import("resource://gre/modules/FxAccountsProfile.jsm"); +Cu.import("resource://gre/modules/PromiseUtils.jsm"); const URL_STRING = "https://example.com"; Services.prefs.setCharPref("identity.fxaccounts.settings.uri", "https://example.com/settings"); @@ -59,8 +60,11 @@ let mockClient = function(fxa) { return new FxAccountsProfileClient(options); }; +const ACCOUNT_UID = "abc123"; +const ACCOUNT_EMAIL = "foo@bar.com"; const ACCOUNT_DATA = { - uid: "abc123" + uid: ACCOUNT_UID, + email: ACCOUNT_EMAIL }; function FxaMock() { @@ -122,13 +126,13 @@ add_test(function cacheProfile_change() { run_next_test(); }); - return profile._cacheProfile({ body: { avatar: "myurl" }, etag: "bogusetag" }); + return profile._cacheProfile({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myurl" }, etag: "bogusetag" }); }); add_test(function fetchAndCacheProfile_ok() { let client = mockClient(mockFxa()); client.fetchProfile = function() { - return Promise.resolve({ body: { avatar: "myimg"} }); + return Promise.resolve({ body: { uid: ACCOUNT_UID, avatar: "myimg"} }); }; let profile = CreateFxAccountsProfile(null, client); profile._cachedAt = 12345; @@ -169,7 +173,7 @@ add_test(function fetchAndCacheProfile_sendsETag() { let client = mockClient(fxa); client.fetchProfile = function(etag) { do_check_eq(etag, "bogusETag"); - return Promise.resolve({ body: { avatar: "myimg"} }); + return Promise.resolve({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"} }); }; let profile = CreateFxAccountsProfile(fxa, client); @@ -195,26 +199,18 @@ add_task(async function fetchAndCacheProfileOnce() { return promiseProfile; }; let fxa = mockFxa(); - fxa.getProfileCache = () => { - // We do this because we are gonna have a race condition and fetchProfile will - // not be called before we check numFetches. - return { - then(thenFunc) { - return thenFunc(); - } - } - }; let profile = CreateFxAccountsProfile(fxa, client); let request1 = profile._fetchAndCacheProfile(); profile._fetchAndCacheProfile(); + await new Promise(res => setTimeout(res, 0)); // Yield so fetchProfile() is called (promise) // should be one request made to fetch the profile (but the promise returned // by it remains unresolved) do_check_eq(numFetches, 1); // resolve the promise. - resolveProfile({ body: { avatar: "myimg"} }); + resolveProfile({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"} }); // both requests should complete with the same data. let got1 = await request1; @@ -242,19 +238,11 @@ add_task(async function fetchAndCacheProfileOnce() { return promiseProfile; }; let fxa = mockFxa(); - fxa.getProfileCache = () => { - // We do this because we are gonna have a race condition and fetchProfile will - // not be called before we check numFetches. - return { - then(thenFunc) { - return thenFunc(); - } - } - }; let profile = CreateFxAccountsProfile(fxa, client); let request1 = profile._fetchAndCacheProfile(); let request2 = profile._fetchAndCacheProfile(); + await new Promise(res => setTimeout(res, 0)); // Yield so fetchProfile() is called (promise) // should be one request made to fetch the profile (but the promise returned // by it remains unresolved) @@ -283,7 +271,7 @@ add_task(async function fetchAndCacheProfileOnce() { // but a new request should works. client.fetchProfile = function() { - return Promise.resolve({body: { avatar: "myimg"}}); + return Promise.resolve({body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}}); }; let got = await profile._fetchAndCacheProfile(); @@ -293,7 +281,7 @@ add_task(async function fetchAndCacheProfileOnce() { add_test(function fetchAndCacheProfile_alreadyCached() { let cachedUrl = "cachedurl"; let fxa = mockFxa(); - fxa.profileCache = { profile: { avatar: cachedUrl }, etag: "bogusETag" }; + fxa.profileCache = { profile: { uid: ACCOUNT_UID, avatar: cachedUrl }, etag: "bogusETag" }; let client = mockClient(fxa); client.fetchProfile = function(etag) { do_check_eq(etag, "bogusETag"); @@ -318,9 +306,9 @@ add_test(function fetchAndCacheProfile_alreadyCached() { add_task(async function fetchAndCacheProfileAfterThreshold() { let numFetches = 0; let client = mockClient(mockFxa()); - client.fetchProfile = function() { + client.fetchProfile = async function() { numFetches += 1; - return Promise.resolve({ avatar: "myimg"}); + return {body: {uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}}; }; let profile = CreateFxAccountsProfile(null, client); profile.PROFILE_FRESHNESS_THRESHOLD = 1000; @@ -335,7 +323,14 @@ add_task(async function fetchAndCacheProfileAfterThreshold() { do_timeout(1000, resolve); }); + let origFetchAndCatch = profile._fetchAndCacheProfile; + let backgroundFetchDone = PromiseUtils.defer(); + profile._fetchAndCacheProfile = async () => { + await origFetchAndCatch.call(profile); + backgroundFetchDone.resolve(); + } await profile.getProfile(); + await backgroundFetchDone.promise; do_check_eq(numFetches, 2); }); @@ -345,9 +340,9 @@ add_task(async function fetchAndCacheProfileAfterThreshold() { add_task(async function fetchAndCacheProfileBeforeThresholdOnNotification() { let numFetches = 0; let client = mockClient(mockFxa()); - client.fetchProfile = function() { + client.fetchProfile = async function() { numFetches += 1; - return Promise.resolve({ avatar: "myimg"}); + return {body: {uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}}; }; let profile = CreateFxAccountsProfile(null, client); profile.PROFILE_FRESHNESS_THRESHOLD = 1000; @@ -357,7 +352,14 @@ add_task(async function fetchAndCacheProfileBeforeThresholdOnNotification() { Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION); + let origFetchAndCatch = profile._fetchAndCacheProfile; + let backgroundFetchDone = PromiseUtils.defer(); + profile._fetchAndCacheProfile = async () => { + await origFetchAndCatch.call(profile); + backgroundFetchDone.resolve(); + } await profile.getProfile(); + await backgroundFetchDone.promise; do_check_eq(numFetches, 2); }); @@ -379,7 +381,7 @@ add_test(function getProfile_ok() { let didFetch = false; let fxa = mockFxa(); - fxa.profileCache = { profile: { avatar: cachedUrl } }; + fxa.profileCache = { profile: { uid: ACCOUNT_UID, avatar: cachedUrl } }; let profile = CreateFxAccountsProfile(fxa); profile._fetchAndCacheProfile = function() { @@ -402,7 +404,7 @@ add_test(function getProfile_no_cache() { let profile = CreateFxAccountsProfile(fxa); profile._fetchAndCacheProfile = function() { - return Promise.resolve({ avatar: fetchedUrl }); + return Promise.resolve({ uid: ACCOUNT_UID, avatar: fetchedUrl }); }; return profile.getProfile() @@ -418,11 +420,11 @@ add_test(function getProfile_has_cached_fetch_deleted() { let fxa = mockFxa(); let client = mockClient(fxa); client.fetchProfile = function() { - return Promise.resolve({ body: { avatar: null } }); + return Promise.resolve({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: null } }); }; let profile = CreateFxAccountsProfile(fxa, client); - fxa.profileCache = { profile: { avatar: cachedUrl } }; + fxa.profileCache = { profile: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: cachedUrl } }; // instead of checking this in a mocked "save" function, just check after the // observer @@ -442,7 +444,7 @@ add_test(function getProfile_has_cached_fetch_deleted() { add_test(function getProfile_fetchAndCacheProfile_throws() { let fxa = mockFxa(); - fxa.profileCache = { profile: { avatar: "myimg" } }; + fxa.profileCache = { profile: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg" } }; let profile = CreateFxAccountsProfile(fxa); profile._fetchAndCacheProfile = () => Promise.reject(new Error()); @@ -454,6 +456,21 @@ add_test(function getProfile_fetchAndCacheProfile_throws() { }); }); +add_test(function getProfile_email_changed() { + let fxa = mockFxa(); + let client = mockClient(fxa); + client.fetchProfile = function() { + return Promise.resolve({ body: { uid: ACCOUNT_UID, email: "newemail@bar.com" } }); + }; + fxa.handleEmailUpdated = email => { + do_check_eq(email, "newemail@bar.com"); + run_next_test(); + }; + + let profile = CreateFxAccountsProfile(fxa, client); + return profile._fetchAndCacheProfile(); +}); + function makeObserver(aObserveTopic, aObserveFunc) { let callback = function(aSubject, aTopic, aData) { log.debug("observed " + aTopic + " " + aData); diff --git a/services/fxaccounts/tests/xpcshell/test_web_channel.js b/services/fxaccounts/tests/xpcshell/test_web_channel.js index 2260688e3776..80987ca88326 100644 --- a/services/fxaccounts/tests/xpcshell/test_web_channel.js +++ b/services/fxaccounts/tests/xpcshell/test_web_channel.js @@ -4,6 +4,7 @@ "use strict"; Cu.import("resource://gre/modules/FxAccountsCommon.js"); +Cu.import("resource://services-crypto/utils.js"); const { FxAccountsWebChannel, FxAccountsWebChannelHelpers } = Cu.import("resource://gre/modules/FxAccountsWebChannel.jsm", {}); @@ -338,7 +339,8 @@ add_task(async function test_helpers_login_without_customize_sync() { do_check_false("verifiedCanLinkAccount" in accountData); // previously signed in user preference is updated. - do_check_eq(helpers.getPreviousAccountNameHashPref(), helpers.sha256("testuser@testuser.com")); + do_check_eq(helpers.getPreviousAccountNameHashPref(), + CryptoUtils.sha256Base64("testuser@testuser.com")); resolve(); }); diff --git a/services/sync/modules/UIState.jsm b/services/sync/modules/UIState.jsm index a6cbbc227f64..7019bf833518 100644 --- a/services/sync/modules/UIState.jsm +++ b/services/sync/modules/UIState.jsm @@ -162,9 +162,6 @@ const UIStateInternal = { _populateWithProfile(state, profile) { state.displayName = profile.displayName; state.avatarURL = profile.avatar; - // A hack to handle that the user's email address may have changed. - // This can probably be removed as part of bug 1383663. - state.email = profile.email; }, async _getUserData() { diff --git a/services/sync/tests/unit/test_uistate.js b/services/sync/tests/unit/test_uistate.js index 1b85db539914..edb289793c1e 100644 --- a/services/sync/tests/unit/test_uistate.js +++ b/services/sync/tests/unit/test_uistate.js @@ -53,7 +53,7 @@ add_task(async function test_refreshState_signedin() { UIStateInternal.fxAccounts = { getSignedInUser: () => Promise.resolve({ verified: true, email: "foo@bar.com" }), - getSignedInUserProfile: () => Promise.resolve({ displayName: "Foo Bar", avatar: "https://foo/bar", email: "foo@bar.com" }), + getSignedInUserProfile: () => Promise.resolve({ displayName: "Foo Bar", avatar: "https://foo/bar" }), hasLocalSession: () => Promise.resolve(true), } @@ -69,32 +69,6 @@ add_task(async function test_refreshState_signedin() { UIStateInternal.fxAccounts = fxAccountsOrig; }); -add_task(async function test_refreshState_preferProfileEmail() { - UIState.reset(); - const fxAccountsOrig = UIStateInternal.fxAccounts; - - const now = new Date().toString(); - Services.prefs.setCharPref("services.sync.lastSync", now); - UIStateInternal.syncing = false; - - UIStateInternal.fxAccounts = { - getSignedInUser: () => Promise.resolve({ verified: true, email: "foo@bar.com" }), - getSignedInUserProfile: () => Promise.resolve({ displayName: "Foo Bar", avatar: "https://foo/bar", email: "bar@foo.com" }), - hasLocalSession: () => Promise.resolve(true), - } - - let state = await UIState.refresh(); - - equal(state.status, UIState.STATUS_SIGNED_IN); - equal(state.email, "bar@foo.com"); - equal(state.displayName, "Foo Bar"); - equal(state.avatarURL, "https://foo/bar"); - equal(state.lastSync, now); - equal(state.syncing, false); - - UIStateInternal.fxAccounts = fxAccountsOrig; -}); - add_task(async function test_refreshState_signedin_profile_unavailable() { UIState.reset(); const fxAccountsOrig = UIStateInternal.fxAccounts; diff --git a/servo/components/style/gecko/media_queries.rs b/servo/components/style/gecko/media_queries.rs index 415700fef6de..2765547aaf9e 100644 --- a/servo/components/style/gecko/media_queries.rs +++ b/servo/components/style/gecko/media_queries.rs @@ -752,7 +752,9 @@ impl Expression { (&BoolInteger(one), &BoolInteger(ref other)) => one.cmp(other), (&Float(one), &Float(ref other)) => one.partial_cmp(other).unwrap(), (&IntRatio(one_num, one_den), &IntRatio(other_num, other_den)) => { - (one_num * other_den).partial_cmp(&(other_num * one_den)).unwrap() + // Extend to avoid overflow. + (one_num as u64 * other_den as u64).cmp( + &(other_num as u64 * one_den as u64)) } (&Resolution(ref one), &Resolution(ref other)) => { let actual_dpi = unsafe { diff --git a/servo/components/style/sharing/mod.rs b/servo/components/style/sharing/mod.rs index d6d159a4bb75..a9c6a06181da 100644 --- a/servo/components/style/sharing/mod.rs +++ b/servo/components/style/sharing/mod.rs @@ -554,11 +554,6 @@ impl StyleSharingCache { validation_data_holder: Option<&mut StyleSharingTarget>, dom_depth: usize, ) { - if style.0.reused_via_rule_node { - debug!("Failing to insert into the cached: this was a cached style"); - return; - } - let parent = match element.traversal_parent() { Some(element) => element, None => { diff --git a/servo/components/style/traversal.rs b/servo/components/style/traversal.rs index 20386d754b47..762e28644aad 100644 --- a/servo/components/style/traversal.rs +++ b/servo/components/style/traversal.rs @@ -723,12 +723,29 @@ where resolver.cascade_styles_with_default_parents(cascade_inputs) }; - context.thread_local.sharing_cache.insert_if_possible( - &element, - &new_styles.primary, - None, - traversal_data.current_dom_depth, - ); + // Insert into the cache, but only if this style isn't reused from a + // sibling or cousin. Otherwise, recascading a bunch of identical + // elements would unnecessarily flood the cache with identical entries. + // + // This is analagous to the obvious "don't insert an element that just + // got a hit in the style sharing cache" behavior in the MatchAndCascade + // handling above. + // + // Note that, for the MatchAndCascade path, we still insert elements that + // shared styles via the rule node, because we know that there's something + // different about them that caused them to miss the sharing cache before + // selector matching. If we didn't, we would still end up with the same + // number of eventual styles, but would potentially miss out on various + // opportunities for skipping selector matching, which could hurt + // performance. + if !new_styles.primary.0.reused_via_rule_node { + context.thread_local.sharing_cache.insert_if_possible( + &element, + &new_styles.primary, + None, + traversal_data.current_dom_depth, + ); + } new_styles } diff --git a/toolkit/themes/shared/extensions/extensions.inc.css b/toolkit/themes/shared/extensions/extensions.inc.css index 0203e357a3a0..cd24da6a4ab9 100644 --- a/toolkit/themes/shared/extensions/extensions.inc.css +++ b/toolkit/themes/shared/extensions/extensions.inc.css @@ -723,7 +723,7 @@ button.warning { margin-bottom: 2em; } -#detail-name-container label { +#detail-name-container { font-size: 2.5rem; font-weight: normal; } diff --git a/toolkit/themes/windows/global/menu.css b/toolkit/themes/windows/global/menu.css index 822682a6c694..9f8b3ea6f9cb 100644 --- a/toolkit/themes/windows/global/menu.css +++ b/toolkit/themes/windows/global/menu.css @@ -58,7 +58,6 @@ menuitem.spell-suggestion { } .menu-text { - padding-inline-start: 1.45em !important; -moz-appearance: menuitemtext; } @@ -85,7 +84,6 @@ menucaption > .menu-iconic-text { .menu-iconic-accel { color: inherit; margin-inline-start: 0.74em !important; - margin-inline-end: 1.35em !important; } .menu-iconic-left { diff --git a/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt b/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt index b48477df86e3..e4bc2a96decf 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt +++ b/tools/lint/eslint/eslint-plugin-mozilla/manifest.tt @@ -4,7 +4,7 @@ "visibility": "public", "filename": "eslint-plugin-mozilla.tar.gz", "unpack": true, - "digest": "15f798175702ec4603676fc6befb7ecf3f169901ae5509edeea73d2ee1861899de39c3ff3e797a65e3a733ac2f0a4b05b8159b17bf5fa2f351667ad34055bcd6", - "size": 4243209 + "digest": "e6494c4b71e94775b7b3341d42338a852c827e050692679b44ef15105b220ed63fa9a08b68ae1d103f8d9c88c7369c2c13079288df7c977699f8be798ac0a170", + "size": 3930721 } ] diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json b/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json index c34bfe8ebebd..ca877fab793b 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json +++ b/tools/lint/eslint/eslint-plugin-mozilla/package-lock.json @@ -5,14 +5,16 @@ "requires": true, "dependencies": { "acorn": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", - "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", + "dev": true }, "acorn-jsx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, "requires": { "acorn": "3.3.0" }, @@ -20,7 +22,8 @@ "acorn": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true } } }, @@ -91,9 +94,9 @@ "dev": true }, "babel-code-frame": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", - "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { "chalk": "1.1.3", @@ -152,9 +155,9 @@ } }, "circular-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", - "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "cli-cursor": { @@ -167,9 +170,9 @@ } }, "cli-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", - "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, "co": { @@ -184,13 +187,13 @@ "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", "dev": true, "requires": { - "color-name": "1.1.2" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz", - "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "commander": { @@ -225,14 +228,6 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "requires": { - "es5-ext": "0.10.24" - } - }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", @@ -260,7 +255,7 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1", - "rimraf": "2.6.1" + "rimraf": "2.6.2" } }, "diff": { @@ -279,87 +274,12 @@ "isarray": "1.0.0" } }, - "es5-ext": { - "version": "0.10.24", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", - "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", - "requires": { - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } - }, - "es6-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-symbol": "3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" - } - }, - "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - } - }, "eslint": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.2.0.tgz", @@ -367,24 +287,24 @@ "dev": true, "requires": { "ajv": "5.2.2", - "babel-code-frame": "6.22.0", + "babel-code-frame": "6.26.0", "chalk": "1.1.3", "concat-stream": "1.6.0", "debug": "2.6.8", "doctrine": "2.0.0", "eslint-scope": "3.7.1", - "espree": "3.4.3", + "espree": "3.5.1", "esquery": "1.0.0", "estraverse": "4.2.0", "esutils": "2.0.2", "file-entry-cache": "2.0.0", "glob": "7.1.2", "globals": "9.18.0", - "ignore": "3.3.3", + "ignore": "3.3.5", "imurmurhash": "0.1.4", - "inquirer": "3.2.0", + "inquirer": "3.2.3", "is-resolvable": "1.0.0", - "js-yaml": "3.9.0", + "js-yaml": "3.10.0", "json-stable-stringify": "1.0.1", "levn": "0.3.0", "lodash": "4.17.4", @@ -412,11 +332,12 @@ } }, "espree": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", - "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz", + "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", + "dev": true, "requires": { - "acorn": "5.1.1", + "acorn": "5.1.2", "acorn-jsx": "3.0.1" } }, @@ -439,6 +360,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, "requires": { "estraverse": "4.2.0", "object-assign": "4.1.1" @@ -447,7 +369,8 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true }, "esutils": { "version": "2.0.2", @@ -455,23 +378,14 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.24" - } - }, "external-editor": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", "dev": true, "requires": { - "iconv-lite": "0.4.18", - "jschardet": "1.4.2", + "iconv-lite": "0.4.19", + "jschardet": "1.5.1", "tmp": "0.0.31" } }, @@ -512,7 +426,7 @@ "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", "dev": true, "requires": { - "circular-json": "0.3.1", + "circular-json": "0.3.3", "del": "2.2.2", "graceful-fs": "4.1.11", "write": "0.2.1" @@ -541,7 +455,8 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true }, "globby": { "version": "5.0.0", @@ -591,15 +506,15 @@ "dev": true }, "iconv-lite": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", "dev": true }, "ignore": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", - "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", "dev": true }, "imurmurhash": { @@ -630,15 +545,15 @@ "integrity": "sha1-+kF4flZ3Y7P/Zdel2alO23QHh+8=" }, "inquirer": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.0.tgz", - "integrity": "sha512-4CyUYMP7lOBkiUU1rR24WGrfRX6SucwbY2Mqb1PdApU24wnTIk4TsnkQwV72dDdIKZ2ycLP+fWCV+tA7wwgoew==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.3.tgz", + "integrity": "sha512-Bc3KbimpDTOeQdDj18Ir/rlsGuhBSSNqdOnxaAuKhpkdnMMuKsEGbZD2v5KFF9oso2OU+BPh7+/u5obmFDRmWw==", "dev": true, "requires": { "ansi-escapes": "2.0.0", - "chalk": "2.0.1", + "chalk": "2.1.0", "cli-cursor": "2.1.0", - "cli-width": "2.1.0", + "cli-width": "2.2.0", "external-editor": "2.0.4", "figures": "2.0.0", "lodash": "4.17.4", @@ -646,7 +561,7 @@ "run-async": "2.3.0", "rx-lite": "4.0.8", "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.0", + "string-width": "2.1.1", "strip-ansi": "4.0.0", "through": "2.3.8" }, @@ -658,23 +573,23 @@ "dev": true }, "ansi-styles": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", - "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { "color-convert": "1.9.0" } }, "chalk": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", - "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", "dev": true, "requires": { - "ansi-styles": "3.1.0", + "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.2.0" + "supports-color": "4.4.0" } }, "strip-ansi": { @@ -687,9 +602,9 @@ } }, "supports-color": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.0.tgz", - "integrity": "sha512-Ts0Mu/A1S1aZxEJNG88I4Oc9rcZSBFNac5e27yh4j2mqbhZSSzR1Ah79EYwSn9Zuh7lrlGD2cVGzw1RKGzyLSg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { "has-flag": "2.0.0" @@ -755,9 +670,9 @@ "dev": true }, "js-yaml": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz", - "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "dev": true, "requires": { "argparse": "1.0.9", @@ -765,9 +680,9 @@ } }, "jschardet": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz", - "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", + "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", "dev": true }, "json-schema-traverse": { @@ -997,7 +912,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "once": { "version": "1.4.0", @@ -1136,9 +1052,9 @@ } }, "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "7.1.2" @@ -1197,19 +1113,10 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", - "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -1233,6 +1140,15 @@ } } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -1265,7 +1181,7 @@ "chalk": "1.1.3", "lodash": "4.17.4", "slice-ansi": "0.0.4", - "string-width": "2.1.0" + "string-width": "2.1.1" }, "dependencies": { "ajv": { diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package.json b/tools/lint/eslint/eslint-plugin-mozilla/package.json index 1fad5c678758..df7d820ba236 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/package.json +++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json @@ -20,10 +20,6 @@ "author": "Mike Ratcliffe", "main": "lib/index.js", "dependencies": { - "escope": "3.6.0", - "espree": "3.4.3", - "estraverse": "4.2.0", - "globals": "9.18.0", "ini-parser": "0.0.2", "sax": "1.2.4" }, diff --git a/tools/lint/eslint/manifest.tt b/tools/lint/eslint/manifest.tt index 5311bac9cb8e..bf01fcbff5ad 100644 --- a/tools/lint/eslint/manifest.tt +++ b/tools/lint/eslint/manifest.tt @@ -4,7 +4,7 @@ "visibility": "public", "filename": "eslint.tar.gz", "unpack": true, - "digest": "9cb0212c8cd21b38edeeae2d00728625d442588bcd076b43a061c0994458698d6377ba28a708dca140202744cb03fcadb02c3153ae8585c5648a0b513b0cefa7", - "size": 2912929 + "digest": "4ed34c6d0b1831bce3ab5def5b7cf6248c7ef459a4c68acba8741e9e32e3ed84919c03b155a1518c6eba95a8c55ab3856a905f27cd861f547e684a37fff582e8", + "size": 2906797 } ] diff --git a/tools/lint/eslint/modules.json b/tools/lint/eslint/modules.json index 96dd5f8ab154..7717b54faf00 100644 --- a/tools/lint/eslint/modules.json +++ b/tools/lint/eslint/modules.json @@ -84,7 +84,7 @@ "fxa_utils.js": ["initializeIdentityWithTokenServerResponse"], "fxaccounts.jsm": ["Authentication"], "FxAccounts.jsm": ["fxAccounts", "FxAccounts"], - "FxAccountsCommon.js": ["log", "logPII", "FXACCOUNTS_PERMISSION", "DATA_FORMAT_VERSION", "DEFAULT_STORAGE_FILENAME", "ASSERTION_LIFETIME", "ASSERTION_USE_PERIOD", "CERT_LIFETIME", "KEY_LIFETIME", "POLL_SESSION", "ONLOGIN_NOTIFICATION", "ONVERIFIED_NOTIFICATION", "ONLOGOUT_NOTIFICATION", "ON_FXA_UPDATE_NOTIFICATION", "ON_DEVICE_CONNECTED_NOTIFICATION", "ON_DEVICE_DISCONNECTED_NOTIFICATION", "ON_PROFILE_UPDATED_NOTIFICATION", "ON_PASSWORD_CHANGED_NOTIFICATION", "ON_PASSWORD_RESET_NOTIFICATION", "ON_VERIFY_LOGIN_NOTIFICATION", "ON_ACCOUNT_DESTROYED_NOTIFICATION", "ON_COLLECTION_CHANGED_NOTIFICATION", "FXA_PUSH_SCOPE_ACCOUNT_UPDATE", "ON_PROFILE_CHANGE_NOTIFICATION", "ON_ACCOUNT_STATE_CHANGE_NOTIFICATION", "UI_REQUEST_SIGN_IN_FLOW", "UI_REQUEST_REFRESH_AUTH", "FX_OAUTH_CLIENT_ID", "WEBCHANNEL_ID", "ERRNO_ACCOUNT_ALREADY_EXISTS", "ERRNO_ACCOUNT_DOES_NOT_EXIST", "ERRNO_INCORRECT_PASSWORD", "ERRNO_UNVERIFIED_ACCOUNT", "ERRNO_INVALID_VERIFICATION_CODE", "ERRNO_NOT_VALID_JSON_BODY", "ERRNO_INVALID_BODY_PARAMETERS", "ERRNO_MISSING_BODY_PARAMETERS", "ERRNO_INVALID_REQUEST_SIGNATURE", "ERRNO_INVALID_AUTH_TOKEN", "ERRNO_INVALID_AUTH_TIMESTAMP", "ERRNO_MISSING_CONTENT_LENGTH", "ERRNO_REQUEST_BODY_TOO_LARGE", "ERRNO_TOO_MANY_CLIENT_REQUESTS", "ERRNO_INVALID_AUTH_NONCE", "ERRNO_ENDPOINT_NO_LONGER_SUPPORTED", "ERRNO_INCORRECT_LOGIN_METHOD", "ERRNO_INCORRECT_KEY_RETRIEVAL_METHOD", "ERRNO_INCORRECT_API_VERSION", "ERRNO_INCORRECT_EMAIL_CASE", "ERRNO_ACCOUNT_LOCKED", "ERRNO_ACCOUNT_UNLOCKED", "ERRNO_UNKNOWN_DEVICE", "ERRNO_DEVICE_SESSION_CONFLICT", "ERRNO_SERVICE_TEMP_UNAVAILABLE", "ERRNO_PARSE", "ERRNO_NETWORK", "ERRNO_UNKNOWN_ERROR", "OAUTH_SERVER_ERRNO_OFFSET", "ERRNO_UNKNOWN_CLIENT_ID", "ERRNO_INCORRECT_CLIENT_SECRET", "ERRNO_INCORRECT_REDIRECT_URI", "ERRNO_INVALID_FXA_ASSERTION", "ERRNO_UNKNOWN_CODE", "ERRNO_INCORRECT_CODE", "ERRNO_EXPIRED_CODE", "ERRNO_OAUTH_INVALID_TOKEN", "ERRNO_INVALID_REQUEST_PARAM", "ERRNO_INVALID_RESPONSE_TYPE", "ERRNO_UNAUTHORIZED", "ERRNO_FORBIDDEN", "ERRNO_INVALID_CONTENT_TYPE", "ERROR_ACCOUNT_ALREADY_EXISTS", "ERROR_ACCOUNT_DOES_NOT_EXIST", "ERROR_ACCOUNT_LOCKED", "ERROR_ACCOUNT_UNLOCKED", "ERROR_ALREADY_SIGNED_IN_USER", "ERROR_DEVICE_SESSION_CONFLICT", "ERROR_ENDPOINT_NO_LONGER_SUPPORTED", "ERROR_INCORRECT_API_VERSION", "ERROR_INCORRECT_EMAIL_CASE", "ERROR_INCORRECT_KEY_RETRIEVAL_METHOD", "ERROR_INCORRECT_LOGIN_METHOD", "ERROR_INVALID_EMAIL", "ERROR_INVALID_AUDIENCE", "ERROR_INVALID_AUTH_TOKEN", "ERROR_INVALID_AUTH_TIMESTAMP", "ERROR_INVALID_AUTH_NONCE", "ERROR_INVALID_BODY_PARAMETERS", "ERROR_INVALID_PASSWORD", "ERROR_INVALID_VERIFICATION_CODE", "ERROR_INVALID_REFRESH_AUTH_VALUE", "ERROR_INVALID_REQUEST_SIGNATURE", "ERROR_INTERNAL_INVALID_USER", "ERROR_MISSING_BODY_PARAMETERS", "ERROR_MISSING_CONTENT_LENGTH", "ERROR_NO_TOKEN_SESSION", "ERROR_NO_SILENT_REFRESH_AUTH", "ERROR_NOT_VALID_JSON_BODY", "ERROR_OFFLINE", "ERROR_PERMISSION_DENIED", "ERROR_REQUEST_BODY_TOO_LARGE", "ERROR_SERVER_ERROR", "ERROR_SYNC_DISABLED", "ERROR_TOO_MANY_CLIENT_REQUESTS", "ERROR_SERVICE_TEMP_UNAVAILABLE", "ERROR_UI_ERROR", "ERROR_UI_REQUEST", "ERROR_PARSE", "ERROR_NETWORK", "ERROR_UNKNOWN", "ERROR_UNKNOWN_DEVICE", "ERROR_UNVERIFIED_ACCOUNT", "ERROR_UNKNOWN_CLIENT_ID", "ERROR_INCORRECT_CLIENT_SECRET", "ERROR_INCORRECT_REDIRECT_URI", "ERROR_INVALID_FXA_ASSERTION", "ERROR_UNKNOWN_CODE", "ERROR_INCORRECT_CODE", "ERROR_EXPIRED_CODE", "ERROR_OAUTH_INVALID_TOKEN", "ERROR_INVALID_REQUEST_PARAM", "ERROR_INVALID_RESPONSE_TYPE", "ERROR_UNAUTHORIZED", "ERROR_FORBIDDEN", "ERROR_INVALID_CONTENT_TYPE", "ERROR_NO_ACCOUNT", "ERROR_AUTH_ERROR", "ERROR_INVALID_PARAMETER", "ERROR_CODE_METHOD_NOT_ALLOWED", "ERROR_MSG_METHOD_NOT_ALLOWED", "FXA_PWDMGR_PLAINTEXT_FIELDS", "FXA_PWDMGR_SECURE_FIELDS", "FXA_PWDMGR_MEMORY_FIELDS", "FXA_PWDMGR_REAUTH_WHITELIST", "FXA_PWDMGR_HOST", "FXA_PWDMGR_REALM", "SERVER_ERRNO_TO_ERROR", "ERROR_TO_GENERAL_ERROR_CLASS"], + "FxAccountsCommon.js": ["log", "logPII", "FXACCOUNTS_PERMISSION", "DATA_FORMAT_VERSION", "DEFAULT_STORAGE_FILENAME", "ASSERTION_LIFETIME", "ASSERTION_USE_PERIOD", "CERT_LIFETIME", "KEY_LIFETIME", "POLL_SESSION", "ONLOGIN_NOTIFICATION", "ONVERIFIED_NOTIFICATION", "ONLOGOUT_NOTIFICATION", "ON_FXA_UPDATE_NOTIFICATION", "ON_DEVICE_CONNECTED_NOTIFICATION", "ON_DEVICE_DISCONNECTED_NOTIFICATION", "ON_PROFILE_UPDATED_NOTIFICATION", "ON_PASSWORD_CHANGED_NOTIFICATION", "ON_PASSWORD_RESET_NOTIFICATION", "ON_VERIFY_LOGIN_NOTIFICATION", "ON_ACCOUNT_DESTROYED_NOTIFICATION", "ON_COLLECTION_CHANGED_NOTIFICATION", "FXA_PUSH_SCOPE_ACCOUNT_UPDATE", "ON_PROFILE_CHANGE_NOTIFICATION", "ON_ACCOUNT_STATE_CHANGE_NOTIFICATION", "UI_REQUEST_SIGN_IN_FLOW", "UI_REQUEST_REFRESH_AUTH", "FX_OAUTH_CLIENT_ID", "WEBCHANNEL_ID", "PREF_LAST_FXA_USER", "ERRNO_ACCOUNT_ALREADY_EXISTS", "ERRNO_ACCOUNT_DOES_NOT_EXIST", "ERRNO_INCORRECT_PASSWORD", "ERRNO_UNVERIFIED_ACCOUNT", "ERRNO_INVALID_VERIFICATION_CODE", "ERRNO_NOT_VALID_JSON_BODY", "ERRNO_INVALID_BODY_PARAMETERS", "ERRNO_MISSING_BODY_PARAMETERS", "ERRNO_INVALID_REQUEST_SIGNATURE", "ERRNO_INVALID_AUTH_TOKEN", "ERRNO_INVALID_AUTH_TIMESTAMP", "ERRNO_MISSING_CONTENT_LENGTH", "ERRNO_REQUEST_BODY_TOO_LARGE", "ERRNO_TOO_MANY_CLIENT_REQUESTS", "ERRNO_INVALID_AUTH_NONCE", "ERRNO_ENDPOINT_NO_LONGER_SUPPORTED", "ERRNO_INCORRECT_LOGIN_METHOD", "ERRNO_INCORRECT_KEY_RETRIEVAL_METHOD", "ERRNO_INCORRECT_API_VERSION", "ERRNO_INCORRECT_EMAIL_CASE", "ERRNO_ACCOUNT_LOCKED", "ERRNO_ACCOUNT_UNLOCKED", "ERRNO_UNKNOWN_DEVICE", "ERRNO_DEVICE_SESSION_CONFLICT", "ERRNO_SERVICE_TEMP_UNAVAILABLE", "ERRNO_PARSE", "ERRNO_NETWORK", "ERRNO_UNKNOWN_ERROR", "OAUTH_SERVER_ERRNO_OFFSET", "ERRNO_UNKNOWN_CLIENT_ID", "ERRNO_INCORRECT_CLIENT_SECRET", "ERRNO_INCORRECT_REDIRECT_URI", "ERRNO_INVALID_FXA_ASSERTION", "ERRNO_UNKNOWN_CODE", "ERRNO_INCORRECT_CODE", "ERRNO_EXPIRED_CODE", "ERRNO_OAUTH_INVALID_TOKEN", "ERRNO_INVALID_REQUEST_PARAM", "ERRNO_INVALID_RESPONSE_TYPE", "ERRNO_UNAUTHORIZED", "ERRNO_FORBIDDEN", "ERRNO_INVALID_CONTENT_TYPE", "ERROR_ACCOUNT_ALREADY_EXISTS", "ERROR_ACCOUNT_DOES_NOT_EXIST", "ERROR_ACCOUNT_LOCKED", "ERROR_ACCOUNT_UNLOCKED", "ERROR_ALREADY_SIGNED_IN_USER", "ERROR_DEVICE_SESSION_CONFLICT", "ERROR_ENDPOINT_NO_LONGER_SUPPORTED", "ERROR_INCORRECT_API_VERSION", "ERROR_INCORRECT_EMAIL_CASE", "ERROR_INCORRECT_KEY_RETRIEVAL_METHOD", "ERROR_INCORRECT_LOGIN_METHOD", "ERROR_INVALID_EMAIL", "ERROR_INVALID_AUDIENCE", "ERROR_INVALID_AUTH_TOKEN", "ERROR_INVALID_AUTH_TIMESTAMP", "ERROR_INVALID_AUTH_NONCE", "ERROR_INVALID_BODY_PARAMETERS", "ERROR_INVALID_PASSWORD", "ERROR_INVALID_VERIFICATION_CODE", "ERROR_INVALID_REFRESH_AUTH_VALUE", "ERROR_INVALID_REQUEST_SIGNATURE", "ERROR_INTERNAL_INVALID_USER", "ERROR_MISSING_BODY_PARAMETERS", "ERROR_MISSING_CONTENT_LENGTH", "ERROR_NO_TOKEN_SESSION", "ERROR_NO_SILENT_REFRESH_AUTH", "ERROR_NOT_VALID_JSON_BODY", "ERROR_OFFLINE", "ERROR_PERMISSION_DENIED", "ERROR_REQUEST_BODY_TOO_LARGE", "ERROR_SERVER_ERROR", "ERROR_SYNC_DISABLED", "ERROR_TOO_MANY_CLIENT_REQUESTS", "ERROR_SERVICE_TEMP_UNAVAILABLE", "ERROR_UI_ERROR", "ERROR_UI_REQUEST", "ERROR_PARSE", "ERROR_NETWORK", "ERROR_UNKNOWN", "ERROR_UNKNOWN_DEVICE", "ERROR_UNVERIFIED_ACCOUNT", "ERROR_UNKNOWN_CLIENT_ID", "ERROR_INCORRECT_CLIENT_SECRET", "ERROR_INCORRECT_REDIRECT_URI", "ERROR_INVALID_FXA_ASSERTION", "ERROR_UNKNOWN_CODE", "ERROR_INCORRECT_CODE", "ERROR_EXPIRED_CODE", "ERROR_OAUTH_INVALID_TOKEN", "ERROR_INVALID_REQUEST_PARAM", "ERROR_INVALID_RESPONSE_TYPE", "ERROR_UNAUTHORIZED", "ERROR_FORBIDDEN", "ERROR_INVALID_CONTENT_TYPE", "ERROR_NO_ACCOUNT", "ERROR_AUTH_ERROR", "ERROR_INVALID_PARAMETER", "ERROR_CODE_METHOD_NOT_ALLOWED", "ERROR_MSG_METHOD_NOT_ALLOWED", "FXA_PWDMGR_PLAINTEXT_FIELDS", "FXA_PWDMGR_SECURE_FIELDS", "FXA_PWDMGR_MEMORY_FIELDS", "FXA_PWDMGR_REAUTH_WHITELIST", "FXA_PWDMGR_HOST", "FXA_PWDMGR_REALM", "SERVER_ERRNO_TO_ERROR", "ERROR_TO_GENERAL_ERROR_CLASS"], "FxAccountsOAuthGrantClient.jsm": ["FxAccountsOAuthGrantClient", "FxAccountsOAuthGrantClientError"], "FxAccountsProfileClient.jsm": ["FxAccountsProfileClient", "FxAccountsProfileClientError"], "FxAccountsPush.js": ["FxAccountsPushService"],