2014-09-20 11:49:04 -04:00
|
|
|
chai = require 'chai'
|
|
|
|
should = chai.should()
|
|
|
|
|
|
|
|
describe 'Profiles', ->
|
|
|
|
Profiles = require '../src/profiles'
|
|
|
|
Conditions = require '../src/conditions'
|
|
|
|
U2 = require 'uglify-js'
|
|
|
|
ruleListResult = (profileName, source) ->
|
|
|
|
profileName: profileName
|
|
|
|
source: source
|
|
|
|
testProfile = (profile, request, expected, expectedCompiled) ->
|
|
|
|
o_request = request
|
|
|
|
if typeof request == 'string'
|
|
|
|
request = Conditions.requestFromUrl(request)
|
|
|
|
expectedCompiled ?= expected[0] ? Profiles.nameAsKey(expected.profileName)
|
|
|
|
|
|
|
|
compiled = Profiles.compile(profile)
|
|
|
|
compileResult = eval '(' + compiled.print_to_string() + ')'
|
|
|
|
if typeof compileResult == 'function'
|
|
|
|
compileResult = compileResult(request.url, request.host, request.scheme)
|
|
|
|
|
|
|
|
if expected?
|
|
|
|
matchResult = Profiles.match(profile, request)
|
|
|
|
try
|
|
|
|
if expected.source?
|
|
|
|
chai.assert.equal(matchResult.profileName, expected.profileName)
|
|
|
|
chai.assert.equal(matchResult.source, expected.source)
|
|
|
|
else
|
|
|
|
chai.assert.deepEqual(matchResult, expected)
|
2018-08-20 21:29:07 -04:00
|
|
|
catch _
|
2014-09-20 11:49:04 -04:00
|
|
|
printResult = JSON.stringify(matchResult)
|
|
|
|
msg = ("expect profile to return #{JSON.stringify(expected)} " +
|
|
|
|
"instead of #{printResult} for request #{o_request}")
|
|
|
|
chai.assert(false, msg)
|
|
|
|
|
|
|
|
if compileResult != expectedCompiled
|
|
|
|
msg = ("expect COMPILED profile to return #{expectedCompiled} " +
|
|
|
|
"instead of #{compileResult} for request #{o_request}")
|
|
|
|
chai.assert(false, msg)
|
|
|
|
|
|
|
|
return expected
|
|
|
|
|
|
|
|
describe '#pacResult', ->
|
|
|
|
it 'should return DIRECT for no proxy', ->
|
|
|
|
Profiles.pacResult().should.equal("DIRECT")
|
|
|
|
it 'should return a valid PAC result for a proxy', ->
|
|
|
|
proxy = {scheme: "http", host: "127.0.0.1", port: 8888}
|
|
|
|
Profiles.pacResult(proxy).should.equal("PROXY 127.0.0.1:8888")
|
2015-04-14 10:03:59 -04:00
|
|
|
it 'should return special compatible result for SOCKS5', ->
|
|
|
|
proxy = {scheme: "socks5", host: "127.0.0.1", port: 8888}
|
|
|
|
compatibleResult = "SOCKS5 127.0.0.1:8888; SOCKS 127.0.0.1:8888"
|
|
|
|
Profiles.pacResult(proxy).should.equal(compatibleResult)
|
2014-09-20 11:49:04 -04:00
|
|
|
describe '#byName', ->
|
|
|
|
it 'should get profiles from builtin profiles', ->
|
|
|
|
profile = Profiles.byName('direct')
|
|
|
|
profile.should.be.an('object')
|
|
|
|
profile.profileType.should.equal('DirectProfile')
|
|
|
|
it 'should get profiles from given options', ->
|
|
|
|
profile = {}
|
|
|
|
profile = Profiles.byName('profile', {"+profile": profile})
|
|
|
|
profile.should.equal(profile)
|
2014-12-15 08:10:54 -05:00
|
|
|
describe '#allReferenceSet', ->
|
|
|
|
profile = Profiles.create('test', 'VirtualProfile')
|
|
|
|
profile.defaultProfileName = 'bogus'
|
|
|
|
it 'should throw if referenced profile does not exist', ->
|
|
|
|
getAllReferenceSet = ->
|
|
|
|
Profiles.allReferenceSet(profile, {})
|
|
|
|
getAllReferenceSet.should.throw(Error)
|
|
|
|
it 'should process a dumb profile for each missing profile if requested', ->
|
|
|
|
profile.defaultProfileName = 'bogus'
|
|
|
|
refs = Profiles.allReferenceSet profile, {}, profileNotFound: 'dumb'
|
|
|
|
refs['+bogus'].should.equal('bogus')
|
|
|
|
|
2014-09-20 11:49:04 -04:00
|
|
|
describe 'SystemProfile', ->
|
|
|
|
it 'should be builtin with the name "system"', ->
|
|
|
|
profile = Profiles.byName('system')
|
|
|
|
profile.should.be.an('object')
|
|
|
|
profile.profileType.should.equal('SystemProfile')
|
|
|
|
it 'should not match request to profiles', ->
|
|
|
|
profile = Profiles.byName('system')
|
|
|
|
should.not.exist Profiles.match(profile, {})
|
|
|
|
it 'should throw when trying to compile', ->
|
|
|
|
profile = Profiles.byName('system')
|
|
|
|
should.throw(-> Profiles.compile(profile))
|
|
|
|
describe 'DirectProfile', ->
|
|
|
|
it 'should be builtin with the name "direct"', ->
|
|
|
|
profile = Profiles.byName('direct')
|
|
|
|
profile.should.be.an('object')
|
|
|
|
profile.profileType.should.equal('DirectProfile')
|
|
|
|
it 'should return "DIRECT" when compiled', ->
|
|
|
|
profile = Profiles.byName('direct')
|
|
|
|
testProfile(profile, {}, null, 'DIRECT')
|
|
|
|
describe 'FixedProfile', ->
|
|
|
|
profile =
|
|
|
|
profileType: 'FixedProfile'
|
|
|
|
bypassList: [{
|
|
|
|
conditionType: 'BypassCondition'
|
|
|
|
pattern: '<local>'
|
|
|
|
}]
|
2017-09-20 19:13:36 -04:00
|
|
|
proxyForHttp:
|
|
|
|
scheme: 'socks4'
|
|
|
|
host: '127.0.0.1'
|
|
|
|
port: 1234
|
2014-09-20 11:49:04 -04:00
|
|
|
proxyForHttps:
|
|
|
|
scheme: 'http'
|
|
|
|
host: '127.0.0.1'
|
2017-09-20 19:13:36 -04:00
|
|
|
port: 2345
|
2014-09-20 11:49:04 -04:00
|
|
|
fallbackProxy:
|
2015-04-14 09:39:22 -04:00
|
|
|
scheme: 'socks4'
|
2014-09-20 11:49:04 -04:00
|
|
|
host: '127.0.0.1'
|
2017-09-20 19:13:36 -04:00
|
|
|
port: 3456
|
|
|
|
auth:
|
|
|
|
proxyForHttps:
|
|
|
|
username: 'test'
|
|
|
|
password: 'cheesecake'
|
2014-09-20 11:49:04 -04:00
|
|
|
it 'should use protocol-specific proxies if suitable', ->
|
2017-09-20 19:13:36 -04:00
|
|
|
testProfile(profile, 'https://www.example.com/', ['PROXY 127.0.0.1:2345',
|
|
|
|
'https', profile.proxyForHttps, profile.auth.proxyForHttps])
|
2014-09-20 11:49:04 -04:00
|
|
|
it 'should use fallback proxies for other protocols', ->
|
|
|
|
testProfile(profile, 'ftp://www.example.com/',
|
2017-09-20 19:13:36 -04:00
|
|
|
['SOCKS 127.0.0.1:3456', '', profile.fallbackProxy, undefined])
|
|
|
|
it 'should not return authentication if not provided for protocol', ->
|
|
|
|
testProfile(profile, 'http://www.example.com/',
|
|
|
|
['SOCKS 127.0.0.1:1234', 'http', profile.proxyForHttp, undefined])
|
2014-09-20 11:49:04 -04:00
|
|
|
it 'should not use any proxy for requests matching the bypassList', ->
|
2017-09-20 19:13:36 -04:00
|
|
|
testProfile profile, 'ftp://localhost/',
|
|
|
|
['DIRECT', profile.bypassList[0], {scheme: 'direct'}, undefined]
|
2014-09-20 11:49:04 -04:00
|
|
|
describe 'PacProfile', ->
|
|
|
|
profile = Profiles.create('test', 'PacProfile')
|
|
|
|
profile.pacScript = '''
|
|
|
|
function FindProxyForURL(url, host) {
|
|
|
|
return "PROXY " + host + ":8080";
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
it 'should return the result of the pac script', ->
|
|
|
|
testProfile(profile, 'ftp://www.example.com:9999/abc', null,
|
|
|
|
'PROXY www.example.com:8080')
|
2015-04-14 09:39:22 -04:00
|
|
|
it 'should not fail for PAC with trailing comments', ->
|
|
|
|
p = Profiles.create('test', 'PacProfile')
|
|
|
|
p.pacScript = profile.pacScript + '''
|
|
|
|
// This is a trailing line comment.
|
|
|
|
'''
|
|
|
|
testProfile(p, 'ftp://www.example.com:9999/abc', null,
|
|
|
|
'PROXY www.example.com:8080')
|
|
|
|
p = Profiles.create('test', 'PacProfile')
|
|
|
|
p.pacScript = profile.pacScript + '''
|
|
|
|
/* This is a multiline comment which is not properly closed.
|
|
|
|
'''
|
|
|
|
testProfile(p, 'ftp://www.example.com:9999/abc', null,
|
|
|
|
'PROXY www.example.com:8080')
|
2014-09-25 09:18:17 -04:00
|
|
|
it 'should return includable for non-file pacUrl', ->
|
|
|
|
Profiles.isIncludable(profile).should.be.true
|
|
|
|
it 'should return not includable for file: pacUrl', ->
|
2015-04-14 09:39:22 -04:00
|
|
|
p = Profiles.create('test', 'PacProfile')
|
|
|
|
p.pacUrl = 'file:///proxy.pac'
|
|
|
|
Profiles.isIncludable(p).should.be.false
|
2014-09-20 11:49:04 -04:00
|
|
|
describe 'SwitchProfile', ->
|
|
|
|
profile = Profiles.create('test', 'SwitchProfile')
|
|
|
|
profile.rules = [
|
|
|
|
{
|
|
|
|
condition:
|
|
|
|
conditionType: 'HostWildcardCondition'
|
|
|
|
pattern: 'company.abc.example.com'
|
|
|
|
profileName: 'company'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
condition:
|
|
|
|
conditionType: 'HostWildcardCondition'
|
|
|
|
pattern: '*.example.com'
|
|
|
|
profileName: 'example'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
condition:
|
|
|
|
conditionType: 'HostWildcardCondition'
|
|
|
|
pattern: '*.abc.example.com'
|
|
|
|
profileName: 'abc'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
profile.defaultProfileName = 'default'
|
|
|
|
it 'should match requests based on rules', ->
|
|
|
|
testProfile(profile, 'http://company.abc.example.com:998/abc',
|
|
|
|
profile.rules[0])
|
|
|
|
it 'should respect the order of rules', ->
|
|
|
|
testProfile(profile, 'http://abc.example.com:9999/abc',
|
|
|
|
profile.rules[1])
|
|
|
|
testProfile(profile, 'http://www.example.com:9999/abc',
|
|
|
|
profile.rules[1])
|
|
|
|
it 'should return defaultProfileName when no rules match', ->
|
|
|
|
testProfile(profile, 'http://www.example.org:9999/abc',
|
|
|
|
['+default', null])
|
|
|
|
it 'should calulate directly referenced profiles correctly', ->
|
|
|
|
set = Profiles.directReferenceSet(profile)
|
|
|
|
set.should.eql(
|
|
|
|
'+company': 'company'
|
|
|
|
'+example': 'example'
|
|
|
|
'+abc': 'abc'
|
|
|
|
'+default': 'default'
|
|
|
|
)
|
|
|
|
it 'should clear the reference cache on profile revision change', ->
|
|
|
|
profile.revision = 'a'
|
|
|
|
set = Profiles.directReferenceSet(profile)
|
|
|
|
# Remove 'default' from references.
|
|
|
|
profile.defaultProfileName = 'abc'
|
|
|
|
profile.revision = 'b'
|
|
|
|
newSet = Profiles.directReferenceSet(profile)
|
|
|
|
newSet.should.eql(
|
|
|
|
'+company': 'company'
|
|
|
|
'+example': 'example'
|
|
|
|
'+abc': 'abc'
|
|
|
|
)
|
2015-01-18 12:09:17 -05:00
|
|
|
it 'should clear the reference cache if explicitly requested', ->
|
|
|
|
profile.revision = 'a'
|
|
|
|
set = Profiles.directReferenceSet(profile)
|
|
|
|
# Remove 'default' from references.
|
|
|
|
profile.defaultProfileName = 'abc'
|
|
|
|
Profiles.dropCache(profile)
|
|
|
|
newSet = Profiles.directReferenceSet(profile)
|
|
|
|
newSet.should.eql(
|
|
|
|
'+company': 'company'
|
|
|
|
'+example': 'example'
|
|
|
|
'+abc': 'abc'
|
|
|
|
)
|
2014-10-25 11:41:39 -04:00
|
|
|
describe 'VirtualProfile', ->
|
|
|
|
profile = Profiles.create('test', 'VirtualProfile')
|
|
|
|
profile.defaultProfileName = 'default'
|
|
|
|
it 'should always return defaultProfileName', ->
|
|
|
|
testProfile(profile, 'http://www.example.com/abc',
|
|
|
|
['+default', null])
|
2014-09-20 11:49:04 -04:00
|
|
|
describe 'RulelistProfile', ->
|
|
|
|
profile = Profiles.create('test', 'AutoProxyRuleListProfile')
|
|
|
|
profile.defaultProfileName = 'default'
|
|
|
|
profile.matchProfileName = 'example'
|
|
|
|
profile.ruleList = 'example.com'
|
|
|
|
profile.revision = 'a'
|
|
|
|
it 'should calulate directly referenced profiles correctly', ->
|
|
|
|
set = Profiles.directReferenceSet(profile)
|
|
|
|
set.should.eql(
|
|
|
|
'+example': 'example'
|
|
|
|
'+default': 'default'
|
|
|
|
)
|
2015-02-09 00:53:11 -05:00
|
|
|
it 'should calulate referenced profiles for rule list with results', ->
|
|
|
|
set = Profiles.directReferenceSet({
|
|
|
|
profileType: 'RuleListProfile'
|
|
|
|
format: 'Switchy'
|
|
|
|
matchProfileName: 'ignored'
|
|
|
|
defaultProfileName: 'alsoIgnored'
|
|
|
|
ruleList: '''
|
|
|
|
[SwitchyOmega Conditions]
|
|
|
|
@with result
|
|
|
|
!*.example.org
|
|
|
|
*.example.com +ABC
|
|
|
|
* +DEF
|
|
|
|
'''
|
|
|
|
})
|
|
|
|
set.should.eql(
|
|
|
|
'+ABC': 'ABC'
|
|
|
|
'+DEF': 'DEF'
|
|
|
|
)
|
2014-09-20 11:49:04 -04:00
|
|
|
it 'should match requests based on the rule list', ->
|
|
|
|
testProfile(profile, 'http://localhost/example.com',
|
|
|
|
ruleListResult('example', 'example.com'))
|
|
|
|
testProfile(profile, 'http://localhost/example.org', ['+default', null])
|
|
|
|
it 'should update rule list on update', ->
|
|
|
|
Profiles.update(profile, 'example.org')
|
|
|
|
profile.revision = 'b'
|
|
|
|
testProfile(profile, 'http://localhost/example.com', ['+default', null])
|
|
|
|
testProfile(profile, 'http://localhost/example.org',
|
|
|
|
ruleListResult('example', 'example.org'))
|
2015-05-01 02:49:05 -04:00
|
|
|
it 'should not fail when ruleList is not provided', ->
|
|
|
|
p =
|
|
|
|
profileType: 'RuleListProfile'
|
|
|
|
format: 'Switchy'
|
|
|
|
matchProfileName: 'match'
|
|
|
|
defaultProfileName: 'default'
|
|
|
|
Profiles.directReferenceSet(p).should.be.an 'object'
|
|
|
|
testProfile(p, 'http://localhost/example.com', ['+default', null])
|
2014-09-20 11:49:04 -04:00
|
|
|
it 'should switch to AutoProxy format on update if detected', ->
|
|
|
|
profile = Profiles.create('test2', 'RuleListProfile')
|
|
|
|
profile.format = 'Switchy'
|
|
|
|
profile.defaultProfileName = 'default'
|
|
|
|
profile.matchProfileName = 'example'
|
|
|
|
|
|
|
|
profile.format.should.equal 'Switchy'
|
|
|
|
Profiles.update(profile, '[AutoProxy]\nexample.org')
|
|
|
|
profile.format.should.equal 'AutoProxy'
|
|
|
|
|
|
|
|
testProfile(profile, 'http://localhost/example.com',
|
|
|
|
['+default', null])
|
|
|
|
testProfile(profile, 'http://localhost/example.org',
|
|
|
|
ruleListResult('example', 'example.org'))
|