diff --git a/manifest.json b/manifest.json index 89a62be7..3d4d3f08 100644 --- a/manifest.json +++ b/manifest.json @@ -38,6 +38,7 @@ "vendor/semver-bundle/semver.js", "vendor/db-to-cloud/db-to-cloud.min.js", "vendor/uuid/uuid.min.js", + "vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js", "background/token-manager.js", "background/sync.js", "background/content-scripts.js", diff --git a/tools/build-vendor.js b/tools/build-vendor.js index 1e3d5c24..73197098 100644 --- a/tools/build-vendor.js +++ b/tools/build-vendor.js @@ -62,6 +62,9 @@ const files = { ], 'uuid': [ 'dist/umd/uuidv4.min.js → uuid.min.js' + ], + 'webext-launch-web-auth-flow': [ + 'dist/webext-launch-web-auth-flow.js → webext-launch-web-auth-flow.js' ] }; diff --git a/vendor/webext-launch-web-auth-flow/LICENSE b/vendor/webext-launch-web-auth-flow/LICENSE new file mode 100644 index 00000000..792e1731 --- /dev/null +++ b/vendor/webext-launch-web-auth-flow/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2020 eight + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/webext-launch-web-auth-flow/README.md b/vendor/webext-launch-web-auth-flow/README.md new file mode 100644 index 00000000..e399613d --- /dev/null +++ b/vendor/webext-launch-web-auth-flow/README.md @@ -0,0 +1,5 @@ +## webext-launch-web-auth-flow v0.0.0 + +Following files are copied from npm (node_modules): + +* webext-launch-web-auth-flow.js: dist\webext-launch-web-auth-flow.js diff --git a/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js b/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js new file mode 100644 index 00000000..243bb83d --- /dev/null +++ b/vendor/webext-launch-web-auth-flow/webext-launch-web-auth-flow.js @@ -0,0 +1,185 @@ +var webextLaunchWebAuthFlow = (function () { + 'use strict'; + + function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + + function _asyncToGenerator(fn) { + return function () { + var self = this, + args = arguments; + return new Promise(function (resolve, reject) { + var gen = fn.apply(self, args); + + function _next(value) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); + } + + function _throw(err) { + asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); + } + + _next(undefined); + }); + }; + } + + /* eslint-env webextensions */ + function createWindow(_x) { + return _createWindow.apply(this, arguments); + } + + function _createWindow() { + _createWindow = _asyncToGenerator(function* (options) { + if (browser.windows) { + return yield browser.windows.create(options); + } + + const tabOptions = { + active: options.focused, + url: options.url + }; + const tab = yield browser.tabs.create(tabOptions); + return { + tabs: [tab] + }; + }); + return _createWindow.apply(this, arguments); + } + + function updateWindow(_x2, _x3, _x4) { + return _updateWindow.apply(this, arguments); + } + + function _updateWindow() { + _updateWindow = _asyncToGenerator(function* (windowId, tabId, options) { + if (windowId) { + return yield browser.windows.update(windowId, options); + } + + return yield browser.tabs.update(tabId, { + active: options.focused + }); + }); + return _updateWindow.apply(this, arguments); + } + + function closeWindow(_x5, _x6) { + return _closeWindow.apply(this, arguments); + } + + function _closeWindow() { + _closeWindow = _asyncToGenerator(function* (windowId, tabId) { + if (windowId) { + return yield browser.windows.remove(windowId); + } + + return yield browser.tabs.remove(tabId); + }); + return _closeWindow.apply(this, arguments); + } + + function defer() { + const o = {}; + o.promise = new Promise((resolve, reject) => { + o.resolve = resolve; + o.reject = reject; + }); + return o; + } + + function launchWebAuthFlow(_x7) { + return _launchWebAuthFlow.apply(this, arguments); + } + + function _launchWebAuthFlow() { + _launchWebAuthFlow = _asyncToGenerator(function* ({ + url, + redirect_uri, + interactive = false + }) { + const wInfo = yield createWindow({ + // Firefox doesn't support focused + type: "popup", + url, + state: "minimized" + }); + const windowId = wInfo.id; + const tabId = wInfo.tabs[0].id; + + const _defer = defer(), + promise = _defer.promise, + resolve = _defer.resolve, + reject = _defer.reject; + + browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, { + urls: ["*://*/*"], + tabId, + types: ["main_frame"] + }, ["blocking"]); + browser.webNavigation.onDOMContentLoaded.addListener(onDOMContentLoaded); + browser.tabs.onRemoved.addListener(onTabRemoved); + + try { + return yield promise; + } finally { + cleanup(); + } + + function onBeforeRequest(details) { + if (details.frameId || details.tabId !== tabId) return; + if (!details.url.startsWith(redirect_uri)) return; + resolve(details.url); + return { + cancel: true + }; + } + + function onDOMContentLoaded(details) { + if (details.frameId || details.tabId !== tabId) return; + + if (interactive) { + updateWindow(windowId, tabId, { + focused: true, + state: "normal" + }).catch(err => console.error(err)); + } else { + reject(new Error("User interaction required")); + } + + browser.webNavigation.onDOMContentLoaded.removeListener(onDOMContentLoaded); + } + + function onTabRemoved(removedTabId) { + if (removedTabId === tabId) { + reject(new Error("Canceled by user")); + } + } + + function cleanup() { + browser.webRequest.onBeforeRequest.removeListener(onBeforeRequest); + browser.webNavigation.onDOMContentLoaded.removeListener(onDOMContentLoaded); + browser.tabs.onRemoved.removeListener(onTabRemoved); + closeWindow(windowId, tabId).catch(err => console.error(err)); + } + }); + return _launchWebAuthFlow.apply(this, arguments); + } + + return launchWebAuthFlow; + +}()); +//# sourceMappingURL=webext-launch-web-auth-flow.js.map