mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-02-08 13:38:14 -05:00
252 lines
8.1 KiB
CoffeeScript
252 lines
8.1 KiB
CoffeeScript
OmegaTarget = require('omega-target')
|
|
OmegaPac = OmegaTarget.OmegaPac
|
|
Promise = OmegaTarget.Promise
|
|
xhr = Promise.promisify(require('xhr'))
|
|
url = require('url')
|
|
chromeApiPromisifyAll = require('./chrome_api')
|
|
proxySettings = chromeApiPromisifyAll(chrome.proxy.settings)
|
|
parseExternalProfile = require('./parse_external_profile')
|
|
|
|
class ChromeOptions extends OmegaTarget.Options
|
|
parseExternalProfile: (details) ->
|
|
parseExternalProfile(details, @_options, @_fixedProfileConfig.bind(this))
|
|
|
|
fetchUrl: (dest_url, opt_bypass_cache) ->
|
|
if opt_bypass_cache
|
|
parsed = url.parse(dest_url, true)
|
|
parsed.search = undefined
|
|
parsed.query['_'] = Date.now()
|
|
dest_url = url.format(parsed)
|
|
xhr(dest_url).get(1)
|
|
|
|
updateProfile: (args...) ->
|
|
super(args...).then (results) ->
|
|
error = false
|
|
for own profileName, result of results
|
|
if result instanceof Error
|
|
error = true
|
|
break
|
|
if error
|
|
# TODO(catus): Find a better way to notify the user.
|
|
###
|
|
@setBadge(
|
|
text: '!'
|
|
color: '#faa732'
|
|
title: chrome.i18n.getMessage('browserAction_titleDownloadFail')
|
|
)
|
|
###
|
|
return results
|
|
|
|
_proxyNotControllable: null
|
|
proxyNotControllable: -> @_proxyNotControllable
|
|
setProxyNotControllable: (reason) ->
|
|
@_proxyNotControllable = reason
|
|
if reason
|
|
@_state.set({'proxyNotControllable': reason})
|
|
@setBadge()
|
|
else
|
|
@_state.remove(['proxyNotControllable'])
|
|
@clearBadge()
|
|
|
|
_badgeTitle: null
|
|
setBadge: (options) ->
|
|
if not options
|
|
options =
|
|
if @_proxyNotControllable
|
|
text: '='
|
|
color: '#da4f49'
|
|
else
|
|
text: '?'
|
|
color: '#49afcd'
|
|
chrome.browserAction.setBadgeText(text: options.text)
|
|
chrome.browserAction.setBadgeBackgroundColor(color: options.color)
|
|
if options.title
|
|
@_badgeTitle = options.title
|
|
chrome.browserAction.setTitle(title: options.title)
|
|
else
|
|
@_badgeTitle = null
|
|
clearBadge: ->
|
|
if @_badgeTitle
|
|
@currentProfileChanged('clearBadge')
|
|
if @_proxyNotControllable
|
|
@setBadge()
|
|
else
|
|
chrome.browserAction.setBadgeText(text: '')
|
|
return
|
|
|
|
_fixedProfileConfig: (profile) ->
|
|
config = {}
|
|
config['mode'] = 'fixed_servers'
|
|
rules = {}
|
|
protocols = ['proxyForHttp', 'proxyForHttps', 'proxyForFtp']
|
|
protocolProxySet = false
|
|
for protocol in protocols when profile[protocol]?
|
|
rules[protocol] = profile[protocol]
|
|
protocolProxySet = true
|
|
|
|
if profile.fallbackProxy
|
|
if profile.fallbackProxy.scheme == 'http'
|
|
# Chromium does not allow HTTP proxies in 'fallbackProxy'.
|
|
if not protocolProxySet
|
|
# Use 'singleProxy' if no proxy is configured for other protocols.
|
|
rules['singleProxy'] = profile.fallbackProxy
|
|
else
|
|
# Try to set the proxies of all possible protocols.
|
|
for protocol in protocols
|
|
rules[protocol] ?= profile.fallbackProxy
|
|
else
|
|
rules['fallbackProxy'] = profile.fallbackProxy
|
|
else if not protocolProxySet
|
|
config['mode'] = 'direct'
|
|
|
|
if config['mode'] != 'direct'
|
|
rules['bypassList'] = profile.bypassList.map((b) -> b.pattern)
|
|
config['rules'] = rules
|
|
return config
|
|
|
|
_proxyChangeWatchers: []
|
|
_proxyChangeListener: null
|
|
watchProxyChange: (callback) ->
|
|
if not @_proxyChangeListener?
|
|
@_proxyChangeListener = (details) =>
|
|
for watcher in @_proxyChangeWatchers
|
|
watcher(details)
|
|
chrome.proxy.settings.onChange.addListener @_proxyChangeListener
|
|
@_proxyChangeWatchers.push(callback)
|
|
applyProfileProxy: (profile, meta) ->
|
|
meta ?= profile
|
|
if profile.profileType == 'SystemProfile'
|
|
# Clear proxy settings, returning proxy control to Chromium.
|
|
return proxySettings.clearAsync({}).then =>
|
|
chrome.proxy.settings.get {}, @_proxyChangeListener
|
|
return
|
|
config = {}
|
|
if profile.profileType == 'DirectProfile'
|
|
config['mode'] = 'direct'
|
|
else if profile.profileType == 'PacProfile'
|
|
config['mode'] = 'pac_script'
|
|
config['pacScript'] = if profile.pacUrl
|
|
url: profile.pacUrl
|
|
mandatory: true
|
|
else
|
|
data: profile.pacScript
|
|
mandatory: true
|
|
else if profile.profileType == 'FixedProfile'
|
|
config = @_fixedProfileConfig(profile)
|
|
else
|
|
config['mode'] = 'pac_script'
|
|
config['pacScript'] =
|
|
data: null
|
|
mandatory: true
|
|
setPacScript = @pacForProfile(profile).then (script) ->
|
|
profileName = OmegaPac.PacGenerator.ascii(JSON.stringify(meta.name))
|
|
profileName = profileName.replace(/\*/g, '\\u002a')
|
|
profileName = profileName.replace(/\\/g, '\\u002f')
|
|
prefix = "/*OmegaProfile*#{profileName}*#{meta.revision}*/"
|
|
config['pacScript'].data = prefix + script
|
|
return
|
|
setPacScript ?= Promise.resolve()
|
|
setPacScript.then(->
|
|
proxySettings.setAsync({value: config})
|
|
).then =>
|
|
chrome.proxy.settings.get {}, @_proxyChangeListener
|
|
return
|
|
|
|
_quickSwitchInit: false
|
|
setQuickSwitch: (quickSwitch) ->
|
|
if quickSwitch
|
|
chrome.browserAction.setPopup({popup: ''})
|
|
if not @_quickSwitchInit
|
|
@_quickSwitchInit = true
|
|
chrome.browserAction.onClicked.addListener (tab) =>
|
|
@clearBadge()
|
|
profiles = @_options['-quickSwitchProfiles']
|
|
index = profiles.indexOf(@_currentProfileName)
|
|
index = (index + 1) % profiles.length
|
|
@applyProfile(profiles[index]).then =>
|
|
if @_options['-refreshOnProfileChange']
|
|
if tab.url and tab.url.indexOf('chrome') != 0
|
|
chrome.tabs.reload(tab.id)
|
|
else
|
|
chrome.browserAction.setPopup({popup: 'popup.html'})
|
|
Promise.resolve()
|
|
|
|
_alarms: null
|
|
schedule: (name, periodInMinutes, callback) ->
|
|
name = 'omega.' + name
|
|
if not _alarms?
|
|
@_alarms = {}
|
|
chrome.alarms.onAlarm.addListener (alarm) =>
|
|
@_alarms[alarm.name]?()
|
|
if periodInMinutes < 0
|
|
delete @_alarms[name]
|
|
chrome.alarms.clear(name)
|
|
else
|
|
@_alarms[name] = callback
|
|
chrome.alarms.create(name, {
|
|
periodInMinutes: periodInMinutes
|
|
})
|
|
Promise.resolve()
|
|
|
|
printFixedProfile: (profile) ->
|
|
return unless profile.profileType == 'FixedProfile'
|
|
result = ''
|
|
for scheme in OmegaPac.Profiles.schemes when profile[scheme.prop]
|
|
pacResult = OmegaPac.Profiles.pacResult(profile[scheme.prop])
|
|
if scheme.scheme
|
|
result += "#{scheme.scheme}: #{pacResult}\n"
|
|
else
|
|
result += "#{pacResult}\n"
|
|
result ||= chrome.i18n.getMessage(
|
|
'browserAction_profileDetails_DirectProfile')
|
|
return result
|
|
|
|
printProfile: (profile) ->
|
|
type = profile.profileType
|
|
if type.indexOf('RuleListProfile') >= 0
|
|
type = 'RuleListProfile'
|
|
|
|
if type == 'FixedProfile'
|
|
@printFixedProfile(profile)
|
|
else if type == 'PacProfile' and profile.pacUrl
|
|
profile.pacUrl
|
|
else
|
|
chrome.i18n.getMessage('browserAction_profileDetails_' + type) || null
|
|
|
|
upgrade: (options, changes) ->
|
|
super(options).catch (err) =>
|
|
return Promise.reject err if options?['schemaVersion']
|
|
getOldOptions = if @switchySharp
|
|
@switchySharp.getOptions().timeout(1000)
|
|
else
|
|
Promise.reject()
|
|
|
|
getOldOptions = getOldOptions.catch =>
|
|
if options?['config']
|
|
Promise.resolve options
|
|
else if localStorage['config']
|
|
Promise.resolve localStorage
|
|
else
|
|
Promise.reject new @NoOptionsError()
|
|
|
|
getOldOptions.then (oldOptions) =>
|
|
i18n = {
|
|
upgrade_profile_auto: chrome.i18n.getMessage('upgrade_profile_auto')
|
|
}
|
|
try
|
|
# Upgrade from SwitchySharp.
|
|
upgraded = require('./upgrade')(oldOptions, i18n)
|
|
catch ex
|
|
@log.error(ex)
|
|
return Promise.reject ex
|
|
if localStorage['config']
|
|
Object.getPrototypeOf(localStorage).clear.call(localStorage)
|
|
@_state.set({'firstRun': 'upgrade'})
|
|
return this && super(upgraded, upgraded)
|
|
|
|
onFirstRun: (reason) ->
|
|
chrome.tabs.create url: chrome.extension.getURL('options.html')
|
|
|
|
module.exports = ChromeOptions
|
|
|