|
|
@@ -3,7 +3,7 @@ var defaults = {
|
|
|
// storage
|
|
|
origins: {},
|
|
|
header: false,
|
|
|
- csp: false,
|
|
|
+ intercept: false,
|
|
|
// static
|
|
|
protocols: ['https', 'http', '*'],
|
|
|
// UI
|
|
|
@@ -11,6 +11,27 @@ var defaults = {
|
|
|
origin: '',
|
|
|
timeout: null,
|
|
|
file: true,
|
|
|
+ encodings: {
|
|
|
+ 'Unicode': ['UTF-8', 'UTF-16LE'],
|
|
|
+ 'Arabic': ['ISO-8859-6', 'Windows-1256'],
|
|
|
+ 'Baltic': ['ISO-8859-4', 'ISO-8859-13', 'Windows-1257'],
|
|
|
+ 'Celtic': ['ISO-8859-14'],
|
|
|
+ 'Central European': ['ISO-8859-2', 'Windows-1250'],
|
|
|
+ 'Chinese Simplified': ['GB18030', 'GBK'],
|
|
|
+ 'Chinese Traditional': ['BIG5'],
|
|
|
+ 'Cyrillic': ['ISO-8859-5', 'IBM866', 'KOI8-R', 'KOI8-U', 'Windows-1251'],
|
|
|
+ 'Greek': ['ISO-8859-7', 'Windows-1253'],
|
|
|
+ 'Hebrew': ['Windows-1255', 'ISO-8859-8', 'ISO-8859-8-I'],
|
|
|
+ 'Japanese': ['EUC-JP', 'ISO-2022-JP', 'Shift_JIS'],
|
|
|
+ 'Korean': ['EUC-KR'],
|
|
|
+ 'Nordic': ['ISO-8859-10'],
|
|
|
+ 'Romanian': ['ISO-8859-16'],
|
|
|
+ 'South European': ['ISO-8859-3'],
|
|
|
+ 'Thai': ['Windows-874'],
|
|
|
+ 'Turkish': ['Windows-1254'],
|
|
|
+ 'Vietnamese': ['Windows-1258'],
|
|
|
+ 'Western': ['ISO-8859-15', 'Windows-1252', 'Macintosh'],
|
|
|
+ }
|
|
|
}
|
|
|
var state = Object.assign({}, defaults)
|
|
|
|
|
|
@@ -27,28 +48,6 @@ var events = {
|
|
|
})
|
|
|
},
|
|
|
|
|
|
- csp: (e) => {
|
|
|
- ;((done) => {
|
|
|
- // ff: webRequest is required permission
|
|
|
- if (/Firefox/.test(navigator.userAgent)) {
|
|
|
- done()
|
|
|
- }
|
|
|
- else {
|
|
|
- var action = state.csp ? 'remove' : 'request'
|
|
|
- chrome.permissions[action]({
|
|
|
- permissions: ['webRequest', 'webRequestBlocking']
|
|
|
- }, done)
|
|
|
- }
|
|
|
- })(() => {
|
|
|
- state.csp = !state.csp
|
|
|
- chrome.runtime.sendMessage({
|
|
|
- message: 'options.csp',
|
|
|
- csp: state.csp,
|
|
|
- })
|
|
|
- m.redraw()
|
|
|
- })
|
|
|
- },
|
|
|
-
|
|
|
origin: {
|
|
|
protocol: (e) => {
|
|
|
state.protocol = state.protocols[e.target.selectedIndex]
|
|
|
@@ -88,22 +87,82 @@ var events = {
|
|
|
})
|
|
|
},
|
|
|
|
|
|
- update: (origin) => (e) => {
|
|
|
- state.origins[origin] = e.target.value
|
|
|
+ refresh: (origin) => () => {
|
|
|
+ chrome.permissions.request({origins: [origin + '/*']})
|
|
|
+ },
|
|
|
+
|
|
|
+ match: (origin) => (e) => {
|
|
|
+ state.origins[origin].match = e.target.value
|
|
|
clearTimeout(state.timeout)
|
|
|
state.timeout = setTimeout(() => {
|
|
|
+ var {match, csp, encoding} = state.origins[origin]
|
|
|
chrome.runtime.sendMessage({
|
|
|
- message: 'origin.update', origin, match: e.target.value
|
|
|
+ message: 'origin.update',
|
|
|
+ origin,
|
|
|
+ options: {match, csp, encoding},
|
|
|
})
|
|
|
}, 750)
|
|
|
},
|
|
|
|
|
|
- refresh: (origin) => () => {
|
|
|
- chrome.permissions.request({origins: [origin + '/*']})
|
|
|
+ csp: (origin) => () => {
|
|
|
+ state.origins[origin].csp = !state.origins[origin].csp
|
|
|
+ var {match, csp, encoding} = state.origins[origin]
|
|
|
+ chrome.runtime.sendMessage({
|
|
|
+ message: 'origin.update',
|
|
|
+ origin,
|
|
|
+ options: {match, csp, encoding},
|
|
|
+ })
|
|
|
+ webRequest.update()
|
|
|
+ webRequest.permission(() => {
|
|
|
+ webRequest.register()
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ encoding: (origin) => (e) => {
|
|
|
+ state.origins[origin].encoding = e.target.value
|
|
|
+ var {match, csp, encoding} = state.origins[origin]
|
|
|
+ chrome.runtime.sendMessage({
|
|
|
+ message: 'origin.update',
|
|
|
+ origin,
|
|
|
+ options: {match, csp, encoding},
|
|
|
+ })
|
|
|
+ webRequest.update()
|
|
|
+ webRequest.permission(() => {
|
|
|
+ webRequest.register()
|
|
|
+ })
|
|
|
},
|
|
|
},
|
|
|
}
|
|
|
|
|
|
+var webRequest = {
|
|
|
+ update: () => {
|
|
|
+ state.intercept = false
|
|
|
+ for (var key in state.origins) {
|
|
|
+ if (state.origins[key].csp || state.origins[key].encoding) {
|
|
|
+ state.intercept = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ permission: (done) => {
|
|
|
+ // ff: webRequest is required permission
|
|
|
+ if (/Firefox/.test(navigator.userAgent)) {
|
|
|
+ done()
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ chrome.permissions[state.intercept ? 'request' : 'remove']({
|
|
|
+ permissions: ['webRequest', 'webRequestBlocking']
|
|
|
+ }, done)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ register: () => {
|
|
|
+ chrome.runtime.sendMessage({
|
|
|
+ message: 'options.intercept',
|
|
|
+ intercept: state.intercept,
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
chrome.extension.isAllowedFileSchemeAccess((isAllowedAccess) => {
|
|
|
state.file = /Firefox/.test(navigator.userAgent)
|
|
|
? true // ff: `Allow access to file URLs` option isn't available
|
|
|
@@ -123,6 +182,9 @@ init()
|
|
|
var oncreate = {
|
|
|
ripple: (vnode) => {
|
|
|
mdc.ripple.MDCRipple.attachTo(vnode.dom)
|
|
|
+ },
|
|
|
+ textfield: (vnode) => {
|
|
|
+ mdc.textfield.MDCTextField.attachTo(vnode.dom)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -132,8 +194,8 @@ var onupdate = {
|
|
|
vnode.dom.classList.toggle('is-checked')
|
|
|
}
|
|
|
},
|
|
|
- csp: (vnode) => {
|
|
|
- if (vnode.dom.classList.contains('is-checked') !== state.csp) {
|
|
|
+ csp: (origin) => (vnode) => {
|
|
|
+ if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].csp) {
|
|
|
vnode.dom.classList.toggle('is-checked')
|
|
|
}
|
|
|
}
|
|
|
@@ -172,13 +234,16 @@ m.mount(document.querySelector('main'), {
|
|
|
protocol + '://'
|
|
|
)
|
|
|
)),
|
|
|
- m('.mdc-text-field m-textfield',
|
|
|
+ m('.mdc-text-field m-textfield', {
|
|
|
+ oncreate: oncreate.textfield,
|
|
|
+ },
|
|
|
m('input.mdc-text-field__input', {
|
|
|
type: 'text',
|
|
|
value: state.origin,
|
|
|
onchange: events.origin.name,
|
|
|
placeholder: 'raw.githubusercontent.com'
|
|
|
- })
|
|
|
+ }),
|
|
|
+ m('.mdc-line-ripple')
|
|
|
),
|
|
|
m('button.mdc-button mdc-button--raised m-button', {
|
|
|
oncreate: oncreate.ripple,
|
|
|
@@ -214,24 +279,8 @@ m.mount(document.querySelector('main'), {
|
|
|
)
|
|
|
),
|
|
|
|
|
|
- // csp
|
|
|
- m('label.mdc-switch m-switch', {
|
|
|
- onupdate: onupdate.csp,
|
|
|
- title: 'Disable Content Security Policy (CSP)'
|
|
|
- },
|
|
|
- m('input.mdc-switch__native-control', {
|
|
|
- type: 'checkbox',
|
|
|
- checked: state.csp,
|
|
|
- onchange: events.csp
|
|
|
- }),
|
|
|
- m('.mdc-switch__background', m('.mdc-switch__knob')),
|
|
|
- m('span.mdc-switch-label',
|
|
|
- 'Disable ',
|
|
|
- m('code', 'Content Security Policy'),
|
|
|
- )
|
|
|
- ),
|
|
|
-
|
|
|
- m('ul.mdc-elevation--z2 m-list',
|
|
|
+ // origins
|
|
|
+ m('ul.m-list',
|
|
|
Object.keys(state.origins).sort().map((origin) =>
|
|
|
(
|
|
|
(
|
|
|
@@ -241,33 +290,104 @@ m.mount(document.querySelector('main'), {
|
|
|
)
|
|
|
|| origin !== 'file://' || null
|
|
|
) &&
|
|
|
- m('li',
|
|
|
- m('span', origin.replace(/^(\*|file|http(s)?).*/, '$1')),
|
|
|
- m('span', origin.replace(/^(\*|file|http(s)?):\/\//, '')),
|
|
|
- m('.mdc-text-field m-textfield', {
|
|
|
- oncreate: oncreate.textfield
|
|
|
+ m('li.mdc-elevation--z2', {
|
|
|
+ class: state.origins[origin].expanded ? 'm-expanded' : null,
|
|
|
+ },
|
|
|
+ m('.m-summary', {
|
|
|
+ onclick: (e) => state.origins[origin].expanded = !state.origins[origin].expanded
|
|
|
},
|
|
|
- m('input.mdc-text-field__input', {
|
|
|
- type: 'text',
|
|
|
- onkeyup: events.origin.update(origin),
|
|
|
- value: state.origins[origin],
|
|
|
+ m('.m-origin', origin),
|
|
|
+ m('.m-options',
|
|
|
+ state.origins[origin].match !== state.match ? m('span', 'match') : null,
|
|
|
+ state.origins[origin].csp ? m('span', 'csp') : null,
|
|
|
+ state.origins[origin].encoding ? m('span', 'encoding') : null,
|
|
|
+ ),
|
|
|
+ m('i.material-icons', {
|
|
|
+ class: state.origins[origin].expanded ? 'icon-arrow-up' : 'icon-arrow-down'
|
|
|
})
|
|
|
),
|
|
|
- (origin !== 'file://' || null) &&
|
|
|
- m('span',
|
|
|
- m('button.mdc-button', {
|
|
|
- oncreate: oncreate.ripple,
|
|
|
- onclick: events.origin.refresh(origin),
|
|
|
- title: 'Refresh'
|
|
|
- },
|
|
|
- m('i.material-icons icon-refresh')
|
|
|
+ m('.m-content',
|
|
|
+ // match
|
|
|
+ m('.m-option m-match',
|
|
|
+ m('.m-name', m('span', 'match')),
|
|
|
+ m('.m-control',
|
|
|
+ m('.mdc-text-field m-textfield', {
|
|
|
+ oncreate: oncreate.textfield
|
|
|
+ },
|
|
|
+ m('input.mdc-text-field__input', {
|
|
|
+ type: 'text',
|
|
|
+ onkeyup: events.origin.match(origin),
|
|
|
+ value: state.origins[origin].match,
|
|
|
+ }),
|
|
|
+ m('.mdc-line-ripple')
|
|
|
+ )
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ // csp
|
|
|
+ (origin !== 'file://' || null) &&
|
|
|
+ m('.m-option m-csp',
|
|
|
+ m('.m-name', m('span', 'csp')),
|
|
|
+ m('.m-control',
|
|
|
+ m('label.mdc-switch m-switch', {
|
|
|
+ onupdate: onupdate.csp(origin),
|
|
|
+ },
|
|
|
+ m('input.mdc-switch__native-control', {
|
|
|
+ type: 'checkbox',
|
|
|
+ checked: state.origins[origin].csp,
|
|
|
+ onchange: events.origin.csp(origin)
|
|
|
+ }),
|
|
|
+ m('.mdc-switch__background', m('.mdc-switch__knob')),
|
|
|
+ m('span.mdc-switch-label',
|
|
|
+ 'Disable ',
|
|
|
+ m('code', 'Content Security Policy'),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ // encoding
|
|
|
+ (origin !== 'file://' || null) &&
|
|
|
+ m('.m-option m-encoding',
|
|
|
+ m('.m-name', m('span', 'encoding')),
|
|
|
+ m('.m-control',
|
|
|
+ m('select.mdc-elevation--z2 m-select', {
|
|
|
+ onchange: events.origin.encoding(origin),
|
|
|
+ },
|
|
|
+ m('option', {
|
|
|
+ value: '',
|
|
|
+ selected: state.origins[origin].encoding === ''
|
|
|
+ },
|
|
|
+ 'auto'
|
|
|
+ ),
|
|
|
+ Object.keys(state.encodings).map((label) =>
|
|
|
+ m('optgroup', {label}, state.encodings[label].map((encoding) =>
|
|
|
+ m('option', {
|
|
|
+ value: encoding,
|
|
|
+ selected: state.origins[origin].encoding === encoding
|
|
|
+ },
|
|
|
+ encoding
|
|
|
+ )
|
|
|
+ ))
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
),
|
|
|
- m('button.mdc-button', {
|
|
|
- oncreate: oncreate.ripple,
|
|
|
- onclick: events.origin.remove(origin),
|
|
|
- title: 'Remove'
|
|
|
- },
|
|
|
- m('i.material-icons icon-remove')
|
|
|
+ // refresh/remove
|
|
|
+ (origin !== 'file://' || null) &&
|
|
|
+ m('.m-footer',
|
|
|
+ m('span',
|
|
|
+ m('button.mdc-button mdc-button--raised m-button', {
|
|
|
+ oncreate: oncreate.ripple,
|
|
|
+ onclick: events.origin.refresh(origin)
|
|
|
+ },
|
|
|
+ 'Refresh'
|
|
|
+ ),
|
|
|
+ m('button.mdc-button mdc-button--raised m-button', {
|
|
|
+ oncreate: oncreate.ripple,
|
|
|
+ onclick: events.origin.remove(origin)
|
|
|
+ },
|
|
|
+ 'Remove'
|
|
|
+ )
|
|
|
+ )
|
|
|
)
|
|
|
)
|
|
|
)
|