mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 06:58:14 -05:00
Implement proxy script for WebExtensions. #102.
This commit is contained in:
parent
d65c29f34d
commit
f421810959
@ -296,6 +296,7 @@ refreshActivePageIfEnabled = ->
|
||||
chrome.tabs.reload(tabs[0].id, {bypassCache: true})
|
||||
|
||||
chrome.runtime.onMessage.addListener (request, sender, respond) ->
|
||||
return unless request and request.method
|
||||
options.ready.then ->
|
||||
target = options
|
||||
method = target[request.method]
|
||||
|
@ -1,3 +1,4 @@
|
||||
path = require('path')
|
||||
module.exports =
|
||||
index:
|
||||
files:
|
||||
@ -26,3 +27,17 @@ module.exports =
|
||||
browserifyOptions:
|
||||
extensions: '.coffee'
|
||||
standalone: 'OmegaTargetChromium'
|
||||
omega_webext_proxy_script:
|
||||
files:
|
||||
'build/js/omega_webext_proxy_script.min.js':
|
||||
'omega_webext_proxy_script.js'
|
||||
options:
|
||||
alias:
|
||||
'omega-pac': 'omega-pac/omega_pac.min.js'
|
||||
plugin:
|
||||
if process.env.BUILD == 'release'
|
||||
[['minifyify', {map: false}]]
|
||||
else
|
||||
[]
|
||||
browserifyOptions:
|
||||
noParse: [require.resolve('omega-pac/omega_pac.min.js')]
|
||||
|
@ -23,6 +23,9 @@ module.exports =
|
||||
src:
|
||||
files: ['src/**/*.coffee']
|
||||
tasks: ['coffeelint:src', 'browserify', 'copy:target_self']
|
||||
browserify_omega_webext_proxy_script:
|
||||
files: ['omega_webext_proxy_script.js']
|
||||
tasks: ['browserify:omega_webext_proxy_script']
|
||||
coffee:
|
||||
files: ['src/**/*.coffee', '*.coffee']
|
||||
tasks: ['coffeelint:src', 'coffee', 'copy:target_self']
|
||||
|
113
omega-target-chromium-extension/omega_webext_proxy_script.js
Normal file
113
omega-target-chromium-extension/omega_webext_proxy_script.js
Normal file
@ -0,0 +1,113 @@
|
||||
FindProxyForURL = (function () {
|
||||
var OmegaPac = require('omega-pac');
|
||||
var options = {};
|
||||
var state = {};
|
||||
var activeProfile = null;
|
||||
var fallbackResult = 'DIRECT';
|
||||
var pacCache = {};
|
||||
|
||||
init();
|
||||
|
||||
return FindProxyForURL;
|
||||
|
||||
function FindProxyForURL(url, host, details) {
|
||||
if (!activeProfile) {
|
||||
warn('Warning: Proxy script not initialized on handling: ' + url);
|
||||
return fallbackResult;
|
||||
}
|
||||
// Moz: Neither path or query is included url regardless of scheme for now.
|
||||
// This is even more strict than Chromium restricting HTTPS URLs.
|
||||
// Therefore, it leads to different behavior than the icon and badge.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1337001
|
||||
var request = OmegaPac.Conditions.requestFromUrl(url);
|
||||
var profile = activeProfile;
|
||||
var matchResult, next;
|
||||
while (profile) {
|
||||
matchResult = OmegaPac.Profiles.match(profile, request)
|
||||
if (!matchResult) {
|
||||
if (profile.profileType === 'DirectProfile') {
|
||||
return 'DIRECT';
|
||||
} else if (profile.pacScript) {
|
||||
return runPacProfile(profile.pacScript);
|
||||
} else {
|
||||
warn('Warning: Unsupported profile: ' + profile.profileType);
|
||||
return fallbackResult;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(matchResult)) {
|
||||
next = matchResult[0];
|
||||
// TODO: Maybe also return user/pass if Mozilla supports it or it ends
|
||||
// up standardized in WebExtensions in the future.
|
||||
// MOZ: Mozilla has a bug tracked for user/pass in PAC return value.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1319641
|
||||
if (next.charCodeAt(0) !== 43) {
|
||||
// MOZ: HTTPS proxies are supported under the prefix PROXY.
|
||||
// https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/ProxyScriptContext.jsm#180
|
||||
return next.replace(/HTTPS /g, 'PROXY ');
|
||||
}
|
||||
} else if (matchResult.profileName) {
|
||||
next = OmegaPac.Profiles.nameAsKey(matchResult.profileName)
|
||||
} else {
|
||||
return fallbackResult;
|
||||
}
|
||||
profile = OmegaPac.Profiles.byKey(next, options)
|
||||
}
|
||||
warn('Warning: Cannot find profile: ' + next);
|
||||
return fallbackResult;
|
||||
}
|
||||
|
||||
function runPacProfile(profile) {
|
||||
var cached = pacCache[profile.name];
|
||||
if (!cached || cached.revision !== profile.revision) {
|
||||
// https://github.com/FelisCatus/SwitchyOmega/issues/390
|
||||
var body = ';\n' + profile.pacScript + '\n\n/* End of PAC */;'
|
||||
body += 'return FindProxyForURL';
|
||||
var func = new Function(body).call(this);
|
||||
|
||||
if (typeof func !== 'function') {
|
||||
warn('Warning: Cannot compile pacScript: ' + profile.name);
|
||||
func = function() { return fallbackResult; };
|
||||
}
|
||||
cached = {func: func, revision: profile.revision}
|
||||
pacCache[cacheKey] = cached;
|
||||
}
|
||||
try {
|
||||
// Moz: Most scripts probably won't run without global PAC functions.
|
||||
// Example: dnsDomainIs, shExpMatch, isInNet.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1353510
|
||||
return cached.func.call(this);
|
||||
} catch (ex) {
|
||||
warn('Warning: Error occured in pacScript: ' + profile.name, ex);
|
||||
return fallbackResult;
|
||||
}
|
||||
}
|
||||
|
||||
function warn(message, error) {
|
||||
// We don't have console here and alert is not implemented.
|
||||
// Throwing and messaging seems to be the only ways to communicate.
|
||||
// MOZ: alert(): https://bugzilla.mozilla.org/show_bug.cgi?id=1353510
|
||||
browser.runtime.sendMessage({
|
||||
event: 'proxyScriptLog',
|
||||
message: message,
|
||||
error: error,
|
||||
level: 'warn',
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
browser.runtime.sendMessage({event: 'proxyScriptLoaded'});
|
||||
browser.runtime.onMessage.addListener(function(message) {
|
||||
if (message.event === 'proxyScriptStateChanged') {
|
||||
state = message.state;
|
||||
options = message.options;
|
||||
if (!state.currentProfileName) {
|
||||
activeProfile = state.tempProfile;
|
||||
} else {
|
||||
activeProfile = OmegaPac.Profiles.byName(state.currentProfileName,
|
||||
options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "__MSG_manifest_app_name__",
|
||||
"version": "2.4.5",
|
||||
"version": "2.4.7",
|
||||
"description": "__MSG_manifest_app_description__",
|
||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhwZJT76btQ04EEMOFtZPLESD1TmSVjbLjs0OyesD9Ht8YllFPfJ3qmtbSQGVuvmxH1GK/jUO2QcEWb8bHuOjoRlq20fi5j5Aq90O8FKET+y5D8PxCyi3WmnquiEwaE5cNmaCsw/G2JlO+bZOtdQ/QKOvMxBAegABYimEGfSvCMVUEvpymys0gBhLoch72zPAiJUBkf0z8BtjYTueMRcRXkrSeRPLygUDQnZ1TkQWMYYBp/zqpD5ggxytAklEMQzR9Hn0lqu5s7iuUAgihbysPn/8Wh00Zj5FySpK//KcpG3JS7UWxC28oSt8z5ZR3YimnX+HX3P36V0mC1pgM4o7wIDAQAB",
|
||||
"icons": {
|
||||
@ -43,11 +43,19 @@
|
||||
"ftp://*/*",
|
||||
"<all_urls>"
|
||||
],
|
||||
"content_security_policy":
|
||||
"script-src 'self' 'unsafe-eval'; object-src 'self';",
|
||||
"commands": {
|
||||
"_execute_browser_action": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+O"
|
||||
}
|
||||
}
|
||||
},
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "switchyomega@example.com",
|
||||
"strict_min_version": "55.0a1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,13 @@
|
||||
"heap": "^0.2.6",
|
||||
"omega-target": "../omega-target",
|
||||
"omega-web": "../omega-web",
|
||||
"omega-pac": "../omega-pac",
|
||||
"xhr": "^1.16.0"
|
||||
},
|
||||
"browser": {
|
||||
"omega-target": "./omega_target_shim.js"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "npm link omega-target && npm link omega-web"
|
||||
"dev": "npm link omega-target && npm link omega-web && npm link omega-pac"
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,14 @@ class ChromeOptions extends OmegaTarget.Options
|
||||
proxySettings.onChange.addListener @_proxyChangeListener
|
||||
@_proxyChangeWatchers.push(callback)
|
||||
applyProfileProxy: (profile, meta) ->
|
||||
if chrome?.proxy?.settings?
|
||||
return @applyProfileProxySettings(profile, meta)
|
||||
else if browser?.proxy?.registerProxyScript?
|
||||
return @applyProfileProxyScript(profile, meta)
|
||||
else
|
||||
ex = new Error('Your browser does not support proxy settings!')
|
||||
return Promise.reject ex
|
||||
applyProfileProxySettings: (profile, meta) ->
|
||||
meta ?= profile
|
||||
if profile.profileType == 'SystemProfile'
|
||||
# Clear proxy settings, returning proxy control to Chromium.
|
||||
@ -171,6 +179,71 @@ class ChromeOptions extends OmegaTarget.Options
|
||||
proxySettings.get {}, @_proxyChangeListener
|
||||
return
|
||||
|
||||
_proxyScriptUrl: 'js/omega_webext_proxy_script.min.js'
|
||||
_proxyScriptDisabled: false
|
||||
applyProfileProxyScript: (profile, state) ->
|
||||
state = state ? {}
|
||||
state.currentProfileName = profile.name
|
||||
if profile.name == ''
|
||||
state.tempProfile = @_tempProfile
|
||||
if profile.profileType == 'SystemProfile'
|
||||
# MOZ: SystemProfile cannot be done now due to lack of "PASS" support.
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1319634
|
||||
# In the mean time, let's just set an invalid script to unregister it.
|
||||
browser.proxy.registerProxyScript('js/omega_invalid_proxy_script.min.js')
|
||||
@_proxyScriptDisabled = true
|
||||
else
|
||||
@_proxyScriptState = state
|
||||
@_initWebextProxyScript().then => @_proxyScriptStateChanged()
|
||||
# Proxy authentication is not covered in WebExtensions standard now.
|
||||
# MOZ: Mozilla has a bug tracked to implemented it in PAC return value.
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1319641
|
||||
return Promise.resolve()
|
||||
|
||||
_proxyScriptInitialized: false
|
||||
_proxyScriptState: {}
|
||||
_initWebextProxyScript: ->
|
||||
if not @_proxyScriptInitialized
|
||||
browser.proxy.onProxyError.addListener (err) =>
|
||||
if err and err.message.indexOf('Invalid Proxy Rule: DIRECT') >= 0
|
||||
# MOZ: DIRECT cannot be correctly parsed due to a bug. Even though it
|
||||
# throws, it actually falls back to direct connection so it works.
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1355198
|
||||
return
|
||||
@log.error(err)
|
||||
browser.runtime.onMessage.addListener (message) =>
|
||||
return unless message.event == 'proxyScriptLog'
|
||||
if message.level == 'error'
|
||||
@log.error(message)
|
||||
else if message.level == 'warn'
|
||||
@log.warn(message)
|
||||
else
|
||||
@log.log(message)
|
||||
|
||||
if not @_proxyScriptInitialized or @_proxyScriptDisabled
|
||||
promise = new Promise (resolve) ->
|
||||
onMessage = (message) ->
|
||||
return unless message.event == 'proxyScriptLoaded'
|
||||
resolve()
|
||||
browser.runtime.onMessage.removeListener onMessage
|
||||
return
|
||||
browser.runtime.onMessage.addListener onMessage
|
||||
browser.proxy.registerProxyScript(@_proxyScriptUrl)
|
||||
@_proxyScriptDisabled = false
|
||||
else
|
||||
promise = Promise.resolve()
|
||||
@_proxyScriptInitialized = true
|
||||
return promise
|
||||
|
||||
_proxyScriptStateChanged: ->
|
||||
browser.runtime.sendMessage({
|
||||
event: 'proxyScriptStateChanged'
|
||||
state: @_proxyScriptState
|
||||
options: @_options
|
||||
}, {
|
||||
toProxyScript: true
|
||||
})
|
||||
|
||||
_quickSwitchInit: false
|
||||
_quickSwitchContextMenuCreated: false
|
||||
_quickSwitchCanEnable: false
|
||||
|
Loading…
Reference in New Issue
Block a user