diff --git a/.gitignore b/.gitignore
index 3475a11bb..1f23b2ba2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ crowdin.yml
add-on/dist
coverage
.nyc_output
+add-on/ui-kit/**/*
diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json
index 8bd0d46bc..c3a696c24 100644
--- a/add-on/_locales/en/messages.json
+++ b/add-on/_locales/en/messages.json
@@ -400,8 +400,37 @@
}
}
},
+ "page_proxyAccessDialog_title": {
+ "message": "Allow $ORIGIN$ to access ipfs.$PERMISSION$?",
+ "description": "Main title of the access permission dialog (page_proxyAccessDialog_title)",
+ "placeholders": {
+ "origin": {
+ "content": "$1"
+ },
+ "permission": {
+ "content": "$2"
+ }
+ }
+ },
+ "page_proxyAccessDialog_wildcardCheckbox_label": {
+ "message": "Apply to all permissions for $ORIGIN$",
+ "description": "Label for the apply permissions to all checkbox (page_proxyAccessDialog_wildcardCheckbox_label)",
+ "placeholders": {
+ "origin": {
+ "content": "$1"
+ }
+ }
+ },
"page_proxyAcl_revoke_all_button_title": {
"message": "Revoke all permissions",
"description": "Button title for revoking all permissions (page_proxyAcl_revoke_all_button_title)"
+ },
+ "page_proxyAccessDialog_allowButton_text": {
+ "message": "Allow",
+ "description": "Button text for allowing a permission (page_proxyAccessDialog_allowButton_text)"
+ },
+ "page_proxyAccessDialog_denyButton_text": {
+ "message": "Deny",
+ "description": "Button text for denying a permission (page_proxyAccessDialog_allowButton_text)"
}
}
diff --git a/add-on/manifest.json b/add-on/manifest.json
index e975253da..84819e3a4 100644
--- a/add-on/manifest.json
+++ b/add-on/manifest.json
@@ -90,7 +90,7 @@
}
],
- "content_security_policy": "script-src 'self'; object-src 'self'; child-src 'self';",
+ "content_security_policy": "script-src 'self'; object-src 'self'; frame-src 'self';",
"default_locale": "en"
}
diff --git a/add-on/src/lib/ipfs-proxy/access-control.js b/add-on/src/lib/ipfs-proxy/access-control.js
index d6fc06510..08a4959e0 100644
--- a/add-on/src/lib/ipfs-proxy/access-control.js
+++ b/add-on/src/lib/ipfs-proxy/access-control.js
@@ -53,6 +53,10 @@ class AccessControl extends EventEmitter {
const grants = await this._getGrants(origin)
+ if (grants.has('*')) {
+ return { origin, permission, allow: grants.get('*') }
+ }
+
return grants.has(permission)
? { origin, permission, allow: grants.get(permission) }
: null
@@ -67,6 +71,23 @@ class AccessControl extends EventEmitter {
const access = { origin, permission, allow }
const grants = await this._getGrants(origin)
+ // Trying to set access for non-wildcard permission, when wildcard
+ // permission is already granted?
+ if (grants.has('*') && permission !== '*') {
+ if (grants.get('*') === allow) {
+ // Noop if requested access is the same as access for wildcard grant
+ return access
+ } else {
+ // Fail if requested access is the different to access for wildcard grant
+ throw new Error(`Illegal set access for ${permission} when wildcard exists`)
+ }
+ }
+
+ // If setting a wildcard permission, remove existing grants
+ if (permission === '*') {
+ grants.clear()
+ }
+
grants.set(permission, allow)
await this._setGrants(origin, grants)
diff --git a/add-on/src/lib/ipfs-proxy/index.js b/add-on/src/lib/ipfs-proxy/index.js
index 7dabd3c2f..f58e9bacf 100644
--- a/add-on/src/lib/ipfs-proxy/index.js
+++ b/add-on/src/lib/ipfs-proxy/index.js
@@ -5,11 +5,13 @@ const browser = require('webextension-polyfill')
const { createProxyServer, closeProxyServer } = require('ipfs-postmsg-proxy')
const AccessControl = require('./access-control')
const createPreAcl = require('./pre-acl')
+const createRequestAccess = require('./request-access')
// Creates an object that manages the "server side" of the IPFS proxy
function createIpfsProxy (getIpfs, getState) {
let connections = []
const accessControl = new AccessControl(browser.storage)
+ const requestAccess = createRequestAccess(browser, screen)
// Port connection events are emitted when a content script attempts to
// communicate with us. Each new URL visited by the user will open a port.
@@ -25,7 +27,7 @@ function createIpfsProxy (getIpfs, getState) {
removeListener: (_, handler) => port.onMessage.removeListener(handler),
postMessage: (data) => port.postMessage(data),
getMessageData: (d) => d,
- pre: (fnName) => createPreAcl(getState, accessControl, origin, fnName)
+ pre: (fnName) => createPreAcl(getState, accessControl, origin, fnName, requestAccess)
})
const close = () => {
diff --git a/add-on/src/lib/ipfs-proxy/pre-acl.js b/add-on/src/lib/ipfs-proxy/pre-acl.js
index dac18cde7..60d9015a7 100644
--- a/add-on/src/lib/ipfs-proxy/pre-acl.js
+++ b/add-on/src/lib/ipfs-proxy/pre-acl.js
@@ -1,13 +1,11 @@
-const defaultRequestAccess = require('./request-access')
-
-// This are the function that DO NOT require an allow/deny decision by the user.
+// This are the functions that DO NOT require an allow/deny decision by the user.
// All other IPFS functions require authorization.
const ACL_WHITELIST = Object.freeze(require('./acl-whitelist.json'))
// Creates a "pre" function that is called prior to calling a real function
// on the IPFS instance. It will throw if access is denied, and ask the user if
// no access decision has been made yet.
-function createPreAcl (getState, accessControl, origin, permission, requestAccess = defaultRequestAccess) {
+function createPreAcl (getState, accessControl, origin, permission, requestAccess) {
return async (...args) => {
// Check if all access to the IPFS node is disabled
if (!getState().ipfsProxy) throw new Error('User disabled access to IPFS')
@@ -18,8 +16,8 @@ function createPreAcl (getState, accessControl, origin, permission, requestAcces
let access = await accessControl.getAccess(origin, permission)
if (!access) {
- const { allow } = await requestAccess(origin, permission)
- access = await accessControl.setAccess(origin, permission, allow)
+ const { allow, wildcard } = await requestAccess(origin, permission)
+ access = await accessControl.setAccess(origin, wildcard ? '*' : permission, allow)
}
if (!access.allow) throw new Error(`User denied access to ${permission}`)
diff --git a/add-on/src/lib/ipfs-proxy/request-access.js b/add-on/src/lib/ipfs-proxy/request-access.js
index d7b9b5cdf..59f27dc30 100644
--- a/add-on/src/lib/ipfs-proxy/request-access.js
+++ b/add-on/src/lib/ipfs-proxy/request-access.js
@@ -1,17 +1,92 @@
-async function requestAccess (origin, permission) {
- const msg = `Allow ${origin} to access ipfs.${permission}?`
+'use strict'
- // TODO: add checkbox to allow all for this origin
- let allow
+const DIALOG_WIDTH = 540
+const DIALOG_HEIGHT = 200
+const DIALOG_PATH = 'dist/pages/proxy-access-dialog/index.html'
+const DIALOG_PORT_NAME = 'proxy-access-dialog'
- try {
- allow = window.confirm(msg)
- } catch (err) {
- console.warn('Failed to confirm, possibly not supported in this environment', err)
- allow = false
+function createRequestAccess (browser, screen) {
+ return async function requestAccess (origin, permission, opts) {
+ opts = opts || {}
+
+ const width = opts.dialogWidth || DIALOG_WIDTH
+ const height = opts.dialogHeight || DIALOG_HEIGHT
+
+ const url = browser.extension.getURL(opts.dialogPath || DIALOG_PATH)
+ const currentWin = await browser.windows.getCurrent()
+
+ const top = Math.round(((screen.width / 2) - (width / 2)) + currentWin.left)
+ const left = Math.round(((screen.height / 2) - (height / 2)) + currentWin.top)
+
+ const { tabs } = await browser.windows.create({ url, width, height, top, left, type: 'popup' })
+
+ // Resolves with { allow, wildcard }
+ const userResponse = getUserResponse(tabs[0].id, origin, permission, opts)
+ // Never resolves, might reject if user closes the tab
+ const userTabRemoved = getUserTabRemoved(tabs[0].id, origin, permission)
+
+ let response
+
+ try {
+ // Will the user respond to or close the dialog?
+ response = await Promise.race([userTabRemoved, userResponse])
+ } finally {
+ userTabRemoved.destroy()
+ userResponse.destroy()
+ }
+
+ await browser.tabs.remove(tabs[0].id)
+
+ return response
+ }
+
+ function getUserResponse (tabId, origin, permission, opts) {
+ opts = opts || {}
+
+ const dialogPortName = opts.dialogPortName || DIALOG_PORT_NAME
+ let onPortConnect
+
+ const userResponse = new Promise((resolve, reject) => {
+ onPortConnect = port => {
+ if (port.name !== dialogPortName) return
+
+ browser.runtime.onConnect.removeListener(onPortConnect)
+
+ // Tell the dialog what origin/permission it is about
+ port.postMessage({ origin, permission })
+
+ // Wait for the user response
+ const onMessage = ({ allow, wildcard }) => {
+ port.onMessage.removeListener(onMessage)
+ resolve({ allow, wildcard })
+ }
+
+ port.onMessage.addListener(onMessage)
+ }
+
+ browser.runtime.onConnect.addListener(onPortConnect)
+ })
+
+ userResponse.destroy = () => browser.runtime.onConnect.removeListener(onPortConnect)
+
+ return userResponse
}
- return { allow }
+ // Since the dialog is a tab not a real dialog it can be closed by the user
+ // with no response, this function creates a promise that will reject if the tab
+ // is removed.
+ function getUserTabRemoved (tabId, origin, permission) {
+ let onTabRemoved
+
+ const userTabRemoved = new Promise((resolve, reject) => {
+ onTabRemoved = () => reject(new Error(`Failed to obtain access response for ${permission} at ${origin}`))
+ browser.tabs.onRemoved.addListener(onTabRemoved)
+ })
+
+ userTabRemoved.destroy = () => browser.tabs.onRemoved.removeListener(onTabRemoved)
+
+ return userTabRemoved
+ }
}
-module.exports = requestAccess
+module.exports = createRequestAccess
diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js
index b802c644d..b902e819a 100644
--- a/add-on/src/lib/state.js
+++ b/add-on/src/lib/state.js
@@ -19,6 +19,7 @@ function initState (options) {
state.preloadAtPublicGateway = options.preloadAtPublicGateway
state.catchUnhandledProtocols = options.catchUnhandledProtocols
state.displayNotifications = options.displayNotifications
+ state.ipfsProxy = options.ipfsProxy
return state
}
diff --git a/add-on/src/options/forms/experiments-form.js b/add-on/src/options/forms/experiments-form.js
index 6142b279c..ac76b2469 100644
--- a/add-on/src/options/forms/experiments-form.js
+++ b/add-on/src/options/forms/experiments-form.js
@@ -77,11 +77,11 @@ function experimentsForm ({
${browser.i18n.getMessage('option_ipfsProxy_title')}
${browser.i18n.getMessage('option_ipfsProxy_description')}
- ${ipfsProxy ? html`
-
- ${browser.i18n.getMessage('option_ipfsProxy_link_manage_permissions')}
-
- ` : null}
+ ${ipfsProxy ? html`
+
+ ${browser.i18n.getMessage('option_ipfsProxy_link_manage_permissions')}
+ ` : html`${browser.i18n.getMessage('option_ipfsProxy_link_manage_permissions')}`}
+
diff --git a/add-on/src/options/page.css b/add-on/src/options/options.css
similarity index 100%
rename from add-on/src/options/page.css
rename to add-on/src/options/options.css
diff --git a/add-on/src/options/options.html b/add-on/src/options/options.html
index 3bff95bf9..9ebbf23e7 100644
--- a/add-on/src/options/options.html
+++ b/add-on/src/options/options.html
@@ -4,6 +4,7 @@
Options
+
diff --git a/add-on/src/options/page.js b/add-on/src/options/page.js
index e3c57f120..6dbb237f2 100644
--- a/add-on/src/options/page.js
+++ b/add-on/src/options/page.js
@@ -7,8 +7,6 @@ const gatewaysForm = require('./forms/gateways-form')
const apiForm = require('./forms/api-form')
const experimentsForm = require('./forms/experiments-form')
-require('./page.css')
-
// Render the options page:
// Passed current app `state` from the store and `emit`, a function to create
// events, allowing views to signal back to the store that something happened.
diff --git a/add-on/src/pages/proxy-access-dialog/index.html b/add-on/src/pages/proxy-access-dialog/index.html
new file mode 100644
index 000000000..40855149b
--- /dev/null
+++ b/add-on/src/pages/proxy-access-dialog/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+ IPFS Companion
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/add-on/src/pages/proxy-access-dialog/index.js b/add-on/src/pages/proxy-access-dialog/index.js
new file mode 100644
index 000000000..c38b61a2f
--- /dev/null
+++ b/add-on/src/pages/proxy-access-dialog/index.js
@@ -0,0 +1,12 @@
+'use strict'
+
+const browser = require('webextension-polyfill')
+const choo = require('choo')
+const createProxyAccessDialogStore = require('./store')
+const createProxyAccessDialogPage = require('./page')
+
+const app = choo()
+
+app.use(createProxyAccessDialogStore(browser.i18n, browser.runtime))
+app.route('*', createProxyAccessDialogPage(browser.i18n))
+app.mount('#root')
diff --git a/add-on/src/pages/proxy-access-dialog/page.js b/add-on/src/pages/proxy-access-dialog/page.js
new file mode 100644
index 000000000..12985cda6
--- /dev/null
+++ b/add-on/src/pages/proxy-access-dialog/page.js
@@ -0,0 +1,78 @@
+'use strict'
+
+const html = require('choo/html')
+
+function createProxyAccessDialogPage (i18n) {
+ return function proxyAccessDialogPage (state, emit) {
+ const onAllow = () => emit('allow')
+ const onDeny = () => emit('deny')
+ const onWildcardToggle = () => emit('wildcardToggle')
+
+ const { loading, origin, permission } = state
+
+ return html`
+
+
+ ${loading ? null : html`
+
+
+ ${i18n.getMessage('page_proxyAccessDialog_title', [origin, permission])}
+
+
+
+
+
+ `}
+
+
+ ${loading ? html`
+
+
+ ${button({
+ text: i18n.getMessage('page_proxyAccessDialog_denyButton_text'),
+ disabled: true
+ })}
+
+ ${button({
+ text: i18n.getMessage('page_proxyAccessDialog_allowButton_text'),
+ disabled: true
+ })}
+
+ ` : html`
+
+
+ ${button({
+ text: i18n.getMessage('page_proxyAccessDialog_denyButton_text'),
+ onClick: onDeny,
+ color: 'red'
+ })}
+
+ ${button({
+ text: i18n.getMessage('page_proxyAccessDialog_allowButton_text'),
+ onClick: onAllow,
+ color: 'aqua'
+ })}
+
+ `}
+
+
+ `
+ }
+}
+
+function button ({ onClick, color, text, disabled }) {
+ if (disabled) {
+ return html`
+
+ `
+ }
+
+ return html`
+
+ `
+}
+
+module.exports = createProxyAccessDialogPage
diff --git a/add-on/src/pages/proxy-access-dialog/proxy-access-dialog.css b/add-on/src/pages/proxy-access-dialog/proxy-access-dialog.css
new file mode 100644
index 000000000..918eecbc9
--- /dev/null
+++ b/add-on/src/pages/proxy-access-dialog/proxy-access-dialog.css
@@ -0,0 +1,10 @@
+@import url('../../../ui-kit/tachyons.css');
+@import url('../../../ui-kit/ipfs.css');
+
+.hover-bg-aqua-muted:hover {
+ background-color: #9ad4db;
+}
+
+.hover-bg-red-muted:hover {
+ background-color: #f36149;
+}
diff --git a/add-on/src/pages/proxy-access-dialog/store.js b/add-on/src/pages/proxy-access-dialog/store.js
new file mode 100644
index 000000000..78daebf84
--- /dev/null
+++ b/add-on/src/pages/proxy-access-dialog/store.js
@@ -0,0 +1,35 @@
+'use strict'
+
+function createProxyAccessDialogStore (i18n, runtime) {
+ return function proxyAccessDialogStore (state, emitter) {
+ state.origin = null
+ state.permission = null
+ state.loading = true
+ state.wildcard = false
+
+ const port = runtime.connect({ name: 'proxy-access-dialog' })
+
+ const onMessage = (data) => {
+ if (!data || !data.origin || !data.permission) return
+ port.onMessage.removeListener(onMessage)
+
+ state.origin = data.origin
+ state.permission = data.permission
+ state.loading = false
+
+ emitter.emit('render')
+ }
+
+ port.onMessage.addListener(onMessage)
+
+ emitter.on('allow', () => port.postMessage({ allow: true, wildcard: state.wildcard }))
+ emitter.on('deny', () => port.postMessage({ allow: false, wildcard: state.wildcard }))
+
+ emitter.on('wildcardToggle', () => {
+ state.wildcard = !state.wildcard
+ emitter.emit('render')
+ })
+ }
+}
+
+module.exports = createProxyAccessDialogStore
diff --git a/add-on/src/pages/proxy-acl/index.html b/add-on/src/pages/proxy-acl/index.html
index bd0b7b9b2..40386161e 100644
--- a/add-on/src/pages/proxy-acl/index.html
+++ b/add-on/src/pages/proxy-acl/index.html
@@ -5,6 +5,7 @@
Manage Permissions
+
diff --git a/add-on/src/pages/proxy-acl/page.js b/add-on/src/pages/proxy-acl/page.js
index a38f4ccb8..cdeb95710 100644
--- a/add-on/src/pages/proxy-acl/page.js
+++ b/add-on/src/pages/proxy-acl/page.js
@@ -3,8 +3,6 @@
const html = require('choo/html')
const logo = require('../../popup/logo')
-require('./page.css')
-
function createProxyAclPage (i18n) {
return function proxyAclPage (state, emit) {
const onRevoke = (e) => emit('revoke', e)
diff --git a/add-on/src/pages/proxy-acl/page.css b/add-on/src/pages/proxy-acl/proxy-acl.css
similarity index 66%
rename from add-on/src/pages/proxy-acl/page.css
rename to add-on/src/pages/proxy-acl/proxy-acl.css
index aaca1a7a1..5bbc23846 100644
--- a/add-on/src/pages/proxy-acl/page.css
+++ b/add-on/src/pages/proxy-acl/proxy-acl.css
@@ -1,4 +1,5 @@
-@import url('node_modules/tachyons/css/tachyons.css');
+@import url('../../../ui-kit/tachyons.css');
+@import url('../../popup/heartbeat.css');
html, body {
height: 100%;
diff --git a/add-on/src/popup/browser-action/page.css b/add-on/src/popup/browser-action/browser-action.css
similarity index 54%
rename from add-on/src/popup/browser-action/page.css
rename to add-on/src/popup/browser-action/browser-action.css
index 401e3daa9..17d77791d 100644
--- a/add-on/src/popup/browser-action/page.css
+++ b/add-on/src/popup/browser-action/browser-action.css
@@ -1,5 +1,5 @@
-@import url('node_modules/tachyons/css/tachyons.css');
-@import url('./mdc.switch.css');
+@import url('../../../ui-kit/tachyons.css');
+@import url('mdc.switch.css');
.bg-near-white--hover:hover {
background-color: #F4F4F4;
diff --git a/add-on/src/popup/browser-action/index.html b/add-on/src/popup/browser-action/index.html
index 8ba9fe11a..286fe1f5e 100644
--- a/add-on/src/popup/browser-action/index.html
+++ b/add-on/src/popup/browser-action/index.html
@@ -3,6 +3,7 @@
+
diff --git a/add-on/src/popup/browser-action/page.js b/add-on/src/popup/browser-action/page.js
index 7d03d411a..658929d4f 100644
--- a/add-on/src/popup/browser-action/page.js
+++ b/add-on/src/popup/browser-action/page.js
@@ -7,8 +7,6 @@ const contextActions = require('./context-actions')
const operations = require('./operations')
const gatewayStatus = require('./gateway-status')
-require('./page.css')
-
// Render the browser action page:
// Passed current app `state` from the store and `emit`, a function to create
// events, allowing views to signal back to the store that something happened.
diff --git a/add-on/src/popup/logo.js b/add-on/src/popup/logo.js
index cc7f9b257..de7422d17 100644
--- a/add-on/src/popup/logo.js
+++ b/add-on/src/popup/logo.js
@@ -2,7 +2,6 @@
/* eslint-env browser, webextensions */
const html = require('choo/html')
-require('./heartbeat.css')
function logo ({ path, size = 52, ipfsNodeType = 'external', isIpfsOnline = true, heartbeat = true }) {
const logoTypePrefix = ipfsNodeType === 'embedded' ? 'js-' : ''
diff --git a/add-on/src/popup/quick-upload.css b/add-on/src/popup/quick-upload.css
index 9c7703a93..c34cad974 100644
--- a/add-on/src/popup/quick-upload.css
+++ b/add-on/src/popup/quick-upload.css
@@ -1,4 +1,5 @@
-@import url('node_modules/tachyons/css/tachyons.css');
+@import url('../../ui-kit/tachyons.css');
+@import url('heartbeat.css');
html, body, #root {
height: 100%;
diff --git a/add-on/src/popup/quick-upload.html b/add-on/src/popup/quick-upload.html
index 24dfc8ae4..b21e81b7b 100644
--- a/add-on/src/popup/quick-upload.html
+++ b/add-on/src/popup/quick-upload.html
@@ -5,6 +5,7 @@
IPFS Upload
+
diff --git a/add-on/src/popup/quick-upload.js b/add-on/src/popup/quick-upload.js
index b28f76ded..2260c121a 100644
--- a/add-on/src/popup/quick-upload.js
+++ b/add-on/src/popup/quick-upload.js
@@ -6,8 +6,6 @@ const choo = require('choo')
const html = require('choo/html')
const logo = require('./logo')
-require('./quick-upload.css')
-
const app = choo()
app.use(quickUploadStore)
diff --git a/package.json b/package.json
index f4d5014d1..1f1038f23 100644
--- a/package.json
+++ b/package.json
@@ -14,8 +14,13 @@
"build": "run-s clean build:*",
"build:copy": "run-s build:copy:*",
"build:copy:src": "shx mkdir -p add-on/dist && shx cp -R add-on/src/* add-on/dist",
+ "build:copy:ui-kit": "run-p build:copy:ui-kit:*",
+ "build:copy:ui-kit:ipfs-css": "run-p build:copy:ui-kit:ipfs-css:*",
+ "build:copy:ui-kit:ipfs-css:css": "shx mkdir -p add-on/ui-kit && shx cp node_modules/ipfs-css/ipfs.css add-on/ui-kit",
+ "build:copy:ui-kit:ipfs-css:fonts": "shx mkdir -p add-on/ui-kit/fonts && shx cp node_modules/ipfs-css/fonts/* add-on/ui-kit/fonts",
+ "build:copy:ui-kit:tachyons": "shx mkdir -p add-on/ui-kit && shx cp node_modules/tachyons/css/tachyons.css add-on/ui-kit",
"build:copy:wx-polyfill-lib": "shx cp node_modules/webextension-polyfill/dist/browser-polyfill.min.js add-on/dist/contentScripts/browser-polyfill.min.js",
- "build:js": "browserify -p prundupify -t browserify-css -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/options/options.js add-on/src/popup/browser-action/index.js add-on/src/popup/quick-upload.js add-on/src/pages/proxy-acl/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/options/options.js -o add-on/dist/popup/browser-action/browser-action.js -o add-on/dist/popup/quick-upload.js -o add-on/dist/pages/proxy-acl/proxy-acl.js ] -o add-on/dist/ipfs-companion-common.js",
+ "build:js": "browserify -p prundupify -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/options/options.js add-on/src/popup/browser-action/index.js add-on/src/popup/quick-upload.js add-on/src/pages/proxy-acl/index.js add-on/src/pages/proxy-access-dialog/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/options/options.js -o add-on/dist/popup/browser-action/browser-action.js -o add-on/dist/popup/quick-upload.js -o add-on/dist/pages/proxy-acl/proxy-acl.js -o add-on/dist/pages/proxy-access-dialog/proxy-access-dialog.js ] -o add-on/dist/ipfs-companion-common.js",
"build:content-scripts": "run-p build:content-scripts:*",
"build:content-scripts:ipfs-proxy": "run-s build:content-scripts:ipfs-proxy:*",
"build:content-scripts:ipfs-proxy:page": "browserify -p prundupify -g uglifyify -t [ browserify-package-json --global ] add-on/src/contentScripts/ipfs-proxy/page.js -o add-on/dist/contentScripts/ipfs-proxy/page.js",
@@ -24,9 +29,9 @@
"build:minimize-dist": "shx rm -rf add-on/dist/lib",
"build:bundle-extension": "web-ext build -s add-on/ -i src/ -a build/",
"watch": "npm-run-all build:copy --parallel watch:*",
- "watch:js": "watchify -p prundupify -t browserify-css -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/options/options.js add-on/src/popup/browser-action/index.js add-on/src/popup/quick-upload.js add-on/src/pages/proxy-acl/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/options/options.js -o add-on/dist/popup/browser-action/browser-action.js -o add-on/dist/popup/quick-upload.js -o add-on/dist/pages/proxy-acl/proxy-acl.js ] -o add-on/dist/ipfs-companion-common.js -v",
+ "watch:js": "watchify -p prundupify -t [ browserify-package-json --global ] add-on/src/background/background.js add-on/src/options/options.js add-on/src/popup/browser-action/index.js add-on/src/popup/quick-upload.js add-on/src/pages/proxy-acl/index.js add-on/src/pages/proxy-access-dialog/index.js -p [ factor-bundle -o add-on/dist/background/background.js -o add-on/dist/options/options.js -o add-on/dist/popup/browser-action/browser-action.js -o add-on/dist/popup/quick-upload.js -o add-on/dist/pages/proxy-acl/proxy-acl.js -o add-on/dist/pages/proxy-access-dialog/proxy-access-dialog.js ] -o add-on/dist/ipfs-companion-common.js -v",
"watch:content-scripts": "run-p watch:content-scripts:*",
- "watch:content-scripts:ipfs-proxy": "run-s watch:content-scripts:ipfs-proxy:*",
+ "watch:content-scripts:ipfs-proxy": "run-p watch:content-scripts:ipfs-proxy:*",
"watch:content-scripts:ipfs-proxy:page": "watchify -p prundupify -t [ browserify-package-json --global ] add-on/src/contentScripts/ipfs-proxy/page.js -o add-on/dist/contentScripts/ipfs-proxy/page.js -v",
"watch:content-scripts:ipfs-proxy:content": "nodemon --exec \"browserify -p prundupify -t brfs -t [ browserify-package-json --global ] -s IpfsProxyContent add-on/src/contentScripts/ipfs-proxy/content.js -o add-on/dist/contentScripts/ipfs-proxy/content.js -v\" --watch add-on/src/contentScripts/ipfs-proxy/content.js --watch add-on/dist/contentScripts/ipfs-proxy/page.js",
"test": "run-s test:*",
@@ -52,7 +57,6 @@
"babelify": "8.0.0",
"brfs": "1.4.4",
"browserify": "14.5.0",
- "browserify-css": "0.14.0",
"browserify-package-json": "1.0.1",
"chai": "4.1.2",
"cross-env": "5.1.3",
@@ -72,7 +76,7 @@
"sinon": "4.1.2",
"sinon-chrome": "2.2.1",
"standard": "10.0.3",
- "uglifyify": "^4.0.5",
+ "uglifyify": "4.0.5",
"watchify": "3.9.0",
"web-ext": "2.3.2"
},
@@ -82,6 +86,7 @@
"file-type": "7.3.0",
"ipfs": "0.27.6",
"ipfs-api": "17.2.7",
+ "ipfs-css": "0.1.0",
"ipfs-postmsg-proxy": "2.7.0",
"is-ipfs": "0.3.2",
"is-svg": "2.1.0",
diff --git a/test/functional/lib/ipfs-companion.test.js b/test/functional/lib/ipfs-companion.test.js
index 558480063..e88897cfa 100644
--- a/test/functional/lib/ipfs-companion.test.js
+++ b/test/functional/lib/ipfs-companion.test.js
@@ -11,6 +11,7 @@ describe('init', function () {
global.window = {}
global.browser = browser
global.URL = URL
+ global.screen = {}
init = require('../../../add-on/src/lib/ipfs-companion')
})
@@ -74,6 +75,7 @@ describe.skip('onStorageChange()', function () {
delete global.window
delete global.browser
delete global.URL
+ delete global.screen
browser.flush()
})
})
diff --git a/test/functional/lib/ipfs-proxy/access-control.test.js b/test/functional/lib/ipfs-proxy/access-control.test.js
index 6522744ea..3f9aa0c52 100644
--- a/test/functional/lib/ipfs-proxy/access-control.test.js
+++ b/test/functional/lib/ipfs-proxy/access-control.test.js
@@ -46,6 +46,105 @@ describe('lib/ipfs-proxy/access-control', () => {
expect(acl).to.deep.equal(expectedAcl)
})
+ it('should allow access for wildcard allow', async () => {
+ const accessControl = new AccessControl(new Storage())
+ let access = await accessControl.getAccess('https://ipfs.io', 'files.add')
+
+ expect(access).to.equal(null)
+
+ // Add wildcard
+ await accessControl.setAccess('https://ipfs.io', '*', true)
+
+ access = await accessControl.getAccess('https://ipfs.io', 'files.add')
+
+ const expectedAccess = { origin: 'https://ipfs.io', permission: 'files.add', allow: true }
+
+ expect(access).to.deep.equal(expectedAccess)
+ })
+
+ it('should deny access for wildcard deny', async () => {
+ const accessControl = new AccessControl(new Storage())
+ let access = await accessControl.getAccess('https://ipfs.io', 'files.add')
+
+ expect(access).to.equal(null)
+
+ // Add wildcard
+ await accessControl.setAccess('https://ipfs.io', '*', false)
+
+ access = await accessControl.getAccess('https://ipfs.io', 'files.add')
+
+ const expectedAccess = { origin: 'https://ipfs.io', permission: 'files.add', allow: false }
+
+ expect(access).to.deep.equal(expectedAccess)
+ })
+
+ it('should clear existing grants when setting wildcard access', async () => {
+ const accessControl = new AccessControl(new Storage())
+
+ await accessControl.setAccess('https://ipfs.io', 'files.add', false)
+ await accessControl.setAccess('https://ipfs.io', 'object.new', true)
+ await accessControl.setAccess('https://ipfs.io', 'config.set', false)
+
+ let acl = await accessControl.getAcl()
+
+ let expectedAcl = objToAcl({
+ 'https://ipfs.io': {
+ 'files.add': false,
+ 'object.new': true,
+ 'config.set': false
+ }
+ })
+
+ expect(acl).to.deep.equal(expectedAcl)
+
+ // Add wildcard
+ await accessControl.setAccess('https://ipfs.io', '*', false)
+
+ acl = await accessControl.getAcl()
+
+ expectedAcl = objToAcl({
+ 'https://ipfs.io': {
+ '*': false
+ }
+ })
+
+ expect(acl).to.deep.equal(expectedAcl)
+ })
+
+ it('should not be able to set different access to specific permission if wildcard access grant exists', async () => {
+ const accessControl = new AccessControl(new Storage())
+
+ // Add wildcard
+ await accessControl.setAccess('https://ipfs.io', '*', false)
+
+ let error
+
+ try {
+ await accessControl.setAccess('https://ipfs.io', 'files.add', true)
+ } catch (err) {
+ error = err
+ }
+
+ expect(() => { if (error) throw error }).to.throw('Illegal set access for files.add when wildcard exists')
+ })
+
+ it('should be able set same access to specific permission if wildcard access grant exists', async () => {
+ const accessControl = new AccessControl(new Storage())
+
+ // Add wildcard
+ await accessControl.setAccess('https://ipfs.io', '*', false)
+
+ let error
+
+ try {
+ await accessControl.setAccess('https://ipfs.io', 'files.add', false)
+ } catch (err) {
+ error = err
+ }
+
+ expect(() => { if (error) throw error }).to.not.throw()
+ })
+
it('should get granted access for origin and permission', async () => {
const accessControl = new AccessControl(new Storage())
diff --git a/test/functional/pages/proxy-access-dialog/page.test.js b/test/functional/pages/proxy-access-dialog/page.test.js
new file mode 100644
index 000000000..e2ddace9e
--- /dev/null
+++ b/test/functional/pages/proxy-access-dialog/page.test.js
@@ -0,0 +1,20 @@
+'use strict'
+const { describe, it } = require('mocha')
+const { expect } = require('chai')
+const createProxyAccessDialogPage = require('../../../../add-on/src/pages/proxy-access-dialog/page')
+const createMockI18n = require('../../../helpers/mock-i18n')
+
+describe('pages/proxy-access-dialog/page', () => {
+ it('should display title, wildcard checkbox and allow/deny buttons', async () => {
+ const i18n = createMockI18n()
+ const state = { origin: 'http://ipfs.io', permission: 'files.add' }
+
+ let res
+
+ expect(() => { res = createProxyAccessDialogPage(i18n)(state).toString() }).to.not.throw()
+ expect(res).to.have.string(`page_proxyAccessDialog_title[${state.origin},${state.permission}]`)
+ expect(res).to.have.string(`page_proxyAccessDialog_wildcardCheckbox_label[${state.origin}]`)
+ expect(res).to.have.string(`page_proxyAccessDialog_denyButton_text`)
+ expect(res).to.have.string(`page_proxyAccessDialog_allowButton_text`)
+ })
+})
diff --git a/test/functional/pages/proxy-acl/page.test.js b/test/functional/pages/proxy-acl/page.test.js
index 7ac519032..6ab913ee4 100644
--- a/test/functional/pages/proxy-acl/page.test.js
+++ b/test/functional/pages/proxy-acl/page.test.js
@@ -3,6 +3,7 @@ const { describe, it } = require('mocha')
const { expect } = require('chai')
const createProxyAclPage = require('../../../../add-on/src/pages/proxy-acl/page')
const { objToAcl } = require('../../../helpers/acl')
+const createMockI18n = require('../../../helpers/mock-i18n')
describe('pages/proxy-acl/page', () => {
it('should render with empty ACL', async () => {
@@ -102,5 +103,3 @@ describe('pages/proxy-acl/page', () => {
expect(res).to.have.string('ipfs.block.put')
})
})
-
-const createMockI18n = () => ({ getMessage: key => key })
diff --git a/test/functional/pages/proxy-acl/store.test.js b/test/functional/pages/proxy-acl/store.test.js
index 0b1ccd846..4cb7e5c11 100644
--- a/test/functional/pages/proxy-acl/store.test.js
+++ b/test/functional/pages/proxy-acl/store.test.js
@@ -8,6 +8,7 @@ const { URL } = require('url')
const AccessControl = require('../../../../add-on/src/lib/ipfs-proxy/access-control')
const createProxyAclStore = require('../../../../add-on/src/pages/proxy-acl/store')
const { objToAcl } = require('../../../helpers/acl')
+const createMockI18n = require('../../../helpers/mock-i18n')
describe('pages/proxy-acl/store', () => {
before(() => {
@@ -316,8 +317,6 @@ describe('pages/proxy-acl/store', () => {
})
})
-const createMockI18n = () => ({ getMessage: key => key })
-
const createMockConfirm = (res = true) => () => res
const createMockEvent = (targetAttributes = {}) => {
diff --git a/test/helpers/mock-i18n.js b/test/helpers/mock-i18n.js
new file mode 100644
index 000000000..b7fad1351
--- /dev/null
+++ b/test/helpers/mock-i18n.js
@@ -0,0 +1,8 @@
+module.exports = () => ({
+ getMessage (key, substititions) {
+ if (!substititions) return key
+ substititions = Array.isArray(substititions) ? substititions : [substititions]
+ if (!substititions.length) return key
+ return `${key}[${substititions}]`
+ }
+})
diff --git a/yarn.lock b/yarn.lock
index 307cc2081..4ced0246b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -472,10 +472,6 @@ atob@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
-atob@~1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773"
-
aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
@@ -1293,19 +1289,6 @@ browserify-cipher@^1.0.0:
browserify-des "^1.0.0"
evp_bytestokey "^1.0.0"
-browserify-css@0.14.0:
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/browserify-css/-/browserify-css-0.14.0.tgz#5ece581aa6f8c9aab262956fd06d57c526c9a334"
- dependencies:
- clean-css "^4.1.5"
- concat-stream "^1.6.0"
- css "^2.2.1"
- find-node-modules "^1.0.4"
- lodash "^4.17.4"
- mime "^1.3.6"
- strip-css-comments "^3.0.0"
- through2 "2.0.x"
-
browserify-des@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
@@ -1737,12 +1720,6 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
-clean-css@^4.1.5:
- version "4.1.9"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301"
- dependencies:
- source-map "0.5.x"
-
cli-boxes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
@@ -2107,15 +2084,6 @@ css-what@2.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
-css@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc"
- dependencies:
- inherits "^2.0.1"
- source-map "^0.1.38"
- source-map-resolve "^0.3.0"
- urix "^0.1.0"
-
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@@ -2340,12 +2308,6 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
-detect-file@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
- dependencies:
- fs-exists-sync "^0.1.0"
-
detect-indent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
@@ -3105,12 +3067,6 @@ expand-template@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.0.tgz#e09efba977bf98f9ee0ed25abd0c692e02aec3fc"
-expand-tilde@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
- dependencies:
- os-homedir "^1.0.1"
-
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -3294,13 +3250,6 @@ find-cache-dir@^0.1.1:
mkdirp "^0.5.1"
pkg-dir "^1.0.0"
-find-node-modules@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/find-node-modules/-/find-node-modules-1.0.4.tgz#b6deb3cccb699c87037677bcede2c5f5862b2550"
- dependencies:
- findup-sync "0.4.2"
- merge "^1.2.0"
-
find-process@^1.0.5:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-process/-/find-process-1.1.0.tgz#f21fa08220fec972b471d92ae3cf0c62bebcd5bb"
@@ -3326,15 +3275,6 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
-findup-sync@0.4.2:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.2.tgz#a8117d0f73124f5a4546839579fe52d7129fb5e5"
- dependencies:
- detect-file "^0.1.0"
- is-glob "^2.0.1"
- micromatch "^2.3.7"
- resolve-dir "^0.1.0"
-
firefox-client@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/firefox-client/-/firefox-client-0.3.0.tgz#3794460f6eb6afcf41376addcbc7462e24a4cd8b"
@@ -3442,10 +3382,6 @@ from@~0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
-fs-exists-sync@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
-
"fs-ext@github:baudehlo/node-fs-ext#master":
version "1.0.0"
resolved "https://codeload.github.com/baudehlo/node-fs-ext/tar.gz/500be8514729c194ac7ca2b30b5bc7eaf812670d"
@@ -3702,22 +3638,6 @@ global-dirs@^0.1.0:
dependencies:
ini "^1.3.4"
-global-modules@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
- dependencies:
- global-prefix "^0.1.4"
- is-windows "^0.2.0"
-
-global-prefix@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
- dependencies:
- homedir-polyfill "^1.0.0"
- ini "^1.3.4"
- is-windows "^0.2.0"
- which "^1.2.12"
-
globals@^11.0.1:
version "11.3.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0"
@@ -4016,12 +3936,6 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
-homedir-polyfill@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
- dependencies:
- parse-passwd "^1.0.0"
-
hosted-git-info@^2.1.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c"
@@ -4374,6 +4288,10 @@ ipfs-block@^0.6.1, ipfs-block@~0.6.1:
dependencies:
cids "^0.5.2"
+ipfs-css@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ipfs-css/-/ipfs-css-0.1.0.tgz#0337e7e3aeddf391bbd1b7b7fb427f98b6ec5ca3"
+
ipfs-multipart@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ipfs-multipart/-/ipfs-multipart-0.1.0.tgz#5a8ed13f42e82d8bef7d2e151d8eaf5e3a30e3ea"
@@ -4920,10 +4838,6 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
-is-regexp@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
-
is-relative@^0.1.0:
version "0.1.3"
resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.1.3.tgz#905fee8ae86f45b3ec614bc3c15c869df0876e82"
@@ -4958,10 +4872,6 @@ is-utf8@^0.2.0, is-utf8@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
-is-windows@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
-
is-windows@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9"
@@ -6112,10 +6022,6 @@ merge-source-map@^1.0.2:
dependencies:
source-map "^0.6.1"
-merge@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
-
merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz#84c606232ef343f1b96fc972e697708754f08573"
@@ -6129,7 +6035,7 @@ merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.2.0:
rlp "^2.0.0"
semaphore ">=1.0.1"
-micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
+micromatch@^2.1.5, micromatch@^2.3.11:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
@@ -6186,10 +6092,6 @@ mime-types@2.1.17, mime-types@^2.1.12, mime-types@^2.1.17, mime-types@~2.1.11, m
dependencies:
mime-db "~1.30.0"
-mime@^1.3.6:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
@@ -7001,10 +6903,6 @@ parse-json@^2.1.0, parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
-
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
@@ -8001,13 +7899,6 @@ require-uncached@1.0.3, require-uncached@^1.0.2, require-uncached@^1.0.3:
caller-path "^0.1.0"
resolve-from "^1.0.0"
-resolve-dir@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
- dependencies:
- expand-tilde "^1.2.2"
- global-modules "^0.2.3"
-
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
@@ -8016,7 +7907,7 @@ resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
-resolve-url@^0.2.1, resolve-url@~0.2.1:
+resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -8492,15 +8383,6 @@ socket.io@^2.0.4:
socket.io-client "2.0.4"
socket.io-parser "~3.1.1"
-source-map-resolve@^0.3.0:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761"
- dependencies:
- atob "~1.1.0"
- resolve-url "~0.2.1"
- source-map-url "~0.3.0"
- urix "~0.1.0"
-
source-map-resolve@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a"
@@ -8545,26 +8427,16 @@ source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
-source-map-url@~0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
-
-source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
-
-source-map@^0.1.38:
- version "0.1.43"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
- dependencies:
- amdefine ">=0.0.4"
-
source-map@^0.4.4, source-map@~0.4.0, source-map@~0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
dependencies:
amdefine ">=0.0.4"
+source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@@ -8891,12 +8763,6 @@ strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
-strip-css-comments@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-css-comments/-/strip-css-comments-3.0.0.tgz#7a5625eff8a2b226cf8947a11254da96e13dae89"
- dependencies:
- is-regexp "^1.0.0"
-
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
@@ -9095,13 +8961,6 @@ thenify-all@^1.0.0, thenify-all@^1.6.0:
dependencies:
any-promise "^1.0.0"
-through2@2.0.x, through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3, through2@~2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
- dependencies:
- readable-stream "^2.1.5"
- xtend "~4.0.1"
-
through2@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/through2/-/through2-0.5.1.tgz#dfdd012eb9c700e2323fd334f38ac622ab372da7"
@@ -9116,6 +8975,13 @@ through2@^1.0.0:
readable-stream ">=1.1.13-1 <1.2.0-0"
xtend ">=4.0.0 <4.1.0-0"
+through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3, through2@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.4:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -9311,7 +9177,7 @@ uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
-uglifyify@^4.0.5:
+uglifyify@4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/uglifyify/-/uglifyify-4.0.5.tgz#49c1fca9828c10a5a8e8d70f191a95f7ab475911"
dependencies:
@@ -9454,7 +9320,7 @@ urijs@^1.18.2:
version "1.19.0"
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.0.tgz#d8aa284d0e7469703a6988ad045c4cbfdf08ada0"
-urix@^0.1.0, urix@~0.1.0:
+urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -9663,7 +9529,7 @@ which@1.2.4:
is-absolute "^0.1.7"
isexe "^1.1.1"
-which@^1.2.12, which@^1.2.9, which@^1.3.0:
+which@^1.2.9, which@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
dependencies: