diff --git a/accessible/jsat/Constants.jsm b/accessible/jsat/Constants.jsm index bf97b60a51a3..8a1591a9b81b 100644 --- a/accessible/jsat/Constants.jsm +++ b/accessible/jsat/Constants.jsm @@ -1,19 +1,19 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const AndroidEvents = { - ANDROID_VIEW_CLICKED: 0x01, - ANDROID_VIEW_LONG_CLICKED: 0x02, - ANDROID_VIEW_SELECTED: 0x04, - ANDROID_VIEW_FOCUSED: 0x08, - ANDROID_VIEW_TEXT_CHANGED: 0x10, - ANDROID_WINDOW_STATE_CHANGED: 0x20, - ANDROID_VIEW_HOVER_ENTER: 0x80, - ANDROID_VIEW_HOVER_EXIT: 0x100, - ANDROID_VIEW_SCROLLED: 0x1000, - ANDROID_VIEW_TEXT_SELECTION_CHANGED: 0x2000, - ANDROID_ANNOUNCEMENT: 0x4000, - ANDROID_VIEW_ACCESSIBILITY_FOCUSED: 0x8000, - ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000, + VIEW_CLICKED: 0x01, + VIEW_LONG_CLICKED: 0x02, + VIEW_SELECTED: 0x04, + VIEW_FOCUSED: 0x08, + VIEW_TEXT_CHANGED: 0x10, + WINDOW_STATE_CHANGED: 0x20, + VIEW_HOVER_ENTER: 0x80, + VIEW_HOVER_EXIT: 0x100, + VIEW_SCROLLED: 0x1000, + VIEW_TEXT_SELECTION_CHANGED: 0x2000, + ANNOUNCEMENT: 0x4000, + VIEW_ACCESSIBILITY_FOCUSED: 0x8000, + VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000, }; function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) { diff --git a/accessible/jsat/Presentation.jsm b/accessible/jsat/Presentation.jsm index 2bf90f221d1e..a0cc6d1dba12 100644 --- a/accessible/jsat/Presentation.jsm +++ b/accessible/jsat/Presentation.jsm @@ -44,13 +44,13 @@ class AndroidPresentor { let isExploreByTouch = (aReason == Ci.nsIAccessiblePivot.REASON_POINT && Utils.AndroidSdkVersion >= 14); let focusEventType = (Utils.AndroidSdkVersion >= 16) ? - AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED : - AndroidEvents.ANDROID_VIEW_FOCUSED; + AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED : + AndroidEvents.VIEW_FOCUSED; if (isExploreByTouch) { // This isn't really used by TalkBack so this is a half-hearted attempt // for now. - androidEvents.push({eventType: AndroidEvents.ANDROID_VIEW_HOVER_EXIT, text: []}); + androidEvents.push({eventType: AndroidEvents.VIEW_HOVER_EXIT, text: []}); } if (aReason === Ci.nsIAccessiblePivot.REASON_TEXT) { @@ -58,7 +58,7 @@ class AndroidPresentor { let adjustedText = context.textAndAdjustedOffsets; androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, text: [adjustedText.text], fromIndex: adjustedText.startOffset, toIndex: adjustedText.endOffset @@ -67,7 +67,7 @@ class AndroidPresentor { } else { let state = Utils.getState(context.accessible); androidEvents.push({eventType: (isExploreByTouch) ? - AndroidEvents.ANDROID_VIEW_HOVER_ENTER : focusEventType, + AndroidEvents.VIEW_HOVER_ENTER : focusEventType, text: Utils.localize(UtteranceGenerator.genForContext( context)), bounds: context.bounds, @@ -105,7 +105,7 @@ class AndroidPresentor { } return [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, text, checked: state.contains(States.CHECKED) }]; @@ -116,7 +116,7 @@ class AndroidPresentor { */ textChanged(aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) { let androidEvent = { - eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_CHANGED, text: [aText], fromIndex: aStart, removedCount: 0, @@ -144,7 +144,7 @@ class AndroidPresentor { if (Utils.AndroidSdkVersion >= 14 && !aIsFromUserInput) { androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED, text: [aText], fromIndex: aStart, toIndex: aEnd, @@ -156,7 +156,7 @@ class AndroidPresentor { let [from, to] = aOldStart < aStart ? [aOldStart, aStart] : [aStart, aOldStart]; androidEvents.push({ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, text: [aText], fromIndex: from, toIndex: to @@ -229,7 +229,7 @@ class AndroidPresentor { } let events = [{ - eventType: AndroidEvents.ANDROID_VIEW_SCROLLED, + eventType: AndroidEvents.VIEW_SCROLLED, text: [], scrollX: aWindow.scrollX, scrollY: aWindow.scrollY, @@ -241,7 +241,7 @@ class AndroidPresentor { let currentAcc = currentContext.accessibleForBounds; if (Utils.isAliveAndVisible(currentAcc)) { events.push({ - eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED, + eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED, bounds: Utils.getBounds(currentAcc) }); } @@ -264,8 +264,8 @@ class AndroidPresentor { let localizedAnnouncement = Utils.localize(aAnnouncement).join(" "); return [{ eventType: (Utils.AndroidSdkVersion >= 16) ? - AndroidEvents.ANDROID_ANNOUNCEMENT : - AndroidEvents.ANDROID_VIEW_TEXT_CHANGED, + AndroidEvents.ANNOUNCEMENT : + AndroidEvents.VIEW_TEXT_CHANGED, text: [localizedAnnouncement], addedCount: localizedAnnouncement.length, removedCount: 0, @@ -280,7 +280,7 @@ class AndroidPresentor { */ noMove(aMoveMethod) { return [{ - eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED, + eventType: AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED, exitView: aMoveMethod, text: [""] }]; diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js index 9da2acfd155b..11fb74c14ea5 100644 --- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -551,7 +551,7 @@ ExpectedPresent.prototype.ignore = function(aMessage) { let firstEvent = (aMessage.json || [])[0]; - return firstEvent && firstEvent.eventType === AndroidEvents.ANDROID_VIEW_SCROLLED; + return firstEvent && firstEvent.eventType === AndroidEvents.VIEW_SCROLLED; }; function ExpectedCursorChange(aSpeech, aOptions) { @@ -564,7 +564,7 @@ ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype); function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, fromIndex: aStartOffset, toIndex: aEndOffset }], aOptions); @@ -578,7 +578,7 @@ ExpectedCursorTextChange.prototype = function ExpectedClickAction(aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED + eventType: AndroidEvents.VIEW_CLICKED }], aOptions); } @@ -586,7 +586,7 @@ ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype); function ExpectedCheckAction(aChecked, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, checked: aChecked }], aOptions); } @@ -595,7 +595,7 @@ ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype); function ExpectedSwitchAction(aSwitched, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_CLICKED, + eventType: AndroidEvents.VIEW_CLICKED, checked: aSwitched }], aOptions); } @@ -619,7 +619,7 @@ ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype); // XXX: Implement Android event? function ExpectedTextChanged(aValue, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED + eventType: AndroidEvents.VIEW_TEXT_CHANGED }], aOptions); } @@ -634,7 +634,7 @@ ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype); function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED, + eventType: AndroidEvents.VIEW_TEXT_SELECTION_CHANGED, }], aOptions); } @@ -643,7 +643,7 @@ ExpectedTextSelectionChanged.prototype = function ExpectedTextCaretChanged(aFrom, aTo, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + eventType: AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, fromIndex: aFrom, toIndex: aTo }], aOptions); @@ -653,7 +653,7 @@ ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype); function ExpectedAnnouncement(aAnnouncement, aOptions) { ExpectedPresent.call(this, [{ - eventType: AndroidEvents.ANDROID_ANNOUNCEMENT, + eventType: AndroidEvents.ANNOUNCEMENT, text: [ aAnnouncement], addedCount: aAnnouncement.length }], aOptions); diff --git a/accessible/tests/mochitest/jsat/test_live_regions.html b/accessible/tests/mochitest/jsat/test_live_regions.html index 0d23786e27a0..0cffb4fb758e 100644 --- a/accessible/tests/mochitest/jsat/test_live_regions.html +++ b/accessible/tests/mochitest/jsat/test_live_regions.html @@ -57,7 +57,7 @@ var tests = [{ expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -71,7 +71,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -86,7 +86,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -100,7 +100,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -115,7 +115,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -129,7 +129,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -144,7 +144,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -158,7 +158,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -173,7 +173,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -187,7 +187,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden I will be hidden"], "addedCount": "hidden I will be hidden".length, "removedCount": 0, @@ -201,7 +201,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -215,7 +215,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I will be shown"], "addedCount": "I will be shown".length, "removedCount": 0, @@ -229,7 +229,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Text Added"], "addedCount": "Text Added".length, "removedCount": 0, @@ -243,7 +243,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Text Added"], "addedCount": "Text Added".length, "removedCount": 0, @@ -257,7 +257,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Text Removed"], "addedCount": "hidden Text Removed".length, "removedCount": 0, @@ -271,7 +271,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -285,7 +285,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -299,7 +299,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Descendant Text Removed"], "addedCount": "hidden Descendant Text Removed".length, "removedCount": 0, @@ -313,7 +313,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -327,7 +327,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["Descendant Text Added"], "addedCount": "Descendant Text Added".length, "removedCount": 0, @@ -341,7 +341,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["hidden Descendant Text Removed"], "addedCount": "hidden Descendant Text Removed".length, "removedCount": 0, @@ -355,7 +355,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am replaced main"], "addedCount": "I am replaced main".length, "removedCount": 0, @@ -370,7 +370,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am a replaced text"], "addedCount": "I am a replaced text".length, "removedCount": 0, @@ -384,7 +384,7 @@ } }, { expected: [{ - "eventType": AndroidEvents.ANDROID_ANNOUNCEMENT, + "eventType": AndroidEvents.ANNOUNCEMENT, "text": ["I am a replaced text"], "addedCount": "I am a replaced text".length, "removedCount": 0, diff --git a/browser/app/LauncherProcessWin.cpp b/browser/app/LauncherProcessWin.cpp new file mode 100644 index 000000000000..ff2b3329ac29 --- /dev/null +++ b/browser/app/LauncherProcessWin.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "LauncherProcessWin.h" + +#include + +#include "mozilla/Attributes.h" +#include "mozilla/CmdLineAndEnvUtils.h" +#include "mozilla/Maybe.h" +#include "mozilla/SafeMode.h" +#include "mozilla/UniquePtr.h" +#include "nsWindowsHelpers.h" + +#include + +#include "ProcThreadAttributes.h" + +/** + * At this point the child process has been created in a suspended state. Any + * additional startup work (eg, blocklist setup) should go here. + * + * @return true if browser startup should proceed, otherwise false. + */ +static bool +PostCreationSetup(HANDLE aChildProcess, HANDLE aChildMainThread, + const bool aIsSafeMode) +{ + return true; +} + +/** + * Any mitigation policies that should be set on the browser process should go + * here. + */ +static void +SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs, const bool aIsSafeMode) +{ +} + +static void +ShowError(DWORD aError = ::GetLastError()) +{ + if (aError == ERROR_SUCCESS) { + return; + } + + LPWSTR rawMsgBuf = nullptr; + DWORD result = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + aError, 0, reinterpret_cast(&rawMsgBuf), + 0, nullptr); + if (!result) { + return; + } + + ::MessageBoxW(nullptr, rawMsgBuf, L"Firefox", MB_OK | MB_ICONERROR); + ::LocalFree(rawMsgBuf); +} + +namespace mozilla { + +// Eventually we want to be able to set a build config flag such that, when set, +// this function will always return true. +bool +RunAsLauncherProcess(int& argc, wchar_t** argv) +{ + return CheckArg(argc, argv, L"launcher", + static_cast(nullptr), + CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); +} + +int +LauncherMain(int argc, wchar_t* argv[]) +{ + UniquePtr cmdLine(MakeCommandLine(argc, argv)); + if (!cmdLine) { + return 1; + } + + const Maybe isSafeMode = IsSafeModeRequested(argc, argv, + SafeModeFlag::None); + if (!isSafeMode) { + ShowError(ERROR_INVALID_PARAMETER); + return 1; + } + + ProcThreadAttributes attrs; + SetMitigationPolicies(attrs, isSafeMode.value()); + + HANDLE stdHandles[] = { + ::GetStdHandle(STD_INPUT_HANDLE), + ::GetStdHandle(STD_OUTPUT_HANDLE), + ::GetStdHandle(STD_ERROR_HANDLE) + }; + + attrs.AddInheritableHandles(stdHandles); + + DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; + + STARTUPINFOEXW siex; + Maybe attrsOk = attrs.AssignTo(siex); + if (!attrsOk) { + ShowError(); + return 1; + } + + BOOL inheritHandles = FALSE; + + if (attrsOk.value()) { + creationFlags |= EXTENDED_STARTUPINFO_PRESENT; + + siex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + siex.StartupInfo.hStdInput = stdHandles[0]; + siex.StartupInfo.hStdOutput = stdHandles[1]; + siex.StartupInfo.hStdError = stdHandles[2]; + + // Since attrsOk == true, we have successfully set the handle inheritance + // whitelist policy, so only the handles added to attrs will be inherited. + inheritHandles = TRUE; + } + + PROCESS_INFORMATION pi = {}; + if (!::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles, + creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi)) { + ShowError(); + return 1; + } + + nsAutoHandle process(pi.hProcess); + nsAutoHandle mainThread(pi.hThread); + + if (!PostCreationSetup(process.get(), mainThread.get(), isSafeMode.value()) || + ::ResumeThread(mainThread.get()) == static_cast(-1)) { + ShowError(); + ::TerminateProcess(process.get(), 1); + return 1; + } + + return 0; +} + +} // namespace mozilla diff --git a/browser/app/LauncherProcessWin.h b/browser/app/LauncherProcessWin.h new file mode 100644 index 000000000000..b198d30724f6 --- /dev/null +++ b/browser/app/LauncherProcessWin.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_LauncherProcessWin_h +#define mozilla_LauncherProcessWin_h + +namespace mozilla { + +bool RunAsLauncherProcess(int& argc, wchar_t* argv[]); +int LauncherMain(int argc, wchar_t* argv[]); + +} // namespace mozilla + +#endif // mozilla_LauncherProcessWin_h + diff --git a/browser/app/ProcThreadAttributes.h b/browser/app/ProcThreadAttributes.h new file mode 100644 index 000000000000..6287e15b5691 --- /dev/null +++ b/browser/app/ProcThreadAttributes.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ProcThreadAttributes_h +#define mozilla_ProcThreadAttributes_h + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include + +namespace mozilla { + +class MOZ_RAII ProcThreadAttributes final +{ + struct ProcThreadAttributeListDeleter + { + void operator()(LPPROC_THREAD_ATTRIBUTE_LIST aList) + { + ::DeleteProcThreadAttributeList(aList); + delete[] reinterpret_cast(aList); + } + }; + + using ProcThreadAttributeListPtr = + UniquePtr<_PROC_THREAD_ATTRIBUTE_LIST, ProcThreadAttributeListDeleter>; + +public: + ProcThreadAttributes() + : mMitigationPolicies(0) + { + } + + ~ProcThreadAttributes() = default; + + ProcThreadAttributes(const ProcThreadAttributes&) = delete; + ProcThreadAttributes(ProcThreadAttributes&&) = delete; + ProcThreadAttributes& operator=(const ProcThreadAttributes&) = delete; + ProcThreadAttributes& operator=(ProcThreadAttributes&&) = delete; + + void AddMitigationPolicy(DWORD64 aPolicy) + { + mMitigationPolicies |= aPolicy; + } + + bool AddInheritableHandle(HANDLE aHandle) + { + return mInheritableHandles.append(aHandle); + } + + template + bool AddInheritableHandles(HANDLE (&aHandles)[N]) + { + return mInheritableHandles.append(aHandles, N); + } + + /** + * @return Some(false) if the STARTUPINFOEXW::lpAttributeList was set to null + * as expected based on the state of |this|; + * Some(true) if the STARTUPINFOEXW::lpAttributeList was set to + * non-null; + * Nothing() if something went wrong in the assignment and we should + * not proceed. + */ + Maybe AssignTo(STARTUPINFOEXW& aSiex) + { + ZeroMemory(&aSiex, sizeof(STARTUPINFOEXW)); + + // We'll set the size to sizeof(STARTUPINFOW) until we determine whether the + // extended fields will be used. + aSiex.StartupInfo.cb = sizeof(STARTUPINFOW); + + DWORD numAttributes = 0; + if (mMitigationPolicies) { + ++numAttributes; + } + + if (!mInheritableHandles.empty()) { + ++numAttributes; + } + + if (!numAttributes) { + return Some(false); + } + + SIZE_T listSize = 0; + if (!::InitializeProcThreadAttributeList(nullptr, numAttributes, 0, + &listSize) && + ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return Nothing(); + } + + auto buf = MakeUnique(listSize); + + LPPROC_THREAD_ATTRIBUTE_LIST tmpList = + reinterpret_cast(buf.get()); + + if (!::InitializeProcThreadAttributeList(tmpList, numAttributes, 0, + &listSize)) { + return Nothing(); + } + + // Transfer buf to a ProcThreadAttributeListPtr - now that the list is + // initialized, we are no longer dealing with a plain old char array. We + // must now deinitialize the attribute list before deallocating the + // underlying buffer. + ProcThreadAttributeListPtr + attrList(reinterpret_cast(buf.release())); + + if (mMitigationPolicies) { + if (!::UpdateProcThreadAttribute(attrList.get(), 0, + PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, + &mMitigationPolicies, + sizeof(mMitigationPolicies), nullptr, + nullptr)) { + return Nothing(); + } + } + + if (!mInheritableHandles.empty()) { + if (!::UpdateProcThreadAttribute(attrList.get(), 0, + PROC_THREAD_ATTRIBUTE_HANDLE_LIST, + mInheritableHandles.begin(), + mInheritableHandles.length() * sizeof(HANDLE), + nullptr, nullptr)) { + return Nothing(); + } + } + + mAttrList = Move(attrList); + aSiex.lpAttributeList = mAttrList.get(); + aSiex.StartupInfo.cb = sizeof(STARTUPINFOEXW); + return Some(true); + } + +private: + static const uint32_t kNumInline = 3; // Inline storage for the std handles + + DWORD64 mMitigationPolicies; + Vector mInheritableHandles; + ProcThreadAttributeListPtr mAttrList; +}; + +} // namespace mozilla + +#endif // mozilla_ProcThreadAttributes_h + diff --git a/browser/app/moz.build b/browser/app/moz.build index 44613bd5b5a6..2befbc57c6ce 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -62,6 +62,9 @@ if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'): if CONFIG['OS_ARCH'] == 'WINNT': RCINCLUDE = 'splash.rc' DEFINES['MOZ_PHOENIX'] = True + SOURCES += [ + 'LauncherProcessWin.cpp', + ] if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': # For sandbox includes and the include dependencies those have diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index 022fbaed4586..f9491f43137b 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -23,6 +23,8 @@ #include "nsIFile.h" #ifdef XP_WIN +#include "LauncherProcessWin.h" + #define XRE_WANT_ENVIRON #define strcasecmp _stricmp #ifdef MOZ_SANDBOX diff --git a/build/valgrind/cross-architecture.sup b/build/valgrind/cross-architecture.sup index c81e6558ed0b..a66c90c15161 100644 --- a/build/valgrind/cross-architecture.sup +++ b/build/valgrind/cross-architecture.sup @@ -8,7 +8,14 @@ PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534.) Memcheck:Leak ... - fun:_ZL9SaveToEnvPKc + fun:_ZN7mozilla9SaveToEnvEPKc + ... +} +{ + PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793534.) + Memcheck:Leak + ... + fun:SaveToEnv ... } { diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index 37ecac02387e..4f632bcc0752 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,12 +1,12 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 45.1 +Version 46 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-45...release-45.1 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-45.1...release-46 Packages: -- babel-plugin-transform-es2015-modules-commonjs @6.26.0 +- babel-plugin-transform-es2015-modules-commonjs @6.26.2 - babel-preset-react @6.24.1 - react @16.2.0 - react-dom @16.2.0 diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index c98c29a77fe5..accac7f95d07 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -1965,18 +1965,6 @@ html .toggle-button.end.vertical svg { --comment-node-color: var(--theme-comment); } -.theme-firebug { - --number-color: #000088; - --string-color: #FF0000; - --null-color: #787878; - --object-color: DarkGreen; - --caption-color: #444444; - --location-color: #555555; - --source-link-color: blue; - --node-color: rgb(0, 0, 136); - --reference-color: rgb(102, 102, 255); -} - /******************************************************************************/ .inline { @@ -2012,7 +2000,8 @@ html .toggle-button.end.vertical svg { color: var(--string-color); } -.objectBox-string a, .objectBox-string a:visited { +.objectBox-string a, +.objectBox-string a:visited { color: currentColor; text-decoration: none; font-style: italic; @@ -2205,7 +2194,7 @@ button.open-inspector { display: inline-block; background-color: var(--comment-node-color); height: 16px; - margin-left: .25em; + margin-left: 0.25em; vertical-align: middle; } @@ -2223,7 +2212,7 @@ button.jump-definition { display: inline-block; background-color: var(--comment-node-color); height: 16px; - margin-left: .25em; + margin-left: 0.25em; vertical-align: middle; } @@ -2278,6 +2267,16 @@ button.jump-definition { display: inline-block; vertical-align: middle; } + +/* Focused styles */ +.tree.object-inspector .tree-node.focused * { + color: inherit; +} + +.tree-node.focused button.jump-definition, +.tree-node.focused button.open-inspector { + background-color: currentColor; +} /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index d84b5479da3b..744d16e64681 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -1,13 +1,13 @@ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device")); + module.exports = factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device"), require("devtools/client/shared/vendor/react-prop-types"), require("devtools/client/shared/vendor/react-dom-factories")); else if(typeof define === 'function' && define.amd) - define(["devtools/client/shared/vendor/react", "devtools/client/shared/vendor/lodash", "devtools/client/shared/vendor/react-dom", "Services", "devtools/shared/flags", "devtools/client/sourceeditor/editor", "devtools/client/shared/vendor/WasmParser", "devtools/client/shared/vendor/WasmDis", "devtools/client/shared/vendor/react-redux", "devtools/client/shared/vendor/redux", "devtools/client/shared/vendor/immutable", "devtools/shared/fronts/device"], factory); + define(["devtools/client/shared/vendor/react", "devtools/client/shared/vendor/lodash", "devtools/client/shared/vendor/react-dom", "Services", "devtools/shared/flags", "devtools/client/sourceeditor/editor", "devtools/client/shared/vendor/WasmParser", "devtools/client/shared/vendor/WasmDis", "devtools/client/shared/vendor/react-redux", "devtools/client/shared/vendor/redux", "devtools/client/shared/vendor/immutable", "devtools/shared/fronts/device", "devtools/client/shared/vendor/react-prop-types", "devtools/client/shared/vendor/react-dom-factories"], factory); else { - var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device")) : factory(root["devtools/client/shared/vendor/react"], root["devtools/client/shared/vendor/lodash"], root["devtools/client/shared/vendor/react-dom"], root["Services"], root["devtools/shared/flags"], root["devtools/client/sourceeditor/editor"], root["devtools/client/shared/vendor/WasmParser"], root["devtools/client/shared/vendor/WasmDis"], root["devtools/client/shared/vendor/react-redux"], root["devtools/client/shared/vendor/redux"], root["devtools/client/shared/vendor/immutable"], root["devtools/shared/fronts/device"]); + var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react"), require("devtools/client/shared/vendor/lodash"), require("devtools/client/shared/vendor/react-dom"), require("Services"), require("devtools/shared/flags"), require("devtools/client/sourceeditor/editor"), require("devtools/client/shared/vendor/WasmParser"), require("devtools/client/shared/vendor/WasmDis"), require("devtools/client/shared/vendor/react-redux"), require("devtools/client/shared/vendor/redux"), require("devtools/client/shared/vendor/immutable"), require("devtools/shared/fronts/device"), require("devtools/client/shared/vendor/react-prop-types"), require("devtools/client/shared/vendor/react-dom-factories")) : factory(root["devtools/client/shared/vendor/react"], root["devtools/client/shared/vendor/lodash"], root["devtools/client/shared/vendor/react-dom"], root["Services"], root["devtools/shared/flags"], root["devtools/client/sourceeditor/editor"], root["devtools/client/shared/vendor/WasmParser"], root["devtools/client/shared/vendor/WasmDis"], root["devtools/client/shared/vendor/react-redux"], root["devtools/client/shared/vendor/redux"], root["devtools/client/shared/vendor/immutable"], root["devtools/shared/fronts/device"], root["devtools/client/shared/vendor/react-prop-types"], root["devtools/client/shared/vendor/react-dom-factories"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_22__, __WEBPACK_EXTERNAL_MODULE_52__, __WEBPACK_EXTERNAL_MODULE_197__, __WEBPACK_EXTERNAL_MODULE_677__, __WEBPACK_EXTERNAL_MODULE_678__, __WEBPACK_EXTERNAL_MODULE_3592__, __WEBPACK_EXTERNAL_MODULE_3593__, __WEBPACK_EXTERNAL_MODULE_3594__, __WEBPACK_EXTERNAL_MODULE_3626__) { +})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_22__, __WEBPACK_EXTERNAL_MODULE_52__, __WEBPACK_EXTERNAL_MODULE_197__, __WEBPACK_EXTERNAL_MODULE_677__, __WEBPACK_EXTERNAL_MODULE_678__, __WEBPACK_EXTERNAL_MODULE_3592__, __WEBPACK_EXTERNAL_MODULE_3593__, __WEBPACK_EXTERNAL_MODULE_3594__, __WEBPACK_EXTERNAL_MODULE_3626__, __WEBPACK_EXTERNAL_MODULE_3642__, __WEBPACK_EXTERNAL_MODULE_3643__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -1573,20 +1573,6 @@ module.exports = "`); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(CommentNode), - supportsObject -}; - -/***/ }), - -/***/ 1578: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Utils -const { - isGrip, - wrapRender -} = __webpack_require__(1353); -const { rep: StringRep } = __webpack_require__(1447); -const { MODE } = __webpack_require__(1357); -const nodeConstants = __webpack_require__(1449); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders DOM element node. - */ -ElementNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function ElementNode(props) { - let { - object, - mode, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - let elements = getElements(object, mode); - - let isInTree = object.preview && object.preview.isConnected === true; - - let baseConfig = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-node" - }; - let inspectIcon; - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(object) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(object, e) - }); - } - } - - return span(baseConfig, ...elements, inspectIcon); -} - -function getElements(grip, mode) { - let { attributes, nodeName } = grip.preview; - const nodeNameElement = span({ - className: "tag-name" - }, nodeName); - - if (mode === MODE.TINY) { - let elements = [nodeNameElement]; - if (attributes.id) { - elements.push(span({ className: "attrName" }, `#${attributes.id}`)); - } - if (attributes.class) { - elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); - } - return elements; - } - let attributeKeys = Object.keys(attributes); - if (attributeKeys.includes("class")) { - attributeKeys.splice(attributeKeys.indexOf("class"), 1); - attributeKeys.unshift("class"); - } - if (attributeKeys.includes("id")) { - attributeKeys.splice(attributeKeys.indexOf("id"), 1); - attributeKeys.unshift("id"); - } - const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { - let value = attributes[name]; - let attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); - - return arr.concat([" ", attribute]); - }, []); - - return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ElementNode), - supportsObject -}; - -/***/ }), - -/***/ 1579: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - cropString, - wrapRender -} = __webpack_require__(1353); -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders DOM #text node. - */ -TextNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function TextNode(props) { - let { - object: grip, - mode = MODE.SHORT, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - let baseConfig = { - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-textNode" - }; - let inspectIcon; - let isInTree = grip.preview && grip.preview.isConnected === true; - - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(grip) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(grip, e) - }); - } - } - - if (mode === MODE.TINY) { - return span(baseConfig, getTitle(grip), inspectIcon); - } - - return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); -} - -function getTextContent(grip) { - return cropString(grip.preview.textContent); -} - -function getTitle(grip) { - const title = "#text"; - return span({}, title); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.class == "Text"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(TextNode), - supportsObject -}; - -/***/ }), - -/***/ 1580: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); -// Utils -const { - getGripType, - isGrip, - wrapRender -} = __webpack_require__(1353); -const { cleanFunctionName } = __webpack_require__(1573); -const { isLongString } = __webpack_require__(1447); -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; -const IGNORED_SOURCE_URLS = ["debugger eval code"]; - -/** - * Renders Error objects. - */ -ErrorRep.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) -}; - -function ErrorRep(props) { - let object = props.object; - let preview = object.preview; - - let name; - if (preview && preview.name && preview.kind) { - switch (preview.kind) { - case "Error": - name = preview.name; - break; - case "DOMException": - name = preview.kind; - break; - default: - throw new Error("Unknown preview kind for the Error rep."); - } - } else { - name = "Error"; - } - - const content = []; - - if (props.mode === MODE.TINY) { - content.push(name); - } else { - content.push(`${name}: "${preview.message}"`); - } - - if (preview.stack && props.mode !== MODE.TINY) { - content.push("\n", getStacktraceElements(props, preview)); - } - - return span({ - "data-link-actor-id": object.actor, - className: "objectBox-stackTrace" - }, content); -} - -/** - * Returns a React element reprensenting the Error stacktrace, i.e. transform error.stack - * from: - * - * semicolon@debugger eval code:1:109 - * jkl@debugger eval code:1:63 - * asdf@debugger eval code:1:28 - * @debugger eval code:1:227 - * - * Into a column layout: - * - * semicolon (:8:10) - * jkl (:5:10) - * asdf (:2:10) - * (:11:1) - */ -function getStacktraceElements(props, preview) { - const stack = []; - if (!preview.stack) { - return stack; - } - - const isStacktraceALongString = isLongString(preview.stack); - const stackString = isStacktraceALongString ? preview.stack.initial : preview.stack; - - stackString.split("\n").forEach((frame, index) => { - if (!frame) { - // Skip any blank lines - return; - } - - let functionName; - let location; - - // Given the input: "functionName@scriptLocation:2:100" - // Result: - // ["functionName@scriptLocation:2:100", "functionName", "scriptLocation:2:100"] - const result = frame.match(/^(.*)@(.*)$/); - if (result && result.length === 3) { - functionName = result[1]; - - // If the resource was loaded by base-loader.js, the location looks like: - // resource://devtools/shared/base-loader.js -> resource://path/to/file.js . - // What's needed is only the last part after " -> ". - location = result[2].split(" -> ").pop(); - } - - if (!functionName) { - functionName = ""; - } - - let onLocationClick; - // Given the input: "scriptLocation:2:100" - // Result: - // ["scriptLocation:2:100", "scriptLocation", "2", "100"] - const locationParts = location.match(/^(.*):(\d+):(\d+)$/); - if (props.onViewSourceInDebugger && location && !IGNORED_SOURCE_URLS.includes(locationParts[1]) && locationParts) { - let [, url, line, column] = locationParts; - onLocationClick = e => { - // Don't trigger ObjectInspector expand/collapse. - e.stopPropagation(); - props.onViewSourceInDebugger({ - url, - line: Number(line), - column: Number(column) - }); - }; - } - - stack.push(span({ - key: "fn" + index, - className: "objectBox-stackTrace-fn" - }, cleanFunctionName(functionName)), span({ - key: "location" + index, - className: "objectBox-stackTrace-location", - onClick: onLocationClick, - title: onLocationClick ? "View source in debugger → " + location : undefined - }, location)); - }); - - if (isStacktraceALongString) { - // Remove the last frame (i.e. 2 last elements in the array, the function name and the - // location) which is certainly incomplete. - // Can be removed when https://bugzilla.mozilla.org/show_bug.cgi?id=1448833 is fixed. - stack.splice(-2); - } - - return span({ - key: "stack", - className: "objectBox-stackTrace-grid" - }, stack); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && getGripType(object, noGrip) === "Error" || object.class === "DOMException"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ErrorRep), - supportsObject -}; - -/***/ }), - -/***/ 1581: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - getGripType, - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(1353); - -const { MODE } = __webpack_require__(1357); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip representing a window. - */ -WindowRep.propTypes = { - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - object: PropTypes.object.isRequired -}; - -function WindowRep(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-Window" - }; - - if (mode === MODE.TINY) { - return span(config, getTitle(object)); - } - - return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); -} - -function getTitle(object, trailingSpace) { - let title = object.displayClass || object.class || "Window"; - if (trailingSpace === true) { - title = `${title} `; - } - return span({ className: "objectTitle" }, title); -} - -function getLocation(object) { - return getURLDisplayString(object.preview.url); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - - return object.preview && getGripType(object, noGrip) == "Window"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(WindowRep), - supportsObject -}; - -/***/ }), - -/***/ 1582: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - wrapRender -} = __webpack_require__(1353); - -const String = __webpack_require__(1447).rep; - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip object with textual data. - */ -ObjectWithText.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithText(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectTitle objectBox objectBox-" + getType(grip) - }, `${getType(grip)} `, getDescription(grip)); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return String({ - object: grip.preview.text - }); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithText"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithText), - supportsObject -}; - -/***/ }), - -/***/ 1583: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(20); - -// Reps -const { - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(1353); - -const dom = __webpack_require__(1758); -const { span } = dom; - -/** - * Renders a grip object with URL data. - */ -ObjectWithURL.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithURL(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-" + getType(grip) - }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); -} - -function getTitle(grip) { - return span({ className: "objectTitle" }, getType(grip) + " "); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return getURLDisplayString(grip.preview.url); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithURL"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithURL), - supportsObject -}; - -/***/ }), - -/***/ 1584: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Dependencies - -const { lengthBubble } = __webpack_require__(2249); -const PropTypes = __webpack_require__(20); -const { - interleave, - isGrip, - wrapRender, - ellipsisElement -} = __webpack_require__(1353); -const PropRep = __webpack_require__(1381); -const { MODE } = __webpack_require__(1357); -const { ModePropType } = __webpack_require__(1448); - -const { span } = __webpack_require__(1758); - -/** - * Renders an map. A map is represented by a list of its - * entries enclosed in curly brackets. - */ -GripMap.propTypes = { - object: PropTypes.object, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: ModePropType, - isInterestingEntry: PropTypes.func, - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func, - title: PropTypes.string -}; - -function GripMap(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-object" - }; - - const title = getTitle(props, object); - const isEmpty = getLength(object) === 0; - - if (isEmpty || mode === MODE.TINY) { - return span(config, title); - } - - const propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode)); - - return span(config, title, span({ - className: "objectLeftBrace" - }, " { "), ...interleave(propsArray, ", "), span({ - className: "objectRightBrace" - }, " }")); -} - -function getTitle(props, object) { - const title = props.title || (object && object.class ? object.class : "Map"); - return span({ - className: "objectTitle" }, title, lengthBubble({ - object, - mode: props.mode, - maxLengthMap, - getLength, - showZeroLength: true - })); -} - -function safeEntriesIterator(props, object, max) { - max = typeof max === "undefined" ? 3 : max; - try { - return entriesIterator(props, object, max); - } catch (err) { - console.error(err); - } - return []; -} - -function entriesIterator(props, object, max) { - // Entry filter. Show only interesting entries to the user. - let isInterestingEntry = props.isInterestingEntry || ((type, value) => { - return type == "boolean" || type == "number" || type == "string" && value.length != 0; - }); - - let mapEntries = object.preview && object.preview.entries ? object.preview.entries : []; - - let indexes = getEntriesIndexes(mapEntries, max, isInterestingEntry); - if (indexes.length < max && indexes.length < mapEntries.length) { - // There are not enough entries yet, so we add uninteresting entries. - indexes = indexes.concat(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => { - return !isInterestingEntry(t, value, name); - })); - } - - let entries = getEntries(props, mapEntries, indexes); - if (entries.length < getLength(object)) { - // There are some undisplayed entries. Then display "…". - entries.push(ellipsisElement); - } - - return entries; -} - -/** - * Get entries ordered by index. - * - * @param {Object} props Component props. - * @param {Array} entries Entries array. - * @param {Array} indexes Indexes of entries. - * @return {Array} Array of PropRep. - */ -function getEntries(props, entries, indexes) { - let { - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - // Make indexes ordered by ascending. - indexes.sort(function (a, b) { - return a - b; - }); - - return indexes.map((index, i) => { - let [key, entryValue] = entries[index]; - let value = entryValue.value !== undefined ? entryValue.value : entryValue; - - return PropRep({ - name: key, - equal: " \u2192 ", - object: value, - mode: MODE.TINY, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - }); - }); -} - -/** - * Get the indexes of entries in the map. - * - * @param {Array} entries Entries array. - * @param {Number} max The maximum length of indexes array. - * @param {Function} filter Filter the entry you want. - * @return {Array} Indexes of filtered entries in the map. - */ -function getEntriesIndexes(entries, max, filter) { - return entries.reduce((indexes, [key, entry], i) => { - if (indexes.length < max) { - let value = entry && entry.value !== undefined ? entry.value : entry; - // Type is specified in grip's "class" field and for primitive - // values use typeof. - let type = (value && value.class ? value.class : typeof value).toLowerCase(); - - if (filter(type, value, key)) { - indexes.push(i); - } - } - - return indexes; - }, []); -} - -function getLength(grip) { - return grip.preview.size || 0; -} - -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - return grip.preview && grip.preview.kind == "MapLike"; -} - -const maxLengthMap = new Map(); -maxLengthMap.set(MODE.SHORT, 3); -maxLengthMap.set(MODE.LONG, 10); - -// Exports from this module -module.exports = { - rep: wrapRender(GripMap), - supportsObject, - maxLengthMap, - getLength -}; - -/***/ }), - -/***/ 1585: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { createElement, createFactory, PureComponent } = __webpack_require__(0); -const { Provider } = __webpack_require__(3592); -const ObjectInspector = createFactory(__webpack_require__(3615)); -const createStore = __webpack_require__(3618); -const Utils = __webpack_require__(1938); -const { - renderRep, - shouldRenderRootsInReps -} = Utils; - -class OI extends PureComponent { - - constructor(props) { - super(props); - this.store = createStore(props); - } - - getStore() { - return this.store; - } - - render() { - return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); - } -} - -module.exports = props => { - let { roots } = props; - if (shouldRenderRootsInReps(roots)) { - return renderRep(roots[0], props); - } - return new OI(props); -}; - -/***/ }), - /***/ 1586: /***/ (function(module, exports, __webpack_require__) { @@ -21830,7 +16881,9 @@ function getCallSites(symbols, breakpoints) { } function findBreakpoint(callSite) { - const { location: { start, end } } = callSite; + const { + location: { start, end } + } = callSite; const breakpointId = (0, _lodash.range)(start.column - 1, end.column).map(column => locationKey({ line: start.line, column })).find(key => bpLocationMap[key]); @@ -22333,7 +17386,7 @@ var _reactRedux = __webpack_require__(3592); var _devtoolsContextmenu = __webpack_require__(1413); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _clipboard = __webpack_require__(1388); @@ -22443,7 +17496,9 @@ function getMenuItems(event, { accesskey: copyFunctionKey, disabled: !functionText, click: () => { - const { location: { start, end } } = getFunctionLocation(sourceLine); + const { + location: { start, end } + } = getFunctionLocation(sourceLine); flashLineRange({ start: start.line, end: end.line, @@ -22823,7 +17878,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -22997,7 +18052,9 @@ class SecondaryPanes extends _react.Component { } getComponentItem() { - const { extra: { react } } = this.props; + const { + extra: { react } + } = this.props; return { header: react.displayName, @@ -23442,7 +18499,7 @@ var _classnames = __webpack_require__(175); var _classnames2 = _interopRequireDefault(_classnames); -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); var _actions = __webpack_require__(1354); @@ -23558,7 +18615,7 @@ class Expressions extends _react.Component { roots: [root], autoExpandDepth: 0, disableWrap: true, - disabledFocus: true, + focusable: false, openLink: openLink, createObjectClient: grip => (0, _firefox.createObjectClient)(grip) }), @@ -24439,7 +19496,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -24924,7 +19981,7 @@ var _selectors = __webpack_require__(3590); var _scopes = __webpack_require__(1792); -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); __webpack_require__(1296); @@ -24983,7 +20040,7 @@ class Scopes extends _react.PureComponent { autoExpandAll: false, autoExpandDepth: 1, disableWrap: true, - disabledFocus: true, + focusable: false, dimTopLevelWindow: true, createObjectClient: grip => (0, _firefox.createObjectClient)(grip) }), @@ -25890,7 +20947,7 @@ var _prefs = __webpack_require__(226); var _log = __webpack_require__(2359); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } @@ -27103,7 +22160,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.paused = paused; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _selectors = __webpack_require__(3590); @@ -27595,7 +22652,9 @@ class QuickOpenModal extends _react.Component { }; this.searchSymbols = query => { - const { symbols: { functions, variables } } = this.props; + const { + symbols: { functions, variables } + } = this.props; let results = functions; if (this.isVariableQuery()) { @@ -28797,341 +23856,6 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! }()); -/***/ }), - -/***/ 1758: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -(function(f) { - if (true) { - module.exports = f(__webpack_require__(0)); - /* global define */ - } else if (typeof define === 'function' && define.amd) { - define(['react'], f); - } else { - var g; - if (typeof window !== 'undefined') { - g = window; - } else if (typeof global !== 'undefined') { - g = global; - } else if (typeof self !== 'undefined') { - g = self; - } else { - g = this; - } - - if (typeof g.React === 'undefined') { - throw Error('React module should be required before ReactDOMFactories'); - } - - g.ReactDOMFactories = f(g.React); - } -})(function(React) { - /** - * Create a factory that creates HTML tag elements. - */ - function createDOMFactory(type) { - var factory = React.createElement.bind(null, type); - // Expose the type on the factory and the prototype so that it can be - // easily accessed on elements. E.g. `.type === Foo`. - // This should not be named `constructor` since this may not be the function - // that created the element, and it may not even be a constructor. - factory.type = type; - return factory; - }; - - /** - * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes. - */ - var ReactDOMFactories = { - a: createDOMFactory('a'), - abbr: createDOMFactory('abbr'), - address: createDOMFactory('address'), - area: createDOMFactory('area'), - article: createDOMFactory('article'), - aside: createDOMFactory('aside'), - audio: createDOMFactory('audio'), - b: createDOMFactory('b'), - base: createDOMFactory('base'), - bdi: createDOMFactory('bdi'), - bdo: createDOMFactory('bdo'), - big: createDOMFactory('big'), - blockquote: createDOMFactory('blockquote'), - body: createDOMFactory('body'), - br: createDOMFactory('br'), - button: createDOMFactory('button'), - canvas: createDOMFactory('canvas'), - caption: createDOMFactory('caption'), - cite: createDOMFactory('cite'), - code: createDOMFactory('code'), - col: createDOMFactory('col'), - colgroup: createDOMFactory('colgroup'), - data: createDOMFactory('data'), - datalist: createDOMFactory('datalist'), - dd: createDOMFactory('dd'), - del: createDOMFactory('del'), - details: createDOMFactory('details'), - dfn: createDOMFactory('dfn'), - dialog: createDOMFactory('dialog'), - div: createDOMFactory('div'), - dl: createDOMFactory('dl'), - dt: createDOMFactory('dt'), - em: createDOMFactory('em'), - embed: createDOMFactory('embed'), - fieldset: createDOMFactory('fieldset'), - figcaption: createDOMFactory('figcaption'), - figure: createDOMFactory('figure'), - footer: createDOMFactory('footer'), - form: createDOMFactory('form'), - h1: createDOMFactory('h1'), - h2: createDOMFactory('h2'), - h3: createDOMFactory('h3'), - h4: createDOMFactory('h4'), - h5: createDOMFactory('h5'), - h6: createDOMFactory('h6'), - head: createDOMFactory('head'), - header: createDOMFactory('header'), - hgroup: createDOMFactory('hgroup'), - hr: createDOMFactory('hr'), - html: createDOMFactory('html'), - i: createDOMFactory('i'), - iframe: createDOMFactory('iframe'), - img: createDOMFactory('img'), - input: createDOMFactory('input'), - ins: createDOMFactory('ins'), - kbd: createDOMFactory('kbd'), - keygen: createDOMFactory('keygen'), - label: createDOMFactory('label'), - legend: createDOMFactory('legend'), - li: createDOMFactory('li'), - link: createDOMFactory('link'), - main: createDOMFactory('main'), - map: createDOMFactory('map'), - mark: createDOMFactory('mark'), - menu: createDOMFactory('menu'), - menuitem: createDOMFactory('menuitem'), - meta: createDOMFactory('meta'), - meter: createDOMFactory('meter'), - nav: createDOMFactory('nav'), - noscript: createDOMFactory('noscript'), - object: createDOMFactory('object'), - ol: createDOMFactory('ol'), - optgroup: createDOMFactory('optgroup'), - option: createDOMFactory('option'), - output: createDOMFactory('output'), - p: createDOMFactory('p'), - param: createDOMFactory('param'), - picture: createDOMFactory('picture'), - pre: createDOMFactory('pre'), - progress: createDOMFactory('progress'), - q: createDOMFactory('q'), - rp: createDOMFactory('rp'), - rt: createDOMFactory('rt'), - ruby: createDOMFactory('ruby'), - s: createDOMFactory('s'), - samp: createDOMFactory('samp'), - script: createDOMFactory('script'), - section: createDOMFactory('section'), - select: createDOMFactory('select'), - small: createDOMFactory('small'), - source: createDOMFactory('source'), - span: createDOMFactory('span'), - strong: createDOMFactory('strong'), - style: createDOMFactory('style'), - sub: createDOMFactory('sub'), - summary: createDOMFactory('summary'), - sup: createDOMFactory('sup'), - table: createDOMFactory('table'), - tbody: createDOMFactory('tbody'), - td: createDOMFactory('td'), - textarea: createDOMFactory('textarea'), - tfoot: createDOMFactory('tfoot'), - th: createDOMFactory('th'), - thead: createDOMFactory('thead'), - time: createDOMFactory('time'), - title: createDOMFactory('title'), - tr: createDOMFactory('tr'), - track: createDOMFactory('track'), - u: createDOMFactory('u'), - ul: createDOMFactory('ul'), - var: createDOMFactory('var'), - video: createDOMFactory('video'), - wbr: createDOMFactory('wbr'), - - // SVG - circle: createDOMFactory('circle'), - clipPath: createDOMFactory('clipPath'), - defs: createDOMFactory('defs'), - ellipse: createDOMFactory('ellipse'), - g: createDOMFactory('g'), - image: createDOMFactory('image'), - line: createDOMFactory('line'), - linearGradient: createDOMFactory('linearGradient'), - mask: createDOMFactory('mask'), - path: createDOMFactory('path'), - pattern: createDOMFactory('pattern'), - polygon: createDOMFactory('polygon'), - polyline: createDOMFactory('polyline'), - radialGradient: createDOMFactory('radialGradient'), - rect: createDOMFactory('rect'), - stop: createDOMFactory('stop'), - svg: createDOMFactory('svg'), - text: createDOMFactory('text'), - tspan: createDOMFactory('tspan'), - }; - - // due to wrapper and conditionals at the top, this will either become - // `module.exports ReactDOMFactories` if that is available, - // otherwise it will be defined via `define(['react'], ReactDOMFactories)` - // if that is available, - // otherwise it will be defined as global variable. - return ReactDOMFactories; -}); - - - -/***/ }), - -/***/ 1759: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var EventEmitter = function EventEmitter() {}; -module.exports = EventEmitter; - -const promise = __webpack_require__(1769); - -/** - * Decorate an object with event emitter functionality. - * - * @param Object aObjectToDecorate - * Bind all public methods of EventEmitter to - * the aObjectToDecorate object. - */ -EventEmitter.decorate = function EventEmitter_decorate(aObjectToDecorate) { - let emitter = new EventEmitter(); - aObjectToDecorate.on = emitter.on.bind(emitter); - aObjectToDecorate.off = emitter.off.bind(emitter); - aObjectToDecorate.once = emitter.once.bind(emitter); - aObjectToDecorate.emit = emitter.emit.bind(emitter); -}; - -EventEmitter.prototype = { - /** - * Connect a listener. - * - * @param string aEvent - * The event name to which we're connecting. - * @param function aListener - * Called when the event is fired. - */ - on: function EventEmitter_on(aEvent, aListener) { - if (!this._eventEmitterListeners) this._eventEmitterListeners = new Map(); - if (!this._eventEmitterListeners.has(aEvent)) { - this._eventEmitterListeners.set(aEvent, []); - } - this._eventEmitterListeners.get(aEvent).push(aListener); - }, - - /** - * Listen for the next time an event is fired. - * - * @param string aEvent - * The event name to which we're connecting. - * @param function aListener - * (Optional) Called when the event is fired. Will be called at most - * one time. - * @return promise - * A promise which is resolved when the event next happens. The - * resolution value of the promise is the first event argument. If - * you need access to second or subsequent event arguments (it's rare - * that this is needed) then use aListener - */ - once: function EventEmitter_once(aEvent, aListener) { - let deferred = promise.defer(); - - let handler = (aEvent, aFirstArg, ...aRest) => { - this.off(aEvent, handler); - if (aListener) { - aListener.apply(null, [aEvent, aFirstArg, ...aRest]); - } - deferred.resolve(aFirstArg); - }; - - handler._originalListener = aListener; - this.on(aEvent, handler); - - return deferred.promise; - }, - - /** - * Remove a previously-registered event listener. Works for events - * registered with either on or once. - * - * @param string aEvent - * The event name whose listener we're disconnecting. - * @param function aListener - * The listener to remove. - */ - off: function EventEmitter_off(aEvent, aListener) { - if (!this._eventEmitterListeners) return; - let listeners = this._eventEmitterListeners.get(aEvent); - if (listeners) { - this._eventEmitterListeners.set(aEvent, listeners.filter(l => { - return l !== aListener && l._originalListener !== aListener; - })); - } - }, - - /** - * Emit an event. All arguments to this method will - * be sent to listener functions. - */ - emit: function EventEmitter_emit(aEvent) { - if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(aEvent)) { - return; - } - - let originalListeners = this._eventEmitterListeners.get(aEvent); - for (let listener of this._eventEmitterListeners.get(aEvent)) { - // If the object was destroyed during event emission, stop - // emitting. - if (!this._eventEmitterListeners) { - break; - } - - // If listeners were removed during emission, make sure the - // event handler we're going to fire wasn't removed. - if (originalListeners === this._eventEmitterListeners.get(aEvent) || this._eventEmitterListeners.get(aEvent).some(l => l === listener)) { - try { - listener.apply(null, arguments); - } catch (ex) { - // Prevent a bad listener from interfering with the others. - let msg = ex + ": " + ex.stack; - //console.error(msg); - console.log(msg); - } - } - } - } -}; - /***/ }), /***/ 1763: @@ -29152,7 +23876,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -var _propTypes = __webpack_require__(20); +var _propTypes = __webpack_require__(3642); var _util = __webpack_require__(1777); @@ -29400,863 +24124,6 @@ function getThisVariable(this_, path) { /***/ }), -/***/ 1767: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const Menu = __webpack_require__(1768); -const MenuItem = __webpack_require__(1770); -const { PrefsHelper } = __webpack_require__(1771); -const Services = __webpack_require__(22); -const KeyShortcuts = __webpack_require__(1772); -const { ZoomKeys } = __webpack_require__(1773); -const EventEmitter = __webpack_require__(1759); - -module.exports = { - KeyShortcuts, - Menu, - MenuItem, - PrefsHelper, - Services, - ZoomKeys, - EventEmitter -}; - -/***/ }), - -/***/ 1768: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const EventEmitter = __webpack_require__(1759); - -function inToolbox() { - return window.parent.document.documentURI == "about:devtools-toolbox"; -} - -/** - * A partial implementation of the Menu API provided by electron: - * https://github.com/electron/electron/blob/master/docs/api/menu.md. - * - * Extra features: - * - Emits an 'open' and 'close' event when the menu is opened/closed - - * @param String id (non standard) - * Needed so tests can confirm the XUL implementation is working - */ -function Menu({ id = null } = {}) { - this.menuitems = []; - this.id = id; - - Object.defineProperty(this, "items", { - get() { - return this.menuitems; - } - }); - - EventEmitter.decorate(this); -} - -/** - * Add an item to the end of the Menu - * - * @param {MenuItem} menuItem - */ -Menu.prototype.append = function (menuItem) { - this.menuitems.push(menuItem); -}; - -/** - * Add an item to a specified position in the menu - * - * @param {int} pos - * @param {MenuItem} menuItem - */ -Menu.prototype.insert = function (pos, menuItem) { - throw Error("Not implemented"); -}; - -/** - * Show the Menu at a specified location on the screen - * - * Missing features: - * - browserWindow - BrowserWindow (optional) - Default is null. - * - positioningItem Number - (optional) OS X - * - * @param {int} screenX - * @param {int} screenY - * @param Toolbox toolbox (non standard) - * Needed so we in which window to inject XUL - */ -Menu.prototype.popup = function (screenX, screenY, toolbox) { - let doc = toolbox.doc; - let popupset = doc.querySelector("popupset"); - // See bug 1285229, on Windows, opening the same popup multiple times in a - // row ends up duplicating the popup. The newly inserted popup doesn't - // dismiss the old one. So remove any previously displayed popup before - // opening a new one. - let popup = popupset.querySelector("menupopup[menu-api=\"true\"]"); - if (popup) { - popup.hidePopup(); - } - - popup = this.createPopup(doc); - popup.setAttribute("menu-api", "true"); - - if (this.id) { - popup.id = this.id; - } - this._createMenuItems(popup); - - // Remove the menu from the DOM once it's hidden. - popup.addEventListener("popuphidden", e => { - if (e.target === popup) { - popup.remove(); - this.emit("close", popup); - } - }); - - popup.addEventListener("popupshown", e => { - if (e.target === popup) { - this.emit("open", popup); - } - }); - - popupset.appendChild(popup); - popup.openPopupAtScreen(screenX, screenY, true); -}; - -Menu.prototype.createPopup = function (doc) { - return doc.createElement("menupopup"); -}; - -Menu.prototype._createMenuItems = function (parent) { - let doc = parent.ownerDocument; - this.menuitems.forEach(item => { - if (!item.visible) { - return; - } - - if (item.submenu) { - let menupopup = doc.createElement("menupopup"); - item.submenu._createMenuItems(menupopup); - - let menuitem = doc.createElement("menuitem"); - menuitem.setAttribute("label", item.label); - if (!inToolbox()) { - menuitem.textContent = item.label; - } - - let menu = doc.createElement("menu"); - menu.appendChild(menuitem); - menu.appendChild(menupopup); - if (item.disabled) { - menu.setAttribute("disabled", "true"); - } - if (item.accesskey) { - menu.setAttribute("accesskey", item.accesskey); - } - if (item.id) { - menu.id = item.id; - } - parent.appendChild(menu); - } else if (item.type === "separator") { - let menusep = doc.createElement("menuseparator"); - parent.appendChild(menusep); - } else { - let menuitem = doc.createElement("menuitem"); - menuitem.setAttribute("label", item.label); - - if (!inToolbox()) { - menuitem.textContent = item.label; - } - - menuitem.addEventListener("command", () => item.click()); - - if (item.type === "checkbox") { - menuitem.setAttribute("type", "checkbox"); - } - if (item.type === "radio") { - menuitem.setAttribute("type", "radio"); - } - if (item.disabled) { - menuitem.setAttribute("disabled", "true"); - } - if (item.checked) { - menuitem.setAttribute("checked", "true"); - } - if (item.accesskey) { - menuitem.setAttribute("accesskey", item.accesskey); - } - if (item.id) { - menuitem.id = item.id; - } - - parent.appendChild(menuitem); - } - }); -}; - -Menu.setApplicationMenu = () => { - throw Error("Not implemented"); -}; - -Menu.sendActionToFirstResponder = () => { - throw Error("Not implemented"); -}; - -Menu.buildFromTemplate = () => { - throw Error("Not implemented"); -}; - -module.exports = Menu; - -/***/ }), - -/***/ 1769: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * A sham for https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/Promise.jsm - */ - -/** - * Promise.jsm is mostly the Promise web API with a `defer` method. Just drop this in here, - * and use the native web API (although building with webpack/babel, it may replace this - * with it's own version if we want to target environments that do not have `Promise`. - */ - -let p = typeof window != "undefined" ? window.Promise : Promise; -p.defer = function defer() { - var resolve, reject; - var promise = new Promise(function () { - resolve = arguments[0]; - reject = arguments[1]; - }); - return { - resolve: resolve, - reject: reject, - promise: promise - }; -}; - -module.exports = p; - -/***/ }), - -/***/ 177: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - - -var emptyFunction = __webpack_require__(178); -var invariant = __webpack_require__(180); -var ReactPropTypesSecret = __webpack_require__(187); - -module.exports = function() { - function shim(props, propName, componentName, location, propFullName, secret) { - if (secret === ReactPropTypesSecret) { - // It is still safe when called from React. - return; - } - invariant( - false, - 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + - 'Use PropTypes.checkPropTypes() to call them. ' + - 'Read more at http://fb.me/use-check-prop-types' - ); - }; - shim.isRequired = shim; - function getShim() { - return shim; - }; - // Important! - // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. - var ReactPropTypes = { - array: shim, - bool: shim, - func: shim, - number: shim, - object: shim, - string: shim, - symbol: shim, - - any: shim, - arrayOf: getShim, - element: shim, - instanceOf: getShim, - node: shim, - objectOf: getShim, - oneOf: getShim, - oneOfType: getShim, - shape: getShim, - exact: getShim - }; - - ReactPropTypes.checkPropTypes = emptyFunction; - ReactPropTypes.PropTypes = ReactPropTypes; - - return ReactPropTypes; -}; - - -/***/ }), - -/***/ 1770: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * A partial implementation of the MenuItem API provided by electron: - * https://github.com/electron/electron/blob/master/docs/api/menu-item.md. - * - * Missing features: - * - id String - Unique within a single menu. If defined then it can be used - * as a reference to this item by the position attribute. - * - role String - Define the action of the menu item; when specified the - * click property will be ignored - * - sublabel String - * - accelerator Accelerator - * - icon NativeImage - * - position String - This field allows fine-grained definition of the - * specific location within a given menu. - * - * Implemented features: - * @param Object options - * Function click - * Will be called with click(menuItem, browserWindow) when the menu item - * is clicked - * String type - * Can be normal, separator, submenu, checkbox or radio - * String label - * Boolean enabled - * If false, the menu item will be greyed out and unclickable. - * Boolean checked - * Should only be specified for checkbox or radio type menu items. - * Menu submenu - * Should be specified for submenu type menu items. If submenu is specified, - * the type: 'submenu' can be omitted. If the value is not a Menu then it - * will be automatically converted to one using Menu.buildFromTemplate. - * Boolean visible - * If false, the menu item will be entirely hidden. - */ -function MenuItem({ - accesskey = null, - checked = false, - click = () => {}, - disabled = false, - label = "", - id = null, - submenu = null, - type = "normal", - visible = true -} = {}) { - this.accesskey = accesskey; - this.checked = checked; - this.click = click; - this.disabled = disabled; - this.id = id; - this.label = label; - this.submenu = submenu; - this.type = type; - this.visible = visible; -} - -module.exports = MenuItem; - -/***/ }), - -/***/ 1771: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const Services = __webpack_require__(22); -const EventEmitter = __webpack_require__(1759); - -/** - * Shortcuts for lazily accessing and setting various preferences. - * Usage: - * let prefs = new Prefs("root.path.to.branch", { - * myIntPref: ["Int", "leaf.path.to.my-int-pref"], - * myCharPref: ["Char", "leaf.path.to.my-char-pref"], - * myJsonPref: ["Json", "leaf.path.to.my-json-pref"], - * myFloatPref: ["Float", "leaf.path.to.my-float-pref"] - * ... - * }); - * - * Get/set: - * prefs.myCharPref = "foo"; - * let aux = prefs.myCharPref; - * - * Observe: - * prefs.registerObserver(); - * prefs.on("pref-changed", (prefName, prefValue) => { - * ... - * }); - * - * @param string prefsRoot - * The root path to the required preferences branch. - * @param object prefsBlueprint - * An object containing { accessorName: [prefType, prefName, prefDefault] } keys. - */ -function PrefsHelper(prefsRoot = "", prefsBlueprint = {}) { - EventEmitter.decorate(this); - - let cache = new Map(); - - for (let accessorName in prefsBlueprint) { - let [prefType, prefName, prefDefault] = prefsBlueprint[accessorName]; - map(this, cache, accessorName, prefType, prefsRoot, prefName, prefDefault); - } - - let observer = makeObserver(this, cache, prefsRoot, prefsBlueprint); - this.registerObserver = () => observer.register(); - this.unregisterObserver = () => observer.unregister(); -} - -/** - * Helper method for getting a pref value. - * - * @param Map cache - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @return any - */ -function get(cache, prefType, prefsRoot, prefName) { - let cachedPref = cache.get(prefName); - if (cachedPref !== undefined) { - return cachedPref; - } - let value = Services.prefs["get" + prefType + "Pref"]([prefsRoot, prefName].join(".")); - cache.set(prefName, value); - return value; -} - -/** - * Helper method for setting a pref value. - * - * @param Map cache - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @param any value - */ -function set(cache, prefType, prefsRoot, prefName, value) { - Services.prefs["set" + prefType + "Pref"]([prefsRoot, prefName].join("."), value); - cache.set(prefName, value); -} - -/** - * Maps a property name to a pref, defining lazy getters and setters. - * Supported types are "Bool", "Char", "Int", "Float" (sugar around "Char" - * type and casting), and "Json" (which is basically just sugar for "Char" - * using the standard JSON serializer). - * - * @param PrefsHelper self - * @param Map cache - * @param string accessorName - * @param string prefType - * @param string prefsRoot - * @param string prefName - * @param string prefDefault - * @param array serializer [optional] - */ -function map(self, cache, accessorName, prefType, prefsRoot, prefName, prefDefault, serializer = { in: e => e, out: e => e }) { - if (prefName in self) { - throw new Error(`Can't use ${prefName} because it overrides a property` + "on the instance."); - } - if (prefType == "Json") { - map(self, cache, accessorName, "String", prefsRoot, prefName, prefDefault, { - in: JSON.parse, - out: JSON.stringify - }); - return; - } - if (prefType == "Float") { - map(self, cache, accessorName, "Char", prefsRoot, prefName, prefDefault, { - in: Number.parseFloat, - out: n => n + "" - }); - return; - } - - Object.defineProperty(self, accessorName, { - get: () => { - try { - return serializer.in(get(cache, prefType, prefsRoot, prefName)); - } catch (e) { - if (typeof prefDefault !== 'undefined') { - return prefDefault; - } - throw e; - } - }, - set: e => set(cache, prefType, prefsRoot, prefName, serializer.out(e)) - }); -} - -/** - * Finds the accessor for the provided pref, based on the blueprint object - * used in the constructor. - * - * @param PrefsHelper self - * @param object prefsBlueprint - * @return string - */ -function accessorNameForPref(somePrefName, prefsBlueprint) { - for (let accessorName in prefsBlueprint) { - let [, prefName] = prefsBlueprint[accessorName]; - if (somePrefName == prefName) { - return accessorName; - } - } - return ""; -} - -/** - * Creates a pref observer for `self`. - * - * @param PrefsHelper self - * @param Map cache - * @param string prefsRoot - * @param object prefsBlueprint - * @return object - */ -function makeObserver(self, cache, prefsRoot, prefsBlueprint) { - return { - register: function () { - this._branch = Services.prefs.getBranch(prefsRoot + "."); - this._branch.addObserver("", this); - }, - unregister: function () { - this._branch.removeObserver("", this); - }, - observe: function (subject, topic, prefName) { - // If this particular pref isn't handled by the blueprint object, - // even though it's in the specified branch, ignore it. - let accessorName = accessorNameForPref(prefName, prefsBlueprint); - if (!(accessorName in self)) { - return; - } - cache.delete(prefName); - self.emit("pref-changed", accessorName, self[accessorName]); - } - }; -} - -exports.PrefsHelper = PrefsHelper; - -/***/ }), - -/***/ 1772: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { appinfo } = __webpack_require__(22); -const EventEmitter = __webpack_require__(1759); -const isOSX = appinfo.OS === "Darwin"; - -// List of electron keys mapped to DOM API (DOM_VK_*) key code -const ElectronKeysMapping = { - "F1": "DOM_VK_F1", - "F2": "DOM_VK_F2", - "F3": "DOM_VK_F3", - "F4": "DOM_VK_F4", - "F5": "DOM_VK_F5", - "F6": "DOM_VK_F6", - "F7": "DOM_VK_F7", - "F8": "DOM_VK_F8", - "F9": "DOM_VK_F9", - "F10": "DOM_VK_F10", - "F11": "DOM_VK_F11", - "F12": "DOM_VK_F12", - "F13": "DOM_VK_F13", - "F14": "DOM_VK_F14", - "F15": "DOM_VK_F15", - "F16": "DOM_VK_F16", - "F17": "DOM_VK_F17", - "F18": "DOM_VK_F18", - "F19": "DOM_VK_F19", - "F20": "DOM_VK_F20", - "F21": "DOM_VK_F21", - "F22": "DOM_VK_F22", - "F23": "DOM_VK_F23", - "F24": "DOM_VK_F24", - "Space": "DOM_VK_SPACE", - "Backspace": "DOM_VK_BACK_SPACE", - "Delete": "DOM_VK_DELETE", - "Insert": "DOM_VK_INSERT", - "Return": "DOM_VK_RETURN", - "Enter": "DOM_VK_RETURN", - "Up": "DOM_VK_UP", - "Down": "DOM_VK_DOWN", - "Left": "DOM_VK_LEFT", - "Right": "DOM_VK_RIGHT", - "Home": "DOM_VK_HOME", - "End": "DOM_VK_END", - "PageUp": "DOM_VK_PAGE_UP", - "PageDown": "DOM_VK_PAGE_DOWN", - "Escape": "DOM_VK_ESCAPE", - "Esc": "DOM_VK_ESCAPE", - "Tab": "DOM_VK_TAB", - "VolumeUp": "DOM_VK_VOLUME_UP", - "VolumeDown": "DOM_VK_VOLUME_DOWN", - "VolumeMute": "DOM_VK_VOLUME_MUTE", - "PrintScreen": "DOM_VK_PRINTSCREEN" -}; - -/** - * Helper to listen for keyboard events decribed in .properties file. - * - * let shortcuts = new KeyShortcuts({ - * window - * }); - * shortcuts.on("Ctrl+F", event => { - * // `event` is the KeyboardEvent which relates to the key shortcuts - * }); - * - * @param DOMWindow window - * The window object of the document to listen events from. - * @param DOMElement target - * Optional DOM Element on which we should listen events from. - * If omitted, we listen for all events fired on `window`. - */ -function KeyShortcuts({ window, target }) { - this.window = window; - this.target = target || window; - this.keys = new Map(); - this.eventEmitter = new EventEmitter(); - this.target.addEventListener("keydown", this); -} - -/* - * Parse an electron-like key string and return a normalized object which - * allow efficient match on DOM key event. The normalized object matches DOM - * API. - * - * @param DOMWindow window - * Any DOM Window object, just to fetch its `KeyboardEvent` object - * @param String str - * The shortcut string to parse, following this document: - * https://github.com/electron/electron/blob/master/docs/api/accelerator.md - */ -KeyShortcuts.parseElectronKey = function (window, str) { - let modifiers = str.split("+"); - let key = modifiers.pop(); - - let shortcut = { - ctrl: false, - meta: false, - alt: false, - shift: false, - // Set for character keys - key: undefined, - // Set for non-character keys - keyCode: undefined - }; - for (let mod of modifiers) { - if (mod === "Alt") { - shortcut.alt = true; - } else if (["Command", "Cmd"].includes(mod)) { - shortcut.meta = true; - } else if (["CommandOrControl", "CmdOrCtrl"].includes(mod)) { - if (isOSX) { - shortcut.meta = true; - } else { - shortcut.ctrl = true; - } - } else if (["Control", "Ctrl"].includes(mod)) { - shortcut.ctrl = true; - } else if (mod === "Shift") { - shortcut.shift = true; - } else { - console.error("Unsupported modifier:", mod, "from key:", str); - return null; - } - } - - // Plus is a special case. It's a character key and shouldn't be matched - // against a keycode as it is only accessible via Shift/Capslock - if (key === "Plus") { - key = "+"; - } - - if (typeof key === "string" && key.length === 1) { - // Match any single character - shortcut.key = key.toLowerCase(); - } else if (key in ElectronKeysMapping) { - // Maps the others manually to DOM API DOM_VK_* - key = ElectronKeysMapping[key]; - shortcut.keyCode = window.KeyboardEvent[key]; - // Used only to stringify the shortcut - shortcut.keyCodeString = key; - shortcut.key = key; - } else { - console.error("Unsupported key:", key); - return null; - } - - return shortcut; -}; - -KeyShortcuts.stringify = function (shortcut) { - let list = []; - if (shortcut.alt) { - list.push("Alt"); - } - if (shortcut.ctrl) { - list.push("Ctrl"); - } - if (shortcut.meta) { - list.push("Cmd"); - } - if (shortcut.shift) { - list.push("Shift"); - } - let key; - if (shortcut.key) { - key = shortcut.key.toUpperCase(); - } else { - key = shortcut.keyCodeString; - } - list.push(key); - return list.join("+"); -}; - -KeyShortcuts.prototype = { - destroy() { - this.target.removeEventListener("keydown", this); - this.keys.clear(); - }, - - doesEventMatchShortcut(event, shortcut) { - if (shortcut.meta != event.metaKey) { - return false; - } - if (shortcut.ctrl != event.ctrlKey) { - return false; - } - if (shortcut.alt != event.altKey) { - return false; - } - // Shift is a special modifier, it may implicitely be required if the - // expected key is a special character accessible via shift. - if (shortcut.shift != event.shiftKey && event.key && event.key.match(/[a-zA-Z]/)) { - return false; - } - if (shortcut.keyCode) { - return event.keyCode == shortcut.keyCode; - } else if (event.key in ElectronKeysMapping) { - return ElectronKeysMapping[event.key] === shortcut.key; - } - - // get the key from the keyCode if key is not provided. - let key = event.key || String.fromCharCode(event.keyCode); - - // For character keys, we match if the final character is the expected one. - // But for digits we also accept indirect match to please azerty keyboard, - // which requires Shift to be pressed to get digits. - return key.toLowerCase() == shortcut.key || shortcut.key.match(/^[0-9]$/) && event.keyCode == shortcut.key.charCodeAt(0); - }, - - handleEvent(event) { - for (let [key, shortcut] of this.keys) { - if (this.doesEventMatchShortcut(event, shortcut)) { - this.eventEmitter.emit(key, event); - } - } - }, - - on(key, listener) { - if (typeof listener !== "function") { - throw new Error("KeyShortcuts.on() expects a function as " + "second argument"); - } - if (!this.keys.has(key)) { - let shortcut = KeyShortcuts.parseElectronKey(this.window, key); - // The key string is wrong and we were unable to compute the key shortcut - if (!shortcut) { - return; - } - this.keys.set(key, shortcut); - } - this.eventEmitter.on(key, listener); - }, - - off(key, listener) { - this.eventEmitter.off(key, listener); - } -}; -module.exports = KeyShortcuts; - -/***/ }), - -/***/ 1773: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - - -/** - * Empty shim for "devtools/client/shared/zoom-keys" module - * - * Based on nsIMarkupDocumentViewer.fullZoom API - * https://developer.mozilla.org/en-US/Firefox/Releases/3/Full_page_zoom - */ - -exports.register = function (window) {}; - -/***/ }), - /***/ 1777: /***/ (function(module, exports, __webpack_require__) { @@ -30400,7 +24267,7 @@ var _pause = __webpack_require__(1394); var _frames = __webpack_require__(3605); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _lodash = __webpack_require__(2); @@ -30437,49 +24304,6 @@ const getCallStackFrames = exports.getCallStackFrames = (0, _reselect.createSele /***/ }), -/***/ 178: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ - -function makeEmptyFunction(arg) { - return function () { - return arg; - }; -} - -/** - * This function accepts and discards inputs; it has no side effects. This is - * primarily useful idiomatically for overridable function endpoints which - * always need to be callable, since JS lacks a null-call idiom ala Cocoa. - */ -var emptyFunction = function emptyFunction() {}; - -emptyFunction.thatReturns = makeEmptyFunction; -emptyFunction.thatReturnsFalse = makeEmptyFunction(false); -emptyFunction.thatReturnsTrue = makeEmptyFunction(true); -emptyFunction.thatReturnsNull = makeEmptyFunction(null); -emptyFunction.thatReturnsThis = function () { - return this; -}; -emptyFunction.thatReturnsArgument = function (arg) { - return arg; -}; - -module.exports = emptyFunction; - -/***/ }), - /***/ 1780: /***/ (function(module, exports, __webpack_require__) { @@ -30495,7 +24319,7 @@ var _sources = __webpack_require__(1369); var _pause = __webpack_require__(1394); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _reselect = __webpack_require__(993); @@ -30627,7 +24451,7 @@ var _ast = __webpack_require__(1638); var _editor = __webpack_require__(1358); -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _promise = __webpack_require__(1653); @@ -30840,7 +24664,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.getScope = getScope; -var _devtoolsReps = __webpack_require__(1408); +var _devtoolsReps = __webpack_require__(3655); var _getVariables = __webpack_require__(1765); @@ -31380,66 +25204,6 @@ function closeTabs(urls) { /***/ }), -/***/ 180: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - - - -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var validateFormat = function validateFormat(format) {}; - -if (false) { - validateFormat = function validateFormat(format) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - }; -} - -function invariant(condition, format, a, b, c, d, e, f) { - validateFormat(format); - - if (!condition) { - var error; - if (format === undefined) { - error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error(format.replace(/%s/g, function () { - return args[argIndex++]; - })); - error.name = 'Invariant Violation'; - } - - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -} - -module.exports = invariant; - -/***/ }), - /***/ 1800: /***/ (function(module, exports, __webpack_require__) { @@ -31489,7 +25253,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.newSource = newSource; exports.newSources = newSources; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _lodash = __webpack_require__(2); @@ -31722,7 +25486,7 @@ exports.selectSpecificSource = selectSpecificSource; exports.jumpToMappedLocation = jumpToMappedLocation; exports.jumpToMappedSelectedLocation = jumpToMappedSelectedLocation; -var _devtoolsSourceMap = __webpack_require__(1360); +var _devtoolsSourceMap = __webpack_require__(3646); var _ast = __webpack_require__(1399); @@ -32316,907 +26080,6 @@ module.exports = "`); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(CommentNode), + supportsObject +}; + +/***/ }), + /***/ 369: /***/ (function(module, exports) { @@ -40086,6 +38344,1066 @@ module.exports = "`); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(CommentNode), - supportsObject -}; - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Utils -const { - isGrip, - wrapRender -} = __webpack_require__(0); -const { rep: StringRep } = __webpack_require__(5); -const { MODE } = __webpack_require__(3); -const nodeConstants = __webpack_require__(12); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders DOM element node. - */ -ElementNode.propTypes = { - object: PropTypes.object.isRequired, - inspectIconTitle: PropTypes.string, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeClick: PropTypes.func, - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function ElementNode(props) { - let { - object, - inspectIconTitle, - mode, - onDOMNodeClick, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - let elements = getElements(object, mode); - - let isInTree = object.preview && object.preview.isConnected === true; - - let baseConfig = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-node" - }; - let inspectIcon; - if (isInTree) { - if (onDOMNodeClick) { - Object.assign(baseConfig, { - onClick: _ => onDOMNodeClick(object) - }); - } - - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(object) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: inspectIconTitle || "Click to select the node in the inspector", - onClick: e => { - if (onDOMNodeClick) { - e.stopPropagation(); - } - - onInspectIconClick(object, e); - } - }); - } - } - - return span(baseConfig, ...elements, inspectIcon); -} - -function getElements(grip, mode) { - let { - attributes, - nodeName, - isAfterPseudoElement, - isBeforePseudoElement - } = grip.preview; - const nodeNameElement = span({ - className: "tag-name" - }, nodeName); - - if (isAfterPseudoElement || isBeforePseudoElement) { - return [span({ className: "attrName" }, `::${isAfterPseudoElement ? "after" : "before"}`)]; - } - - if (mode === MODE.TINY) { - let elements = [nodeNameElement]; - if (attributes.id) { - elements.push(span({ className: "attrName" }, `#${attributes.id}`)); - } - if (attributes.class) { - elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); - } - return elements; - } - - let attributeKeys = Object.keys(attributes); - if (attributeKeys.includes("class")) { - attributeKeys.splice(attributeKeys.indexOf("class"), 1); - attributeKeys.unshift("class"); - } - if (attributeKeys.includes("id")) { - attributeKeys.splice(attributeKeys.indexOf("id"), 1); - attributeKeys.unshift("id"); - } - const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { - let value = attributes[name]; - let attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); - - return arr.concat([" ", attribute]); - }, []); - - return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ElementNode), - supportsObject -}; - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - cropString, - wrapRender -} = __webpack_require__(0); -const { MODE } = __webpack_require__(3); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders DOM #text node. - */ -TextNode.propTypes = { - object: PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - onDOMNodeMouseOver: PropTypes.func, - onDOMNodeMouseOut: PropTypes.func, - onInspectIconClick: PropTypes.func -}; - -function TextNode(props) { - let { - object: grip, - mode = MODE.SHORT, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = props; - - let baseConfig = { - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-textNode" - }; - let inspectIcon; - let isInTree = grip.preview && grip.preview.isConnected === true; - - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(grip) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = dom.button({ - className: "open-inspector", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(grip, e) - }); - } - } - - if (mode === MODE.TINY) { - return span(baseConfig, getTitle(grip), inspectIcon); - } - - return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); -} - -function getTextContent(grip) { - return cropString(grip.preview.textContent); -} - -function getTitle(grip) { - const title = "#text"; - return span({}, title); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.class == "Text"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(TextNode), - supportsObject -}; - -/***/ }), -/* 44 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - getGripType, - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(0); - -const { MODE } = __webpack_require__(3); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip representing a window. - */ -WindowRep.propTypes = { - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - object: PropTypes.object.isRequired -}; - -function WindowRep(props) { - let { - mode, - object - } = props; - - const config = { - "data-link-actor-id": object.actor, - className: "objectBox objectBox-Window" - }; - - if (mode === MODE.TINY) { - return span(config, getTitle(object)); - } - - return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); -} - -function getTitle(object, trailingSpace) { - let title = object.displayClass || object.class || "Window"; - if (trailingSpace === true) { - title = `${title} `; - } - return span({ className: "objectTitle" }, title); -} - -function getLocation(object) { - return getURLDisplayString(object.preview.url); -} - -// Registration -function supportsObject(object, noGrip = false) { - if (noGrip === true || !isGrip(object)) { - return false; - } - - return object.preview && getGripType(object, noGrip) == "Window"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(WindowRep), - supportsObject -}; - -/***/ }), -/* 45 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - wrapRender -} = __webpack_require__(0); - -const String = __webpack_require__(5).rep; - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip object with textual data. - */ -ObjectWithText.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithText(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectTitle objectBox objectBox-" + getType(grip) - }, `${getType(grip)} `, getDescription(grip)); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return String({ - object: grip.preview.text - }); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithText"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithText), - supportsObject -}; - -/***/ }), -/* 46 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// ReactJS -const PropTypes = __webpack_require__(2); - -// Reps -const { - isGrip, - getURLDisplayString, - wrapRender -} = __webpack_require__(0); - -const dom = __webpack_require__(1); -const { span } = dom; - -/** - * Renders a grip object with URL data. - */ -ObjectWithURL.propTypes = { - object: PropTypes.object.isRequired -}; - -function ObjectWithURL(props) { - let grip = props.object; - return span({ - "data-link-actor-id": grip.actor, - className: "objectBox objectBox-" + getType(grip) - }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); -} - -function getTitle(grip) { - return span({ className: "objectTitle" }, getType(grip) + " "); -} - -function getType(grip) { - return grip.class; -} - -function getDescription(grip) { - return getURLDisplayString(grip.preview.url); -} - -// Registration -function supportsObject(grip, noGrip = false) { - if (noGrip === true || !isGrip(grip)) { - return false; - } - - return grip.preview && grip.preview.kind == "ObjectWithURL"; -} - -// Exports from this module -module.exports = { - rep: wrapRender(ObjectWithURL), - supportsObject -}; - -/***/ }), -/* 47 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { createElement, createFactory, PureComponent } = __webpack_require__(9); -const { Provider } = __webpack_require__(18); -const ObjectInspector = createFactory(__webpack_require__(48)); -const createStore = __webpack_require__(56); -const Utils = __webpack_require__(10); -const { - renderRep, - shouldRenderRootsInReps -} = Utils; - -class OI extends PureComponent { - - constructor(props) { - super(props); - this.store = createStore(props); - } - - getStore() { - return this.store; - } - - render() { - return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); - } -} - -module.exports = props => { - let { roots } = props; - if (shouldRenderRootsInReps(roots)) { - return renderRep(roots[0], props); - } - return new OI(props); -}; - -/***/ }), -/* 48 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _devtoolsComponents = __webpack_require__(49); - -var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { - Component, - createFactory -} = __webpack_require__(9); -const dom = __webpack_require__(1); -const { connect } = __webpack_require__(18); -const { bindActionCreators } = __webpack_require__(19); - -const Tree = createFactory(_devtoolsComponents2.default.Tree); -__webpack_require__(52); - -const classnames = __webpack_require__(53); -const { - MODE -} = __webpack_require__(3); - -const Utils = __webpack_require__(10); - -const { - getChildren, - getClosestGripNode, - getParent, - getValue, - nodeHasAccessors, - nodeHasProperties, - nodeIsBlock, - nodeIsDefaultProperties, - nodeIsFunction, - nodeIsGetter, - nodeIsMapEntry, - nodeIsMissingArguments, - nodeIsOptimizedOut, - nodeIsPrimitive, - nodeIsPrototype, - nodeIsSetter, - nodeIsUninitializedBinding, - nodeIsUnmappedBinding, - nodeIsUnscopedBinding, - nodeIsWindow, - nodeIsLongString, - nodeHasFullText -} = Utils.node; - -// This implements a component that renders an interactive inspector -// for looking at JavaScript objects. It expects descriptions of -// objects from the protocol, and will dynamically fetch children -// properties as objects are expanded. -// -// If you want to inspect a single object, pass the name and the -// protocol descriptor of it: -// -// ObjectInspector({ -// name: "foo", -// desc: { writable: true, ..., { value: { actor: "1", ... }}}, -// ... -// }) -// -// If you want multiple top-level objects (like scopes), you can pass -// an array of manually constructed nodes as `roots`: -// -// ObjectInspector({ -// roots: [{ name: ... }, ...], -// ... -// }); - -// There are 3 types of nodes: a simple node with a children array, an -// object that has properties that should be children when they are -// fetched, and a primitive value that should be displayed with no -// children. - -class ObjectInspector extends Component { - constructor(props) { - super(); - this.cachedNodes = new Map(); - - const self = this; - - self.getItemChildren = this.getItemChildren.bind(this); - self.renderTreeItem = this.renderTreeItem.bind(this); - self.setExpanded = this.setExpanded.bind(this); - self.focusItem = this.focusItem.bind(this); - self.getRoots = this.getRoots.bind(this); - } - - shouldComponentUpdate(nextProps) { - const { - expandedPaths, - focusedItem, - loadedProperties, - roots - } = this.props; - - if (roots !== nextProps.roots) { - // Since the roots changed, we assume the properties did as well, so we need to - // cleanup the component internal state. - - // We can clear the cachedNodes to avoid bugs and memory leaks. - this.cachedNodes.clear(); - // The rootsChanged action will be handled in a middleware to release the actors - // of the old roots, as well as cleanup the state properties (expandedPaths, - // loadedProperties, …). - this.props.rootsChanged(nextProps); - // We don't render right away since the state is going to be changed by the - // rootsChanged action. The `state.forceUpdate` flag will be set to `true` so we - // can execute a new render cycle with the cleaned state. - return false; - } - - if (nextProps.forceUpdate === true) { - return true; - } - - // We should update if: - // - there are new loaded properties - // - OR the expanded paths number changed, and all of them have properties loaded - // - OR the expanded paths number did not changed, but old and new sets differ - // - OR the focused node changed. - return loadedProperties.size !== nextProps.loadedProperties.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || focusedItem !== nextProps.focusedItem; - } - - componentDidUpdate(prevProps) { - if (this.props.forceUpdate) { - // If the component was updated, we can then reset the forceUpdate flag. - this.props.forceUpdated(); - } - } - - componentWillUnmount() { - const { releaseActor } = this.props; - if (typeof releaseActor !== "function") { - return; - } - - const { actors } = this.props; - for (let actor of actors) { - releaseActor(actor); - } - } - - getItemChildren(item) { - const { - loadedProperties - } = this.props; - const { cachedNodes } = this; - - return getChildren({ - loadedProperties, - cachedNodes, - item - }); - } - - getRoots() { - return this.props.roots; - } - - getNodeKey(item) { - return item.path && typeof item.path.toString === "function" ? item.path.toString() : JSON.stringify(item); - } - - setExpanded(item, expand) { - if (nodeIsPrimitive(item)) { - return; - } - - const { - createObjectClient, - createLongStringClient, - loadedProperties, - nodeExpand, - nodeCollapse, - roots - } = this.props; - - if (expand === true) { - const gripItem = getClosestGripNode(item); - const value = getValue(gripItem); - const isRoot = value && roots.some(root => { - const rootValue = getValue(root); - return rootValue && rootValue.actor === value.actor; - }); - const actor = isRoot || !value ? null : value.actor; - nodeExpand(item, actor, loadedProperties, createObjectClient, createLongStringClient); - } else { - nodeCollapse(item); - } - } - - focusItem(item) { - const { - focusable = true, - focusedItem, - nodeFocus, - onFocus - } = this.props; - - if (focusable && focusedItem !== item) { - nodeFocus(item); - if (focusedItem !== item && onFocus) { - onFocus(item); - } - } - } - - getTreeItemLabelAndValue(item, depth, expanded) { - const label = item.name; - const isPrimitive = nodeIsPrimitive(item); - - if (nodeIsOptimizedOut(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(optimized away)") - }; - } - - if (nodeIsUninitializedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(uninitialized)") - }; - } - - if (nodeIsUnmappedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unmapped)") - }; - } - - if (nodeIsUnscopedBinding(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unscoped)") - }; - } - - if (nodeIsOptimizedOut(item)) { - return { - label, - value: dom.span({ className: "unavailable" }, "(optimized away)") - }; - } - - const itemValue = getValue(item); - const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); - - if (nodeIsMissingArguments(item) || unavailable) { - return { - label, - value: dom.span({ className: "unavailable" }, "(unavailable)") - }; - } - - if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) { - return { - label: Utils.renderRep(item, { - ...this.props, - functionName: label - }) - }; - } - - if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive) { - let repProps = { ...this.props }; - if (depth > 0) { - repProps.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY; - } - if (expanded) { - repProps.mode = MODE.TINY; - } - - if (nodeIsLongString(item)) { - repProps.member = { - open: nodeHasFullText(item) && expanded - }; - } - - return { - label, - value: Utils.renderRep(item, repProps) - }; - } - - return { - label - }; - } - - renderTreeItemLabel(label, item, depth, focused, expanded) { - if (label === null || typeof label === "undefined") { - return null; - } - - const { - onLabelClick - } = this.props; - - return dom.span({ - className: "object-label", - onClick: onLabelClick ? event => { - event.stopPropagation(); - - // If the user selected text, bail out. - if (Utils.selection.documentHasSelection()) { - return; - } - - onLabelClick(item, { - depth, - focused, - expanded, - setExpanded: this.setExpanded - }); - } : undefined - }, label); - } - - getTreeTopElementProps(item, depth, focused, expanded) { - const { - onCmdCtrlClick, - onDoubleClick, - dimTopLevelWindow - } = this.props; - - let parentElementProps = { - className: classnames("node object-node", { - focused, - lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0), - block: nodeIsBlock(item) - }), - onClick: e => { - if (e.metaKey && onCmdCtrlClick) { - onCmdCtrlClick(item, { - depth, - event: e, - focused, - expanded - }); - e.stopPropagation(); - return; - } - - // If this click happened because the user selected some text, bail out. - // Note that if the user selected some text before and then clicks here, - // the previously selected text will be first unselected, unless the user - // clicked on the arrow itself. Indeed because the arrow is an image, clicking on - // it does not remove any existing text selection. So we need to also check if - // teh arrow was clicked. - if (Utils.selection.documentHasSelection() && !(e.target && e.target.matches && e.target.matches(".arrow"))) { - e.stopPropagation(); - } - } - }; - - if (onDoubleClick) { - parentElementProps.onDoubleClick = e => { - e.stopPropagation(); - onDoubleClick(item, { - depth, - focused, - expanded - }); - }; - } - - return parentElementProps; - } - - renderTreeItem(item, depth, focused, arrow, expanded) { - const { label, value } = this.getTreeItemLabelAndValue(item, depth, expanded); - const labelElement = this.renderTreeItemLabel(label, item, depth, focused, expanded); - const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; - - return dom.div(this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value); - } - - render() { - const { - autoExpandAll = true, - autoExpandDepth = 1, - focusable = true, - disableWrap = false, - expandedPaths, - focusedItem, - inline - } = this.props; - - return Tree({ - className: classnames({ - inline, - nowrap: disableWrap, - "object-inspector": true - }), - autoExpandAll, - autoExpandDepth, - - isExpanded: item => expandedPaths && expandedPaths.has(item.path), - isExpandable: item => nodeIsPrimitive(item) === false, - focused: focusedItem, - - getRoots: this.getRoots, - getParent, - getChildren: this.getItemChildren, - getKey: this.getNodeKey, - - onExpand: item => this.setExpanded(item, true), - onCollapse: item => this.setExpanded(item, false), - onFocus: focusable ? this.focusItem : null, - - renderItem: this.renderTreeItem - }); - } -} - -function mapStateToProps(state, props) { - return { - actors: state.actors, - expandedPaths: state.expandedPaths, - // If the root changes, we want to pass a possibly new focusedItem property - focusedItem: state.roots !== props.roots ? props.focusedItem : state.focusedItem, - loadedProperties: state.loadedProperties, - forceUpdate: state.forceUpdate - }; -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators(__webpack_require__(55), dispatch); -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(ObjectInspector); - -/***/ }), -/* 49 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _tree = __webpack_require__(50); +var _tree = __webpack_require__(3670); var _tree2 = _interopRequireDefault(_tree); @@ -5762,7 +3626,8 @@ module.exports = { * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /***/ }), -/* 50 */ + +/***/ 3670: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5772,15 +3637,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _react = __webpack_require__(9); +var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -var _reactDomFactories = __webpack_require__(1); +var _reactDomFactories = __webpack_require__(3643); var _reactDomFactories2 = _interopRequireDefault(_reactDomFactories); -var _propTypes = __webpack_require__(2); +var _propTypes = __webpack_require__(3642); var _propTypes2 = _interopRequireDefault(_propTypes); @@ -5788,11 +3653,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de const { Component, createFactory } = _react2.default; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ -__webpack_require__(51); +__webpack_require__(3671); -const AUTO_EXPAND_DEPTH = 0; // depth +// depth +const AUTO_EXPAND_DEPTH = 0; /** * An arrow that displays whether its node is expanded (▼) or collapsed @@ -5810,9 +3676,7 @@ class ArrowExpander extends Component { } render() { - const { - expanded - } = this.props; + const { expanded } = this.props; const classNames = ["arrow"]; if (expanded) { @@ -5870,11 +3734,11 @@ class TreeNode extends Component { } const indents = Array.from({ length: depth }).fill(treeIndent); - let items = indents.concat(renderItem(item, depth, focused, arrow, expanded)); + const items = indents.concat(renderItem(item, depth, focused, arrow, expanded)); return _reactDomFactories2.default.div({ id, - className: "tree-node" + (focused ? " focused" : ""), + className: `tree-node${focused ? " focused" : ""}`, onClick: this.props.onClick, role: "treeitem", "aria-level": depth + 1, @@ -5930,8 +3794,8 @@ function oncePerAnimationFrame(fn) { * "traditional" tree or as rows in a table or anything else. It doesn't * restrict you to only one certain kind of tree. * - * The tree comes with basic styling for the indent, the arrow, as well as hovered - * and focused styles which can be override in CSS. + * The tree comes with basic styling for the indent, the arrow, as well as + * hovered and focused styles which can be override in CSS. * * ### Example Usage * @@ -6087,15 +3951,15 @@ class Tree extends Component { // Note: the two properties below are mutually exclusive. Only one of the // label properties is necessary. - // ID of an element whose textual content serves as an accessible label for - // a tree. + // ID of an element whose textual content serves as an accessible label + // for a tree. labelledby: _propTypes2.default.string, // Accessibility label for a tree widget. label: _propTypes2.default.string, - // Optional event handlers for when items are expanded or collapsed. Useful - // for dispatching redux events and updating application state, maybe lazily - // loading subtrees from a worker, etc. + // Optional event handlers for when items are expanded or collapsed. + // Useful for dispatching redux events and updating application state, + // maybe lazily loading subtrees from a worker, etc. // // Type: // onExpand(item: Item) @@ -6106,8 +3970,9 @@ class Tree extends Component { // onExpand: item => dispatchExpandActionToRedux(item) onExpand: _propTypes2.default.func, onCollapse: _propTypes2.default.func, - // Optional event handler called with the current focused node when the Enter key - // is pressed. Can be useful to allow further keyboard actions within the tree node. + // Optional event handler called with the current focused node when the + // Enter key is pressed. Can be useful to allow further keyboard actions + // within the tree node. onActivate: _propTypes2.default.func, isExpandable: _propTypes2.default.func, // Additional classes to add to the root element. @@ -6165,7 +4030,7 @@ class Tree extends Component { } componentDidUpdate(prevProps, prevState) { - if (prevProps.focused !== this.props.focused) { + if (this.props.focused && prevProps.focused !== this.props.focused) { this._scrollNodeIntoView(this.props.focused); // Always keep the focus on the tree itself. this.treeRef.focus(); @@ -6304,9 +4169,9 @@ class Tree extends Component { * * @param {Object|undefined} options * An options object which can contain: - * - dir: "up" or "down" to indicate if we should scroll the element to the - * top or the bottom of the scrollable container when the element is - * off canvas. + * - dir: "up" or "down" to indicate if we should scroll the element + * to the top or the bottom of the scrollable container when + * the element is off canvas. */ _focus(item, options = {}) { const { preventAutoScroll } = options; @@ -6326,9 +4191,9 @@ class Tree extends Component { * * @param {Object|undefined} options * An options object which can contain: - * - dir: "up" or "down" to indicate if we should scroll the element to the - * top or the bottom of the scrollable container when the element is - * off canvas. + * - dir: "up" or "down" to indicate if we should scroll the element + * to the top or the bottom of the scrollable container when + * the element is off canvas. */ _scrollNodeIntoView(item, options = {}) { if (item !== undefined) { @@ -6353,7 +4218,7 @@ class Tree extends Component { if (!isVisible) { const { alignTo } = options; - let scrollToTop = alignTo ? alignTo === "top" : !scrolledParentRect || top < scrolledParentRect.top; + const scrollToTop = alignTo ? alignTo === "top" : !scrolledParentRect || top < scrolledParentRect.top; element.scrollIntoView(scrollToTop); } } @@ -6518,9 +4383,7 @@ class Tree extends Component { render() { const traversal = this._dfsFromRoots(); - const { - focused - } = this.props; + const { focused } = this.props; const nodes = traversal.map((v, i) => { const { item, depth } = traversal[i]; @@ -6538,8 +4401,8 @@ class Tree extends Component { onExpand: this._onExpand, onCollapse: this._onCollapse, onClick: e => { - // Since the user just clicked the node, there's no need to check if it should - // be scrolled into view. + // Since the user just clicked the node, there's no need to check if + // it should be scrolled into view. this._focus(item, { preventAutoScroll: true }); if (this.props.isExpanded(item)) { this.props.onCollapse(item); @@ -6570,7 +4433,7 @@ class Tree extends Component { return; } - let { explicitOriginalTarget } = nativeEvent; + const { explicitOriginalTarget } = nativeEvent; // Only set default focus to the first tree node if the focus came // from outside the tree (e.g. by tabbing to the tree from other // external elements). @@ -6579,10 +4442,6 @@ class Tree extends Component { } }, onBlur: this._onBlur, - onClick: () => { - // Focus should always remain on the tree container itself. - this.treeRef.focus(); - }, "aria-label": this.props.label, "aria-labelledby": this.props.labelledby, "aria-activedescendant": focused && this.props.getKey(focused), @@ -6594,74 +4453,22 @@ class Tree extends Component { exports.default = Tree; /***/ }), -/* 51 */ + +/***/ 3671: /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), -/* 52 */ + +/***/ 3672: /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), -/* 53 */ -/***/ (function(module, exports, __webpack_require__) { -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! - Copyright (c) 2016 Jed Watson. - Licensed under the MIT License (MIT), see - http://jedwatson.github.io/classnames -*/ -/* global define */ - -(function () { - 'use strict'; - - var hasOwn = {}.hasOwnProperty; - - function classNames () { - var classes = []; - - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - if (!arg) continue; - - var argType = typeof arg; - - if (argType === 'string' || argType === 'number') { - classes.push(arg); - } else if (Array.isArray(arg)) { - classes.push(classNames.apply(null, arg)); - } else if (argType === 'object') { - for (var key in arg) { - if (hasOwn.call(arg, key) && arg[key]) { - classes.push(key); - } - } - } - } - - return classes.join(' '); - } - - if (typeof module !== 'undefined' && module.exports) { - module.exports = classNames; - } else if (true) { - // register as 'classnames', consistent with npm package name - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () { - return classNames; - }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else { - window.classNames = classNames; - } -}()); - - -/***/ }), -/* 54 */ +/***/ 3673: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6669,7 +4476,2084 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ + +// Dependencies +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders undefined value + */ +const Undefined = function () { + return span({ className: "objectBox objectBox-undefined" }, "undefined"); +}; + +function supportsObject(object, noGrip = false) { + if (noGrip === true) { + return object === undefined; + } + + return object && object.type && object.type == "undefined" || getGripType(object, noGrip) == "undefined"; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Undefined), + supportsObject +}; + +/***/ }), + +/***/ 3674: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const { wrapRender } = __webpack_require__(3644); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders null value + */ +function Null(props) { + return span({ className: "objectBox objectBox-null" }, "null"); +} + +function supportsObject(object, noGrip = false) { + if (noGrip === true) { + return object === null; + } + + if (object && object.type && object.type == "null") { + return true; + } + + return object == null; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Null), + supportsObject +}; + +/***/ }), + +/***/ 3675: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a number + */ +Number.propTypes = { + object: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.bool]).isRequired +}; + +function Number(props) { + const value = props.object; + + return span({ className: "objectBox objectBox-number" }, stringify(value)); +} + +function stringify(object) { + const isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0"; + + return isNegativeZero ? "-0" : String(object); +} + +function supportsObject(object, noGrip = false) { + return ["boolean", "number", "-0"].includes(getGripType(object, noGrip)); +} + +// Exports from this module + +module.exports = { + rep: wrapRender(Number), + supportsObject +}; + +/***/ }), + +/***/ 3676: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); +const { wrapRender, ellipsisElement } = __webpack_require__(3644); +const PropRep = __webpack_require__(3650); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +const DEFAULT_TITLE = "Object"; + +/** + * Renders an object. An object is represented by a list of its + * properties enclosed in curly brackets. + */ +ObjectRep.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + title: PropTypes.string +}; + +function ObjectRep(props) { + const object = props.object; + const propsArray = safePropIterator(props, object); + + if (props.mode === MODE.TINY) { + const tinyModeItems = []; + if (getTitle(props, object) !== DEFAULT_TITLE) { + tinyModeItems.push(getTitleElement(props, object)); + } else { + tinyModeItems.push(span({ + className: "objectLeftBrace" + }, "{"), propsArray.length > 0 ? ellipsisElement : null, span({ + className: "objectRightBrace" + }, "}")); + } + + return span({ className: "objectBox objectBox-object" }, ...tinyModeItems); + } + + return span({ className: "objectBox objectBox-object" }, getTitleElement(props, object), span({ + className: "objectLeftBrace" + }, " { "), ...propsArray, span({ + className: "objectRightBrace" + }, " }")); +} + +function getTitleElement(props, object) { + return span({ className: "objectTitle" }, getTitle(props, object)); +} + +function getTitle(props, object) { + return props.title || DEFAULT_TITLE; +} + +function safePropIterator(props, object, max) { + max = typeof max === "undefined" ? 3 : max; + try { + return propIterator(props, object, max); + } catch (err) { + console.error(err); + } + return []; +} + +function propIterator(props, object, max) { + // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377 + if (Object.prototype.toString.call(object) === "[object Generator]") { + object = Object.getPrototypeOf(object); + } + + const elements = []; + const unimportantProperties = []; + let propertiesNumber = 0; + const propertiesNames = Object.keys(object); + + const pushPropRep = (name, value) => { + elements.push(PropRep(_extends({}, props, { + key: name, + mode: MODE.TINY, + name, + object: value, + equal: ": " + }))); + propertiesNumber++; + + if (propertiesNumber < propertiesNames.length) { + elements.push(", "); + } + }; + + try { + for (const name of propertiesNames) { + if (propertiesNumber >= max) { + break; + } + + let value; + try { + value = object[name]; + } catch (exc) { + continue; + } + + // Object members with non-empty values are preferred since it gives the + // user a better overview of the object. + if (isInterestingProp(value)) { + pushPropRep(name, value); + } else { + // If the property is not important, put its name on an array for later + // use. + unimportantProperties.push(name); + } + } + } catch (err) { + console.error(err); + } + + if (propertiesNumber < max) { + for (const name of unimportantProperties) { + if (propertiesNumber >= max) { + break; + } + + let value; + try { + value = object[name]; + } catch (exc) { + continue; + } + + pushPropRep(name, value); + } + } + + if (propertiesNumber < propertiesNames.length) { + elements.push(ellipsisElement); + } + + return elements; +} + +function isInterestingProp(value) { + const type = typeof value; + return type == "boolean" || type == "number" || type == "string" && value; +} + +function supportsObject(object) { + return true; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectRep), + supportsObject +}; + +/***/ }), + +/***/ 3677: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a symbol. + */ +SymbolRep.propTypes = { + object: PropTypes.object.isRequired +}; + +function SymbolRep(props) { + const { className = "objectBox objectBox-symbol", object } = props; + const { name } = object; + + return span({ + className, + "data-link-actor-id": object.actor + }, `Symbol(${name || ""})`); +} + +function supportsObject(object, noGrip = false) { + return getGripType(object, noGrip) == "symbol"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(SymbolRep), + supportsObject +}; + +/***/ }), + +/***/ 3678: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); + +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a Infinity object + */ +InfinityRep.propTypes = { + object: PropTypes.object.isRequired +}; + +function InfinityRep(props) { + const { object } = props; + + return span({ className: "objectBox objectBox-number" }, object.type); +} + +function supportsObject(object, noGrip = false) { + const type = getGripType(object, noGrip); + return type == "Infinity" || type == "-Infinity"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(InfinityRep), + supportsObject +}; + +/***/ }), + +/***/ 3679: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const { getGripType, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a NaN object + */ +function NaNRep(props) { + return span({ className: "objectBox objectBox-nan" }, "NaN"); +} + +function supportsObject(object, noGrip = false) { + return getGripType(object, noGrip) == "NaN"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(NaNRep), + supportsObject +}; + +/***/ }), + +/***/ 3680: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const dom = __webpack_require__(3643); +const PropTypes = __webpack_require__(3642); +const { wrapRender } = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); +const { span } = dom; + +/** + * Renders an object. An object is represented by a list of its + * properties enclosed in curly brackets. + */ +Accessor.propTypes = { + object: PropTypes.object.isRequired, + mode: PropTypes.oneOf(Object.values(MODE)) +}; + +function Accessor(props) { + const { object } = props; + + const accessors = []; + if (hasGetter(object)) { + accessors.push("Getter"); + } + if (hasSetter(object)) { + accessors.push("Setter"); + } + const title = accessors.join(" & "); + + return span({ className: "objectBox objectBox-accessor objectTitle" }, title); +} + +function hasGetter(object) { + return object && object.get && object.get.type !== "undefined"; +} + +function hasSetter(object) { + return object && object.set && object.set.type !== "undefined"; +} + +function supportsObject(object, noGrip = false) { + if (noGrip !== true && (hasGetter(object) || hasSetter(object))) { + return true; + } + + return false; +} + +// Exports from this module +module.exports = { + rep: wrapRender(Accessor), + supportsObject +}; + +/***/ }), + +/***/ 3681: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); +const dom = __webpack_require__(3643); +const { span } = dom; + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); +const { rep: StringRep } = __webpack_require__(3648); + +/** + * Renders DOM attribute + */ +Attribute.propTypes = { + object: PropTypes.object.isRequired +}; + +function Attribute(props) { + const { object } = props; + const value = object.preview.value; + + return span({ + "data-link-actor-id": object.actor, + className: "objectBox-Attr" + }, span({ className: "attrName" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); +} + +function getTitle(grip) { + return grip.preview.nodeName; +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return getGripType(grip, noGrip) == "Attr" && grip.preview; +} + +module.exports = { + rep: wrapRender(Attribute), + supportsObject +}; + +/***/ }), + +/***/ 3682: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Used to render JS built-in Date() object. + */ +DateTime.propTypes = { + object: PropTypes.object.isRequired +}; + +function DateTime(props) { + const grip = props.object; + let date; + try { + date = span({ + "data-link-actor-id": grip.actor, + className: "objectBox" + }, getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString())); + } catch (e) { + date = span({ className: "objectBox" }, "Invalid Date"); + } + + return date; +} + +function getTitle(grip) { + return span({ + className: "objectTitle" + }, `${grip.class} `); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return getGripType(grip, noGrip) == "Date" && grip.preview; +} + +// Exports from this module +module.exports = { + rep: wrapRender(DateTime), + supportsObject +}; + +/***/ }), + +/***/ 3683: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM document object. + */ +Document.propTypes = { + object: PropTypes.object.isRequired +}; + +function Document(props) { + const grip = props.object; + const location = getLocation(grip); + return span({ + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-document" + }, getTitle(grip), location ? span({ className: "location" }, ` ${location}`) : null); +} + +function getLocation(grip) { + const location = grip.preview.location; + return location ? getURLDisplayString(location) : null; +} + +function getTitle(grip) { + return span({ + className: "objectTitle" + }, grip.class); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + const type = getGripType(object, noGrip); + return object.preview && (type === "HTMLDocument" || type === "XULDocument"); +} + +// Exports from this module +module.exports = { + rep: wrapRender(Document), + supportsObject +}; + +/***/ }), + +/***/ 3684: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM documentType object. + */ +DocumentType.propTypes = { + object: PropTypes.object.isRequired +}; + +function DocumentType(props) { + const { object } = props; + const name = object && object.preview && object.preview.nodeName ? ` ${object.preview.nodeName}` : ""; + return span({ + "data-link-actor-id": props.object.actor, + className: "objectBox objectBox-document" + }, ``); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + const type = getGripType(object, noGrip); + return object.preview && type === "DocumentType"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(DocumentType), + supportsObject +}; + +/***/ }), + +/***/ 3685: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, wrapRender } = __webpack_require__(3644); + +const { MODE } = __webpack_require__(3645); +const { rep } = __webpack_require__(3656); + +/** + * Renders DOM event objects. + */ +Event.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function Event(props) { + const gripProps = _extends({}, props, { + title: getTitle(props), + object: _extends({}, props.object, { + preview: _extends({}, props.object.preview, { + ownProperties: {} + }) + }) + }); + + if (gripProps.object.preview.target) { + Object.assign(gripProps.object.preview.ownProperties, { + target: gripProps.object.preview.target + }); + } + Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties); + + delete gripProps.object.preview.properties; + gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length; + + switch (gripProps.object.class) { + case "MouseEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name); + }; + break; + case "KeyboardEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "key", "charCode", "keyCode"].includes(name); + }; + break; + case "MessageEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "isTrusted", "data"].includes(name); + }; + break; + default: + gripProps.isInterestingProp = (type, value, name) => { + // We want to show the properties in the order they are declared. + return Object.keys(gripProps.object.preview.ownProperties).includes(name); + }; + } + + return rep(gripProps); +} + +function getTitle(props) { + const preview = props.object.preview; + let title = preview.type; + + if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) { + title = `${title} ${preview.modifiers.join("-")}`; + } + return title; +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "DOMEvent"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(Event), + supportsObject +}; + +/***/ }), + +/***/ 3686: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); +// Dependencies +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const PropRep = __webpack_require__(3650); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a DOM Promise object. + */ +PromiseRep.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function PromiseRep(props) { + const object = props.object; + const { promiseState } = object; + + const config = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-object" + }; + + if (props.mode === MODE.TINY) { + const { Rep } = __webpack_require__(3647); + + return span(config, getTitle(object), span({ + className: "objectLeftBrace" + }, " { "), Rep({ object: promiseState.state }), span({ + className: "objectRightBrace" + }, " }")); + } + + const propsArray = getProps(props, promiseState); + return span(config, getTitle(object), span({ + className: "objectLeftBrace" + }, " { "), ...propsArray, span({ + className: "objectRightBrace" + }, " }")); +} + +function getTitle(object) { + return span({ + className: "objectTitle" + }, object.class); +} + +function getProps(props, promiseState) { + const keys = ["state"]; + if (Object.keys(promiseState).includes("value")) { + keys.push("value"); + } + + return keys.reduce((res, key, i) => { + const object = promiseState[key]; + res = res.concat(PropRep(_extends({}, props, { + mode: MODE.TINY, + name: `<${key}>`, + object, + equal: ": ", + suppressQuotes: true + }))); + + // Interleave commas between elements + if (i !== keys.length - 1) { + res.push(", "); + } + + return res; + }, []); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return getGripType(object, noGrip) == "Promise"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(PromiseRep), + supportsObject +}; + +/***/ }), + +/***/ 3687: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { getGripType, isGrip, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with regular expression. + */ +RegExp.propTypes = { + object: PropTypes.object.isRequired +}; + +function RegExp(props) { + const { object } = props; + + return span({ + "data-link-actor-id": object.actor, + className: "objectBox objectBox-regexp regexpSource" + }, getSource(object)); +} + +function getSource(grip) { + return grip.displayString; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return getGripType(object, noGrip) == "RegExp"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(RegExp), + supportsObject +}; + +/***/ }), + +/***/ 3688: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip representing CSSStyleSheet + */ +StyleSheet.propTypes = { + object: PropTypes.object.isRequired +}; + +function StyleSheet(props) { + const grip = props.object; + + return span({ + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-object" + }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip))); +} + +function getTitle(grip) { + const title = "StyleSheet "; + return span({ className: "objectBoxTitle" }, title); +} + +function getLocation(grip) { + // Embedded stylesheets don't have URL and so, no preview. + const url = grip.preview ? grip.preview.url : ""; + return url ? getURLDisplayString(url) : ""; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return getGripType(object, noGrip) == "CSSStyleSheet"; +} + +// Exports from this module + +module.exports = { + rep: wrapRender(StyleSheet), + supportsObject +}; + +/***/ }), + +/***/ 3689: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// Dependencies +const PropTypes = __webpack_require__(3642); +const { + isGrip, + cropString, + cropMultipleLines, + wrapRender +} = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); +const nodeConstants = __webpack_require__(3659); +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM comment node. + */ +CommentNode.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) +}; + +function CommentNode(props) { + const { object, mode = MODE.SHORT } = props; + + let { textContent } = object.preview; + if (mode === MODE.TINY) { + textContent = cropMultipleLines(textContent, 30); + } else if (mode === MODE.SHORT) { + textContent = cropString(textContent, 50); + } + + return span({ + className: "objectBox theme-comment", + "data-link-actor-id": object.actor + }, ``); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(CommentNode), + supportsObject +}; + +/***/ }), + +/***/ 3690: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Utils +const { isGrip, wrapRender } = __webpack_require__(3644); +const { rep: StringRep } = __webpack_require__(3648); +const { MODE } = __webpack_require__(3645); +const nodeConstants = __webpack_require__(3659); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM element node. + */ +ElementNode.propTypes = { + object: PropTypes.object.isRequired, + inspectIconTitle: PropTypes.string, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeClick: PropTypes.func, + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function ElementNode(props) { + const { + object, + inspectIconTitle, + mode, + onDOMNodeClick, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + const elements = getElements(object, mode); + + const isInTree = object.preview && object.preview.isConnected === true; + + const baseConfig = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-node" + }; + let inspectIcon; + if (isInTree) { + if (onDOMNodeClick) { + Object.assign(baseConfig, { + onClick: _ => onDOMNodeClick(object) + }); + } + + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(object) + }); + } + + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); + } + + if (onInspectIconClick) { + inspectIcon = dom.button({ + className: "open-inspector", + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: inspectIconTitle || "Click to select the node in the inspector", + onClick: e => { + if (onDOMNodeClick) { + e.stopPropagation(); + } + + onInspectIconClick(object, e); + } + }); + } + } + + return span(baseConfig, ...elements, inspectIcon); +} + +function getElements(grip, mode) { + const { + attributes, + nodeName, + isAfterPseudoElement, + isBeforePseudoElement + } = grip.preview; + const nodeNameElement = span({ + className: "tag-name" + }, nodeName); + + if (isAfterPseudoElement || isBeforePseudoElement) { + return [span({ className: "attrName" }, `::${isAfterPseudoElement ? "after" : "before"}`)]; + } + + if (mode === MODE.TINY) { + const elements = [nodeNameElement]; + if (attributes.id) { + elements.push(span({ className: "attrName" }, `#${attributes.id}`)); + } + if (attributes.class) { + elements.push(span({ className: "attrName" }, attributes.class.trim().split(/\s+/).map(cls => `.${cls}`).join(""))); + } + return elements; + } + + const attributeKeys = Object.keys(attributes); + if (attributeKeys.includes("class")) { + attributeKeys.splice(attributeKeys.indexOf("class"), 1); + attributeKeys.unshift("class"); + } + if (attributeKeys.includes("id")) { + attributeKeys.splice(attributeKeys.indexOf("id"), 1); + attributeKeys.unshift("id"); + } + const attributeElements = attributeKeys.reduce((arr, name, i, keys) => { + const value = attributes[name]; + const attribute = span({}, span({ className: "attrName" }, name), span({ className: "attrEqual" }, "="), StringRep({ className: "attrValue", object: value })); + + return arr.concat([" ", attribute]); + }, []); + + return [span({ className: "angleBracket" }, "<"), nodeNameElement, ...attributeElements, span({ className: "angleBracket" }, ">")]; +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ElementNode), + supportsObject +}; + +/***/ }), + +/***/ 3691: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, cropString, wrapRender } = __webpack_require__(3644); +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders DOM #text node. + */ +TextNode.propTypes = { + object: PropTypes.object.isRequired, + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: PropTypes.func, + onDOMNodeMouseOut: PropTypes.func, + onInspectIconClick: PropTypes.func +}; + +function TextNode(props) { + const { + object: grip, + mode = MODE.SHORT, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + + const baseConfig = { + "data-link-actor-id": grip.actor, + className: "objectBox objectBox-textNode" + }; + let inspectIcon; + const isInTree = grip.preview && grip.preview.isConnected === true; + + if (isInTree) { + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(grip) + }); + } + + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); + } + + if (onInspectIconClick) { + inspectIcon = dom.button({ + className: "open-inspector", + draggable: false, + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: "Click to select the node in the inspector", + onClick: e => onInspectIconClick(grip, e) + }); + } + } + + if (mode === MODE.TINY) { + return span(baseConfig, getTitle(grip), inspectIcon); + } + + return span(baseConfig, getTitle(grip), span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); +} + +function getTextContent(grip) { + return cropString(grip.preview.textContent); +} + +function getTitle(grip) { + const title = "#text"; + return span({}, title); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.class == "Text"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(TextNode), + supportsObject +}; + +/***/ }), + +/***/ 3692: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { + getGripType, + isGrip, + getURLDisplayString, + wrapRender +} = __webpack_require__(3644); + +const { MODE } = __webpack_require__(3645); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip representing a window. + */ +WindowRep.propTypes = { + // @TODO Change this to Object.values when supported in Node's version of V8 + mode: PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + object: PropTypes.object.isRequired +}; + +function WindowRep(props) { + const { mode, object } = props; + + const config = { + "data-link-actor-id": object.actor, + className: "objectBox objectBox-Window" + }; + + if (mode === MODE.TINY) { + return span(config, getTitle(object)); + } + + return span(config, getTitle(object, true), span({ className: "location" }, getLocation(object))); +} + +function getTitle(object, trailingSpace) { + let title = object.displayClass || object.class || "Window"; + if (trailingSpace === true) { + title = `${title} `; + } + return span({ className: "objectTitle" }, title); +} + +function getLocation(object) { + return getURLDisplayString(object.preview.url); +} + +// Registration +function supportsObject(object, noGrip = false) { + if (noGrip === true || !isGrip(object)) { + return false; + } + + return object.preview && getGripType(object, noGrip) == "Window"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(WindowRep), + supportsObject +}; + +/***/ }), + +/***/ 3693: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, wrapRender } = __webpack_require__(3644); + +const String = __webpack_require__(3648).rep; + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with textual data. + */ +ObjectWithText.propTypes = { + object: PropTypes.object.isRequired +}; + +function ObjectWithText(props) { + const grip = props.object; + return span({ + "data-link-actor-id": grip.actor, + className: `objectTitle objectBox objectBox-${getType(grip)}` + }, `${getType(grip)} `, getDescription(grip)); +} + +function getType(grip) { + return grip.class; +} + +function getDescription(grip) { + return String({ + object: grip.preview.text + }); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "ObjectWithText"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectWithText), + supportsObject +}; + +/***/ }), + +/***/ 3694: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +// ReactJS +const PropTypes = __webpack_require__(3642); + +// Reps +const { isGrip, getURLDisplayString, wrapRender } = __webpack_require__(3644); + +const dom = __webpack_require__(3643); +const { span } = dom; + +/** + * Renders a grip object with URL data. + */ +ObjectWithURL.propTypes = { + object: PropTypes.object.isRequired +}; + +function ObjectWithURL(props) { + const grip = props.object; + return span({ + "data-link-actor-id": grip.actor, + className: `objectBox objectBox-${getType(grip)}` + }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip))); +} + +function getTitle(grip) { + return span({ className: "objectTitle" }, `${getType(grip)} `); +} + +function getType(grip) { + return grip.class; +} + +function getDescription(grip) { + return getURLDisplayString(grip.preview.url); +} + +// Registration +function supportsObject(grip, noGrip = false) { + if (noGrip === true || !isGrip(grip)) { + return false; + } + + return grip.preview && grip.preview.kind == "ObjectWithURL"; +} + +// Exports from this module +module.exports = { + rep: wrapRender(ObjectWithURL), + supportsObject +}; + +/***/ }), + +/***/ 3695: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +const { createElement, createFactory, PureComponent } = __webpack_require__(0); +const { Provider } = __webpack_require__(3592); +const ObjectInspector = createFactory(__webpack_require__(3696)); +const createStore = __webpack_require__(3700); +const Utils = __webpack_require__(3657); +const { renderRep, shouldRenderRootsInReps } = Utils; + +class OI extends PureComponent { + constructor(props) { + super(props); + this.store = createStore(props); + } + + getStore() { + return this.store; + } + + render() { + return createElement(Provider, { store: this.store }, ObjectInspector(this.props)); + } +} + +module.exports = props => { + const { roots } = props; + if (shouldRenderRootsInReps(roots)) { + return renderRep(roots[0], props); + } + return new OI(props); +}; + +/***/ }), + +/***/ 3696: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _devtoolsComponents = __webpack_require__(3669); + +var _devtoolsComponents2 = _interopRequireDefault(_devtoolsComponents); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +const { Component, createFactory } = __webpack_require__(0); +const dom = __webpack_require__(3643); +const { connect } = __webpack_require__(3592); +const { bindActionCreators } = __webpack_require__(3593); + +const Tree = createFactory(_devtoolsComponents2.default.Tree); +__webpack_require__(3697); + +const classnames = __webpack_require__(175); +const { MODE } = __webpack_require__(3645); + +const Utils = __webpack_require__(3657); + +const { + getChildren, + getClosestGripNode, + getParent, + getValue, + nodeHasAccessors, + nodeHasProperties, + nodeIsBlock, + nodeIsDefaultProperties, + nodeIsFunction, + nodeIsGetter, + nodeIsMapEntry, + nodeIsMissingArguments, + nodeIsOptimizedOut, + nodeIsPrimitive, + nodeIsPrototype, + nodeIsSetter, + nodeIsUninitializedBinding, + nodeIsUnmappedBinding, + nodeIsUnscopedBinding, + nodeIsWindow, + nodeIsLongString, + nodeHasFullText +} = Utils.node; + +// This implements a component that renders an interactive inspector +// for looking at JavaScript objects. It expects descriptions of +// objects from the protocol, and will dynamically fetch children +// properties as objects are expanded. +// +// If you want to inspect a single object, pass the name and the +// protocol descriptor of it: +// +// ObjectInspector({ +// name: "foo", +// desc: { writable: true, ..., { value: { actor: "1", ... }}}, +// ... +// }) +// +// If you want multiple top-level objects (like scopes), you can pass +// an array of manually constructed nodes as `roots`: +// +// ObjectInspector({ +// roots: [{ name: ... }, ...], +// ... +// }); + +// There are 3 types of nodes: a simple node with a children array, an +// object that has properties that should be children when they are +// fetched, and a primitive value that should be displayed with no +// children. + +class ObjectInspector extends Component { + constructor(props) { + super(); + this.cachedNodes = new Map(); + + const self = this; + + self.getItemChildren = this.getItemChildren.bind(this); + self.renderTreeItem = this.renderTreeItem.bind(this); + self.setExpanded = this.setExpanded.bind(this); + self.focusItem = this.focusItem.bind(this); + self.getRoots = this.getRoots.bind(this); + } + + shouldComponentUpdate(nextProps) { + const { expandedPaths, focusedItem, loadedProperties, roots } = this.props; + + if (roots !== nextProps.roots) { + // Since the roots changed, we assume the properties did as well, + // so we need to cleanup the component internal state. + + // We can clear the cachedNodes to avoid bugs and memory leaks. + this.cachedNodes.clear(); + // The rootsChanged action will be handled in a middleware to release the + // actors of the old roots, as well as cleanup the state properties + // (expandedPaths, loadedProperties, …). + this.props.rootsChanged(nextProps); + // We don't render right away since the state is going to be changed by + // the rootsChanged action. The `state.forceUpdate` flag will be set + // to `true` so we can execute a new render cycle with the cleaned state. + return false; + } + + if (nextProps.forceUpdate === true) { + return true; + } + + // We should update if: + // - there are new loaded properties + // - OR the expanded paths number changed, and all of them have properties + // loaded + // - OR the expanded paths number did not changed, but old and new sets + // differ + // - OR the focused node changed. + return loadedProperties.size !== nextProps.loadedProperties.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || focusedItem !== nextProps.focusedItem; + } + + componentDidUpdate(prevProps) { + if (this.props.forceUpdate) { + // If the component was updated, we can then reset the forceUpdate flag. + this.props.forceUpdated(); + } + } + + componentWillUnmount() { + const { releaseActor } = this.props; + if (typeof releaseActor !== "function") { + return; + } + + const { actors } = this.props; + for (const actor of actors) { + releaseActor(actor); + } + } + + getItemChildren(item) { + const { loadedProperties } = this.props; + const { cachedNodes } = this; + + return getChildren({ + loadedProperties, + cachedNodes, + item + }); + } + + getRoots() { + return this.props.roots; + } + + getNodeKey(item) { + return item.path && typeof item.path.toString === "function" ? item.path.toString() : JSON.stringify(item); + } + + setExpanded(item, expand) { + if (nodeIsPrimitive(item)) { + return; + } + + const { + createObjectClient, + createLongStringClient, + loadedProperties, + nodeExpand, + nodeCollapse, + roots + } = this.props; + + if (expand === true) { + const gripItem = getClosestGripNode(item); + const value = getValue(gripItem); + const isRoot = value && roots.some(root => { + const rootValue = getValue(root); + return rootValue && rootValue.actor === value.actor; + }); + const actor = isRoot || !value ? null : value.actor; + nodeExpand(item, actor, loadedProperties, createObjectClient, createLongStringClient); + } else { + nodeCollapse(item); + } + } + + focusItem(item) { + const { focusable = true, focusedItem, nodeFocus, onFocus } = this.props; + + if (focusable && focusedItem !== item) { + nodeFocus(item); + if (focusedItem !== item && onFocus) { + onFocus(item); + } + } + } + + // eslint-disable-next-line complexity + getTreeItemLabelAndValue(item, depth, expanded) { + const label = item.name; + const isPrimitive = nodeIsPrimitive(item); + + if (nodeIsOptimizedOut(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(optimized away)") + }; + } + + if (nodeIsUninitializedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(uninitialized)") + }; + } + + if (nodeIsUnmappedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unmapped)") + }; + } + + if (nodeIsUnscopedBinding(item)) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unscoped)") + }; + } + + const itemValue = getValue(item); + const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); + + if (nodeIsMissingArguments(item) || unavailable) { + return { + label, + value: dom.span({ className: "unavailable" }, "(unavailable)") + }; + } + + if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode)) { + return { + label: Utils.renderRep(item, _extends({}, this.props, { + functionName: label + })) + }; + } + + if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive) { + const repProps = _extends({}, this.props); + if (depth > 0) { + repProps.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY; + } + if (expanded) { + repProps.mode = MODE.TINY; + } + + if (nodeIsLongString(item)) { + repProps.member = { + open: nodeHasFullText(item) && expanded + }; + } + + return { + label, + value: Utils.renderRep(item, repProps) + }; + } + + return { + label + }; + } + + renderTreeItemLabel(label, item, depth, focused, expanded) { + if (label === null || typeof label === "undefined") { + return null; + } + + const { onLabelClick } = this.props; + + return dom.span({ + className: "object-label", + onClick: onLabelClick ? event => { + event.stopPropagation(); + + // If the user selected text, bail out. + if (Utils.selection.documentHasSelection()) { + return; + } + + onLabelClick(item, { + depth, + focused, + expanded, + setExpanded: this.setExpanded + }); + } : undefined + }, label); + } + + getTreeTopElementProps(item, depth, focused, expanded) { + const { onCmdCtrlClick, onDoubleClick, dimTopLevelWindow } = this.props; + + const parentElementProps = { + className: classnames("node object-node", { + focused, + lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0), + block: nodeIsBlock(item) + }), + onClick: e => { + if (e.metaKey && onCmdCtrlClick) { + onCmdCtrlClick(item, { + depth, + event: e, + focused, + expanded + }); + e.stopPropagation(); + return; + } + + // If this click happened because the user selected some text, bail out. + // Note that if the user selected some text before and then clicks here, + // the previously selected text will be first unselected, unless the + // user clicked on the arrow itself. Indeed because the arrow is an + // image, clicking on it does not remove any existing text selection. + // So we need to also check if the arrow was clicked. + if (Utils.selection.documentHasSelection() && !(e.target && e.target.matches && e.target.matches(".arrow"))) { + e.stopPropagation(); + } + } + }; + + if (onDoubleClick) { + parentElementProps.onDoubleClick = e => { + e.stopPropagation(); + onDoubleClick(item, { + depth, + focused, + expanded + }); + }; + } + + return parentElementProps; + } + + renderTreeItem(item, depth, focused, arrow, expanded) { + const { label, value } = this.getTreeItemLabelAndValue(item, depth, expanded); + const labelElement = this.renderTreeItemLabel(label, item, depth, focused, expanded); + const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; + + return dom.div(this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value); + } + + render() { + const { + autoExpandAll = true, + autoExpandDepth = 1, + focusable = true, + disableWrap = false, + expandedPaths, + focusedItem, + inline + } = this.props; + + return Tree({ + className: classnames({ + inline, + nowrap: disableWrap, + "object-inspector": true + }), + autoExpandAll, + autoExpandDepth, + + isExpanded: item => expandedPaths && expandedPaths.has(item.path), + isExpandable: item => nodeIsPrimitive(item) === false, + focused: focusedItem, + + getRoots: this.getRoots, + getParent, + getChildren: this.getItemChildren, + getKey: this.getNodeKey, + + onExpand: item => this.setExpanded(item, true), + onCollapse: item => this.setExpanded(item, false), + onFocus: focusable ? this.focusItem : null, + + renderItem: this.renderTreeItem + }); + } +} + +function mapStateToProps(state, props) { + return { + actors: state.actors, + expandedPaths: state.expandedPaths, + // If the root changes, we want to pass a possibly new focusedItem property + focusedItem: state.roots !== props.roots ? props.focusedItem : state.focusedItem, + loadedProperties: state.loadedProperties, + forceUpdate: state.forceUpdate + }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators(__webpack_require__(3699), dispatch); +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(ObjectInspector); + +/***/ }), + +/***/ 3697: +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), + +/***/ 3698: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ function documentHasSelection() { const selection = getSelection(); @@ -6685,21 +6569,20 @@ module.exports = { }; /***/ }), -/* 55 */ + +/***/ 3699: /***/ (function(module, exports, __webpack_require__) { "use strict"; -const { - loadItemProperties -} = __webpack_require__(21); /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const { loadItemProperties } = __webpack_require__(3666); /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ /** - * This action is responsible for expanding a given node, - * which also means that it will call the action responsible to fetch properties. + * This action is responsible for expanding a given node, which also means that + * it will call the action responsible to fetch properties. */ function nodeExpand(node, actor, loadedProperties, createObjectClient, createLongStringClient) { return async ({ dispatch }) => { @@ -6728,8 +6611,9 @@ function nodeFocus(node) { }; } /* - * This action checks if we need to fetch properties, entries, prototype and symbols - * for a given node. If we do, it will call the appropriate ObjectClient functions. + * This action checks if we need to fetch properties, entries, prototype and + * symbols for a given node. If we do, it will call the appropriate ObjectClient + * functions. */ function nodeLoadProperties(item, actor, loadedProperties, createObjectClient, createLongStringClient) { return async ({ dispatch }) => { @@ -6750,11 +6634,12 @@ function nodePropertiesLoaded(node, actor, properties) { } /* - * This action is dispatched when the `roots` prop, provided by a consumer of the - * ObjectInspector (inspector, console, …), is modified. It will clean the internal - * state properties (expandedPaths, loadedProperties, …) and release the actors consumed - * with the previous roots. - * It takes a props argument which reflects what is passed by the upper-level consumer. + * This action is dispatched when the `roots` prop, provided by a consumer of + * the ObjectInspector (inspector, console, …), is modified. It will clean the + * internal state properties (expandedPaths, loadedProperties, …) and release + * the actors consumed with the previous roots. + * It takes a props argument which reflects what is passed by the upper-level + * consumer. */ function rootsChanged(props) { return { @@ -6783,30 +6668,34 @@ module.exports = { }; /***/ }), -/* 56 */ + +/***/ 3700: /***/ (function(module, exports, __webpack_require__) { "use strict"; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ -const { applyMiddleware, createStore, compose } = __webpack_require__(19); -const { thunk } = __webpack_require__(57); -const { waitUntilService } = __webpack_require__(58); -const reducer = __webpack_require__(59); +const { applyMiddleware, createStore, compose } = __webpack_require__(3593); +const { thunk } = __webpack_require__(3701); +const { + waitUntilService +} = __webpack_require__(3702); +const reducer = __webpack_require__(3703); function createInitialState(overrides) { - return { + return _extends({ actors: new Set(), expandedPaths: new Set(), focusedItem: null, loadedProperties: new Map(), - forceUpdated: false, - ...overrides - }; + forceUpdated: false + }, overrides); } function enableStateReinitializer(props) { @@ -6820,14 +6709,14 @@ function enableStateReinitializer(props) { initialState.actors.forEach(props.releaseActor); } - return { - ...action.data, + return _extends({}, action.data, { actors: new Set(), expandedPaths: new Set(), loadedProperties: new Map(), - // Indicates to the component that we do want to render on the next render cycle. + // Indicates to the component that we do want to render on the next + // render cycle. forceUpdate: true - }; + }); } return next(reinitializerEnhancer, initialState, enhancer); }; @@ -6844,7 +6733,8 @@ module.exports = props => { }; /***/ }), -/* 57 */ + +/***/ 3701: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6852,7 +6742,7 @@ module.exports = props => { /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ /** * A middleware that allows thunks (functions) to be dispatched. @@ -6868,7 +6758,8 @@ function thunk({ dispatch, getState }) { exports.thunk = thunk; /***/ }), -/* 58 */ + +/***/ 3702: /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -6876,7 +6767,7 @@ exports.thunk = thunk; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ const WAIT_UNTIL_TYPE = "@@service/waitUntil"; /** @@ -6942,19 +6833,19 @@ module.exports = { }; /***/ }), -/* 59 */ + +/***/ 3703: /***/ (function(module, exports, __webpack_require__) { "use strict"; -function reducer(state = {}, action) { - const { - type, - data - } = action; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - const cloneState = overrides => ({ ...state, ...overrides }); +function reducer(state = {}, action) { + const { type, data } = action; + + const cloneState = overrides => _extends({}, state, overrides); if (type === "NODE_EXPAND") { return cloneState({ @@ -6994,11 +6885,12 @@ function reducer(state = {}, action) { return state; } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ module.exports = reducer; /***/ }) -/******/ ]); + +/******/ }); }); \ No newline at end of file diff --git a/devtools/client/shared/source-map/index.js b/devtools/client/shared/source-map/index.js index a92b3a661642..f0b233417146 100644 --- a/devtools/client/shared/source-map/index.js +++ b/devtools/client/shared/source-map/index.js @@ -7,7 +7,7 @@ var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(this, function() { +})(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -67,158 +67,22 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; +/******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 15); +/******/ return __webpack_require__(__webpack_require__.s = 3646); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { +/******/ ({ -var charenc = { - // UTF-8 encoding - utf8: { - // Convert a string to a byte array - stringToBytes: function(str) { - return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); - }, - - // Convert a byte array to a string - bytesToString: function(bytes) { - return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); - } - }, - - // Binary encoding - bin: { - // Convert a string to a byte array - stringToBytes: function(str) { - for (var bytes = [], i = 0; i < str.length; i++) - bytes.push(str.charCodeAt(i) & 0xFF); - return bytes; - }, - - // Convert a byte array to a string - bytesToString: function(bytes) { - for (var str = [], i = 0; i < bytes.length; i++) - str.push(String.fromCharCode(bytes[i])); - return str.join(''); - } - } -}; - -module.exports = charenc; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const networkRequest = __webpack_require__(7); -const workerUtils = __webpack_require__(8); - -module.exports = { - networkRequest, - workerUtils -}; - -/***/ }), -/* 2 */, -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const md5 = __webpack_require__(4); - -function originalToGeneratedId(originalId) { - const match = originalId.match(/(.*)\/originalSource/); - return match ? match[1] : ""; -} - -function generatedToOriginalId(generatedId, url) { - return `${generatedId}/originalSource-${md5(url)}`; -} - -function isOriginalId(id) { - return !!id.match(/\/originalSource/); -} - -function isGeneratedId(id) { - return !isOriginalId(id); -} - -/** - * Trims the query part or reference identifier of a URL string, if necessary. - */ -function trimUrlQuery(url) { - let length = url.length; - let q1 = url.indexOf("?"); - let q2 = url.indexOf("&"); - let q3 = url.indexOf("#"); - let q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); - - return url.slice(0, q); -} - -// Map suffix to content type. -const contentMap = { - "js": "text/javascript", - "jsm": "text/javascript", - "mjs": "text/javascript", - "ts": "text/typescript", - "tsx": "text/typescript-jsx", - "jsx": "text/jsx", - "coffee": "text/coffeescript", - "elm": "text/elm", - "cljs": "text/x-clojure" -}; - -/** - * Returns the content type for the specified URL. If no specific - * content type can be determined, "text/plain" is returned. - * - * @return String - * The content type. - */ -function getContentType(url) { - url = trimUrlQuery(url); - let dot = url.lastIndexOf("."); - if (dot >= 0) { - let name = url.substring(dot + 1); - if (name in contentMap) { - return contentMap[name]; - } - } - return "text/plain"; -} - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isOriginalId, - isGeneratedId, - getContentType, - contentMapForTesting: contentMap -}; - -/***/ }), -/* 4 */ +/***/ 248: /***/ (function(module, exports, __webpack_require__) { (function(){ - var crypt = __webpack_require__(5), - utf8 = __webpack_require__(0).utf8, - isBuffer = __webpack_require__(6), - bin = __webpack_require__(0).bin, + var crypt = __webpack_require__(249), + utf8 = __webpack_require__(250).utf8, + isBuffer = __webpack_require__(251), + bin = __webpack_require__(250).bin, // The core md5 = function (message, options) { @@ -377,7 +241,8 @@ module.exports = { /***/ }), -/* 5 */ + +/***/ 249: /***/ (function(module, exports) { (function() { @@ -479,13 +344,54 @@ module.exports = { /***/ }), -/* 6 */ + +/***/ 250: +/***/ (function(module, exports) { + +var charenc = { + // UTF-8 encoding + utf8: { + // Convert a string to a byte array + stringToBytes: function(str) { + return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); + } + }, + + // Binary encoding + bin: { + // Convert a string to a byte array + stringToBytes: function(str) { + for (var bytes = [], i = 0; i < str.length; i++) + bytes.push(str.charCodeAt(i) & 0xFF); + return bytes; + }, + + // Convert a byte array to a string + bytesToString: function(bytes) { + for (var str = [], i = 0; i < bytes.length; i++) + str.push(String.fromCharCode(bytes[i])); + return str.join(''); + } + } +}; + +module.exports = charenc; + + +/***/ }), + +/***/ 251: /***/ (function(module, exports) { /*! * Determine if an object is a Buffer * - * @author Feross Aboukhadijeh + * @author Feross Aboukhadijeh * @license MIT */ @@ -506,13 +412,177 @@ function isSlowBuffer (obj) { /***/ }), -/* 7 */ -/***/ (function(module, exports) { + +/***/ 3646: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +const { + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId +} = __webpack_require__(3652); + +const { + workerUtils: { WorkerDispatcher } +} = __webpack_require__(3651); + +const dispatcher = new WorkerDispatcher(); + +const getOriginalURLs = dispatcher.task("getOriginalURLs"); +const getGeneratedRanges = dispatcher.task("getGeneratedRanges", { + queue: true +}); +const getGeneratedLocation = dispatcher.task("getGeneratedLocation", { + queue: true +}); +const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations", { + queue: true +}); +const getOriginalLocation = dispatcher.task("getOriginalLocation"); +const getLocationScopes = dispatcher.task("getLocationScopes"); +const getOriginalSourceText = dispatcher.task("getOriginalSourceText"); +const applySourceMap = dispatcher.task("applySourceMap"); +const clearSourceMaps = dispatcher.task("clearSourceMaps"); +const hasMappedSource = dispatcher.task("hasMappedSource"); + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId, + hasMappedSource, + getOriginalURLs, + getGeneratedRanges, + getGeneratedLocation, + getAllGeneratedLocations, + getOriginalLocation, + getLocationScopes, + getOriginalSourceText, + applySourceMap, + clearSourceMaps, + startSourceMapWorker: dispatcher.start.bind(dispatcher), + stopSourceMapWorker: dispatcher.stop.bind(dispatcher) +}; + +/***/ }), + +/***/ 3651: +/***/ (function(module, exports, __webpack_require__) { /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const networkRequest = __webpack_require__(3653); +const workerUtils = __webpack_require__(3654); + +module.exports = { + networkRequest, + workerUtils +}; + +/***/ }), + +/***/ 3652: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +const md5 = __webpack_require__(248); + +function originalToGeneratedId(originalId) { + const match = originalId.match(/(.*)\/originalSource/); + return match ? match[1] : ""; +} + +function generatedToOriginalId(generatedId, url) { + return `${generatedId}/originalSource-${md5(url)}`; +} + +function isOriginalId(id) { + return !!id.match(/\/originalSource/); +} + +function isGeneratedId(id) { + return !isOriginalId(id); +} + +/** + * Trims the query part or reference identifier of a URL string, if necessary. + */ +function trimUrlQuery(url) { + const length = url.length; + const q1 = url.indexOf("?"); + const q2 = url.indexOf("&"); + const q3 = url.indexOf("#"); + const q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); + + return url.slice(0, q); +} + +// Map suffix to content type. +const contentMap = { + js: "text/javascript", + jsm: "text/javascript", + mjs: "text/javascript", + ts: "text/typescript", + tsx: "text/typescript-jsx", + jsx: "text/jsx", + coffee: "text/coffeescript", + elm: "text/elm", + cljs: "text/x-clojure" +}; + +/** + * Returns the content type for the specified URL. If no specific + * content type can be determined, "text/plain" is returned. + * + * @return String + * The content type. + */ +function getContentType(url) { + url = trimUrlQuery(url); + const dot = url.lastIndexOf("."); + if (dot >= 0) { + const name = url.substring(dot + 1); + if (name in contentMap) { + return contentMap[name]; + } + } + return "text/plain"; +} + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isOriginalId, + isGeneratedId, + getContentType, + contentMapForTesting: contentMap +}; + +/***/ }), + +/***/ 3653: +/***/ (function(module, exports) { + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + function networkRequest(url, opts) { return fetch(url, { cache: opts.loadFromCache ? "default" : "no-cache" @@ -527,7 +597,8 @@ function networkRequest(url, opts) { module.exports = networkRequest; /***/ }), -/* 8 */ + +/***/ 3654: /***/ (function(module, exports) { function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } @@ -537,7 +608,7 @@ function WorkerDispatcher() { this.worker = null; } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ WorkerDispatcher.prototype = { start(url) { @@ -577,7 +648,11 @@ WorkerDispatcher.prototype = { calls.length = 0; const id = this.msgId++; - this.worker.postMessage({ id, method, calls: items.map(item => item[0]) }); + this.worker.postMessage({ + id, + method, + calls: items.map(item => item[0]) + }); const listener = ({ data: result }) => { if (result.id !== id) { @@ -620,9 +695,8 @@ function workerHandler(publicInterface) { // Error can't be sent via postMessage, so be sure to // convert to string. err => ({ error: err.toString() })); - } else { - return { response }; } + return { response }; } catch (error) { // Error can't be sent via postMessage, so be sure to convert to // string. @@ -639,7 +713,7 @@ function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker var _ref = _asyncToGenerator(function* (id, tasks) { let isWorking = true; - const intervalId = setTimeout(function () { + const timeoutId = setTimeout(function () { isWorking = false; }, timeout); @@ -650,7 +724,7 @@ function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker results.push(result); } worker.postMessage({ id, status: "pending", data: results }); - clearInterval(intervalId); + clearTimeout(timeoutId); if (tasks.length !== 0) { yield streamingWorker(id, tasks); @@ -692,61 +766,7 @@ module.exports = { streamingWorkerHandler }; -/***/ }), -/* 9 */, -/* 10 */, -/* 11 */, -/* 12 */, -/* 13 */, -/* 14 */, -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { - originalToGeneratedId, - generatedToOriginalId, - isGeneratedId, - isOriginalId -} = __webpack_require__(3); - -const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1); - -const dispatcher = new WorkerDispatcher(); - -const getOriginalURLs = dispatcher.task("getOriginalURLs"); -const getGeneratedRanges = dispatcher.task("getGeneratedRanges", { queue: true }); -const getGeneratedLocation = dispatcher.task("getGeneratedLocation", { queue: true }); -const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations", { queue: true }); -const getOriginalLocation = dispatcher.task("getOriginalLocation"); -const getLocationScopes = dispatcher.task("getLocationScopes"); -const getOriginalSourceText = dispatcher.task("getOriginalSourceText"); -const applySourceMap = dispatcher.task("applySourceMap"); -const clearSourceMaps = dispatcher.task("clearSourceMaps"); -const hasMappedSource = dispatcher.task("hasMappedSource"); - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isGeneratedId, - isOriginalId, - hasMappedSource, - getOriginalURLs, - getGeneratedRanges, - getGeneratedLocation, - getAllGeneratedLocations, - getOriginalLocation, - getLocationScopes, - getOriginalSourceText, - applySourceMap, - clearSourceMaps, - startSourceMapWorker: dispatcher.start.bind(dispatcher), - stopSourceMapWorker: dispatcher.stop.bind(dispatcher) -}; - /***/ }) -/******/ ]); + +/******/ }); }); \ No newline at end of file diff --git a/devtools/client/shared/source-map/worker.js b/devtools/client/shared/source-map/worker.js index e95904bcfca8..0db44a6bdd2c 100644 --- a/devtools/client/shared/source-map/worker.js +++ b/devtools/client/shared/source-map/worker.js @@ -7,7 +7,7 @@ var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(this, function() { +})(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -67,14 +67,285 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; +/******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 16); +/******/ return __webpack_require__(__webpack_require__.s = 3709); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ +/******/ ({ + +/***/ 248: +/***/ (function(module, exports, __webpack_require__) { + +(function(){ + var crypt = __webpack_require__(249), + utf8 = __webpack_require__(250).utf8, + isBuffer = __webpack_require__(251), + bin = __webpack_require__(250).bin, + + // The core + md5 = function (message, options) { + // Convert to byte array + if (message.constructor == String) + if (options && options.encoding === 'binary') + message = bin.stringToBytes(message); + else + message = utf8.stringToBytes(message); + else if (isBuffer(message)) + message = Array.prototype.slice.call(message, 0); + else if (!Array.isArray(message)) + message = message.toString(); + // else, assume byte array already + + var m = crypt.bytesToWords(message), + l = message.length * 8, + a = 1732584193, + b = -271733879, + c = -1732584194, + d = 271733878; + + // Swap endian + for (var i = 0; i < m.length; i++) { + m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF | + ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00; + } + + // Padding + m[l >>> 5] |= 0x80 << (l % 32); + m[(((l + 64) >>> 9) << 4) + 14] = l; + + // Method shortcuts + var FF = md5._ff, + GG = md5._gg, + HH = md5._hh, + II = md5._ii; + + for (var i = 0; i < m.length; i += 16) { + + var aa = a, + bb = b, + cc = c, + dd = d; + + a = FF(a, b, c, d, m[i+ 0], 7, -680876936); + d = FF(d, a, b, c, m[i+ 1], 12, -389564586); + c = FF(c, d, a, b, m[i+ 2], 17, 606105819); + b = FF(b, c, d, a, m[i+ 3], 22, -1044525330); + a = FF(a, b, c, d, m[i+ 4], 7, -176418897); + d = FF(d, a, b, c, m[i+ 5], 12, 1200080426); + c = FF(c, d, a, b, m[i+ 6], 17, -1473231341); + b = FF(b, c, d, a, m[i+ 7], 22, -45705983); + a = FF(a, b, c, d, m[i+ 8], 7, 1770035416); + d = FF(d, a, b, c, m[i+ 9], 12, -1958414417); + c = FF(c, d, a, b, m[i+10], 17, -42063); + b = FF(b, c, d, a, m[i+11], 22, -1990404162); + a = FF(a, b, c, d, m[i+12], 7, 1804603682); + d = FF(d, a, b, c, m[i+13], 12, -40341101); + c = FF(c, d, a, b, m[i+14], 17, -1502002290); + b = FF(b, c, d, a, m[i+15], 22, 1236535329); + + a = GG(a, b, c, d, m[i+ 1], 5, -165796510); + d = GG(d, a, b, c, m[i+ 6], 9, -1069501632); + c = GG(c, d, a, b, m[i+11], 14, 643717713); + b = GG(b, c, d, a, m[i+ 0], 20, -373897302); + a = GG(a, b, c, d, m[i+ 5], 5, -701558691); + d = GG(d, a, b, c, m[i+10], 9, 38016083); + c = GG(c, d, a, b, m[i+15], 14, -660478335); + b = GG(b, c, d, a, m[i+ 4], 20, -405537848); + a = GG(a, b, c, d, m[i+ 9], 5, 568446438); + d = GG(d, a, b, c, m[i+14], 9, -1019803690); + c = GG(c, d, a, b, m[i+ 3], 14, -187363961); + b = GG(b, c, d, a, m[i+ 8], 20, 1163531501); + a = GG(a, b, c, d, m[i+13], 5, -1444681467); + d = GG(d, a, b, c, m[i+ 2], 9, -51403784); + c = GG(c, d, a, b, m[i+ 7], 14, 1735328473); + b = GG(b, c, d, a, m[i+12], 20, -1926607734); + + a = HH(a, b, c, d, m[i+ 5], 4, -378558); + d = HH(d, a, b, c, m[i+ 8], 11, -2022574463); + c = HH(c, d, a, b, m[i+11], 16, 1839030562); + b = HH(b, c, d, a, m[i+14], 23, -35309556); + a = HH(a, b, c, d, m[i+ 1], 4, -1530992060); + d = HH(d, a, b, c, m[i+ 4], 11, 1272893353); + c = HH(c, d, a, b, m[i+ 7], 16, -155497632); + b = HH(b, c, d, a, m[i+10], 23, -1094730640); + a = HH(a, b, c, d, m[i+13], 4, 681279174); + d = HH(d, a, b, c, m[i+ 0], 11, -358537222); + c = HH(c, d, a, b, m[i+ 3], 16, -722521979); + b = HH(b, c, d, a, m[i+ 6], 23, 76029189); + a = HH(a, b, c, d, m[i+ 9], 4, -640364487); + d = HH(d, a, b, c, m[i+12], 11, -421815835); + c = HH(c, d, a, b, m[i+15], 16, 530742520); + b = HH(b, c, d, a, m[i+ 2], 23, -995338651); + + a = II(a, b, c, d, m[i+ 0], 6, -198630844); + d = II(d, a, b, c, m[i+ 7], 10, 1126891415); + c = II(c, d, a, b, m[i+14], 15, -1416354905); + b = II(b, c, d, a, m[i+ 5], 21, -57434055); + a = II(a, b, c, d, m[i+12], 6, 1700485571); + d = II(d, a, b, c, m[i+ 3], 10, -1894986606); + c = II(c, d, a, b, m[i+10], 15, -1051523); + b = II(b, c, d, a, m[i+ 1], 21, -2054922799); + a = II(a, b, c, d, m[i+ 8], 6, 1873313359); + d = II(d, a, b, c, m[i+15], 10, -30611744); + c = II(c, d, a, b, m[i+ 6], 15, -1560198380); + b = II(b, c, d, a, m[i+13], 21, 1309151649); + a = II(a, b, c, d, m[i+ 4], 6, -145523070); + d = II(d, a, b, c, m[i+11], 10, -1120210379); + c = II(c, d, a, b, m[i+ 2], 15, 718787259); + b = II(b, c, d, a, m[i+ 9], 21, -343485551); + + a = (a + aa) >>> 0; + b = (b + bb) >>> 0; + c = (c + cc) >>> 0; + d = (d + dd) >>> 0; + } + + return crypt.endian([a, b, c, d]); + }; + + // Auxiliary functions + md5._ff = function (a, b, c, d, x, s, t) { + var n = a + (b & c | ~b & d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._gg = function (a, b, c, d, x, s, t) { + var n = a + (b & d | c & ~d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._hh = function (a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + md5._ii = function (a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; + return ((n << s) | (n >>> (32 - s))) + b; + }; + + // Package private blocksize + md5._blocksize = 16; + md5._digestsize = 16; + + module.exports = function (message, options) { + if (message === undefined || message === null) + throw new Error('Illegal argument ' + message); + + var digestbytes = crypt.wordsToBytes(md5(message, options)); + return options && options.asBytes ? digestbytes : + options && options.asString ? bin.bytesToString(digestbytes) : + crypt.bytesToHex(digestbytes); + }; + +})(); + + +/***/ }), + +/***/ 249: +/***/ (function(module, exports) { + +(function() { + var base64map + = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', + + crypt = { + // Bit-wise rotation left + rotl: function(n, b) { + return (n << b) | (n >>> (32 - b)); + }, + + // Bit-wise rotation right + rotr: function(n, b) { + return (n << (32 - b)) | (n >>> b); + }, + + // Swap big-endian to little-endian and vice versa + endian: function(n) { + // If number given, swap endian + if (n.constructor == Number) { + return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; + } + + // Else, assume array and swap all items + for (var i = 0; i < n.length; i++) + n[i] = crypt.endian(n[i]); + return n; + }, + + // Generate an array of any length of random bytes + randomBytes: function(n) { + for (var bytes = []; n > 0; n--) + bytes.push(Math.floor(Math.random() * 256)); + return bytes; + }, + + // Convert a byte array to big-endian 32-bit words + bytesToWords: function(bytes) { + for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) + words[b >>> 5] |= bytes[i] << (24 - b % 32); + return words; + }, + + // Convert big-endian 32-bit words to a byte array + wordsToBytes: function(words) { + for (var bytes = [], b = 0; b < words.length * 32; b += 8) + bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); + return bytes; + }, + + // Convert a byte array to a hex string + bytesToHex: function(bytes) { + for (var hex = [], i = 0; i < bytes.length; i++) { + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + } + return hex.join(''); + }, + + // Convert a hex string to a byte array + hexToBytes: function(hex) { + for (var bytes = [], c = 0; c < hex.length; c += 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; + }, + + // Convert a byte array to a base-64 string + bytesToBase64: function(bytes) { + for (var base64 = [], i = 0; i < bytes.length; i += 3) { + var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + for (var j = 0; j < 4; j++) + if (i * 8 + j * 6 <= bytes.length * 8) + base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); + else + base64.push('='); + } + return base64.join(''); + }, + + // Convert a base-64 string to a byte array + base64ToBytes: function(base64) { + // Remove non-base-64 characters + base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); + + for (var bytes = [], i = 0, imod4 = 0; i < base64.length; + imod4 = ++i % 4) { + if (imod4 == 0) continue; + bytes.push(((base64map.indexOf(base64.charAt(i - 1)) + & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) + | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); + } + return bytes; + } + }; + + module.exports = crypt; +})(); + + +/***/ }), + +/***/ 250: /***/ (function(module, exports) { var charenc = { @@ -113,15 +384,44 @@ module.exports = charenc; /***/ }), -/* 1 */ + +/***/ 251: +/***/ (function(module, exports) { + +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} + +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} + +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} + + +/***/ }), + +/***/ 3651: /***/ (function(module, exports, __webpack_require__) { /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const networkRequest = __webpack_require__(7); -const workerUtils = __webpack_require__(8); +const networkRequest = __webpack_require__(3653); +const workerUtils = __webpack_require__(3654); module.exports = { networkRequest, @@ -129,7 +429,285 @@ module.exports = { }; /***/ }), -/* 2 */ + +/***/ 3652: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +const md5 = __webpack_require__(248); + +function originalToGeneratedId(originalId) { + const match = originalId.match(/(.*)\/originalSource/); + return match ? match[1] : ""; +} + +function generatedToOriginalId(generatedId, url) { + return `${generatedId}/originalSource-${md5(url)}`; +} + +function isOriginalId(id) { + return !!id.match(/\/originalSource/); +} + +function isGeneratedId(id) { + return !isOriginalId(id); +} + +/** + * Trims the query part or reference identifier of a URL string, if necessary. + */ +function trimUrlQuery(url) { + const length = url.length; + const q1 = url.indexOf("?"); + const q2 = url.indexOf("&"); + const q3 = url.indexOf("#"); + const q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); + + return url.slice(0, q); +} + +// Map suffix to content type. +const contentMap = { + js: "text/javascript", + jsm: "text/javascript", + mjs: "text/javascript", + ts: "text/typescript", + tsx: "text/typescript-jsx", + jsx: "text/jsx", + coffee: "text/coffeescript", + elm: "text/elm", + cljs: "text/x-clojure" +}; + +/** + * Returns the content type for the specified URL. If no specific + * content type can be determined, "text/plain" is returned. + * + * @return String + * The content type. + */ +function getContentType(url) { + url = trimUrlQuery(url); + const dot = url.lastIndexOf("."); + if (dot >= 0) { + const name = url.substring(dot + 1); + if (name in contentMap) { + return contentMap[name]; + } + } + return "text/plain"; +} + +module.exports = { + originalToGeneratedId, + generatedToOriginalId, + isOriginalId, + isGeneratedId, + getContentType, + contentMapForTesting: contentMap +}; + +/***/ }), + +/***/ 3653: +/***/ (function(module, exports) { + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +function networkRequest(url, opts) { + return fetch(url, { + cache: opts.loadFromCache ? "default" : "no-cache" + }).then(res => { + if (res.status >= 200 && res.status < 300) { + return res.text().then(text => ({ content: text })); + } + return Promise.reject(`request failed with status ${res.status}`); + }); +} + +module.exports = networkRequest; + +/***/ }), + +/***/ 3654: +/***/ (function(module, exports) { + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +function WorkerDispatcher() { + this.msgId = 1; + this.worker = null; +} /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +WorkerDispatcher.prototype = { + start(url) { + this.worker = new Worker(url); + this.worker.onerror = () => { + console.error(`Error in worker ${url}`); + }; + }, + + stop() { + if (!this.worker) { + return; + } + + this.worker.terminate(); + this.worker = null; + }, + + task(method, { queue = false } = {}) { + const calls = []; + const push = args => { + return new Promise((resolve, reject) => { + if (queue && calls.length === 0) { + Promise.resolve().then(flush); + } + + calls.push([args, resolve, reject]); + + if (!queue) { + flush(); + } + }); + }; + + const flush = () => { + const items = calls.slice(); + calls.length = 0; + + const id = this.msgId++; + this.worker.postMessage({ + id, + method, + calls: items.map(item => item[0]) + }); + + const listener = ({ data: result }) => { + if (result.id !== id) { + return; + } + + if (!this.worker) { + return; + } + + this.worker.removeEventListener("message", listener); + + result.results.forEach((resultData, i) => { + const [, resolve, reject] = items[i]; + + if (resultData.error) { + reject(resultData.error); + } else { + resolve(resultData.response); + } + }); + }; + + this.worker.addEventListener("message", listener); + }; + + return (...args) => push(args); + } +}; + +function workerHandler(publicInterface) { + return function (msg) { + const { id, method, calls } = msg.data; + + Promise.all(calls.map(args => { + try { + const response = publicInterface[method].apply(undefined, args); + if (response instanceof Promise) { + return response.then(val => ({ response: val }), + // Error can't be sent via postMessage, so be sure to + // convert to string. + err => ({ error: err.toString() })); + } + return { response }; + } catch (error) { + // Error can't be sent via postMessage, so be sure to convert to + // string. + return { error: error.toString() }; + } + })).then(results => { + self.postMessage({ id, results }); + }); + }; +} + +function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) { + let streamingWorker = (() => { + var _ref = _asyncToGenerator(function* (id, tasks) { + let isWorking = true; + + const timeoutId = setTimeout(function () { + isWorking = false; + }, timeout); + + const results = []; + while (tasks.length !== 0 && isWorking) { + const { callback, context, args } = tasks.shift(); + const result = yield callback.call(context, args); + results.push(result); + } + worker.postMessage({ id, status: "pending", data: results }); + clearTimeout(timeoutId); + + if (tasks.length !== 0) { + yield streamingWorker(id, tasks); + } + }); + + return function streamingWorker(_x, _x2) { + return _ref.apply(this, arguments); + }; + })(); + + return (() => { + var _ref2 = _asyncToGenerator(function* (msg) { + const { id, method, args } = msg.data; + const workerMethod = publicInterface[method]; + if (!workerMethod) { + console.error(`Could not find ${method} defined in worker.`); + } + worker.postMessage({ id, status: "start" }); + + try { + const tasks = workerMethod(args); + yield streamingWorker(id, tasks); + worker.postMessage({ id, status: "done" }); + } catch (error) { + worker.postMessage({ id, status: "error", error }); + } + }); + + return function (_x3) { + return _ref2.apply(this, arguments); + }; + })(); +} + +module.exports = { + WorkerDispatcher, + workerHandler, + streamingWorkerHandler +}; + +/***/ }), + +/***/ 3668: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -623,575 +1201,18 @@ exports.computeSourceURL = computeSourceURL; /***/ }), -/* 3 */ + +/***/ 3704: /***/ (function(module, exports, __webpack_require__) { +"use strict"; + + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ -const md5 = __webpack_require__(4); - -function originalToGeneratedId(originalId) { - const match = originalId.match(/(.*)\/originalSource/); - return match ? match[1] : ""; -} - -function generatedToOriginalId(generatedId, url) { - return `${generatedId}/originalSource-${md5(url)}`; -} - -function isOriginalId(id) { - return !!id.match(/\/originalSource/); -} - -function isGeneratedId(id) { - return !isOriginalId(id); -} - -/** - * Trims the query part or reference identifier of a URL string, if necessary. - */ -function trimUrlQuery(url) { - let length = url.length; - let q1 = url.indexOf("?"); - let q2 = url.indexOf("&"); - let q3 = url.indexOf("#"); - let q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length); - - return url.slice(0, q); -} - -// Map suffix to content type. -const contentMap = { - "js": "text/javascript", - "jsm": "text/javascript", - "mjs": "text/javascript", - "ts": "text/typescript", - "tsx": "text/typescript-jsx", - "jsx": "text/jsx", - vue: "text/vue", - "coffee": "text/coffeescript", - "elm": "text/elm", - "cljs": "text/x-clojure" -}; - -/** - * Returns the content type for the specified URL. If no specific - * content type can be determined, "text/plain" is returned. - * - * @return String - * The content type. - */ -function getContentType(url) { - url = trimUrlQuery(url); - let dot = url.lastIndexOf("."); - if (dot >= 0) { - let name = url.substring(dot + 1); - if (name in contentMap) { - return contentMap[name]; - } - } - return "text/plain"; -} - -module.exports = { - originalToGeneratedId, - generatedToOriginalId, - isOriginalId, - isGeneratedId, - getContentType, - contentMapForTesting: contentMap -}; - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -(function(){ - var crypt = __webpack_require__(5), - utf8 = __webpack_require__(0).utf8, - isBuffer = __webpack_require__(6), - bin = __webpack_require__(0).bin, - - // The core - md5 = function (message, options) { - // Convert to byte array - if (message.constructor == String) - if (options && options.encoding === 'binary') - message = bin.stringToBytes(message); - else - message = utf8.stringToBytes(message); - else if (isBuffer(message)) - message = Array.prototype.slice.call(message, 0); - else if (!Array.isArray(message)) - message = message.toString(); - // else, assume byte array already - - var m = crypt.bytesToWords(message), - l = message.length * 8, - a = 1732584193, - b = -271733879, - c = -1732584194, - d = 271733878; - - // Swap endian - for (var i = 0; i < m.length; i++) { - m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF | - ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00; - } - - // Padding - m[l >>> 5] |= 0x80 << (l % 32); - m[(((l + 64) >>> 9) << 4) + 14] = l; - - // Method shortcuts - var FF = md5._ff, - GG = md5._gg, - HH = md5._hh, - II = md5._ii; - - for (var i = 0; i < m.length; i += 16) { - - var aa = a, - bb = b, - cc = c, - dd = d; - - a = FF(a, b, c, d, m[i+ 0], 7, -680876936); - d = FF(d, a, b, c, m[i+ 1], 12, -389564586); - c = FF(c, d, a, b, m[i+ 2], 17, 606105819); - b = FF(b, c, d, a, m[i+ 3], 22, -1044525330); - a = FF(a, b, c, d, m[i+ 4], 7, -176418897); - d = FF(d, a, b, c, m[i+ 5], 12, 1200080426); - c = FF(c, d, a, b, m[i+ 6], 17, -1473231341); - b = FF(b, c, d, a, m[i+ 7], 22, -45705983); - a = FF(a, b, c, d, m[i+ 8], 7, 1770035416); - d = FF(d, a, b, c, m[i+ 9], 12, -1958414417); - c = FF(c, d, a, b, m[i+10], 17, -42063); - b = FF(b, c, d, a, m[i+11], 22, -1990404162); - a = FF(a, b, c, d, m[i+12], 7, 1804603682); - d = FF(d, a, b, c, m[i+13], 12, -40341101); - c = FF(c, d, a, b, m[i+14], 17, -1502002290); - b = FF(b, c, d, a, m[i+15], 22, 1236535329); - - a = GG(a, b, c, d, m[i+ 1], 5, -165796510); - d = GG(d, a, b, c, m[i+ 6], 9, -1069501632); - c = GG(c, d, a, b, m[i+11], 14, 643717713); - b = GG(b, c, d, a, m[i+ 0], 20, -373897302); - a = GG(a, b, c, d, m[i+ 5], 5, -701558691); - d = GG(d, a, b, c, m[i+10], 9, 38016083); - c = GG(c, d, a, b, m[i+15], 14, -660478335); - b = GG(b, c, d, a, m[i+ 4], 20, -405537848); - a = GG(a, b, c, d, m[i+ 9], 5, 568446438); - d = GG(d, a, b, c, m[i+14], 9, -1019803690); - c = GG(c, d, a, b, m[i+ 3], 14, -187363961); - b = GG(b, c, d, a, m[i+ 8], 20, 1163531501); - a = GG(a, b, c, d, m[i+13], 5, -1444681467); - d = GG(d, a, b, c, m[i+ 2], 9, -51403784); - c = GG(c, d, a, b, m[i+ 7], 14, 1735328473); - b = GG(b, c, d, a, m[i+12], 20, -1926607734); - - a = HH(a, b, c, d, m[i+ 5], 4, -378558); - d = HH(d, a, b, c, m[i+ 8], 11, -2022574463); - c = HH(c, d, a, b, m[i+11], 16, 1839030562); - b = HH(b, c, d, a, m[i+14], 23, -35309556); - a = HH(a, b, c, d, m[i+ 1], 4, -1530992060); - d = HH(d, a, b, c, m[i+ 4], 11, 1272893353); - c = HH(c, d, a, b, m[i+ 7], 16, -155497632); - b = HH(b, c, d, a, m[i+10], 23, -1094730640); - a = HH(a, b, c, d, m[i+13], 4, 681279174); - d = HH(d, a, b, c, m[i+ 0], 11, -358537222); - c = HH(c, d, a, b, m[i+ 3], 16, -722521979); - b = HH(b, c, d, a, m[i+ 6], 23, 76029189); - a = HH(a, b, c, d, m[i+ 9], 4, -640364487); - d = HH(d, a, b, c, m[i+12], 11, -421815835); - c = HH(c, d, a, b, m[i+15], 16, 530742520); - b = HH(b, c, d, a, m[i+ 2], 23, -995338651); - - a = II(a, b, c, d, m[i+ 0], 6, -198630844); - d = II(d, a, b, c, m[i+ 7], 10, 1126891415); - c = II(c, d, a, b, m[i+14], 15, -1416354905); - b = II(b, c, d, a, m[i+ 5], 21, -57434055); - a = II(a, b, c, d, m[i+12], 6, 1700485571); - d = II(d, a, b, c, m[i+ 3], 10, -1894986606); - c = II(c, d, a, b, m[i+10], 15, -1051523); - b = II(b, c, d, a, m[i+ 1], 21, -2054922799); - a = II(a, b, c, d, m[i+ 8], 6, 1873313359); - d = II(d, a, b, c, m[i+15], 10, -30611744); - c = II(c, d, a, b, m[i+ 6], 15, -1560198380); - b = II(b, c, d, a, m[i+13], 21, 1309151649); - a = II(a, b, c, d, m[i+ 4], 6, -145523070); - d = II(d, a, b, c, m[i+11], 10, -1120210379); - c = II(c, d, a, b, m[i+ 2], 15, 718787259); - b = II(b, c, d, a, m[i+ 9], 21, -343485551); - - a = (a + aa) >>> 0; - b = (b + bb) >>> 0; - c = (c + cc) >>> 0; - d = (d + dd) >>> 0; - } - - return crypt.endian([a, b, c, d]); - }; - - // Auxiliary functions - md5._ff = function (a, b, c, d, x, s, t) { - var n = a + (b & c | ~b & d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._gg = function (a, b, c, d, x, s, t) { - var n = a + (b & d | c & ~d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._hh = function (a, b, c, d, x, s, t) { - var n = a + (b ^ c ^ d) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - md5._ii = function (a, b, c, d, x, s, t) { - var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; - return ((n << s) | (n >>> (32 - s))) + b; - }; - - // Package private blocksize - md5._blocksize = 16; - md5._digestsize = 16; - - module.exports = function (message, options) { - if (message === undefined || message === null) - throw new Error('Illegal argument ' + message); - - var digestbytes = crypt.wordsToBytes(md5(message, options)); - return options && options.asBytes ? digestbytes : - options && options.asString ? bin.bytesToString(digestbytes) : - crypt.bytesToHex(digestbytes); - }; - -})(); - - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -(function() { - var base64map - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - - crypt = { - // Bit-wise rotation left - rotl: function(n, b) { - return (n << b) | (n >>> (32 - b)); - }, - - // Bit-wise rotation right - rotr: function(n, b) { - return (n << (32 - b)) | (n >>> b); - }, - - // Swap big-endian to little-endian and vice versa - endian: function(n) { - // If number given, swap endian - if (n.constructor == Number) { - return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; - } - - // Else, assume array and swap all items - for (var i = 0; i < n.length; i++) - n[i] = crypt.endian(n[i]); - return n; - }, - - // Generate an array of any length of random bytes - randomBytes: function(n) { - for (var bytes = []; n > 0; n--) - bytes.push(Math.floor(Math.random() * 256)); - return bytes; - }, - - // Convert a byte array to big-endian 32-bit words - bytesToWords: function(bytes) { - for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) - words[b >>> 5] |= bytes[i] << (24 - b % 32); - return words; - }, - - // Convert big-endian 32-bit words to a byte array - wordsToBytes: function(words) { - for (var bytes = [], b = 0; b < words.length * 32; b += 8) - bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); - return bytes; - }, - - // Convert a byte array to a hex string - bytesToHex: function(bytes) { - for (var hex = [], i = 0; i < bytes.length; i++) { - hex.push((bytes[i] >>> 4).toString(16)); - hex.push((bytes[i] & 0xF).toString(16)); - } - return hex.join(''); - }, - - // Convert a hex string to a byte array - hexToBytes: function(hex) { - for (var bytes = [], c = 0; c < hex.length; c += 2) - bytes.push(parseInt(hex.substr(c, 2), 16)); - return bytes; - }, - - // Convert a byte array to a base-64 string - bytesToBase64: function(bytes) { - for (var base64 = [], i = 0; i < bytes.length; i += 3) { - var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - for (var j = 0; j < 4; j++) - if (i * 8 + j * 6 <= bytes.length * 8) - base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); - else - base64.push('='); - } - return base64.join(''); - }, - - // Convert a base-64 string to a byte array - base64ToBytes: function(base64) { - // Remove non-base-64 characters - base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); - - for (var bytes = [], i = 0, imod4 = 0; i < base64.length; - imod4 = ++i % 4) { - if (imod4 == 0) continue; - bytes.push(((base64map.indexOf(base64.charAt(i - 1)) - & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) - | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); - } - return bytes; - } - }; - - module.exports = crypt; -})(); - - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} - -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} - - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -function networkRequest(url, opts) { - return fetch(url, { - cache: opts.loadFromCache ? "default" : "no-cache" - }).then(res => { - if (res.status >= 200 && res.status < 300) { - return res.text().then(text => ({ content: text })); - } - return Promise.reject(`request failed with status ${res.status}`); - }); -} - -module.exports = networkRequest; - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } - -function WorkerDispatcher() { - this.msgId = 1; - this.worker = null; -} /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -WorkerDispatcher.prototype = { - start(url) { - this.worker = new Worker(url); - this.worker.onerror = () => { - console.error(`Error in worker ${url}`); - }; - }, - - stop() { - if (!this.worker) { - return; - } - - this.worker.terminate(); - this.worker = null; - }, - - task(method, { queue = false } = {}) { - const calls = []; - const push = args => { - return new Promise((resolve, reject) => { - if (queue && calls.length === 0) { - Promise.resolve().then(flush); - } - - calls.push([args, resolve, reject]); - - if (!queue) { - flush(); - } - }); - }; - - const flush = () => { - const items = calls.slice(); - calls.length = 0; - - const id = this.msgId++; - this.worker.postMessage({ id, method, calls: items.map(item => item[0]) }); - - const listener = ({ data: result }) => { - if (result.id !== id) { - return; - } - - if (!this.worker) { - return; - } - - this.worker.removeEventListener("message", listener); - - result.results.forEach((resultData, i) => { - const [, resolve, reject] = items[i]; - - if (resultData.error) { - reject(resultData.error); - } else { - resolve(resultData.response); - } - }); - }; - - this.worker.addEventListener("message", listener); - }; - - return (...args) => push(args); - } -}; - -function workerHandler(publicInterface) { - return function (msg) { - const { id, method, calls } = msg.data; - - Promise.all(calls.map(args => { - try { - const response = publicInterface[method].apply(undefined, args); - if (response instanceof Promise) { - return response.then(val => ({ response: val }), - // Error can't be sent via postMessage, so be sure to - // convert to string. - err => ({ error: err.toString() })); - } else { - return { response }; - } - } catch (error) { - // Error can't be sent via postMessage, so be sure to convert to - // string. - return { error: error.toString() }; - } - })).then(results => { - self.postMessage({ id, results }); - }); - }; -} - -function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) { - let streamingWorker = (() => { - var _ref = _asyncToGenerator(function* (id, tasks) { - let isWorking = true; - - const intervalId = setTimeout(function () { - isWorking = false; - }, timeout); - - const results = []; - while (tasks.length !== 0 && isWorking) { - const { callback, context, args } = tasks.shift(); - const result = yield callback.call(context, args); - results.push(result); - } - worker.postMessage({ id, status: "pending", data: results }); - clearInterval(intervalId); - - if (tasks.length !== 0) { - yield streamingWorker(id, tasks); - } - }); - - return function streamingWorker(_x, _x2) { - return _ref.apply(this, arguments); - }; - })(); - - return (() => { - var _ref2 = _asyncToGenerator(function* (msg) { - const { id, method, args } = msg.data; - const workerMethod = publicInterface[method]; - if (!workerMethod) { - console.error(`Could not find ${method} defined in worker.`); - } - worker.postMessage({ id, status: "start" }); - - try { - const tasks = workerMethod(args); - yield streamingWorker(id, tasks); - worker.postMessage({ id, status: "done" }); - } catch (error) { - worker.postMessage({ id, status: "error", error }); - } - }); - - return function (_x3) { - return _ref2.apply(this, arguments); - }; - })(); -} - -module.exports = { - WorkerDispatcher, - workerHandler, - streamingWorkerHandler -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - -let sourceMapRequests = new Map(); +const sourceMapRequests = new Map(); function clearSourceMaps() { sourceMapRequests.clear(); @@ -1212,7 +1233,8 @@ module.exports = { }; /***/ }), -/* 10 */ + +/***/ 3705: /***/ (function(module, exports, __webpack_require__) { /* @@ -1220,13 +1242,14 @@ module.exports = { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(11).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(20).SourceMapConsumer; -exports.SourceNode = __webpack_require__(23).SourceNode; +exports.SourceMapGenerator = __webpack_require__(3706).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(3713).SourceMapConsumer; +exports.SourceNode = __webpack_require__(3716).SourceNode; /***/ }), -/* 11 */ + +/***/ 3706: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1236,10 +1259,10 @@ exports.SourceNode = __webpack_require__(23).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(12); -var util = __webpack_require__(2); -var ArraySet = __webpack_require__(13).ArraySet; -var MappingList = __webpack_require__(19).MappingList; +var base64VLQ = __webpack_require__(3707); +var util = __webpack_require__(3668); +var ArraySet = __webpack_require__(3708).ArraySet; +var MappingList = __webpack_require__(3712).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -1657,7 +1680,8 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 12 */ + +/***/ 3707: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1697,7 +1721,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(18); +var base64 = __webpack_require__(3711); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -1803,7 +1827,8 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 13 */ + +/***/ 3708: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -1813,7 +1838,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); +var util = __webpack_require__(3668); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -1930,127 +1955,16 @@ exports.ArraySet = ArraySet; /***/ }), -/* 14 */ + +/***/ 3709: /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * SourceMapConsumer for WebAssembly source maps. It transposes columns with - * lines, which allows mapping data to be used with SpiderMonkey Debugger API. - */ - -class WasmRemap { - /** - * @param map SourceMapConsumer - */ - constructor(map) { - this._map = map; - this.version = map.version; - this.file = map.file; - this._computeColumnSpans = false; - } - - get sources() { - return this._map.sources; - } - - get sourceRoot() { - return this._map.sourceRoot; - } - - get names() { - return this._map.names; - } - - get sourcesContent() { - return this._map.sourcesContent; - } - - get mappings() { - throw new Error("not supported"); - } - - computeColumnSpans() { - this._computeColumnSpans = true; - } - - originalPositionFor(generatedPosition) { - let result = this._map.originalPositionFor({ - line: 1, - column: generatedPosition.line, - bias: generatedPosition.bias - }); - return result; - } - - _remapGeneratedPosition(position) { - let generatedPosition = { - line: position.column, - column: 0 - }; - if (this._computeColumnSpans) { - generatedPosition.lastColumn = Infinity; - } - return generatedPosition; - } - - generatedPositionFor(originalPosition) { - let position = this._map.generatedPositionFor(originalPosition); - return this._remapGeneratedPosition(position); - } - - allGeneratedPositionsFor(originalPosition) { - let positions = this._map.allGeneratedPositionsFor(originalPosition); - return positions.map(position => { - return this._remapGeneratedPosition(position); - }); - } - - hasContentsOfAllSources() { - return this._map.hasContentsOfAllSources(); - } - - sourceContentFor(source, returnNullOnMissing) { - return this._map.sourceContentFor(source, returnNullOnMissing); - } - - eachMapping(callback, context, order) { - this._map.eachMapping(entry => { - let { - source, - generatedColumn, - originalLine, - originalColumn, - name - } = entry; - callback({ - source, - generatedLine: generatedColumn, - generatedColumn: 0, - originalLine, - originalColumn, - name - }); - }, context, order); - } -} - -exports.WasmRemap = WasmRemap; - -/***/ }), -/* 15 */, -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ const { getOriginalURLs, @@ -2062,11 +1976,13 @@ const { getLocationScopes, hasMappedSource, applySourceMap -} = __webpack_require__(17); +} = __webpack_require__(3710); -const { clearSourceMaps } = __webpack_require__(9); +const { clearSourceMaps } = __webpack_require__(3704); -const { workerUtils: { workerHandler } } = __webpack_require__(1); +const { + workerUtils: { workerHandler } +} = __webpack_require__(3651); // The interface is implemented in source-map to be // easier to unit test. @@ -2084,248 +2000,204 @@ self.onmessage = workerHandler({ }); /***/ }), -/* 17 */ + +/***/ 3710: /***/ (function(module, exports, __webpack_require__) { -let getOriginalURLs = (() => { - var _ref = _asyncToGenerator(function* (generatedSource) { - const map = yield fetchSourceMap(generatedSource); - return map && map.sources; - }); +"use strict"; - return function getOriginalURLs(_x) { - return _ref.apply(this, arguments); - }; -})(); - -/** - * Given an original location, find the ranges on the generated file that - * are mapped from the original range containing the location. - */ -let getGeneratedRanges = (() => { - var _ref2 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return []; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return []; - } - - if (!COMPUTED_SPANS.has(map)) { - COMPUTED_SPANS.add(map); - map.computeColumnSpans(); - } - - // We want to use 'allGeneratedPositionsFor' to get the _first_ generated - // location, but it hard-codes SourceMapConsumer.LEAST_UPPER_BOUND as the - // bias, making it search in the wrong direction for this usecase. - // To work around this, we use 'generatedPositionFor' and then look up the - // exact original location, making any bias value unnecessary, and then - // use that location for the call to 'allGeneratedPositionsFor'. - const genPos = map.generatedPositionFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column, - bias: SourceMapConsumer.GREATEST_LOWER_BOUND - }); - if (genPos.line === null) return []; - - const positions = map.allGeneratedPositionsFor(map.originalPositionFor({ - line: genPos.line, - column: genPos.column - })); - - return positions.map(function (mapping) { - return { - line: mapping.line, - columnStart: mapping.column, - columnEnd: mapping.lastColumn - }; - }).sort(function (a, b) { - const line = a.line - b.line; - return line === 0 ? a.column - b.column : line; - }); - }); - - return function getGeneratedRanges(_x2, _x3) { - return _ref2.apply(this, arguments); - }; -})(); - -let getGeneratedLocation = (() => { - var _ref3 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return location; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return location; - } - - const { line, column } = map.generatedPositionFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column, - bias: SourceMapConsumer.LEAST_UPPER_BOUND - }); - - return { - sourceId: generatedSourceId, - line, - column - }; - }); - - return function getGeneratedLocation(_x4, _x5) { - return _ref3.apply(this, arguments); - }; -})(); - -let getAllGeneratedLocations = (() => { - var _ref4 = _asyncToGenerator(function* (location, originalSource) { - if (!isOriginalId(location.sourceId)) { - return []; - } - - const generatedSourceId = originalToGeneratedId(location.sourceId); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return []; - } - - const positions = map.allGeneratedPositionsFor({ - source: originalSource.url, - line: location.line, - column: location.column == null ? 0 : location.column - }); - - return positions.map(function ({ line, column }) { - return { - sourceId: generatedSourceId, - line, - column - }; - }); - }); - - return function getAllGeneratedLocations(_x6, _x7) { - return _ref4.apply(this, arguments); - }; -})(); - -let getOriginalLocation = (() => { - var _ref5 = _asyncToGenerator(function* (location) { - if (!isGeneratedId(location.sourceId)) { - return location; - } - - const map = yield getSourceMap(location.sourceId); - if (!map) { - return location; - } - - const { source: sourceUrl, line, column } = map.originalPositionFor({ - line: location.line, - column: location.column == null ? 0 : location.column - }); - - if (sourceUrl == null) { - // No url means the location didn't map. - return location; - } - - return { - sourceId: generatedToOriginalId(location.sourceId, sourceUrl), - sourceUrl, - line, - column - }; - }); - - return function getOriginalLocation(_x8) { - return _ref5.apply(this, arguments); - }; -})(); - -let getOriginalSourceText = (() => { - var _ref6 = _asyncToGenerator(function* (originalSource) { - assert(isOriginalId(originalSource.id), "Source is not an original source"); - - const generatedSourceId = originalToGeneratedId(originalSource.id); - const map = yield getSourceMap(generatedSourceId); - if (!map) { - return null; - } - - let text = map.sourceContentFor(originalSource.url); - if (!text) { - text = (yield networkRequest(originalSource.url, { loadFromCache: false })).content; - } - - return { - text, - contentType: getContentType(originalSource.url || "") - }; - }); - - return function getOriginalSourceText(_x9) { - return _ref6.apply(this, arguments); - }; -})(); - -let hasMappedSource = (() => { - var _ref7 = _asyncToGenerator(function* (location) { - if (isOriginalId(location.sourceId)) { - return true; - } - - const loc = yield getOriginalLocation(location); - return loc.sourceId !== location.sourceId; - }); - - return function hasMappedSource(_x10) { - return _ref7.apply(this, arguments); - }; -})(); - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ /** * Source Map Worker * @module utils/source-map-worker */ -const { networkRequest } = __webpack_require__(1); -const { SourceMapConsumer, SourceMapGenerator } = __webpack_require__(10); +const { networkRequest } = __webpack_require__(3651); +const { SourceMapConsumer, SourceMapGenerator } = __webpack_require__(3705); -const assert = __webpack_require__(24); -const { fetchSourceMap } = __webpack_require__(25); +const assert = __webpack_require__(3717); +const { fetchSourceMap } = __webpack_require__(3718); const { getSourceMap, setSourceMap, clearSourceMaps -} = __webpack_require__(9); +} = __webpack_require__(3704); const { originalToGeneratedId, generatedToOriginalId, isGeneratedId, isOriginalId, getContentType -} = __webpack_require__(3); +} = __webpack_require__(3652); -const { WasmRemap } = __webpack_require__(14); +async function getOriginalURLs(generatedSource) { + const map = await fetchSourceMap(generatedSource); + return map && map.sources; +} const COMPUTED_SPANS = new WeakSet(); +/** + * Given an original location, find the ranges on the generated file that + * are mapped from the original range containing the location. + */ +async function getGeneratedRanges(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return []; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return []; + } + + if (!COMPUTED_SPANS.has(map)) { + COMPUTED_SPANS.add(map); + map.computeColumnSpans(); + } + + // We want to use 'allGeneratedPositionsFor' to get the _first_ generated + // location, but it hard-codes SourceMapConsumer.LEAST_UPPER_BOUND as the + // bias, making it search in the wrong direction for this usecase. + // To work around this, we use 'generatedPositionFor' and then look up the + // exact original location, making any bias value unnecessary, and then + // use that location for the call to 'allGeneratedPositionsFor'. + const genPos = map.generatedPositionFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column, + bias: SourceMapConsumer.GREATEST_LOWER_BOUND + }); + if (genPos.line === null) { + return []; + } + + const positions = map.allGeneratedPositionsFor(map.originalPositionFor({ + line: genPos.line, + column: genPos.column + })); + + return positions.map(mapping => ({ + line: mapping.line, + columnStart: mapping.column, + columnEnd: mapping.lastColumn + })).sort((a, b) => { + const line = a.line - b.line; + return line === 0 ? a.column - b.column : line; + }); +} + +async function getGeneratedLocation(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return location; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return location; + } + + const { line, column } = map.generatedPositionFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column, + bias: SourceMapConsumer.LEAST_UPPER_BOUND + }); + + return { + sourceId: generatedSourceId, + line, + column + }; +} + +async function getAllGeneratedLocations(location, originalSource) { + if (!isOriginalId(location.sourceId)) { + return []; + } + + const generatedSourceId = originalToGeneratedId(location.sourceId); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return []; + } + + const positions = map.allGeneratedPositionsFor({ + source: originalSource.url, + line: location.line, + column: location.column == null ? 0 : location.column + }); + + return positions.map(({ line, column }) => ({ + sourceId: generatedSourceId, + line, + column + })); +} + +async function getOriginalLocation(location) { + if (!isGeneratedId(location.sourceId)) { + return location; + } + + const map = await getSourceMap(location.sourceId); + if (!map) { + return location; + } + + const { source: sourceUrl, line, column } = map.originalPositionFor({ + line: location.line, + column: location.column == null ? 0 : location.column + }); + + if (sourceUrl == null) { + // No url means the location didn't map. + return location; + } + + return { + sourceId: generatedToOriginalId(location.sourceId, sourceUrl), + sourceUrl, + line, + column + }; +} + +async function getOriginalSourceText(originalSource) { + assert(isOriginalId(originalSource.id), "Source is not an original source"); + + const generatedSourceId = originalToGeneratedId(originalSource.id); + const map = await getSourceMap(generatedSourceId); + if (!map) { + return null; + } + + let text = map.sourceContentFor(originalSource.url); + if (!text) { + text = (await networkRequest(originalSource.url, { loadFromCache: false })).content; + } + + return { + text, + contentType: getContentType(originalSource.url || "") + }; +} + +async function hasMappedSource(location) { + if (isOriginalId(location.sourceId)) { + return true; + } + + const loc = await getOriginalLocation(location); + return loc.sourceId !== location.sourceId; +} + function applySourceMap(generatedId, url, code, mappings) { const generator = new SourceMapGenerator({ file: url }); mappings.forEach(mapping => generator.addMapping(mapping)); @@ -2348,7 +2220,8 @@ module.exports = { }; /***/ }), -/* 18 */ + +/***/ 3711: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2421,7 +2294,8 @@ exports.decode = function (charCode) { /***/ }), -/* 19 */ + +/***/ 3712: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2431,7 +2305,7 @@ exports.decode = function (charCode) { * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); +var util = __webpack_require__(3668); /** * Determine whether mappingB is after mappingA with respect to generated @@ -2506,7 +2380,8 @@ exports.MappingList = MappingList; /***/ }), -/* 20 */ + +/***/ 3713: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -2516,11 +2391,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(2); -var binarySearch = __webpack_require__(21); -var ArraySet = __webpack_require__(13).ArraySet; -var base64VLQ = __webpack_require__(12); -var quickSort = __webpack_require__(22).quickSort; +var util = __webpack_require__(3668); +var binarySearch = __webpack_require__(3714); +var ArraySet = __webpack_require__(3708).ArraySet; +var base64VLQ = __webpack_require__(3707); +var quickSort = __webpack_require__(3715).quickSort; function SourceMapConsumer(aSourceMap, aSourceMapURL) { var sourceMap = aSourceMap; @@ -3564,7 +3439,7 @@ IndexedSourceMapConsumer.prototype.sourceContentFor = * and an object is returned with the following properties: * * - line: The line number in the generated source, or null. The - * line number is 1-based. + * line number is 1-based. * - column: The column number in the generated source, or null. * The column number is 0-based. */ @@ -3657,7 +3532,8 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 21 */ + +/***/ 3714: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3774,7 +3650,8 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 22 */ + +/***/ 3715: /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3894,7 +3771,8 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 23 */ + +/***/ 3716: /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -3904,8 +3782,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(11).SourceMapGenerator; -var util = __webpack_require__(2); +var SourceMapGenerator = __webpack_require__(3706).SourceMapGenerator; +var util = __webpack_require__(3668); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -4313,12 +4191,16 @@ exports.SourceNode = SourceNode; /***/ }), -/* 24 */ -/***/ (function(module, exports) { + +/***/ 3717: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ function assert(condition, message) { if (!condition) { @@ -4329,40 +4211,21 @@ function assert(condition, message) { module.exports = assert; /***/ }), -/* 25 */ + +/***/ 3718: /***/ (function(module, exports, __webpack_require__) { -let _resolveAndFetch = (() => { - var _ref = _asyncToGenerator(function* (generatedSource) { - // Fetch the sourcemap over the network and create it. - const { sourceMapURL, baseURL } = _resolveSourceMapURL(generatedSource); +"use strict"; - const fetched = yield networkRequest(sourceMapURL, { loadFromCache: false }); - - // Create the source map and fix it up. - let map = new SourceMapConsumer(fetched.content, baseURL); - if (generatedSource.isWasm) { - map = new WasmRemap(map); - } - - return map; - }); - - return function _resolveAndFetch(_x) { - return _ref.apply(this, arguments); - }; -})(); - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + * file, You can obtain one at . */ -const { networkRequest } = __webpack_require__(1); -const { getSourceMap, setSourceMap } = __webpack_require__(9); -const { WasmRemap } = __webpack_require__(14); -const { SourceMapConsumer } = __webpack_require__(10); +const { networkRequest } = __webpack_require__(3651); +const { getSourceMap, setSourceMap } = __webpack_require__(3704); +const { WasmRemap } = __webpack_require__(3719); +const { SourceMapConsumer } = __webpack_require__(3705); function _resolveSourceMapURL(source) { const { url = "", sourceMapURL = "" } = source; @@ -4385,6 +4248,21 @@ function _resolveSourceMapURL(source) { return { sourceMapURL: resolvedString, baseURL }; } +async function _resolveAndFetch(generatedSource) { + // Fetch the sourcemap over the network and create it. + const { sourceMapURL, baseURL } = _resolveSourceMapURL(generatedSource); + + const fetched = await networkRequest(sourceMapURL, { loadFromCache: false }); + + // Create the source map and fix it up. + let map = new SourceMapConsumer(fetched.content, baseURL); + if (generatedSource.isWasm) { + map = new WasmRemap(map); + } + + return map; +} + function fetchSourceMap(generatedSource) { const existingRequest = getSourceMap(generatedSource.id); @@ -4400,7 +4278,7 @@ function fetchSourceMap(generatedSource) { } if (!generatedSource.sourceMapURL) { - return Promise.resolve(null); + return null; } // Fire off the request, set it in the cache, and return it. @@ -4413,6 +4291,121 @@ function fetchSourceMap(generatedSource) { module.exports = { fetchSourceMap }; +/***/ }), + +/***/ 3719: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ + +/** + * SourceMapConsumer for WebAssembly source maps. It transposes columns with + * lines, which allows mapping data to be used with SpiderMonkey Debugger API. + */ +class WasmRemap { + /** + * @param map SourceMapConsumer + */ + constructor(map) { + this._map = map; + this.version = map.version; + this.file = map.file; + this._computeColumnSpans = false; + } + + get sources() { + return this._map.sources; + } + + get sourceRoot() { + return this._map.sourceRoot; + } + + get names() { + return this._map.names; + } + + get sourcesContent() { + return this._map.sourcesContent; + } + + get mappings() { + throw new Error("not supported"); + } + + computeColumnSpans() { + this._computeColumnSpans = true; + } + + originalPositionFor(generatedPosition) { + const result = this._map.originalPositionFor({ + line: 1, + column: generatedPosition.line, + bias: generatedPosition.bias + }); + return result; + } + + _remapGeneratedPosition(position) { + const generatedPosition = { + line: position.column, + column: 0 + }; + if (this._computeColumnSpans) { + generatedPosition.lastColumn = Infinity; + } + return generatedPosition; + } + + generatedPositionFor(originalPosition) { + const position = this._map.generatedPositionFor(originalPosition); + return this._remapGeneratedPosition(position); + } + + allGeneratedPositionsFor(originalPosition) { + const positions = this._map.allGeneratedPositionsFor(originalPosition); + return positions.map(position => { + return this._remapGeneratedPosition(position); + }); + } + + hasContentsOfAllSources() { + return this._map.hasContentsOfAllSources(); + } + + sourceContentFor(source, returnNullOnMissing) { + return this._map.sourceContentFor(source, returnNullOnMissing); + } + + eachMapping(callback, context, order) { + this._map.eachMapping(entry => { + const { + source, + generatedColumn, + originalLine, + originalColumn, + name + } = entry; + callback({ + source, + generatedLine: generatedColumn, + generatedColumn: 0, + originalLine, + originalColumn, + name + }); + }, context, order); + } +} + +exports.WasmRemap = WasmRemap; + /***/ }) -/******/ ]); -}); + +/******/ }); +}); \ No newline at end of file diff --git a/gfx/qcms/iccread.c b/gfx/qcms/iccread.c index 5e6836f82523..1a921ba7133a 100644 --- a/gfx/qcms/iccread.c +++ b/gfx/qcms/iccread.c @@ -606,7 +606,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag // 24bits * 3 won't overflow either clut_size = clut_size * num_out_channels; - if (clut_size > MAX_CLUT_SIZE) + if (clut_size == 0 || clut_size > MAX_CLUT_SIZE) return NULL; lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float)); diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index ccac97afc0a2..7855b3d7662a 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2353,11 +2353,6 @@ extern "C" { -> bool; } -#[no_mangle] -pub extern "C" fn wr_shutdown_log_for_gpu_process() { - // log does not support shutdown -} - #[no_mangle] pub extern "C" fn wr_root_scroll_node_id() -> usize { // The PipelineId doesn't matter here, since we just want the numeric part of the id diff --git a/gfx/webrender_bindings/webrender_ffi_generated.h b/gfx/webrender_bindings/webrender_ffi_generated.h index 54c4f96472c5..33f3fe77d571 100644 --- a/gfx/webrender_bindings/webrender_ffi_generated.h +++ b/gfx/webrender_bindings/webrender_ffi_generated.h @@ -1587,10 +1587,6 @@ void wr_set_item_tag(WrState *aState, uint16_t aHitInfo) WR_FUNC; -WR_INLINE -void wr_shutdown_log_for_gpu_process() -WR_FUNC; - WR_INLINE void wr_state_delete(WrState *aState) WR_DESTRUCTOR_SAFE_FUNC; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a8f3805f654b..46152bfd3aa9 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -979,6 +979,10 @@ TraceParser(JSTracer* trc, AutoGCRooter* parser) bool ParserBase::setSourceMapInfo() { + // Not all clients initialize ss. Can't update info to an object that isn't there. + if (!ss) + return true; + if (anyChars.hasDisplayURL()) { if (!ss->setDisplayURL(context, anyChars.displayURL())) return false; diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java index 4d4c37403cb9..a86202de969b 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/TestDownloadAction.java @@ -14,6 +14,7 @@ import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.dlc.catalog.DownloadContent; import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder; import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -223,7 +224,7 @@ public class TestDownloadAction { verify(connection).getInputStream(); verify(connection).setRequestProperty("Range", "bytes=1337-"); - Assert.assertEquals("HelloWorld", new String(outputStream.toByteArray(), "UTF-8")); + Assert.assertEquals("HelloWorld", new String(outputStream.toByteArray(), StringUtils.UTF_8)); verify(action).openFile(eq(temporaryFile), eq(true)); verify(catalog).markAsDownloaded(content); @@ -635,7 +636,7 @@ public class TestDownloadAction { HttpURLConnection connection = mock(HttpURLConnection.class); doReturn(statusCode).when(connection).getResponseCode(); - doReturn(new ByteArrayInputStream(content.getBytes("UTF-8"))).when(connection).getInputStream(); + doReturn(new ByteArrayInputStream(content.getBytes(StringUtils.UTF_8))).when(connection).getInputStream(); return connection; } diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java index f7d7089699a9..d16fdd61e996 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/dlc/catalog/TestDownloadContentCatalog.java @@ -13,6 +13,7 @@ import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.mozilla.gecko.AppConstants; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.FileNotFoundException; @@ -37,7 +38,7 @@ public class TestDownloadContentCatalog { @Test public void testUntouchedCatalogHasNotChangedAndWillNotBePersisted() throws Exception { AtomicFile file = mock(AtomicFile.class); - doReturn("{content:[]}".getBytes("UTF-8")).when(file).readFully(); + doReturn("{content:[]}".getBytes(StringUtils.UTF_8)).when(file).readFully(); DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file)); catalog.loadFromDisk(); diff --git a/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java b/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java index 76e6e64128b8..779da35e3223 100644 --- a/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java +++ b/mobile/android/app/src/test/java/org/mozilla/gecko/push/TestPushState.java @@ -7,6 +7,7 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RuntimeEnvironment; import java.io.File; @@ -57,7 +58,7 @@ public class TestPushState { FileOutputStream fos = null; try { fos = new FileOutputStream(file); - fos.write("}".getBytes("UTF-8")); + fos.write("}".getBytes(StringUtils.UTF_8)); } finally { if (fos != null) { fos.close(); diff --git a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java index 4b86c418ced1..a23a7b738e83 100644 --- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java +++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java @@ -43,6 +43,7 @@ import org.mozilla.gecko.sync.SynchronizerConfiguration; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.repositories.android.RepoUtils; import org.mozilla.gecko.util.FileUtils; +import org.mozilla.gecko.util.StringUtils; import static org.mozilla.gecko.db.DBUtils.qualifyColumn; @@ -1782,18 +1783,13 @@ public class BrowserDatabaseHelper extends SQLiteOpenHelper { @RobocopTarget public static String getReaderCacheFileNameForURL(String url) { try { - // On KitKat and above we can use java.nio.charset.StandardCharsets.UTF_8 in place of "UTF8" - // which avoids having to handle UnsupportedCodingException - byte[] utf8 = url.getBytes("UTF8"); + byte[] utf8 = url.getBytes(StringUtils.UTF_8); final MessageDigest digester = MessageDigest.getInstance("MD5"); byte[] hash = digester.digest(utf8); final String hashString = new Base32().encodeAsString(hash); return hashString.substring(0, hashString.indexOf('=')) + ".json"; - } catch (UnsupportedEncodingException e) { - // This should never happen - throw new IllegalStateException("UTF8 encoding not available - can't process readercache filename"); } catch (NoSuchAlgorithmException e) { // This should also never happen throw new IllegalStateException("MD5 digester unavailable - can't process readercache filename"); diff --git a/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java b/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java index d4a71d6ce9e5..ab4356db5ffb 100644 --- a/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java +++ b/mobile/android/base/java/org/mozilla/gecko/db/LoginsProvider.java @@ -498,7 +498,7 @@ public class LoginsProvider extends SharedBrowserDatabaseProvider { private String encrypt(@NonNull String initialValue) { try { final Cipher cipher = getCipher(Cipher.ENCRYPT_MODE); - return Base64.encodeToString(cipher.doFinal(initialValue.getBytes("UTF-8")), Base64.URL_SAFE); + return Base64.encodeToString(cipher.doFinal(initialValue.getBytes(StringUtils.UTF_8)), Base64.URL_SAFE); } catch (Exception e) { debug("encryption failed : " + e); throw new IllegalStateException("Logins encryption failed", e); @@ -509,7 +509,7 @@ public class LoginsProvider extends SharedBrowserDatabaseProvider { try { final Cipher cipher = getCipher(Cipher.DECRYPT_MODE); return new String(cipher.doFinal(Base64.decode( - initialValue.getBytes("UTF-8"), Base64.URL_SAFE)), StringUtils.UTF_8); + initialValue.getBytes(StringUtils.UTF_8), Base64.URL_SAFE)), StringUtils.UTF_8); } catch (Exception e) { debug("Decryption failed : " + e); throw new IllegalStateException("Logins decryption failed", e); diff --git a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java index b7afa4c09eac..e00da38d0603 100644 --- a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java +++ b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContentCatalog.java @@ -14,12 +14,12 @@ import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; @@ -218,7 +218,7 @@ public class DownloadContentCatalog { JSONObject catalog; synchronized (file) { - catalog = new JSONObject(new String(file.readFully(), "UTF-8")); + catalog = new JSONObject(new String(file.readFully(), StringUtils.UTF_8)); } JSONArray array = catalog.getJSONArray(JSON_KEY_CONTENT); @@ -233,10 +233,6 @@ public class DownloadContentCatalog { Log.w(LOGTAG, "Unable to parse catalog JSON. Re-creating empty catalog.", e); loadedContent = new ArrayMap<>(); hasCatalogChanged = true; // Indicate that we want to persist the new catalog - } catch (UnsupportedEncodingException e) { - AssertionError error = new AssertionError("Should not happen: This device does not speak UTF-8"); - error.initCause(e); - throw error; } catch (IOException e) { Log.d(LOGTAG, "Can't read catalog due to IOException", e); } @@ -275,15 +271,11 @@ public class DownloadContentCatalog { JSONObject catalog = new JSONObject(); catalog.put(JSON_KEY_CONTENT, array); - outputStream.write(catalog.toString().getBytes("UTF-8")); + outputStream.write(catalog.toString().getBytes(StringUtils.UTF_8)); file.finishWrite(outputStream); hasCatalogChanged = false; - } catch (UnsupportedEncodingException e) { - AssertionError error = new AssertionError("Should not happen: This device does not speak UTF-8"); - error.initCause(e); - throw error; } catch (IOException | JSONException e) { Log.e(LOGTAG, "IOException during writing catalog", e); diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java b/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java index 3c0e2a55423b..d0438ac5002c 100644 --- a/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java +++ b/mobile/android/base/java/org/mozilla/gecko/icons/storage/DiskStorage.java @@ -19,12 +19,12 @@ import org.mozilla.gecko.icons.IconRequest; import org.mozilla.gecko.icons.IconResponse; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.util.IOUtils; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.security.MessageDigest; /** @@ -257,10 +257,10 @@ public class DiskStorage { return null; } - byte[] data = prefix.getBytes("UTF-8"); + byte[] data = prefix.getBytes(StringUtils.UTF_8); NativeCrypto.sha256update(ctx, data, data.length); - data = url.getBytes("UTF-8"); + data = url.getBytes(StringUtils.UTF_8); NativeCrypto.sha256update(ctx, data, data.length); return Utils.byte2Hex(NativeCrypto.sha256finalize(ctx)); } catch (NoClassDefFoundError | ExceptionInInitializerError error) { @@ -269,15 +269,13 @@ public class DiskStorage { // we will have a lot of other problems if we can't load libmozglue.so try { MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(prefix.getBytes("UTF-8")); - md.update(url.getBytes("UTF-8")); + md.update(prefix.getBytes(StringUtils.UTF_8)); + md.update(url.getBytes(StringUtils.UTF_8)); return Utils.byte2Hex(md.digest()); } catch (Exception e) { // Just give up. And let everyone know. throw new RuntimeException(e); } - } catch (UnsupportedEncodingException e) { - throw new AssertionError("Should not happen: Device does not understand UTF-8"); } } diff --git a/mobile/android/base/java/org/mozilla/gecko/push/PushState.java b/mobile/android/base/java/org/mozilla/gecko/push/PushState.java index 686bf5a0d1e3..2f84cd9690e5 100644 --- a/mobile/android/base/java/org/mozilla/gecko/push/PushState.java +++ b/mobile/android/base/java/org/mozilla/gecko/push/PushState.java @@ -13,6 +13,7 @@ import android.util.Log; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.util.StringUtils; import java.io.File; import java.io.FileNotFoundException; @@ -46,7 +47,7 @@ public class PushState { file = new AtomicFile(new File(context.getApplicationInfo().dataDir, fileName)); synchronized (file) { try { - final String s = new String(file.readFully(), "UTF-8"); + final String s = new String(file.readFully(), StringUtils.UTF_8); final JSONObject temp = new JSONObject(s); if (temp.optLong("version", 0L) != VERSION) { throw new JSONException("Unknown version!"); @@ -91,7 +92,7 @@ public class PushState { FileOutputStream fileOutputStream = null; try { fileOutputStream = file.startWrite(); - fileOutputStream.write(toJSONObject().toString().getBytes("UTF-8")); + fileOutputStream.write(toJSONObject().toString().getBytes(StringUtils.UTF_8)); file.finishWrite(fileOutputStream); return true; } catch (JSONException | IOException e) { diff --git a/mobile/android/modules/geckoview/GeckoViewModule.jsm b/mobile/android/modules/geckoview/GeckoViewModule.jsm index 82f1dca65e48..8fb4fb5adcf6 100644 --- a/mobile/android/modules/geckoview/GeckoViewModule.jsm +++ b/mobile/android/modules/geckoview/GeckoViewModule.jsm @@ -79,6 +79,8 @@ class GeckoViewModule { } self.messageManager.removeMessageListener("GeckoView:ContentRegistered", listener); + self.messageManager.sendAsyncMessage("GeckoView:UpdateSettings", + self.settings); self._eventProxy.enableQueuing(false); self._eventProxy.dispatchQueuedEvents(); }); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java index 98809137fb2d..9e696db6792d 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java @@ -6,6 +6,7 @@ package org.mozilla.gecko.background.fxa; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; @@ -25,7 +26,6 @@ public class FxAccount20CreateDelegate { * @param preVerified * true if account should be marked already verified; only effective * for non-production auth servers. - * @throws UnsupportedEncodingException * @throws GeneralSecurityException */ public FxAccount20CreateDelegate(byte[] emailUTF8, byte[] quickStretchedPW, boolean preVerified) throws UnsupportedEncodingException, GeneralSecurityException { @@ -34,19 +34,15 @@ public class FxAccount20CreateDelegate { this.preVerified = preVerified; } - public ExtendedJSONObject getCreateBody() throws FxAccountClientException { + public ExtendedJSONObject getCreateBody() { final ExtendedJSONObject body = new ExtendedJSONObject(); - try { - body.put("email", new String(emailUTF8, "UTF-8")); - body.put("authPW", Utils.byte2Hex(authPW)); - if (preVerified) { - // Production endpoints do not allow preVerified; this assumes we only - // set it when it's okay to send it. - body.put("preVerified", preVerified); - } - return body; - } catch (UnsupportedEncodingException e) { - throw new FxAccountClientException(e); + body.put("email", new String(emailUTF8, StringUtils.UTF_8)); + body.put("authPW", Utils.byte2Hex(authPW)); + if (preVerified) { + // Production endpoints do not allow preVerified; this assumes we only + // set it when it's okay to send it. + body.put("preVerified", preVerified); } + return body; } } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java index 0266a6eab9ac..f2544c9a9057 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java @@ -6,6 +6,7 @@ package org.mozilla.gecko.background.fxa; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; @@ -23,14 +24,10 @@ public class FxAccount20LoginDelegate { this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW); } - public ExtendedJSONObject getCreateBody() throws FxAccountClientException { + public ExtendedJSONObject getCreateBody() { final ExtendedJSONObject body = new ExtendedJSONObject(); - try { - body.put("email", new String(emailUTF8, "UTF-8")); - body.put("authPW", Utils.byte2Hex(authPW)); - return body; - } catch (UnsupportedEncodingException e) { - throw new FxAccountClientException(e); - } + body.put("email", new String(emailUTF8, StringUtils.UTF_8)); + body.put("authPW", Utils.byte2Hex(authPW)); + return body; } } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java index e35fca9e045a..fa2d927b47cc 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java @@ -24,6 +24,7 @@ import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; import org.mozilla.gecko.sync.net.Resource; import org.mozilla.gecko.sync.net.SyncResponse; import org.mozilla.gecko.sync.net.SyncStorageResponse; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -647,7 +648,7 @@ public class FxAccountClient20 implements FxAccountClient { if (getKeys) { keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN)); } - LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken); + LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, StringUtils.UTF_8), uid, verified, sessionToken, keyFetchToken); delegate.handleSuccess(loginResponse); } @@ -697,7 +698,7 @@ public class FxAccountClient20 implements FxAccountClient { if (getKeys) { keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN)); } - LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken); + LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, StringUtils.UTF_8), uid, verified, sessionToken, keyFetchToken); delegate.handleSuccess(loginResponse); } @@ -736,7 +737,7 @@ public class FxAccountClient20 implements FxAccountClient { final RequestDelegate delegate) { byte[] quickStretchedPW; try { - FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, "UTF-8") + "'" ); + FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, StringUtils.UTF_8) + "'" ); quickStretchedPW = stretcher.getQuickStretchedPW(emailUTF8); } catch (Exception e) { delegate.handleError(e); @@ -768,7 +769,7 @@ public class FxAccountClient20 implements FxAccountClient { try { // Nota bene: this is not recursive, since we call the fixed password // signature here, which invokes a non-retrying version. - byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8"); + byte[] alternateEmailUTF8 = alternateEmail.getBytes(StringUtils.UTF_8); byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8); login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, queryParameters, delegate); } catch (Exception innerException) { diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java index 6b8919fc4527..c4e7b1ae5bca 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java @@ -20,6 +20,7 @@ import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.crypto.HKDF; import org.mozilla.gecko.sync.crypto.KeyBundle; import org.mozilla.gecko.sync.crypto.PBKDF2; +import org.mozilla.gecko.util.StringUtils; import android.content.Context; @@ -49,21 +50,21 @@ public class FxAccountUtils { } } - public static String bytes(String string) throws UnsupportedEncodingException { - return Utils.byte2Hex(string.getBytes("UTF-8")); + public static String bytes(String string) { + return Utils.byte2Hex(string.getBytes(StringUtils.UTF_8)); } - public static byte[] KW(String name) throws UnsupportedEncodingException { + public static byte[] KW(String name) { return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8")); + KW_VERSION_STRING.getBytes(StringUtils.UTF_8), + name.getBytes(StringUtils.UTF_8)); } - public static byte[] KWE(String name, byte[] emailUTF8) throws UnsupportedEncodingException { + public static byte[] KWE(String name, byte[] emailUTF8) { return Utils.concatAll( - KW_VERSION_STRING.getBytes("UTF-8"), - name.getBytes("UTF-8"), - ":".getBytes("UTF-8"), + KW_VERSION_STRING.getBytes(StringUtils.UTF_8), + name.getBytes(StringUtils.UTF_8), + ":".getBytes(StringUtils.UTF_8), emailUTF8); } @@ -71,8 +72,8 @@ public class FxAccountUtils { * Calculate the SRP verifier x value. */ public static BigInteger srpVerifierLowercaseX(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes("UTF-8"), srpPWBytes)); + throws NoSuchAlgorithmException { + byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes(StringUtils.UTF_8), srpPWBytes)); byte[] outer = Utils.sha256(Utils.concatAll(srpSaltBytes, inner)); return new BigInteger(1, outer); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java index bf4b1bc97558..a45f6dc2a23f 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; public class QuickPasswordStretcher implements PasswordStretcher { protected final String password; @@ -26,7 +27,7 @@ public class QuickPasswordStretcher implements PasswordStretcher { } String key = Utils.byte2Hex(emailUTF8); if (!cache.containsKey(key)) { - byte[] value = FxAccountUtils.generateQuickStretchedPW(emailUTF8, password.getBytes("UTF-8")); + byte[] value = FxAccountUtils.generateQuickStretchedPW(emailUTF8, password.getBytes(StringUtils.UTF_8)); cache.put(key, Utils.byte2Hex(value)); return value; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java index 4d4589b7256d..4a4b4341014f 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/browserid/JSONWebTokenUtils.java @@ -4,15 +4,16 @@ package org.mozilla.gecko.browserid; +import static org.mozilla.apache.commons.codec.binary.StringUtils.newStringUtf8; + import org.json.simple.JSONObject; import org.mozilla.apache.commons.codec.binary.Base64; -import org.mozilla.apache.commons.codec.binary.StringUtils; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.TreeMap; @@ -32,21 +33,21 @@ public class JSONWebTokenUtils { public static final String DEFAULT_CERTIFICATE_ISSUER = "127.0.0.1"; public static final String DEFAULT_ASSERTION_ISSUER = "127.0.0.1"; - public static String encode(String payload, SigningPrivateKey privateKey) throws UnsupportedEncodingException, GeneralSecurityException { + public static String encode(String payload, SigningPrivateKey privateKey) throws GeneralSecurityException { final ExtendedJSONObject header = new ExtendedJSONObject(); header.put("alg", privateKey.getAlgorithm()); - String encodedHeader = Base64.encodeBase64URLSafeString(header.toJSONString().getBytes("UTF-8")); - String encodedPayload = Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")); + String encodedHeader = Base64.encodeBase64URLSafeString(header.toJSONString().getBytes(StringUtils.UTF_8)); + String encodedPayload = Base64.encodeBase64URLSafeString(payload.getBytes(StringUtils.UTF_8)); ArrayList segments = new ArrayList(); segments.add(encodedHeader); segments.add(encodedPayload); - byte[] message = Utils.toDelimitedString(".", segments).getBytes("UTF-8"); + byte[] message = Utils.toDelimitedString(".", segments).getBytes(StringUtils.UTF_8); byte[] signature = privateKey.signMessage(message); segments.add(Base64.encodeBase64URLSafeString(signature)); return Utils.toDelimitedString(".", segments); } - public static String decode(String token, VerifyingPublicKey publicKey) throws GeneralSecurityException, UnsupportedEncodingException { + public static String decode(String token, VerifyingPublicKey publicKey) throws GeneralSecurityException { if (token == null) { throw new IllegalArgumentException("token must not be null"); } @@ -54,13 +55,13 @@ public class JSONWebTokenUtils { if (segments == null || segments.length != 3) { throw new GeneralSecurityException("malformed token"); } - byte[] message = (segments[0] + "." + segments[1]).getBytes("UTF-8"); + byte[] message = (segments[0] + "." + segments[1]).getBytes(StringUtils.UTF_8); byte[] signature = Base64.decodeBase64(segments[2]); boolean verifies = publicKey.verifyMessage(message, signature); if (!verifies) { throw new GeneralSecurityException("bad signature"); } - String payload = StringUtils.newStringUtf8(Base64.decodeBase64(segments[1])); + String payload = newStringUtf8(Base64.decodeBase64(segments[1])); return payload; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java index eaf619068fdc..830a1a9bf233 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java @@ -45,6 +45,7 @@ import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.ThreadPool; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.setup.Constants; +import org.mozilla.gecko.util.StringUtils; import org.mozilla.gecko.util.ThreadUtils; import java.io.IOException; @@ -495,11 +496,7 @@ public class AndroidFxAccount { public ExtendedJSONObject toJSONObject() { ExtendedJSONObject o = unbundle(); o.put("email", account.name); - try { - o.put("emailUTF8", Utils.byte2Hex(account.name.getBytes("UTF-8"))); - } catch (UnsupportedEncodingException e) { - // Ignore. - } + o.put("emailUTF8", Utils.byte2Hex(account.name.getBytes(StringUtils.UTF_8))); o.put("fxaDeviceId", getDeviceId()); o.put("fxaDeviceRegistrationVersion", getDeviceRegistrationVersion()); o.put("fxaDeviceRegistrationTimestamp", getDeviceRegistrationTimestamp()); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java index 3677a8d133ed..9b53c0671c85 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java @@ -57,6 +57,7 @@ import org.mozilla.gecko.tokenserver.TokenServerClient; import org.mozilla.gecko.tokenserver.TokenServerClientDelegate; import org.mozilla.gecko.tokenserver.TokenServerException; import org.mozilla.gecko.tokenserver.TokenServerToken; +import org.mozilla.gecko.util.StringUtils; import java.net.URI; import java.net.URISyntaxException; @@ -408,7 +409,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { // so we explicitly do not send payload verification hashes to the // Sync storage endpoint. final boolean includePayloadVerificationHash = false; - final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes("UTF-8"), includePayloadVerificationHash, storageServerSkew); + final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes(StringUtils.UTF_8), includePayloadVerificationHash, storageServerSkew); final Context context = getContext(); final SyncConfiguration syncConfig = new SyncConfiguration(token.uid, authHeaderProvider, sharedPrefs, syncKeyBundle); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java index 8570095e045f..15890b953aac 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CommandProcessor.java @@ -21,8 +21,8 @@ import org.mozilla.gecko.sync.repositories.NullCursorException; import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; import org.mozilla.gecko.sync.telemetry.TelemetryEventCollector; +import org.mozilla.gecko.util.StringUtils; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; @@ -267,10 +267,10 @@ public class CommandProcessor { extra.put("flowID", command.flowID); } try { - extra.put("deviceID", Utils.byte2Hex(Utils.sha256(clientID.concat(hashedFxAUID).getBytes("UTF-8")))); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + extra.put("deviceID", Utils.byte2Hex(Utils.sha256(clientID.concat(hashedFxAUID).getBytes(StringUtils.UTF_8)))); + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } TelemetryEventCollector.recordEvent(context, "sendcommand", command.commandType, null, extra); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java index ca7e08a952ff..86bee17f1d06 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/CryptoRecord.java @@ -5,7 +5,6 @@ package org.mozilla.gecko.sync; import java.io.IOException; -import java.io.UnsupportedEncodingException; import org.json.simple.JSONObject; import org.mozilla.apache.commons.codec.binary.Base64; @@ -56,11 +55,10 @@ public class CryptoRecord extends Record { * Input: JSONObject containing a valid payload (cipherText, IV, HMAC), * KeyBundle with keys for decryption. Output: byte[] clearText * @throws CryptoException - * @throws UnsupportedEncodingException */ - private static byte[] decryptPayload(ExtendedJSONObject payload, KeyBundle keybundle) throws CryptoException, UnsupportedEncodingException { - byte[] ciphertext = Base64.decodeBase64(((String) payload.get(KEY_CIPHERTEXT)).getBytes("UTF-8")); - byte[] iv = Base64.decodeBase64(((String) payload.get(KEY_IV)).getBytes("UTF-8")); + private static byte[] decryptPayload(ExtendedJSONObject payload, KeyBundle keybundle) throws CryptoException { + byte[] ciphertext = Base64.decodeBase64(((String) payload.get(KEY_CIPHERTEXT)).getBytes(StringUtils.UTF_8)); + byte[] iv = Base64.decodeBase64(((String) payload.get(KEY_IV)).getBytes(StringUtils.UTF_8)); byte[] hmac = Utils.hex2Byte((String) payload.get(KEY_HMAC)); return CryptoInfo.decrypt(ciphertext, iv, hmac, keybundle).getMessage(); @@ -131,7 +129,7 @@ public class CryptoRecord extends Record { */ public static CryptoRecord fromJSONRecord(String jsonRecord) throws NonObjectJSONException, IOException, RecordParseException { - byte[] bytes = jsonRecord.getBytes("UTF-8"); + byte[] bytes = jsonRecord.getBytes(StringUtils.UTF_8); ExtendedJSONObject object = ExtendedJSONObject.parseUTF8AsJSONObject(bytes); return CryptoRecord.fromJSONRecord(object); @@ -201,7 +199,7 @@ public class CryptoRecord extends Record { return this; } - public CryptoRecord encrypt() throws CryptoException, UnsupportedEncodingException { + public CryptoRecord encrypt() throws CryptoException { if (this.keyBundle == null) { throw new NoKeyBundleException(); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java index 69ffbbd61fdc..8a572f4336d2 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/ExtendedJSONObject.java @@ -10,6 +10,7 @@ import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.Reader; @@ -138,7 +139,7 @@ public class ExtendedJSONObject implements Cloneable { */ public static ExtendedJSONObject parseUTF8AsJSONObject(byte[] in) throws NonObjectJSONException, IOException { - return new ExtendedJSONObject(new String(in, "UTF-8")); + return new ExtendedJSONObject(new String(in, StringUtils.UTF_8)); } public ExtendedJSONObject() { diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java index 4544aa919e62..fbf67648bdc8 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java @@ -7,7 +7,6 @@ package org.mozilla.gecko.sync; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; @@ -127,11 +126,9 @@ public class Utils { * An input string. Will be decoded as UTF-8. * @return * A byte array of decoded values. - * @throws UnsupportedEncodingException - * Should not occur. */ - public static byte[] decodeBase64(String base64) throws UnsupportedEncodingException { - return Base64.decodeBase64(base64.getBytes("UTF-8")); + public static byte[] decodeBase64(String base64) { + return Base64.decodeBase64(base64.getBytes(StringUtils.UTF_8)); } public static byte[] decodeFriendlyBase32(String base32) { @@ -202,8 +199,8 @@ public class Utils { } protected static byte[] sha1(final String utf8) - throws NoSuchAlgorithmException, UnsupportedEncodingException { - final byte[] bytes = utf8.getBytes("UTF-8"); + throws NoSuchAlgorithmException { + final byte[] bytes = utf8.getBytes(StringUtils.UTF_8); try { return NativeCrypto.sha1(bytes); } catch (final LinkageError e) { @@ -213,12 +210,12 @@ public class Utils { Logger.warn(LOG_TAG, "Got throwable stretching password using native sha1 implementation; " + "ignoring and using Java implementation.", e); final MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); - return sha1.digest(utf8.getBytes("UTF-8")); + return sha1.digest(utf8.getBytes(StringUtils.UTF_8)); } } protected static String sha1Base32(final String utf8) - throws NoSuchAlgorithmException, UnsupportedEncodingException { + throws NoSuchAlgorithmException { return new Base32().encodeAsString(sha1(utf8)).toLowerCase(Locale.US); } @@ -229,10 +226,9 @@ public class Utils { * An account string. * @return * An acceptable string. - * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException */ - public static String usernameFromAccount(final String account) throws NoSuchAlgorithmException, UnsupportedEncodingException { + public static String usernameFromAccount(final String account) throws NoSuchAlgorithmException { if (account == null || account.equals("")) { throw new IllegalArgumentException("No account name provided."); } @@ -252,10 +248,9 @@ public class Utils { * @param version the version of preferences to reference. * @return the path. * @throws NoSuchAlgorithmException - * @throws UnsupportedEncodingException */ public static String getPrefsPath(final String product, final String accountKey, final String serverURL, final String profile, final long version) - throws NoSuchAlgorithmException, UnsupportedEncodingException { + throws NoSuchAlgorithmException { final String encodedAccount = sha1Base32(serverURL + ":" + usernameFromAccount(accountKey)); if (version <= 0) { @@ -515,13 +510,13 @@ public class Utils { * This is the format produced by desktop Firefox when exchanging credentials * containing non-ASCII characters. */ - public static String decodeUTF8(final String in) throws UnsupportedEncodingException { + public static String decodeUTF8(final String in) { final int length = in.length(); final byte[] asciiBytes = new byte[length]; for (int i = 0; i < length; ++i) { asciiBytes[i] = (byte) in.codePointAt(i); } - return new String(asciiBytes, "UTF-8"); + return new String(asciiBytes, StringUtils.UTF_8); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java index f5136f10966d..7e273fc2861e 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/HKDF.java @@ -12,6 +12,7 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; /* * A standards-compliant implementation of RFC 5869 @@ -25,11 +26,7 @@ public class HKDF { * Used for conversion in cases in which you *know* the encoding exists. */ public static final byte[] bytes(String in) { - try { - return in.getBytes("UTF-8"); - } catch (java.io.UnsupportedEncodingException e) { - return null; - } + return in.getBytes(StringUtils.UTF_8); } public static final int BLOCKSIZE = 256 / 8; diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java index 2063b1e32aaa..b61d546d2dda 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/crypto/KeyBundle.java @@ -4,7 +4,6 @@ package org.mozilla.gecko.sync.crypto; -import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -14,6 +13,7 @@ import javax.crypto.Mac; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; public class KeyBundle { private static final String KEY_ALGORITHM_SPEC = "AES"; @@ -44,7 +44,7 @@ public class KeyBundle { // Hash appropriately. try { username = Utils.usernameFromAccount(username); - } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("Invalid username."); } @@ -77,9 +77,9 @@ public class KeyBundle { * * @return A KeyBundle with the specified keys. */ - public static KeyBundle fromBase64EncodedKeys(String base64EncryptionKey, String base64HmacKey) throws UnsupportedEncodingException { - return new KeyBundle(Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8")), - Base64.decodeBase64(base64HmacKey.getBytes("UTF-8"))); + public static KeyBundle fromBase64EncodedKeys(String base64EncryptionKey, String base64HmacKey) { + return new KeyBundle(Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8)), + Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8))); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java index 8377e7d12042..ead31d581646 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/middleware/Crypto5MiddlewareRepositorySession.java @@ -4,7 +4,6 @@ package org.mozilla.gecko.sync.middleware; -import java.io.UnsupportedEncodingException; import java.util.concurrent.ExecutorService; import org.mozilla.gecko.sync.CryptoRecord; @@ -161,7 +160,7 @@ public class Crypto5MiddlewareRepositorySession extends MiddlewareRepositorySess rec.keyBundle = this.keyBundle; try { rec.encrypt(); - } catch (UnsupportedEncodingException | CryptoException e) { + } catch (CryptoException e) { storeDelegate.onRecordStoreFailed(e, record.guid); return; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java index 5314d345b63c..6a601c02212a 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HMACAuthHeaderProvider.java @@ -16,6 +16,7 @@ import javax.crypto.spec.SecretKeySpec; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase; @@ -197,11 +198,10 @@ public class HMACAuthHeaderProvider implements AuthHeaderProvider { * @return signature as base-64 encoded string. * @throws InvalidKeyException * @throws NoSuchAlgorithmException - * @throws UnsupportedEncodingException */ protected static String getSignature(String requestString, String key) - throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { - String macString = Base64.encodeBase64String(sha1(requestString.getBytes("UTF-8"), key.getBytes("UTF-8"))); + throws InvalidKeyException, NoSuchAlgorithmException { + String macString = Base64.encodeBase64String(sha1(requestString.getBytes(StringUtils.UTF_8), key.getBytes(StringUtils.UTF_8))); return macString; } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java index 2bdd5604a871..97ec3e84c64a 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/HawkAuthHeaderProvider.java @@ -20,6 +20,7 @@ import javax.crypto.spec.SecretKeySpec; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.HttpEntity; @@ -151,7 +152,7 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { String app = null; String dlg = null; String requestString = getRequestString(request, "header", timestamp, nonce, payloadHash, extra, app, dlg); - String macString = getSignature(requestString.getBytes("UTF-8"), this.key); + String macString = getSignature(requestString.getBytes(StringUtils.UTF_8), this.key); StringBuilder sb = new StringBuilder(); sb.append("Hawk id=\""); @@ -191,12 +192,11 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { * to compute hash for. * @return verification hash, or null if the request does not enclose an entity. * @throws IllegalArgumentException if the request does not enclose a valid non-null entity. - * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException * @throws IOException */ protected static String getPayloadHashString(HttpRequestBase request) - throws UnsupportedEncodingException, NoSuchAlgorithmException, IOException, IllegalArgumentException { + throws NoSuchAlgorithmException, IOException, IllegalArgumentException { final boolean shouldComputePayloadHash = request instanceof HttpEntityEnclosingRequest; if (!shouldComputePayloadHash) { Logger.debug(LOG_TAG, "Not computing payload verification hash for non-enclosing request."); @@ -278,14 +278,14 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { * @return hash. * @throws IllegalArgumentException if entity is not repeatable. */ - protected static byte[] getPayloadHash(HttpEntity entity) throws UnsupportedEncodingException, IOException, NoSuchAlgorithmException { + protected static byte[] getPayloadHash(HttpEntity entity) throws IOException, NoSuchAlgorithmException { if (!entity.isRepeatable()) { throw new IllegalArgumentException("entity must be repeatable"); } final MessageDigest digest = MessageDigest.getInstance("SHA-256"); - digest.update(("hawk." + HAWK_HEADER_VERSION + ".payload\n").getBytes("UTF-8")); - digest.update(getBaseContentType(entity.getContentType()).getBytes("UTF-8")); - digest.update("\n".getBytes("UTF-8")); + digest.update(("hawk." + HAWK_HEADER_VERSION + ".payload\n").getBytes(StringUtils.UTF_8)); + digest.update(getBaseContentType(entity.getContentType()).getBytes(StringUtils.UTF_8)); + digest.update("\n".getBytes(StringUtils.UTF_8)); InputStream stream = entity.getContent(); try { int numRead; @@ -295,7 +295,7 @@ public class HawkAuthHeaderProvider implements AuthHeaderProvider { digest.update(buffer, 0, numRead); } } - digest.update("\n".getBytes("UTF-8")); // Trailing newline is specified by Hawk. + digest.update("\n".getBytes(StringUtils.UTF_8)); // Trailing newline is specified by Hawk. return digest.digest(); } finally { stream.close(); diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java index 5ca3a4ffa1b4..e09aaead5fb0 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/domain/Record.java @@ -11,6 +11,7 @@ import java.io.UnsupportedEncodingException; import org.json.simple.JSONObject; import org.mozilla.gecko.sync.CryptoRecord; import org.mozilla.gecko.sync.ExtendedJSONObject; +import org.mozilla.gecko.util.StringUtils; /** * Record is the abstract base class for all entries that Sync processes: @@ -259,12 +260,7 @@ public abstract class Record { } public static byte[] stringToJSONBytes(String in) { - try { - return in.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - // Can't happen. - return null; - } + return in.getBytes(StringUtils.UTF_8); } /** diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java index cb82c8f60504..d18c075bd6e6 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SyncClientsEngineStage.java @@ -11,7 +11,6 @@ import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -672,8 +671,6 @@ public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage { return null; } return cryptoRecord.encrypt(); - } catch (UnsupportedEncodingException e) { - doAbort(e, encryptionFailure + " Unsupported encoding."); } catch (CryptoException e) { doAbort(e, encryptionFailure); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java index 15b0d08eaba4..8ce884386809 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryCollector.java @@ -18,8 +18,8 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse; import org.mozilla.gecko.sync.repositories.FetchFailedException; import org.mozilla.gecko.sync.repositories.StoreFailedException; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; +import org.mozilla.gecko.util.StringUtils; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; @@ -77,11 +77,11 @@ public class TelemetryCollector { this.hashedUID = uid; try { this.hashedDeviceID = Utils.byte2Hex(Utils.sha256( - deviceID.concat(uid).getBytes("UTF-8") + deviceID.concat(uid).getBytes(StringUtils.UTF_8) )); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } } @@ -128,11 +128,11 @@ public class TelemetryCollector { try { device.putString( TelemetryContract.KEY_DEVICE_ID, - Utils.byte2Hex(Utils.sha256(clientAndUid.getBytes("UTF-8"))) + Utils.byte2Hex(Utils.sha256(clientAndUid.getBytes(StringUtils.UTF_8))) ); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. - Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); + Log.e(LOG_TAG, "SHA-256 is not supported", e); } devices.add(device); } diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java index 03b76f9f7c8a..fe3bb0e9f54d 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/telemetry/TelemetryEventCollector.java @@ -21,6 +21,7 @@ import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.delegates.ClientsDataDelegate; import org.mozilla.gecko.sync.net.BaseResource; +import org.mozilla.gecko.util.StringUtils; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; @@ -126,10 +127,10 @@ public class TelemetryEventCollector { final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs, context); try { final String hashedDeviceID = Utils.byte2Hex(Utils.sha256( - clientsDataDelegate.getAccountGUID().concat(hashedFxAUID).getBytes("UTF-8") + clientsDataDelegate.getAccountGUID().concat(hashedFxAUID).getBytes(StringUtils.UTF_8) )); event.putString(TelemetryContract.KEY_LOCAL_DEVICE_ID, hashedDeviceID); - } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // Should not happen. Log.e(LOG_TAG, "Either UTF-8 or SHA-256 are not supported", e); return false; diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java b/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java index ebb50f765927..25d5c6ff1893 100644 --- a/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java +++ b/mobile/android/services/src/main/java/org/mozilla/gecko/util/PRNGFixes.java @@ -22,7 +22,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; @@ -330,10 +329,6 @@ public final class PRNGFixes { if (serial != null) { result.append(serial); } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } + return result.toString().getBytes(StringUtils.UTF_8); } } diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java index 53615670b27c..c9a096411327 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/net/test/TestCredentialsEndToEnd.java @@ -9,6 +9,7 @@ import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -53,7 +54,7 @@ public class TestCredentialsEndToEnd { final String decoded = Utils.decodeUTF8(password); final byte[] expectedBytes = Utils.decodeBase64(BTOA_PASSWORD); - final String expected = new String(expectedBytes, "UTF-8"); + final String expected = new String(expectedBytes, StringUtils.UTF_8); assertEquals(DESKTOP_ASSERTED_SIZE, password.length()); assertEquals(expected, decoded); diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java index 3ee2f20a6afb..a4c23b1b8819 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCollectionKeys.java @@ -13,6 +13,7 @@ import org.mozilla.gecko.sync.NoCollectionKeysSetException; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -80,7 +81,7 @@ public class TestCollectionKeys { rec.encrypt(); CollectionKeys ck = new CollectionKeys(); ck.setKeyPairsFromWBO(rec, syncKeyBundle); - byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes("UTF-8"); + byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes(StringUtils.UTF_8); byte[] expected = Base64.decodeBase64(input); assertSame(expected, ck.defaultKeyBundle().getEncryptionKey()); } diff --git a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java index 648a75819929..d741a6fbf609 100644 --- a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java +++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/TestCryptoRecord.java @@ -17,6 +17,7 @@ import org.mozilla.gecko.sync.crypto.KeyBundle; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; import org.mozilla.gecko.sync.repositories.domain.HistoryRecord; import org.mozilla.gecko.sync.repositories.domain.Record; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -109,8 +110,8 @@ public class TestCryptoRecord { payload.put("hmac", base16Hmac); body.put("payload", payload.toJSONString()); CryptoRecord record = CryptoRecord.fromJSONRecord(body); - byte[] decodedKey = Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8")); - byte[] decodedHMAC = Base64.decodeBase64(base64HmacKey.getBytes("UTF-8")); + byte[] decodedKey = Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8)); + byte[] decodedHMAC = Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8)); record.keyBundle = new KeyBundle(decodedKey, decodedHMAC); record.decrypt(); @@ -125,14 +126,14 @@ public class TestCryptoRecord { String user = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd"; // Check our friendly base32 decoding. - assertTrue(Arrays.equals(Utils.decodeFriendlyBase32(key), Base64.decodeBase64("8xbKrJfQYwbFkguKmlSm/g==".getBytes("UTF-8")))); + assertTrue(Arrays.equals(Utils.decodeFriendlyBase32(key), Base64.decodeBase64("8xbKrJfQYwbFkguKmlSm/g==".getBytes(StringUtils.UTF_8)))); KeyBundle bundle = new KeyBundle(user, key); String expectedEncryptKeyBase64 = "/8RzbFT396htpZu5rwgIg2WKfyARgm7dLzsF5pwrVz8="; String expectedHMACKeyBase64 = "NChGjrqoXYyw8vIYP2334cvmMtsjAMUZNqFwV2LGNkM="; byte[] computedEncryptKey = bundle.getEncryptionKey(); byte[] computedHMACKey = bundle.getHMACKey(); - assertTrue(Arrays.equals(computedEncryptKey, Base64.decodeBase64(expectedEncryptKeyBase64.getBytes("UTF-8")))); - assertTrue(Arrays.equals(computedHMACKey, Base64.decodeBase64(expectedHMACKeyBase64.getBytes("UTF-8")))); + assertTrue(Arrays.equals(computedEncryptKey, Base64.decodeBase64(expectedEncryptKeyBase64.getBytes(StringUtils.UTF_8)))); + assertTrue(Arrays.equals(computedHMACKey, Base64.decodeBase64(expectedHMACKeyBase64.getBytes(StringUtils.UTF_8)))); } @Test @@ -264,8 +265,8 @@ public class TestCryptoRecord { JSONArray keys = new ExtendedJSONObject(decrypted.payload.toJSONString()).getArray("default"); KeyBundle keyBundle = KeyBundle.fromBase64EncodedKeys((String)keys.get(0), (String)keys.get(1)); - assertArrayEquals(Base64.decodeBase64(expectedBase64EncryptionKey.getBytes("UTF-8")), keyBundle.getEncryptionKey()); - assertArrayEquals(Base64.decodeBase64(expectedBase64HmacKey.getBytes("UTF-8")), keyBundle.getHMACKey()); + assertArrayEquals(Base64.decodeBase64(expectedBase64EncryptionKey.getBytes(StringUtils.UTF_8)), keyBundle.getEncryptionKey()); + assertArrayEquals(Base64.decodeBase64(expectedBase64HmacKey.getBytes(StringUtils.UTF_8)), keyBundle.getHMACKey()); } @Test diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java b/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java index 9539403105c3..0463af2eff70 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/fxa/login/TestFxAccountLoginStateMachine.java @@ -16,6 +16,7 @@ import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.LoginStateMachineD import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition; import org.mozilla.gecko.fxa.login.State.StateLabel; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.security.NoSuchAlgorithmException; @@ -39,10 +40,10 @@ public class TestFxAccountLoginStateMachine { @Before public void setUp() throws Exception { if (TEST_EMAIL_UTF8 == null) { - TEST_EMAIL_UTF8 = TEST_EMAIL.getBytes("UTF-8"); + TEST_EMAIL_UTF8 = TEST_EMAIL.getBytes(StringUtils.UTF_8); } if (TEST_PASSWORD_UTF8 == null) { - TEST_PASSWORD_UTF8 = TEST_PASSWORD.getBytes("UTF-8"); + TEST_PASSWORD_UTF8 = TEST_PASSWORD.getBytes(StringUtils.UTF_8); } if (TEST_QUICK_STRETCHED_PW == null) { TEST_QUICK_STRETCHED_PW = FxAccountUtils.generateQuickStretchedPW(TEST_EMAIL_UTF8, TEST_PASSWORD_UTF8); diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java index 6e76109db4bf..1d9b2d0814d8 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestCryptoInfo.java @@ -10,6 +10,7 @@ import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.CryptoInfo; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.UnsupportedEncodingException; @@ -24,17 +25,17 @@ import static org.junit.Assert.assertTrue; public class TestCryptoInfo { @Test - public void testEncryptedHMACIsSet() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException { + public void testEncryptedHMACIsSet() throws CryptoException, InvalidKeyException, NoSuchAlgorithmException { KeyBundle kb = KeyBundle.withRandomKeys(); - CryptoInfo encrypted = CryptoInfo.encrypt("plaintext".getBytes("UTF-8"), kb); + CryptoInfo encrypted = CryptoInfo.encrypt("plaintext".getBytes(StringUtils.UTF_8), kb); assertSame(kb, encrypted.getKeys()); assertTrue(encrypted.generatedHMACIsHMAC()); } @Test - public void testRandomEncryptedDecrypted() throws CryptoException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException { + public void testRandomEncryptedDecrypted() throws CryptoException, InvalidKeyException, NoSuchAlgorithmException { KeyBundle kb = KeyBundle.withRandomKeys(); - byte[] plaintext = "plaintext".getBytes("UTF-8"); + byte[] plaintext = "plaintext".getBytes(StringUtils.UTF_8); CryptoInfo info = CryptoInfo.encrypt(plaintext, kb); byte[] iv = info.getIV(); info.decrypt(); @@ -141,4 +142,4 @@ public class TestCryptoInfo { assertArrayEquals(Base64.decodeBase64(base64CipherText), encrypted.getMessage()); assertArrayEquals(Utils.hex2Byte(base16Hmac), encrypted.getHMAC()); } -} \ No newline at end of file +} diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java index 6bb45ed8bd63..0c3f3ba12528 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/crypto/test/TestKeyBundle.java @@ -8,6 +8,7 @@ import org.junit.runner.RunWith; import org.mozilla.apache.commons.codec.binary.Base64; import org.mozilla.gecko.sync.crypto.CryptoException; import org.mozilla.gecko.sync.crypto.KeyBundle; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.UnsupportedEncodingException; @@ -30,8 +31,8 @@ public class TestKeyBundle { "dKj0O+b0fwI="; KeyBundle keys = new KeyBundle(username, friendlyBase32SyncKey); - assertArrayEquals(keys.getEncryptionKey(), Base64.decodeBase64(base64EncryptionKey.getBytes("UTF-8"))); - assertArrayEquals(keys.getHMACKey(), Base64.decodeBase64(base64HmacKey.getBytes("UTF-8"))); + assertArrayEquals(keys.getEncryptionKey(), Base64.decodeBase64(base64EncryptionKey.getBytes(StringUtils.UTF_8))); + assertArrayEquals(keys.getHMACKey(), Base64.decodeBase64(base64HmacKey.getBytes(StringUtils.UTF_8))); } /* diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java index eb343078ef8c..69d5a98e3397 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHMACAuthHeaderProvider.java @@ -32,7 +32,7 @@ public class TestHMACAuthHeaderProvider { } public static String getSignature(String requestString, String key) - throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + throws InvalidKeyException, NoSuchAlgorithmException { return HMACAuthHeaderProvider.getSignature(requestString, key); } } diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java index 367fb80f52af..82e8320399cc 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestHawkAuthHeaderProvider.java @@ -15,6 +15,7 @@ import ch.boye.httpclientandroidlib.protocol.BasicHttpContext; import org.junit.Test; import org.junit.runner.RunWith; import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -46,7 +47,7 @@ public class TestHawkAuthHeaderProvider { // Public for testing. public static String getSignature(String requestString, String key) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { - return HawkAuthHeaderProvider.getSignature(requestString.getBytes("UTF-8"), key.getBytes("UTF-8")); + return HawkAuthHeaderProvider.getSignature(requestString.getBytes(StringUtils.UTF_8), key.getBytes(StringUtils.UTF_8)); } // Public for testing. @@ -106,7 +107,7 @@ public class TestHawkAuthHeaderProvider { @Test public void testSpecPayloadExample() throws Exception { - LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8")); + LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8)); URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2"); HttpPost req = new HttpPost(uri); String body = "Thank you for flying Hawk"; @@ -119,7 +120,7 @@ public class TestHawkAuthHeaderProvider { @Test public void testSpecAuthorizationHeader() throws Exception { - LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8")); + LeakyHawkAuthHeaderProvider provider = new LeakyHawkAuthHeaderProvider("dh37fgj492je", "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8)); URI uri = new URI("http://example.com:8000/resource/1?b=1&a=2"); HttpGet req = new HttpGet(uri); Header header = provider.getAuthHeader(req, null, null, 1353832234L, "j4h3g2", "some-app-ext-data", false); diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java index 8f136e3d09e2..f8d01fdb2b27 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/net/test/TestLiveHawkAuth.java @@ -19,6 +19,7 @@ import org.mozilla.gecko.sync.net.BaseResourceDelegate; import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider; import org.mozilla.gecko.sync.net.Resource; import org.mozilla.gecko.sync.net.SyncResponse; +import org.mozilla.gecko.util.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -39,7 +40,7 @@ public class TestLiveHawkAuth { public void testHawkUsage() throws Exception { // Id and credentials are hard-coded in example/usage.js. final String id = "dh37fgj492je"; - final byte[] key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes("UTF-8"); + final byte[] key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn".getBytes(StringUtils.UTF_8); final BaseResource resource = new BaseResource("http://localhost:8000/", false); // Basic GET. diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java index a5e71834f3f6..df7e7471447e 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/telemetry/TelemetryCollectorTest.java @@ -18,6 +18,7 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse; import org.mozilla.gecko.sync.repositories.FetchFailedException; import org.mozilla.gecko.sync.repositories.StoreFailedException; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; @@ -51,7 +52,7 @@ public class TelemetryCollectorTest { assertEquals(uid, bundle.get("uid")); // Expect device ID to be hashed with the UID. assertEquals( - Utils.byte2Hex(Utils.sha256(deviceID.concat(uid).getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256(deviceID.concat(uid).getBytes(StringUtils.UTF_8))), bundle.get("deviceID") ); } @@ -79,7 +80,7 @@ public class TelemetryCollectorTest { ArrayList devices = data.getParcelableArrayList("devices"); assertEquals(1, devices.size()); assertEquals( - Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(0).getString("id") ); assertEquals("iOS", devices.get(0).getString("os")); @@ -98,14 +99,14 @@ public class TelemetryCollectorTest { assertEquals("iOS", devices.get(0).getString("os")); assertEquals("1.33.7", devices.get(0).getString("version")); assertEquals( - Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client1-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(0).getString("id") ); assertEquals("Android", devices.get(1).getString("os")); assertEquals("55.0a1", devices.get(1).getString("version")); assertEquals( - Utils.byte2Hex(Utils.sha256("client2-guid".concat("hashed-uid").getBytes("UTF-8"))), + Utils.byte2Hex(Utils.sha256("client2-guid".concat("hashed-uid").getBytes(StringUtils.UTF_8))), devices.get(1).getString("id") ); } @@ -346,4 +347,4 @@ public class TelemetryCollectorTest { assertEquals("othererror", error.getString("name")); assertEquals("store:IllegalStateException", error.getString("error")); } -} \ No newline at end of file +} diff --git a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java index 55bed700f3bf..fa7216a884d5 100644 --- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java +++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/test/TestExtendedJSONObject.java @@ -11,6 +11,7 @@ import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonArrayJSONException; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.sync.UnexpectedJSONException.BadRequiredFieldJSONException; +import org.mozilla.gecko.util.StringUtils; import org.robolectric.RobolectricTestRunner; import java.io.IOException; @@ -102,7 +103,7 @@ public class TestExtendedJSONObject { public void testParseUTF8AsJSONObject() throws Exception { String TEST = "{\"key\":\"value\"}"; - ExtendedJSONObject o = ExtendedJSONObject.parseUTF8AsJSONObject(TEST.getBytes("UTF-8")); + ExtendedJSONObject o = ExtendedJSONObject.parseUTF8AsJSONObject(TEST.getBytes(StringUtils.UTF_8)); assertNotNull(o); assertEquals("value", o.getString("key")); } @@ -117,7 +118,7 @@ public class TestExtendedJSONObject { } try { - ExtendedJSONObject.parseUTF8AsJSONObject("{".getBytes("UTF-8")); + ExtendedJSONObject.parseUTF8AsJSONObject("{".getBytes(StringUtils.UTF_8)); fail(); } catch (NonObjectJSONException e) { // Do nothing. diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java index 993e80931b2c..d25204458d21 100644 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java +++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testBrowserProvider.java @@ -20,6 +20,7 @@ import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.URLMetadata; import org.mozilla.gecko.db.URLImageDataTable; import org.mozilla.gecko.sync.Utils; +import org.mozilla.gecko.util.StringUtils; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; @@ -195,7 +196,7 @@ public class testBrowserProvider extends ContentProviderTest { faviconEntry.put(BrowserContract.Favicons.PAGE_URL, pageUrl); faviconEntry.put(BrowserContract.Favicons.URL, pageUrl + "/favicon.ico"); - faviconEntry.put(BrowserContract.Favicons.DATA, data.getBytes("UTF8")); + faviconEntry.put(BrowserContract.Favicons.DATA, data.getBytes(StringUtils.UTF_8)); return faviconEntry; } @@ -204,7 +205,7 @@ public class testBrowserProvider extends ContentProviderTest { ContentValues thumbnailEntry = new ContentValues(); thumbnailEntry.put(BrowserContract.Thumbnails.URL, pageUrl); - thumbnailEntry.put(BrowserContract.Thumbnails.DATA, data.getBytes("UTF8")); + thumbnailEntry.put(BrowserContract.Thumbnails.DATA, data.getBytes(StringUtils.UTF_8)); return thumbnailEntry; } diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java index 2ae2bb532d08..eef8abcc3089 100644 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java +++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java @@ -19,6 +19,7 @@ import java.security.NoSuchAlgorithmException; import org.mozilla.gecko.background.nativecode.NativeCrypto; import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.tests.helpers.GeckoHelper; +import org.mozilla.gecko.util.StringUtils; import android.os.SystemClock; @@ -238,9 +239,9 @@ public class testNativeCrypto extends UITest { } } - private void _testSHA256WithMultipleUpdatesFromStream() throws UnsupportedEncodingException { + private void _testSHA256WithMultipleUpdatesFromStream() { final String input = "HelloWorldThisIsASuperLongStringThatIsReadAsAStreamOfBytes"; - final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes("UTF-8")); + final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StringUtils.UTF_8)); final String expected = "8b5cb76b80f7eb6fb83ee138bfd31e2922e71dd245daa21a8d9876e8dee9eef5"; byte[] buffer = new byte[10]; diff --git a/mozglue/misc/interceptor/VMSharingPolicies.h b/mozglue/misc/interceptor/VMSharingPolicies.h index 8e2dd27f72c4..05bd391c799b 100644 --- a/mozglue/misc/interceptor/VMSharingPolicies.h +++ b/mozglue/misc/interceptor/VMSharingPolicies.h @@ -9,7 +9,6 @@ #include "mozilla/Assertions.h" #include "mozilla/Types.h" -#include "mozilla/StaticPtr.h" namespace mozilla { namespace interceptor { @@ -165,7 +164,8 @@ public: return; } - MOZ_RELEASE_ASSERT(sPerProcVM->append(ProcMapEntry(aArgs...))); + bool appended = sPerProcVM->append(ProcMapEntry(aArgs...)); + MOZ_RELEASE_ASSERT(appended); } explicit operator bool() const @@ -173,7 +173,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); return !!entry->mVMPolicy; } @@ -183,7 +184,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); return entry->mVMPolicy; } @@ -241,7 +243,8 @@ public: AutoCriticalSection lock(&sCS); ProcMapEntry* entry; - MOZ_RELEASE_ASSERT(find(mPid, &entry)); + bool found = find(mPid, &entry); + MOZ_RELEASE_ASSERT(found); TrampolineCollection items(Move(entry->mVMPolicy.Items())); @@ -292,12 +295,12 @@ private: static DWORD GetPid(HANDLE aHandle) { return ::GetProcessId(aHandle); } DWORD mPid; - static StaticAutoPtr sPerProcVM; + static MapT* sPerProcVM; static CRITICAL_SECTION sCS; }; template -StaticAutoPtr::MapT> +typename VMSharingPolicyShared::MapT * VMSharingPolicyShared::sPerProcVM; template diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index 36f5dbb15913..bb2ddbce8b76 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -88,7 +88,7 @@ enum }; template > class WindowsDllInterceptor final { diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index 575c7a052724..114c06137d45 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -66,6 +66,7 @@ enum class SHA1ModeResult { enum class DistrustedCAPolicy : uint32_t { Permit = 0, DistrustSymantecRoots = 1, + DistrustSymantecRootsRegardlessOfDate = 2, }; enum class NetscapeStepUpPolicy : uint32_t; diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index c154709ad46e..f5f283147be1 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -891,7 +891,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // handshake. To determine this, we check mHostname: If it isn't set, this is // not TLS, so don't run the algorithm. if (mHostname && CertDNIsInList(root.get(), RootSymantecDNs) && - mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) { + mDistrustedCAPolicy != DistrustedCAPolicy::Permit) { rootCert = nullptr; // Clear the state for Segment... nsCOMPtr intCerts; @@ -907,8 +907,13 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // (new Date("2016-06-01T00:00:00Z")).getTime() * 1000 static const PRTime JUNE_1_2016 = 1464739200000000; + PRTime permitAfterDate = 0; // 0 indicates there is no permitAfterDate + if (mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) { + permitAfterDate = JUNE_1_2016; + } + bool isDistrusted = false; - nsrv = CheckForSymantecDistrust(intCerts, eeCert, JUNE_1_2016, + nsrv = CheckForSymantecDistrust(intCerts, eeCert, permitAfterDate, RootAppleAndGoogleSPKIs, isDistrusted); if (NS_FAILED(nsrv)) { return Result::FATAL_ERROR_LIBRARY_FAILURE; diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 5a1d27b7fb25..768d3e36946e 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -1694,6 +1694,7 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting) switch(distrustedCAPolicy) { case DistrustedCAPolicy::Permit: case DistrustedCAPolicy::DistrustSymantecRoots: + case DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate: break; default: distrustedCAPolicy = defaultCAPolicyMode; diff --git a/security/manager/ssl/tests/unit/test_symantec_apple_google.js b/security/manager/ssl/tests/unit/test_symantec_apple_google.js index 2ffdb5804b6a..2fe90553a826 100644 --- a/security/manager/ssl/tests/unit/test_symantec_apple_google.js +++ b/security/manager/ssl/tests/unit/test_symantec_apple_google.js @@ -39,6 +39,23 @@ add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, null, null); +// Enable the Firefox 63 total distrust; before or after cutoff should now all +// behave the same. +add_test(function() { + clearSessionCache(); + Services.prefs.setIntPref("security.pki.distrust_ca_policy", + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + run_next_test(); +}); + +add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", + MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + null, null); + +add_connection_test("symantec-not-whitelisted-after-cutoff.example.com", + MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + null, null); + // Disable the distrust, should be back to the console warning add_test(function() { clearSessionCache(); @@ -77,6 +94,7 @@ add_task(async function() { // (as an external fetch is bad in the tests), disable OCSP first. Services.prefs.setIntPref("security.OCSP.enabled", 0); + // Try with the policy for 60 Services.prefs.setIntPref("security.pki.distrust_ca_policy", /* DistrustedCAPolicy::DistrustSymantecRoots */ 1); @@ -85,4 +103,11 @@ add_task(async function() { await checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess, certificateUsageSSLServer, VALIDATION_TIME); + + // Try with the policy for 63 + Services.prefs.setIntPref("security.pki.distrust_ca_policy", + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + + await checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess, + certificateUsageSSLServer, VALIDATION_TIME); }); diff --git a/taskcluster/ci/upload-symbols/kind.yml b/taskcluster/ci/upload-symbols/kind.yml index e1a6e93dac30..fe2e02ba78d2 100644 --- a/taskcluster/ci/upload-symbols/kind.yml +++ b/taskcluster/ci/upload-symbols/kind.yml @@ -12,24 +12,6 @@ transforms: kind-dependencies: - build -only-for-build-platforms: - - linux64/opt - - linux64/debug - - linux64-nightly/opt - - linux-nightly/opt - - linux64-devedition-nightly/opt - - linux-devedition-nightly/opt - - android-aarch64-nightly/opt - - android-api-16/opt - - android-api-16-nightly/opt - - android-x86-nightly/opt - - macosx64-nightly/opt - - macosx64-devedition-nightly/opt - - win32-nightly/opt - - win64-nightly/opt - - win32-devedition-nightly/opt - - win64-devedition-nightly/opt - job-template: description: Upload Symbols worker-type: aws-provisioner-v1/gecko-{level}-b-linux @@ -53,4 +35,7 @@ job-template: run-on-projects: by-build-platform: .*devedition.*: ['mozilla-beta', 'maple'] - default: ['all'] + # Only upload symbols for nightlies on most branches. + .*(?("MOZ_USING_SERVICE=1")); - LOG(("Starting service with cmdline: %ls", cmdLine)); - processStarted = CreateProcessW(argv[0], cmdLine, + LOG(("Starting service with cmdline: %ls", cmdLine.get())); + processStarted = CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, FALSE, CREATE_DEFAULT_ERROR_MODE, nullptr, @@ -279,13 +279,12 @@ StartUpdateProcess(int argc, DWORD lastError = GetLastError(); LOG_WARN(("Could not create process as current user, " "updaterPath: %ls; cmdLine: %ls. (%d)", - argv[0], cmdLine, lastError)); + argv[0], cmdLine.get(), lastError)); } // Empty value on putenv is how you remove an env variable in Windows putenv(const_cast("MOZ_USING_SERVICE=")); - free(cmdLine); return updateWasSuccessful; } diff --git a/toolkit/components/telemetry/parse_histograms.py b/toolkit/components/telemetry/parse_histograms.py index 3efa8445e821..2f24a009f084 100755 --- a/toolkit/components/telemetry/parse_histograms.py +++ b/toolkit/components/telemetry/parse_histograms.py @@ -12,6 +12,7 @@ import sys import atexit import shared_telemetry_utils as utils +from ctypes import c_int from shared_telemetry_utils import ParserError from collections import OrderedDict atexit.register(ParserError.exit_func) @@ -517,6 +518,11 @@ associated with the histogram. Returns None if no guarding is necessary.""" ParserError('Value for key "{0}" in histogram "{1}" should be {2}.' .format(key, name, nice_type_name(key_type))).handle_later() + # Make sure the max range is lower than or equal to INT_MAX + if "high" in definition and not c_int(definition["high"]).value > 0: + ParserError('Value for high in histogram "{0}" should be lower or equal to INT_MAX.' + .format(nice_type_name(c_int))).handle_later() + for key, key_type in type_checked_list_fields.iteritems(): if key not in definition: continue diff --git a/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py b/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py index c0b99767892a..d9a3fe63b0c9 100644 --- a/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py +++ b/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py @@ -122,6 +122,29 @@ class TestParser(unittest.TestCase): parse_histograms.whitelists = None + def test_high_value(self): + SAMPLE_HISTOGRAM = { + "TEST_HISTOGRAM_WHITELIST_N_BUCKETS": { + "record_in_processes": ["main", "content"], + "alert_emails": ["team@mozilla.xyz"], + "bug_numbers": [1383793], + "expires_in_version": "never", + "kind": "exponential", + "low": 1024, + "high": 2 ** 64, + "n_buckets": 100, + "description": "Test histogram", + } + } + histograms = load_histogram(SAMPLE_HISTOGRAM) + parse_histograms.load_whitelist() + + parse_histograms.Histogram('TEST_HISTOGRAM_WHITELIST_N_BUCKETS', + histograms['TEST_HISTOGRAM_WHITELIST_N_BUCKETS'], + strict_type_checks=True) + + self.assertRaises(SystemExit, ParserError.exit_func) + def test_high_n_buckets(self): SAMPLE_HISTOGRAM = { "TEST_HISTOGRAM_WHITELIST_N_BUCKETS": { diff --git a/toolkit/crashreporter/tools/upload_symbols.py b/toolkit/crashreporter/tools/upload_symbols.py index 91ca0d05cd69..98e2e8f52ed5 100644 --- a/toolkit/crashreporter/tools/upload_symbols.py +++ b/toolkit/crashreporter/tools/upload_symbols.py @@ -92,10 +92,6 @@ def main(): # Allow overwriting of the upload url with an environmental variable if 'SOCORRO_SYMBOL_UPLOAD_URL' in os.environ: url = os.environ['SOCORRO_SYMBOL_UPLOAD_URL'] - elif os.environ.get('MOZ_SCM_LEVEL', '1') == '1': - # Use the Tecken staging server for try uploads for now. - # This will eventually be changed in bug 1138617. - url = 'https://symbols.stage.mozaws.net/upload/' else: url = DEFAULT_URL diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 6a95affb089b..cdb318704534 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -3092,7 +3092,7 @@ int NS_main(int argc, NS_tchar **argv) return 1; } - wchar_t *cmdLine = MakeCommandLine(argc - 1, argv + 1); + auto cmdLine = mozilla::MakeCommandLine(argc - 1, argv + 1); if (!cmdLine) { CloseHandle(elevatedFileHandle); return 1; @@ -3238,12 +3238,11 @@ int NS_main(int argc, NS_tchar **argv) SEE_MASK_NOCLOSEPROCESS; sinfo.hwnd = nullptr; sinfo.lpFile = argv[0]; - sinfo.lpParameters = cmdLine; + sinfo.lpParameters = cmdLine.get(); sinfo.lpVerb = L"runas"; sinfo.nShow = SW_SHOWNORMAL; bool result = ShellExecuteEx(&sinfo); - free(cmdLine); if (result) { WaitForSingleObject(sinfo.hProcess, INFINITE); diff --git a/toolkit/themes/linux/global/printPreview.css b/toolkit/themes/linux/global/printPreview.css index 5d20e35b97ed..6170c1aee79d 100644 --- a/toolkit/themes/linux/global/printPreview.css +++ b/toolkit/themes/linux/global/printPreview.css @@ -17,3 +17,8 @@ .toolbar-landscape-page { list-style-image: url("moz-icon://stock/gtk-orientation-landscape?size=button"); } + +#pageNumber { + /* 3 chars + 4px padding left + 2px padding right + 2*6px border */ + width: calc(18px + 3ch); +} diff --git a/toolkit/xre/CmdLineAndEnvUtils.h b/toolkit/xre/CmdLineAndEnvUtils.h new file mode 100644 index 000000000000..3222baeee10a --- /dev/null +++ b/toolkit/xre/CmdLineAndEnvUtils.h @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_CmdLineAndEnvUtils_h +#define mozilla_CmdLineAndEnvUtils_h + +// NB: This code may be used outside of xul and thus must not depend on XPCOM + +#if defined(MOZILLA_INTERNAL_API) +#include "prenv.h" +#include "prprf.h" +#include +#elif defined(XP_WIN) +#include +#endif + +#if defined(XP_WIN) +#include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include +#endif // defined(XP_WIN) + +#include "mozilla/TypedEnumBits.h" + +#include +#include + +// Undo X11/X.h's definition of None +#undef None + +namespace mozilla { + +enum ArgResult { + ARG_NONE = 0, + ARG_FOUND = 1, + ARG_BAD = 2 // you wanted a param, but there isn't one +}; + +template +inline void +RemoveArg(int& argc, CharT **argv) +{ + do { + *argv = *(argv + 1); + ++argv; + } while (*argv); + + --argc; +} + +namespace internal { + +template +inline bool +strimatch(FuncT aToLowerFn, const CharT* lowerstr, const CharT* mixedstr) +{ + while(*lowerstr) { + if (!*mixedstr) return false; // mixedstr is shorter + if (static_cast(aToLowerFn(*mixedstr)) != *lowerstr) return false; // no match + + ++lowerstr; + ++mixedstr; + } + + if (*mixedstr) return false; // lowerstr is shorter + + return true; +} + +} // namespace internal + +inline bool +strimatch(const char* lowerstr, const char* mixedstr) +{ + return internal::strimatch(&tolower, lowerstr, mixedstr); +} + +inline bool +strimatch(const wchar_t* lowerstr, const wchar_t* mixedstr) +{ + return internal::strimatch(&towlower, lowerstr, mixedstr); +} + +enum class FlagLiteral +{ + osint, + safemode +}; + +template +inline const CharT* GetLiteral(); + +#define DECLARE_FLAG_LITERAL(enum_name, literal) \ + template <> inline \ + const char* GetLiteral() \ + { \ + return literal; \ + } \ + \ + template <> inline \ + const wchar_t* GetLiteral() \ + { \ + return L##literal; \ + } + +DECLARE_FLAG_LITERAL(osint, "osint") +DECLARE_FLAG_LITERAL(safemode, "safe-mode") + +enum class CheckArgFlag : uint32_t +{ + None = 0, + CheckOSInt = (1 << 0), // Retrun ARG_BAD if osint arg is also present. + RemoveArg = (1 << 1) // Remove the argument from the argv array. +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CheckArgFlag) + +/** + * Check for a commandline flag. If the flag takes a parameter, the + * parameter is returned in aParam. Flags may be in the form -arg or + * --arg (or /arg on win32). + * + * @param aArgc The argc value. + * @param aArgv The original argv. + * @param aArg the parameter to check. Must be lowercase. + * @param aParam if non-null, the -arg will be stored in this pointer. + * This is *not* allocated, but rather a pointer to the argv data. + * @param aFlags Flags @see CheckArgFlag + */ +template +inline ArgResult +CheckArg(int& aArgc, CharT** aArgv, const CharT* aArg, const CharT **aParam, + CheckArgFlag aFlags) +{ + MOZ_ASSERT(aArgv && aArg); + + CharT **curarg = aArgv + 1; // skip argv[0] + ArgResult ar = ARG_NONE; + + while (*curarg) { + CharT *arg = curarg[0]; + + if (arg[0] == '-' +#if defined(XP_WIN) + || *arg == '/' +#endif + ) { + ++arg; + + if (*arg == '-') { + ++arg; + } + + if (strimatch(aArg, arg)) { + if (aFlags & CheckArgFlag::RemoveArg) { + RemoveArg(aArgc, curarg); + } else { + ++curarg; + } + + if (!aParam) { + ar = ARG_FOUND; + break; + } + + if (*curarg) { + if (**curarg == '-' +#if defined(XP_WIN) + || **curarg == '/' +#endif + ) { + return ARG_BAD; + } + + *aParam = *curarg; + + if (aFlags & CheckArgFlag::RemoveArg) { + RemoveArg(aArgc, curarg); + } + + ar = ARG_FOUND; + break; + } + + return ARG_BAD; + } + } + + ++curarg; + } + + if ((aFlags & CheckArgFlag::CheckOSInt) && ar == ARG_FOUND) { + ArgResult arOSInt = CheckArg(aArgc, aArgv, + GetLiteral(), + static_cast(nullptr), + CheckArgFlag::None); + if (arOSInt == ARG_FOUND) { + ar = ARG_BAD; +#if defined(MOZILLA_INTERNAL_API) + PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n"); +#endif // defined(MOZILLA_INTERNAL_API) + } + } + + return ar; +} + +#if defined(XP_WIN) + +namespace internal { + +/** + * Get the length that the string will take and takes into account the + * additional length if the string needs to be quoted and if characters need to + * be escaped. + */ +inline int +ArgStrLen(const wchar_t *s) +{ + int backslashes = 0; + int i = wcslen(s); + bool hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + i += 2; // initial and final duoblequote + } + + if (hasDoubleQuote) { + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + i += backslashes + 1; + } + + backslashes = 0; + } + + ++s; + } + } + + return i; +} + +/** + * Copy string "s" to string "d", quoting the argument as appropriate and + * escaping doublequotes along with any backslashes that immediately precede + * doublequotes. + * The CRT parses this to retrieve the original argc/argv that we meant, + * see STDARGV.C in the MSVC CRT sources. + * + * @return the end of the string + */ +inline wchar_t* +ArgToString(wchar_t *d, const wchar_t *s) +{ + int backslashes = 0; + bool hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + *d = '"'; // initial doublequote + ++d; + } + + if (hasDoubleQuote) { + int i; + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + for (i = 0; i <= backslashes; ++i) { + *d = '\\'; + ++d; + } + } + + backslashes = 0; + } + + *d = *s; + ++d; ++s; + } + } else { + wcscpy(d, s); + d += wcslen(s); + } + + if (addDoubleQuotes) { + *d = '"'; // final doublequote + ++d; + } + + return d; +} + +} // namespace internal + +/** + * Creates a command line from a list of arguments. + */ +inline UniquePtr +MakeCommandLine(int argc, wchar_t **argv) +{ + int i; + int len = 0; + + // The + 1 of the last argument handles the allocation for null termination + for (i = 0; i < argc; ++i) { + len += internal::ArgStrLen(argv[i]) + 1; + } + + // Protect against callers that pass 0 arguments + if (len == 0) { + len = 1; + } + + auto s = MakeUnique(len); + if (!s) { + return nullptr; + } + + wchar_t *c = s.get(); + for (i = 0; i < argc; ++i) { + c = internal::ArgToString(c, argv[i]); + if (i + 1 != argc) { + *c = ' '; + ++c; + } + } + + *c = '\0'; + + return Move(s); +} + +#endif // defined(XP_WIN) + +// Save literal putenv string to environment variable. +inline void +SaveToEnv(const char *aEnvString) +{ +#if defined(MOZILLA_INTERNAL_API) + char *expr = strdup(aEnvString); + if (expr) { + PR_SetEnv(expr); + } + + // We intentionally leak |expr| here since it is required by PR_SetEnv. + MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr); +#elif defined(XP_WIN) + // This is the same as the NSPR implementation + // (Note that we don't need to do a strdup for this case; the CRT makes a copy) + _putenv(aEnvString); +#else +#error "Not implemented for this configuration" +#endif +} + +inline bool +EnvHasValue(const char* aVarName) +{ +#if defined(MOZILLA_INTERNAL_API) + const char* val = PR_GetEnv(aVarName); + return val && *val; +#elif defined(XP_WIN) + // This is the same as the NSPR implementation + const char* val = getenv(aVarName); + return val && *val; +#else +#error "Not implemented for this configuration" +#endif +} + +} // namespace mozilla + +#endif // mozilla_CmdLineAndEnvUtils_h diff --git a/toolkit/xre/PolicyChecks.h b/toolkit/xre/PolicyChecks.h new file mode 100644 index 000000000000..5a93153c1ea6 --- /dev/null +++ b/toolkit/xre/PolicyChecks.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_PolicyChecks_h +#define mozilla_PolicyChecks_h + +#if defined(XP_WIN) + +#include + +// NB: This code must be able to run apart from XPCOM + +namespace mozilla { + +inline bool +PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue) +{ + DWORD len = sizeof(DWORD); + LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName, + RRF_RT_DWORD, nullptr, aValue, &len); + return ret == ERROR_SUCCESS; +} + +inline bool +PolicyCheckBoolean(LPCWSTR aPolicyName) +{ + DWORD value; + if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, aPolicyName, &value)) { + return value == 1; + } + + if (PolicyHasRegValue(HKEY_CURRENT_USER, aPolicyName, &value)) { + return value == 1; + } + + return false; +} + +} // namespace mozilla + +#endif // defined(XP_WIN) + +#endif // mozilla_PolicyChecks_h diff --git a/toolkit/xre/SafeMode.h b/toolkit/xre/SafeMode.h new file mode 100644 index 000000000000..2c4aa978473b --- /dev/null +++ b/toolkit/xre/SafeMode.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_SafeMode_h +#define mozilla_SafeMode_h + +// NB: This code must be able to run apart from XPCOM + +#include "mozilla/CmdLineAndEnvUtils.h" +#include "mozilla/Maybe.h" + +#if defined(XP_WIN) +#include "mozilla/PolicyChecks.h" +#include +#endif // defined(XP_WIN) + +// Undo X11/X.h's definition of None +#undef None + +namespace mozilla { + +enum class SafeModeFlag : uint32_t +{ + None = 0, + Unset = (1 << 0) +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SafeModeFlag) + +template +inline Maybe +IsSafeModeRequested(int& aArgc, CharT* aArgv[], + const SafeModeFlag aFlags = SafeModeFlag::Unset) +{ + CheckArgFlag checkArgFlags = CheckArgFlag::CheckOSInt; + if (aFlags & SafeModeFlag::Unset) { + checkArgFlags |= CheckArgFlag::RemoveArg; + } + + ArgResult ar = CheckArg(aArgc, aArgv, + GetLiteral(), + static_cast(nullptr), + checkArgFlags); + if (ar == ARG_BAD) { + return Nothing(); + } + + bool result = ar == ARG_FOUND; + +#if defined(XP_WIN) + // If the shift key is pressed and the ctrl and / or alt keys are not pressed + // during startup, start in safe mode. GetKeyState returns a short and the high + // order bit will be 1 if the key is pressed. By masking the returned short + // with 0x8000 the result will be 0 if the key is not pressed and non-zero + // otherwise. + if ((GetKeyState(VK_SHIFT) & 0x8000) && + !(GetKeyState(VK_CONTROL) & 0x8000) && + !(GetKeyState(VK_MENU) & 0x8000) && + !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { + result = true; + } + + if (result && PolicyCheckBoolean(L"DisableSafeMode")) { + result = false; + } +#endif // defined(XP_WIN) + +#if defined(XP_MACOSX) + if ((GetCurrentEventKeyModifiers() & optionKey) && + !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { + result = true; + } +#endif // defined(XP_MACOSX) + + // The Safe Mode Policy should not be enforced for the env var case + // (used by updater and crash-recovery). + if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) { + result = true; + if (aFlags & SafeModeFlag::Unset) { + // unset the env variable + SaveToEnv("MOZ_SAFE_MODE_RESTART="); + } + } + + return Some(result); +} + +} // namespace mozilla + +#endif // mozilla_SafeMode_h diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index b7bf67ac25e0..431b98917e62 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -30,13 +30,19 @@ EXPORTS += [ 'nsIAppStartupNotifier.h', ] -EXPORTS.mozilla += ['AutoSQLiteLifetime.h', 'Bootstrap.h'] +EXPORTS.mozilla += [ + 'AutoSQLiteLifetime.h', + 'Bootstrap.h', + 'CmdLineAndEnvUtils.h', + 'SafeMode.h', +] if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']: EXPORTS += ['EventTracer.h'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXPORTS.mozilla += [ + 'PolicyChecks.h', 'WinDllServices.h', ] SOURCES += [ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 9b33cc51fb46..c6f2ba2986ed 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -10,6 +10,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/ChaosMode.h" +#include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/IOInterposer.h" #include "mozilla/Likely.h" #include "mozilla/MemoryChecking.h" @@ -232,6 +233,7 @@ #endif #include "mozilla/mozalloc_oom.h" +#include "SafeMode.h" extern uint32_t gRestartMode; extern void InstallSignalHandlers(const char *ProgramName); @@ -306,25 +308,6 @@ using mozilla::dom::ContentParent; using mozilla::dom::ContentChild; using mozilla::intl::LocaleService; -// Save literal putenv string to environment variable. -static void -SaveToEnv(const char *putenv) -{ - char *expr = strdup(putenv); - if (expr) - PR_SetEnv(expr); - // We intentionally leak |expr| here since it is required by PR_SetEnv. - MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr); -} - -// Tests that an environment variable exists and has a value -static bool -EnvHasValue(const char *name) -{ - const char *val = PR_GetEnv(name); - return (val && *val); -} - // Save the given word to the specified environment variable. static void SaveWordToEnv(const char *name, const nsACString & word) @@ -400,22 +383,6 @@ SaveFileToEnvIfUnset(const char *name, nsIFile *file) SaveFileToEnv(name, file); } -static bool -strimatch(const char* lowerstr, const char* mixedstr) -{ - while(*lowerstr) { - if (!*mixedstr) return false; // mixedstr is shorter - if (tolower(*mixedstr) != *lowerstr) return false; // no match - - ++lowerstr; - ++mixedstr; - } - - if (*mixedstr) return false; // lowerstr is shorter - - return true; -} - static bool gIsExpectedExit = false; void MozExpectedExit() { @@ -482,94 +449,22 @@ enum RemoteResult { REMOTE_ARG_BAD = 2 }; -enum ArgResult { - ARG_NONE = 0, - ARG_FOUND = 1, - ARG_BAD = 2 // you wanted a param, but there isn't one -}; - -static void RemoveArg(char **argv) -{ - do { - *argv = *(argv + 1); - ++argv; - } while (*argv); - - --gArgc; -} - /** * Check for a commandline flag. If the flag takes a parameter, the * parameter is returned in aParam. Flags may be in the form -arg or * --arg (or /arg on win32). * * @param aArg the parameter to check. Must be lowercase. - * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present - * when aArg is also present. * @param aParam if non-null, the -arg will be stored in this pointer. * This is *not* allocated, but rather a pointer to the argv data. - * @param aRemArg if true, the argument is removed from the gArgv array. + * @param aFlags flags @see CheckArgFlag */ static ArgResult -CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true) +CheckArg(const char* aArg, const char** aParam = nullptr, + CheckArgFlag aFlags = CheckArgFlag::RemoveArg) { MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()"); - - char **curarg = gArgv + 1; // skip argv[0] - ArgResult ar = ARG_NONE; - - while (*curarg) { - char *arg = curarg[0]; - - if (arg[0] == '-' -#if defined(XP_WIN) - || *arg == '/' -#endif - ) { - ++arg; - if (*arg == '-') - ++arg; - - if (strimatch(aArg, arg)) { - if (aRemArg) - RemoveArg(curarg); - else - ++curarg; - if (!aParam) { - ar = ARG_FOUND; - break; - } - - if (*curarg) { - if (**curarg == '-' -#if defined(XP_WIN) - || **curarg == '/' -#endif - ) - return ARG_BAD; - - *aParam = *curarg; - if (aRemArg) - RemoveArg(curarg); - ar = ARG_FOUND; - break; - } - return ARG_BAD; - } - } - - ++curarg; - } - - if (aCheckOSInt && ar == ARG_FOUND) { - ArgResult arOSInt = CheckArg("osint"); - if (arOSInt == ARG_FOUND) { - ar = ARG_BAD; - PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n"); - } - } - - return ar; + return CheckArg(gArgc, gArgv, aArg, aParam, aFlags); } /** @@ -582,38 +477,7 @@ CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullp static ArgResult CheckArgExists(const char* aArg) { - char **curarg = gArgv + 1; // skip argv[0] - while (*curarg) { - char *arg = curarg[0]; - - if (arg[0] == '-' -#if defined(XP_WIN) - || *arg == '/' -#endif - ) { - ++arg; - if (*arg == '-') - ++arg; - - char delimiter = '='; -#if defined(XP_WIN) - delimiter = ':'; -#endif - int i; - for (i = 0; arg[i] && arg[i] != delimiter; i++) {} - char tmp = arg[i]; - arg[i] = '\0'; - bool found = strimatch(aArg, arg); - arg[i] = tmp; - if (found) { - return ARG_FOUND; - } - } - - ++curarg; - } - - return ARG_NONE; + return CheckArg(aArg, nullptr, CheckArgFlag::None); } #if defined(XP_WIN) @@ -1799,14 +1663,14 @@ ParseRemoteCommandLine(nsCString& program, { ArgResult ar; - ar = CheckArg("p", false, profile, false); + ar = CheckArg("p", profile, CheckArgFlag::None); if (ar == ARG_BAD) { // Leave it to the normal command line handling to handle this situation. return REMOTE_NOT_FOUND; } const char *temp = nullptr; - ar = CheckArg("a", true, &temp); + ar = CheckArg("a", &temp, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n"); return REMOTE_ARG_BAD; @@ -1815,7 +1679,7 @@ ParseRemoteCommandLine(nsCString& program, program.Assign(temp); } - ar = CheckArg("u", true, username); + ar = CheckArg("u", username, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n"); return REMOTE_ARG_BAD; @@ -2322,7 +2186,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n *aResult = nullptr; *aStartOffline = false; - ar = CheckArg("offline", true); + ar = CheckArg("offline", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --offline is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2344,7 +2208,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n } // reset-profile and migration args need to be checked before any profiles are chosen below. - ar = CheckArg("reset-profile", true); + ar = CheckArg("reset-profile", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --reset-profile is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2353,7 +2217,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n gDoProfileReset = true; } - ar = CheckArg("migration", true); + ar = CheckArg("migration", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --migration is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -2380,8 +2244,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n // Clear out flags that we handled (or should have handled!) last startup. const char *dummy; - CheckArg("p", false, &dummy); - CheckArg("profile", false, &dummy); + CheckArg("p", &dummy); + CheckArg("profile", &dummy); CheckArg("profilemanager"); if (gDoProfileReset) { @@ -2410,7 +2274,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return NS_LockProfilePath(lf, localDir, nullptr, aResult); } - ar = CheckArg("profile", true, &arg); + ar = CheckArg("profile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --profile requires a path\n"); return NS_ERROR_FAILURE; @@ -2444,7 +2308,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult); } - ar = CheckArg("createprofile", true, &arg); + ar = CheckArg("createprofile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --createprofile requires a profile name\n"); return NS_ERROR_FAILURE; @@ -2500,7 +2364,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n rv = aProfileSvc->GetProfileCount(&count); NS_ENSURE_SUCCESS(rv, rv); - ar = CheckArg("p", false, &arg); + ar = CheckArg("p", &arg); if (ar == ARG_BAD) { ar = CheckArg("osint"); if (ar == ARG_FOUND) { @@ -2565,7 +2429,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n } } - ar = CheckArg("profilemanager", true); + ar = CheckArg("profilemanager", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n"); return NS_ERROR_FAILURE; @@ -3161,33 +3025,6 @@ public: #endif }; -#ifdef XP_WIN -namespace { - -bool PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue) -{ - DWORD len = sizeof(DWORD); - LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName, - RRF_RT_DWORD, nullptr, aValue, &len); - return ret == ERROR_SUCCESS; -} - -bool SafeModeBlockedByPolicy() -{ - LPCTSTR policyName = L"DisableSafeMode"; - DWORD value; - if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, policyName, &value)) { - return value == 1; - } - if (PolicyHasRegValue(HKEY_CURRENT_USER, policyName, &value)) { - return value == 1; - } - return false; -} - -} // anonymous namespace -#endif // XP_WIN - #if defined(XP_UNIX) && !defined(ANDROID) static SmprintfPointer FormatUid(uid_t aId) @@ -3366,7 +3203,7 @@ XREMain::XRE_mainInit(bool* aExitFlag) // Check for application.ini overrides const char* override = nullptr; - ar = CheckArg("override", true, &override); + ar = CheckArg("override", &override, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { Output(true, "Incorrect number of arguments passed to --override"); return 1; @@ -3586,49 +3423,12 @@ XREMain::XRE_mainInit(bool* aExitFlag) gRestartArgv[gRestartArgc] = nullptr; - - ar = CheckArg("safe-mode", true); - if (ar == ARG_BAD) { - PR_fprintf(PR_STDERR, "Error: argument --safe-mode is invalid when argument --osint is specified\n"); + Maybe safeModeRequested = IsSafeModeRequested(gArgc, gArgv); + if (!safeModeRequested) { return 1; } - if (ar == ARG_FOUND) { - gSafeMode = true; - } -#ifdef XP_WIN - // If the shift key is pressed and the ctrl and / or alt keys are not pressed - // during startup start in safe mode. GetKeyState returns a short and the high - // order bit will be 1 if the key is pressed. By masking the returned short - // with 0x8000 the result will be 0 if the key is not pressed and non-zero - // otherwise. - if ((GetKeyState(VK_SHIFT) & 0x8000) && - !(GetKeyState(VK_CONTROL) & 0x8000) && - !(GetKeyState(VK_MENU) & 0x8000) && - !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) { - gSafeMode = true; - } -#endif - -#ifdef XP_MACOSX - if ((GetCurrentEventKeyModifiers() & optionKey) && - !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) - gSafeMode = true; -#endif - -#ifdef XP_WIN -if (gSafeMode && SafeModeBlockedByPolicy()) { - gSafeMode = false; - } -#endif - - // The Safe Mode Policy should not be enforced for the env var case - // (used by updater and crash-recovery). - if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) { - gSafeMode = true; - // unset the env variable - SaveToEnv("MOZ_SAFE_MODE_RESTART="); - } + gSafeMode = safeModeRequested.value(); #ifdef XP_WIN { @@ -3681,7 +3481,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { // Handle --no-remote and --new-instance command line arguments. Setup // the environment to better accommodate other components and various // restart scenarios. - ar = CheckArg("no-remote", true); + ar = CheckArg("no-remote", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n"); return 1; @@ -3690,7 +3490,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { SaveToEnv("MOZ_NO_REMOTE=1"); } - ar = CheckArg("new-instance", true); + ar = CheckArg("new-instance", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --new-instance is invalid when argument --osint is specified\n"); return 1; @@ -3717,7 +3517,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) { NS_ENSURE_SUCCESS(rv, 1); // Check for --register, which registers chrome and then exits immediately. - ar = CheckArg("register", true); + ar = CheckArg("register", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --register is invalid when argument --osint is specified\n"); return 1; @@ -4253,7 +4053,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag) // to make sure that the maintenance service successfully launches the // callback application. const char *logFile = nullptr; - if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) { + if (ARG_FOUND == CheckArg("dump-args", &logFile)) { FILE* logFP = fopen(logFile, "wb"); if (logFP) { for (int i = 1; i < gRestartArgc; ++i) { @@ -5108,7 +4908,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[]) #endif const char *path = nullptr; - ArgResult ar = CheckArg("greomni", false, &path); + ArgResult ar = CheckArg("greomni", &path); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n"); return NS_ERROR_FAILURE; @@ -5124,7 +4924,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[]) return rv; } - ar = CheckArg("appomni", false, &path); + ar = CheckArg("appomni", &path); if (ar == ARG_BAD) { PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n"); return NS_ERROR_FAILURE; diff --git a/toolkit/xre/nsWindowsRestart.cpp b/toolkit/xre/nsWindowsRestart.cpp index 11a654f34c92..7fa3b0de7e66 100644 --- a/toolkit/xre/nsWindowsRestart.cpp +++ b/toolkit/xre/nsWindowsRestart.cpp @@ -11,6 +11,7 @@ #define nsWindowsRestart_cpp #endif +#include "mozilla/CmdLineAndEnvUtils.h" #include "nsUTF8Utils.h" #include @@ -19,135 +20,6 @@ #include #pragma comment(lib, "userenv.lib") -/** - * Get the length that the string will take and takes into account the - * additional length if the string needs to be quoted and if characters need to - * be escaped. - */ -static int ArgStrLen(const wchar_t *s) -{ - int backslashes = 0; - int i = wcslen(s); - BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; - // Only add doublequotes if the string contains a space or a tab - BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; - - if (addDoubleQuotes) { - i += 2; // initial and final duoblequote - } - - if (hasDoubleQuote) { - while (*s) { - if (*s == '\\') { - ++backslashes; - } else { - if (*s == '"') { - // Escape the doublequote and all backslashes preceding the doublequote - i += backslashes + 1; - } - - backslashes = 0; - } - - ++s; - } - } - - return i; -} - -/** - * Copy string "s" to string "d", quoting the argument as appropriate and - * escaping doublequotes along with any backslashes that immediately precede - * doublequotes. - * The CRT parses this to retrieve the original argc/argv that we meant, - * see STDARGV.C in the MSVC CRT sources. - * - * @return the end of the string - */ -static wchar_t* ArgToString(wchar_t *d, const wchar_t *s) -{ - int backslashes = 0; - BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; - // Only add doublequotes if the string contains a space or a tab - BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; - - if (addDoubleQuotes) { - *d = '"'; // initial doublequote - ++d; - } - - if (hasDoubleQuote) { - int i; - while (*s) { - if (*s == '\\') { - ++backslashes; - } else { - if (*s == '"') { - // Escape the doublequote and all backslashes preceding the doublequote - for (i = 0; i <= backslashes; ++i) { - *d = '\\'; - ++d; - } - } - - backslashes = 0; - } - - *d = *s; - ++d; ++s; - } - } else { - wcscpy(d, s); - d += wcslen(s); - } - - if (addDoubleQuotes) { - *d = '"'; // final doublequote - ++d; - } - - return d; -} - -/** - * Creates a command line from a list of arguments. The returned - * string is allocated with "malloc" and should be "free"d. - * - * argv is UTF8 - */ -wchar_t* -MakeCommandLine(int argc, wchar_t **argv) -{ - int i; - int len = 0; - - // The + 1 of the last argument handles the allocation for null termination - for (i = 0; i < argc; ++i) - len += ArgStrLen(argv[i]) + 1; - - // Protect against callers that pass 0 arguments - if (len == 0) - len = 1; - - wchar_t *s = (wchar_t*) malloc(len * sizeof(wchar_t)); - if (!s) - return nullptr; - - wchar_t *c = s; - for (i = 0; i < argc; ++i) { - c = ArgToString(c, argv[i]); - if (i + 1 != argc) { - *c = ' '; - ++c; - } - } - - *c = '\0'; - - return s; -} - /** * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we * can't link to updater.exe. @@ -222,10 +94,9 @@ WinLaunchChild(const wchar_t *exePath, HANDLE userToken, HANDLE *hProcess) { - wchar_t *cl; BOOL ok; - cl = MakeCommandLine(argc, argv); + mozilla::UniquePtr cl(mozilla::MakeCommandLine(argc, argv)); if (!cl) { return FALSE; } @@ -237,7 +108,7 @@ WinLaunchChild(const wchar_t *exePath, if (userToken == nullptr) { ok = CreateProcessW(exePath, - cl, + cl.get(), nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles @@ -256,7 +127,7 @@ WinLaunchChild(const wchar_t *exePath, ok = CreateProcessAsUserW(userToken, exePath, - cl, + cl.get(), nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles @@ -294,7 +165,5 @@ WinLaunchChild(const wchar_t *exePath, LocalFree(lpMsgBuf); } - free(cl); - return ok; } diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index 7e1ff121278c..fce792afc9c8 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -2,6 +2,9 @@ * 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/. */ +#ifndef nsWindowsWMain_cpp +#define nsWindowsWMain_cpp + // This file is a .cpp file meant to be included in nsBrowserApp.cpp and other // similar bootstrap code. It converts wide-character windows wmain into UTF-8 // narrow-character strings. @@ -101,6 +104,14 @@ int wmain(int argc, WCHAR **argv) SanitizeEnvironmentVariables(); SetDllDirectoryW(L""); + // Only run this code if LauncherProcessWin.h was included beforehand, thus + // signalling that the hosting process should support launcher mode. +#if defined(mozilla_LauncherProcessWin_h) + if (mozilla::RunAsLauncherProcess(argc, argv)) { + return mozilla::LauncherMain(argc, argv); + } +#endif // defined(mozilla_LauncherProcessWin_h) + char **argvConverted = new char*[argc + 1]; if (!argvConverted) return 127; @@ -134,3 +145,5 @@ int wmain(int argc, WCHAR **argv) return result; } + +#endif // nsWindowsWMain_cpp diff --git a/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp index 00d786aa2bfc..d0c13335a2e8 100644 --- a/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp +++ b/toolkit/xre/test/win/TestXREMakeCommandLineWin.cpp @@ -69,10 +69,10 @@ verifyCmdLineCreation(wchar_t *inCmdLine, wcscat(inCmdLineNew, inCmdLine); LPWSTR *inArgv = CommandLineToArgvW(inCmdLineNew, &inArgc); - wchar_t *outCmdLine = MakeCommandLine(inArgc - 1, inArgv + 1); - wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine) + 1) * sizeof(wchar_t)); + auto outCmdLine = mozilla::MakeCommandLine(inArgc - 1, inArgv + 1); + wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine.get()) + 1) * sizeof(wchar_t)); wcscpy(outCmdLineNew, DUMMY_ARG1); - wcscat(outCmdLineNew, outCmdLine); + wcscat(outCmdLineNew, outCmdLine.get()); LPWSTR *outArgv = CommandLineToArgvW(outCmdLineNew, &outArgc); if (VERBOSE) { @@ -80,7 +80,7 @@ verifyCmdLineCreation(wchar_t *inCmdLine, wprintf(L"Verbose Output\n"); wprintf(L"--------------\n"); wprintf(L"Input command line : >%s<\n", inCmdLine); - wprintf(L"MakeComandLine output: >%s<\n", outCmdLine); + wprintf(L"MakeComandLine output: >%s<\n", outCmdLine.get()); wprintf(L"Expected command line: >%s<\n", compareCmdLine); wprintf(L"input argc : %d\n", inArgc - 1); @@ -107,7 +107,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } @@ -123,12 +122,11 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } } - isEqual = (wcscmp(outCmdLine, compareCmdLine) == 0); + isEqual = (wcscmp(outCmdLine.get(), compareCmdLine) == 0); if (!isEqual) { wprintf(L"TEST-%s-FAIL | %s | Command Line Comparison (check %2d)\n", passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); @@ -139,7 +137,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; } @@ -156,7 +153,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine, LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); - free(outCmdLine); return rv; }