mirror of https://github.com/fail2ban/fail2ban
cherry-pick newer version of extractOptions, in order to avoid large discrepancy between 0.10 and 0.9 config-parsers:
allow to use dual parameter lists (coming through substitutions), e. g.: `name[p1=0, p2="..."][p3='...']`; simplified explanation: `][` treats as `,` in new version. cherry-picked from 0.10.pull/1908/head
parent
82f8bd8639
commit
3d9a112c8f
|
@ -27,14 +27,13 @@ __license__ = "GPL"
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
|
||||||
|
|
||||||
from .configreader import ConfigReaderUnshared, ConfigReader
|
from .configreader import ConfigReaderUnshared, ConfigReader
|
||||||
from .filterreader import FilterReader
|
from .filterreader import FilterReader
|
||||||
from .actionreader import ActionReader
|
from .actionreader import ActionReader
|
||||||
from ..version import version
|
from ..version import version
|
||||||
from ..helpers import getLogger
|
from ..helpers import getLogger
|
||||||
from ..helpers import splitwords
|
from ..helpers import extractOptions, splitwords
|
||||||
|
|
||||||
# Gets the instance of the logger.
|
# Gets the instance of the logger.
|
||||||
logSys = getLogger(__name__)
|
logSys = getLogger(__name__)
|
||||||
|
@ -42,10 +41,6 @@ logSys = getLogger(__name__)
|
||||||
|
|
||||||
class JailReader(ConfigReader):
|
class JailReader(ConfigReader):
|
||||||
|
|
||||||
optionCRE = re.compile("^((?:\w|-|_|\.)+)(?:\[(.*)\])?$")
|
|
||||||
optionExtractRE = re.compile(
|
|
||||||
r'([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,]*))(?:,|$)')
|
|
||||||
|
|
||||||
def __init__(self, name, force_enable=False, **kwargs):
|
def __init__(self, name, force_enable=False, **kwargs):
|
||||||
ConfigReader.__init__(self, **kwargs)
|
ConfigReader.__init__(self, **kwargs)
|
||||||
self.__name = name
|
self.__name = name
|
||||||
|
@ -121,7 +116,7 @@ class JailReader(ConfigReader):
|
||||||
if self.isEnabled():
|
if self.isEnabled():
|
||||||
# Read filter
|
# Read filter
|
||||||
if self.__opts["filter"]:
|
if self.__opts["filter"]:
|
||||||
filterName, filterOpt = JailReader.extractOptions(
|
filterName, filterOpt = extractOptions(
|
||||||
self.__opts["filter"])
|
self.__opts["filter"])
|
||||||
self.__filter = FilterReader(
|
self.__filter = FilterReader(
|
||||||
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
|
filterName, self.__name, filterOpt, share_config=self.share_config, basedir=self.getBaseDir())
|
||||||
|
@ -150,7 +145,7 @@ class JailReader(ConfigReader):
|
||||||
try:
|
try:
|
||||||
if not act: # skip empty actions
|
if not act: # skip empty actions
|
||||||
continue
|
continue
|
||||||
actName, actOpt = JailReader.extractOptions(act)
|
actName, actOpt = extractOptions(act)
|
||||||
if actName.endswith(".py"):
|
if actName.endswith(".py"):
|
||||||
self.__actions.append([
|
self.__actions.append([
|
||||||
"set",
|
"set",
|
||||||
|
@ -244,18 +239,4 @@ class JailReader(ConfigReader):
|
||||||
stream.insert(0, ["add", self.__name, backend])
|
stream.insert(0, ["add", self.__name, backend])
|
||||||
return stream
|
return stream
|
||||||
|
|
||||||
@staticmethod
|
JailReader.extractOptions = staticmethod(extractOptions)
|
||||||
def extractOptions(option):
|
|
||||||
match = JailReader.optionCRE.match(option)
|
|
||||||
if not match:
|
|
||||||
# TODO proper error handling
|
|
||||||
return None, None
|
|
||||||
option_name, optstr = match.groups()
|
|
||||||
option_opts = dict()
|
|
||||||
if optstr:
|
|
||||||
for optmatch in JailReader.optionExtractRE.finditer(optstr):
|
|
||||||
opt = optmatch.group(1)
|
|
||||||
value = [
|
|
||||||
val for val in optmatch.group(2,3,4) if val is not None][0]
|
|
||||||
option_opts[opt.strip()] = value.strip()
|
|
||||||
return option_name, option_opts
|
|
||||||
|
|
|
@ -137,3 +137,32 @@ def splitwords(s):
|
||||||
if not s:
|
if not s:
|
||||||
return []
|
return []
|
||||||
return filter(bool, map(str.strip, re.split('[ ,\n]+', s)))
|
return filter(bool, map(str.strip, re.split('[ ,\n]+', s)))
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Following function used for parse options from parameter (e.g. `name[p1=0, p2="..."][p3='...']`).
|
||||||
|
#
|
||||||
|
|
||||||
|
# regex, to extract list of options:
|
||||||
|
OPTION_CRE = re.compile(r"^([^\[]+)(?:\[(.*)\])?\s*$", re.DOTALL)
|
||||||
|
# regex, to iterate over single option in option list, syntax:
|
||||||
|
# `action = act[p1="...", p2='...', p3=...]`, where the p3=... not contains `,` or ']'
|
||||||
|
# since v0.10 separator extended with `]\s*[` for support of multiple option groups, syntax
|
||||||
|
# `action = act[p1=...][p2=...]`
|
||||||
|
OPTION_EXTRACT_CRE = re.compile(
|
||||||
|
r'([\w\-_\.]+)=(?:"([^"]*)"|\'([^\']*)\'|([^,\]]*))(?:,|\]\s*\[|$)', re.DOTALL)
|
||||||
|
|
||||||
|
def extractOptions(option):
|
||||||
|
match = OPTION_CRE.match(option)
|
||||||
|
if not match:
|
||||||
|
# TODO proper error handling
|
||||||
|
return None, None
|
||||||
|
option_name, optstr = match.groups()
|
||||||
|
option_opts = dict()
|
||||||
|
if optstr:
|
||||||
|
for optmatch in OPTION_EXTRACT_CRE.finditer(optstr):
|
||||||
|
opt = optmatch.group(1)
|
||||||
|
value = [
|
||||||
|
val for val in optmatch.group(2,3,4) if val is not None][0]
|
||||||
|
option_opts[opt.strip()] = value.strip()
|
||||||
|
return option_name, option_opts
|
||||||
|
|
Loading…
Reference in New Issue