mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 15:08:12 -05:00
Improve error handling for rule lists.
This commit is contained in:
parent
674f501ada
commit
054d1c8b58
@ -389,6 +389,8 @@ module.exports = exports =
|
||||
profile.matchProfileName ?= 'direct'
|
||||
profile.ruleList ?= ''
|
||||
directReferenceSet: (profile) ->
|
||||
refs = RuleList[profile.format]?.directReferenceSet?(profile)
|
||||
return refs if refs
|
||||
refs = {}
|
||||
for name in [profile.matchProfileName, profile.defaultProfileName]
|
||||
refs[exports.nameAsKey(name)] = name
|
||||
@ -407,7 +409,7 @@ module.exports = exports =
|
||||
formatHandler = RuleList[format]
|
||||
if not formatHandler
|
||||
throw new Error "Unsupported rule list format #{format}!"
|
||||
ruleList = profile.ruleList
|
||||
ruleList = profile.ruleList?.trim() || ''
|
||||
if formatHandler.preprocess?
|
||||
ruleList = formatHandler.preprocess(ruleList)
|
||||
return formatHandler.parse(ruleList, profile.matchProfileName,
|
||||
@ -418,6 +420,7 @@ module.exports = exports =
|
||||
exports.compile(profile, 'SwitchProfile')
|
||||
updateUrl: (profile) -> profile.sourceUrl
|
||||
update: (profile, data) ->
|
||||
data = data.trim()
|
||||
original = profile.format ? exports.formatByType[profile.profileType]
|
||||
profile.profileType = 'RuleListProfile'
|
||||
format = original
|
||||
|
@ -14,12 +14,10 @@ module.exports = exports =
|
||||
return true
|
||||
return
|
||||
preprocess: (text) ->
|
||||
text = text.trim()
|
||||
if strStartsWith(text, exports['AutoProxy'].magicPrefix)
|
||||
text = new Buffer(text, 'base64').toString('utf8')
|
||||
return text
|
||||
parse: (text, matchProfileName, defaultProfileName) ->
|
||||
text = text.trim()
|
||||
normal_rules = []
|
||||
exclusive_rules = []
|
||||
for line in text.split(/\n|\r/)
|
||||
@ -55,21 +53,36 @@ module.exports = exports =
|
||||
|
||||
'Switchy':
|
||||
omegaPrefix: '[SwitchyOmega Conditions'
|
||||
specialLineStart: "[;#@!"
|
||||
|
||||
detect: (text) ->
|
||||
text = text.trim()
|
||||
if strStartsWith(text, exports['Switchy'].omegaPrefix)
|
||||
return true
|
||||
return
|
||||
|
||||
parse: (text, matchProfileName, defaultProfileName) ->
|
||||
text = text.trim()
|
||||
switchy = exports['Switchy']
|
||||
parser = 'parseOmega'
|
||||
if not strStartsWith(text, switchy.omegaPrefix)
|
||||
if text[0] == '#' or text.indexOf('\n#') >= 0
|
||||
parser = 'parseLegacy'
|
||||
parser = switchy.getParser(text)
|
||||
return switchy[parser](text, matchProfileName, defaultProfileName)
|
||||
|
||||
directReferenceSet: ({ruleList, matchProfileName, defaultProfileName}) ->
|
||||
text = ruleList.trim()
|
||||
switchy = exports['Switchy']
|
||||
parser = switchy.getParser(text)
|
||||
return unless parser == 'parseOmega'
|
||||
return unless /(^|\n)@with\s+results?(\r|\n)/i.test(text)
|
||||
refs = {}
|
||||
for line in text.split(/\n|\r/)
|
||||
line = line.trim()
|
||||
if switchy.specialLineStart.indexOf(line[0]) < 0
|
||||
iSpace = line.lastIndexOf(' +')
|
||||
if iSpace < 0
|
||||
profile = defaultProfileName || 'direct'
|
||||
else
|
||||
profile = line.substr(iSpace + 2).trim()
|
||||
refs['+' + profile] = profile
|
||||
refs
|
||||
|
||||
# For the omega rule list format, please see the following wiki page:
|
||||
# https://github.com/FelisCatus/SwitchyOmega/wiki/SwitchyOmega-conditions-format
|
||||
compose: ({rules, defaultProfileName}, {withResult, useExclusive} = {}) ->
|
||||
@ -80,23 +93,31 @@ module.exports = exports =
|
||||
ruleList += '@with result' + eol + eol
|
||||
else
|
||||
ruleList += eol
|
||||
specialLineStart = exports['Switchy'].specialLineStart + '+'
|
||||
for rule in rules
|
||||
line = Conditions.str(rule.condition)
|
||||
if line[0] == '#' or line[0] == '+'
|
||||
# Escape leading # to avoid being detected as legacy format.
|
||||
# Reserve leading + for condition results.
|
||||
line = ': ' + line
|
||||
if useExclusive and rule.profileName == defaultProfileName
|
||||
line = '!' + line
|
||||
else if withResult
|
||||
# TODO(catus): What if rule.profileName contains ' +' or new lines?
|
||||
line += ' +' + rule.profileName
|
||||
else
|
||||
if specialLineStart.indexOf(line[0]) >= 0
|
||||
line = ': ' + line
|
||||
if withResult
|
||||
# TODO(catus): What if rule.profileName contains ' +' or new lines?
|
||||
line += ' +' + rule.profileName
|
||||
ruleList += line + eol
|
||||
if withResult
|
||||
# TODO(catus): Also special chars and sequences in defaultProfileName.
|
||||
ruleList += '* +' + defaultProfileName + eol
|
||||
return ruleList
|
||||
|
||||
getParser: (text) ->
|
||||
switchy = exports['Switchy']
|
||||
parser = 'parseOmega'
|
||||
if not strStartsWith(text, switchy.omegaPrefix)
|
||||
if text[0] == '#' or text.indexOf('\n#') >= 0
|
||||
parser = 'parseLegacy'
|
||||
return parser
|
||||
|
||||
conditionFromLegacyWildcard: (pattern) ->
|
||||
if pattern[0] == '@'
|
||||
pattern = pattern.substring(1)
|
||||
@ -151,10 +172,12 @@ module.exports = exports =
|
||||
# Exclusive rules have higher priority, so they come first.
|
||||
return exclusive_rules.concat normal_rules
|
||||
|
||||
parseOmega: (text, matchProfileName, defaultProfileName) ->
|
||||
parseOmega: (text, matchProfileName, defaultProfileName, args = {}) ->
|
||||
{strict} = args
|
||||
rules = []
|
||||
rulesWithDefaultProfile = []
|
||||
withResult = false
|
||||
exclusiveProfile = null
|
||||
for line in text.split(/\n|\r/)
|
||||
line = line.trim()
|
||||
continue if line.length == 0
|
||||
@ -183,16 +206,18 @@ module.exports = exports =
|
||||
else if withResult
|
||||
iSpace = line.lastIndexOf(' +')
|
||||
if iSpace < 0
|
||||
throw new Error("Missing result profile name: " + line)
|
||||
throw new Error("Missing result profile name: " + line) if strict
|
||||
continue
|
||||
profile = line.substr(iSpace + 2).trim()
|
||||
line = line.substr(0, iSpace).trim()
|
||||
defaultProfileName = profile if line == '*'
|
||||
exclusiveProfile = profile if line == '*'
|
||||
else
|
||||
profile = matchProfileName
|
||||
|
||||
cond = Conditions.fromStr(line)
|
||||
if not cond
|
||||
throw new Error("Invalid rule: " + line)
|
||||
throw new Error("Invalid rule: " + line) if strict
|
||||
continue
|
||||
|
||||
rule = {condition: cond, profileName: profile, source: source ? line}
|
||||
rules.push(rule)
|
||||
@ -200,8 +225,10 @@ module.exports = exports =
|
||||
rulesWithDefaultProfile.push(rule)
|
||||
|
||||
if withResult
|
||||
if not defaultProfileName
|
||||
throw new Error("Missing default rule with catch-all '*' condition!")
|
||||
if not exclusiveProfile
|
||||
if strict
|
||||
throw new Error("Missing default rule with catch-all '*' condition")
|
||||
exclusiveProfile = defaultProfileName || 'direct'
|
||||
for rule in rulesWithDefaultProfile
|
||||
rule.profileName = defaultProfileName
|
||||
rule.profileName = exclusiveProfile
|
||||
return rules
|
||||
|
@ -209,6 +209,24 @@ describe 'Profiles', ->
|
||||
'+example': 'example'
|
||||
'+default': 'default'
|
||||
)
|
||||
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'
|
||||
)
|
||||
it 'should match requests based on the rule list', ->
|
||||
testProfile(profile, 'http://localhost/example.com',
|
||||
ruleListResult('example', 'example.com'))
|
||||
|
@ -291,6 +291,17 @@ describe 'RuleList', ->
|
||||
result = parse(list, 'match', 'notmatch')
|
||||
result.should.have.length(1)
|
||||
result[0].should.eql(rule)
|
||||
it 'should compose and parse conditions starting with special chars', ->
|
||||
rule =
|
||||
source: ': ;abc'
|
||||
condition:
|
||||
conditionType: 'HostWildcardCondition',
|
||||
pattern: ';abc'
|
||||
profileName: 'match'
|
||||
list = compose({rules: [rule], defaultProfileName: 'notmatch'})
|
||||
result = parse(list, 'match', 'notmatch')
|
||||
result.should.have.length(1)
|
||||
result[0].should.eql(rule)
|
||||
it 'should parse multiple conditions', ->
|
||||
rules = [{
|
||||
source: '*.example.com'
|
||||
|
Loading…
Reference in New Issue
Block a user