mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 06:58:14 -05:00
add PAC Profiles support on Firefox PC #74
This commit is contained in:
parent
0fd0a945b2
commit
ae7c07cb4c
@ -1,8 +1,14 @@
|
||||
FirefoxProxyImpl = require('./proxy_impl_firefox')
|
||||
ListenerProxyImpl = require('./proxy_impl_listener')
|
||||
SettingsProxyImpl = require('./proxy_impl_settings')
|
||||
ScriptProxyImpl = require('./proxy_impl_script')
|
||||
|
||||
exports.proxyImpls = [ListenerProxyImpl, ScriptProxyImpl, SettingsProxyImpl]
|
||||
exports.proxyImpls = [
|
||||
FirefoxProxyImpl,
|
||||
ListenerProxyImpl,
|
||||
ScriptProxyImpl,
|
||||
SettingsProxyImpl
|
||||
]
|
||||
exports.getProxyImpl = (log) ->
|
||||
for Impl in exports.proxyImpls
|
||||
if Impl.isSupported()
|
||||
|
@ -0,0 +1,121 @@
|
||||
OmegaTarget = require('omega-target')
|
||||
# The browser only accepts native promises as onRequest return values.
|
||||
# DO NOT USE Bluebird Promises here!
|
||||
NativePromise = Promise ? null
|
||||
ProxyImpl = require('./proxy_impl')
|
||||
|
||||
blobUrl = null
|
||||
|
||||
class FirefoxProxyImpl extends ProxyImpl
|
||||
@isSupported: ->
|
||||
# chrome.contextMenus check is Android or PC,
|
||||
# browser.proxy.settings doesn't support on Firefox Android
|
||||
return !!chrome.contextMenus and
|
||||
Promise? and
|
||||
browser?.proxy?.onRequest? and
|
||||
browser?.proxy?.settings
|
||||
features: ['fullUrl', 'socks5Auth']
|
||||
constructor: ->
|
||||
super(arguments...)
|
||||
@_optionsReady = new NativePromise (resolve) =>
|
||||
@_optionsReadyCallback = resolve
|
||||
# We want to register listeners early so that it can start blocking requests
|
||||
# when starting the browser & extension, returning correct results later.
|
||||
@_initRequestListeners()
|
||||
_initRequestListeners: ->
|
||||
browser.proxy.onRequest.addListener(@onRequest.bind(this),
|
||||
{urls: ["<all_urls>"]})
|
||||
browser.proxy.onError.addListener(@onError.bind(this))
|
||||
watchProxyChange: (callback) -> null
|
||||
applyProfile: (profile, state, options) ->
|
||||
if blobUrl
|
||||
URL.revokeObjectURL(blobUrl)
|
||||
if browser.extension.isAllowedIncognitoAccess()
|
||||
if profile.profileType is 'DirectProfile'
|
||||
browser.proxy.settings.set({
|
||||
value: {
|
||||
proxyType: 'none'
|
||||
}
|
||||
})
|
||||
else if profile.profileType is 'SystemProfile'
|
||||
# Clear proxy settings, returning proxy control to Firefox.
|
||||
browser.proxy.settings.clear({})
|
||||
else
|
||||
pacScript = @getProfilePacScript(profile, state, options)
|
||||
blob = new Blob(
|
||||
[pacScript],
|
||||
{ type: 'application/x-ns-proxy-autoconfig' })
|
||||
blobUrl = URL.createObjectURL(blob)
|
||||
browser.proxy.settings.set({
|
||||
value: {
|
||||
proxyType: 'autoConfig',
|
||||
autoConfigUrl: blobUrl
|
||||
}
|
||||
})
|
||||
@_options = options
|
||||
@_profile = profile
|
||||
@_optionsReadyCallback?()
|
||||
@_optionsReadyCallback = null
|
||||
return @setProxyAuth(profile, options)
|
||||
onRequest: (requestDetails) ->
|
||||
return undefined if browser.extension.isAllowedIncognitoAccess()
|
||||
# TODO 将来可以在这里实现按标签进行代理控制功能
|
||||
#return undefined
|
||||
# The browser only recognizes native promises return values, not Bluebird.
|
||||
return NativePromise.resolve(@_optionsReady.then(=>
|
||||
request = OmegaPac.Conditions.requestFromUrl(requestDetails.url)
|
||||
profile = @_profile
|
||||
while profile
|
||||
result = OmegaPac.Profiles.match(profile, request)
|
||||
if not result
|
||||
switch profile.profileType
|
||||
when 'DirectProfile'
|
||||
return {type: 'direct'}
|
||||
when 'SystemProfile'
|
||||
# Returning undefined means using the default proxy from previous.
|
||||
# https://hg.mozilla.org/mozilla-central/rev/9f0ee2f582a2#l1.337
|
||||
return undefined
|
||||
else
|
||||
throw new Error('Unsupported profile: ' + profile.profileType)
|
||||
if Array.isArray(result)
|
||||
proxy = result[2]
|
||||
auth = result[3]
|
||||
return @proxyInfo(proxy, auth) if proxy
|
||||
next = result[0]
|
||||
else if result.profileName
|
||||
next = OmegaPac.Profiles.nameAsKey(result.profileName)
|
||||
else
|
||||
break
|
||||
profile = OmegaPac.Profiles.byKey(next, @_options)
|
||||
|
||||
throw new Error('Profile not found: ' + next)
|
||||
))
|
||||
onError: (error) ->
|
||||
@log.error(error)
|
||||
proxyInfo: (proxy, auth) ->
|
||||
proxyInfo =
|
||||
type: proxy.scheme
|
||||
host: proxy.host
|
||||
port: proxy.port
|
||||
if proxyInfo.type == 'socks5'
|
||||
# MOZ: SOCKS5 proxies should be specified as "type": "socks".
|
||||
# https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/proxy/ProxyInfo
|
||||
proxyInfo.type = 'socks'
|
||||
if auth
|
||||
# Username & password here are only available for SOCKS5.
|
||||
# https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/proxy/ProxyInfo
|
||||
# HTTP proxy auth must be handled via webRequest.onAuthRequired.
|
||||
proxyInfo.username = auth.username
|
||||
proxyInfo.password = auth.password
|
||||
if proxyInfo.type == 'socks'
|
||||
# Enable SOCKS remote DNS.
|
||||
# TODO(catus): Maybe allow the users to configure this?
|
||||
proxyInfo.proxyDNS = true
|
||||
|
||||
# TODO(catus): Maybe allow proxyDNS for socks4? Server may support SOCKS4a.
|
||||
# It cannot default to true though, since SOCKS4 servers that does not have
|
||||
# the SOCKS4a extension may simply refuse to work.
|
||||
|
||||
return [proxyInfo]
|
||||
|
||||
module.exports = FirefoxProxyImpl
|
@ -2,10 +2,48 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<title>Permissions required</title>
|
||||
<style>
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,body{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.incognito-access-img-container{
|
||||
margin-right: 20px;
|
||||
}
|
||||
.incognito-access-img{
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
border: 2px solid;
|
||||
border-radius: 5px;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button id="grant-permissions-btn">grant site permissions</button>
|
||||
<body style="opacity: 0">
|
||||
<ol style="margin-right: 20px;">
|
||||
<li class="site-permissions-required">
|
||||
<div>
|
||||
<p>
|
||||
<strong>Site permissions is required.</strong> The Api <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/onRequest">proxy.onRequest</a> requires site permissions. <button id="grant-permissions-btn">grant site permissions</button>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="incognito-access-required">
|
||||
<div>
|
||||
<p><strong>IncognitoAccess is required.</strong>According to <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/settings" target="_blank"/>Firefox API</a> requirements.Changing proxy settings requires private browsing window access.</p>
|
||||
<div class="incognito-access-img-container">
|
||||
<img class="incognito-access-img" src="./img/AllowedIncognitoAccess.png"/>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
<dialog opened class="loading-dialog">loading...</dialog>
|
||||
<script src="../js/omega_target_popup.js"></script>
|
||||
<script src="js/style.js"></script>
|
||||
<script src="js/grant_permissions.js"></script>
|
||||
|
BIN
omega-web/src/popup/img/AllowedIncognitoAccess.png
Normal file
BIN
omega-web/src/popup/img/AllowedIncognitoAccess.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 163 KiB |
@ -1,9 +1,32 @@
|
||||
|
||||
window.addEventListener('load', async function(){
|
||||
const dialogEl = document.querySelector('.loading-dialog')
|
||||
dialogEl.showModal()
|
||||
dialogEl.addEventListener('cancel', (e)=>e.preventDefault())
|
||||
const permissionValue = {origins: ["<all_urls>"]}
|
||||
const hasPermission = await browser.permissions.contains(permissionValue);
|
||||
const isAllowedIncognitoAccess = !chrome.contextMenus || await browser.extension.isAllowedIncognitoAccess()
|
||||
if (hasPermission) {
|
||||
document.querySelector('.site-permissions-required').remove()
|
||||
}
|
||||
if (isAllowedIncognitoAccess) {
|
||||
document.querySelector('.incognito-access-required').remove()
|
||||
}
|
||||
dialogEl.remove()
|
||||
document.body.style.opacity = '';
|
||||
}, {once: true})
|
||||
const btn = document.querySelector('#grant-permissions-btn')
|
||||
btn.onclick = async ()=>{
|
||||
const permissionValue = {origins: ["<all_urls>"]}
|
||||
const hasPermission = await browser.permissions.request(permissionValue);
|
||||
const isAllowedIncognitoAccess = !chrome.contextMenus || await browser.extension.isAllowedIncognitoAccess()
|
||||
if (hasPermission) {
|
||||
document.querySelector('.site-permissions-required')?.remove()
|
||||
}
|
||||
if (isAllowedIncognitoAccess) {
|
||||
document.querySelector('.incognito-access-required')?.remove()
|
||||
}
|
||||
if (hasPermission && isAllowedIncognitoAccess) {
|
||||
location.href = 'index.html'
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,14 @@ $script('../js/omega_target_popup.js', 'om-target', function() {
|
||||
}
|
||||
const permissionValue = {origins: ["<all_urls>"]}
|
||||
if (globalThis.browser && browser.proxy && browser.proxy.onRequest){
|
||||
chrome.permissions.contains(permissionValue).then((hasPermission)=>{
|
||||
if (!hasPermission) {
|
||||
location.href = 'grant_permissions.html'
|
||||
} else {
|
||||
Promise.all([browser.permissions.contains(permissionValue), browser.extension.isAllowedIncognitoAccess()])
|
||||
.then(([sitePermissions, isAllowedIncognitoAccess])=>{
|
||||
// chrome.contextMenus check is Android or PC,
|
||||
// browser.proxy.settings doesn't support Android
|
||||
if (sitePermissions && (!chrome.contextMenus || isAllowedIncognitoAccess)) {
|
||||
init();
|
||||
} else {
|
||||
location.href = 'grant_permissions.html'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user