rename config option args to options

This commit is contained in:
2021-10-08 13:09:16 +02:00
parent 97915498e1
commit f99fc24e64
7 changed files with 252 additions and 31 deletions

View File

@@ -97,7 +97,7 @@ def list_quarantines(quarantines, args):
else:
qlist = []
for q in quarantines:
cfg = q["args"]
cfg = q["options"]
storage_type = cfg["store"]["type"]
if "notify" in cfg:

View File

@@ -269,7 +269,7 @@ class ActionConfig(BaseConfig):
JSON_SCHEMA = {
"type": "object",
"required": ["name", "type", "args"],
"required": ["name", "type", "options"],
"additionalProperties": False,
"properties": {
"name": {"type": "string"},
@@ -277,14 +277,14 @@ class ActionConfig(BaseConfig):
"pretend": {"type": "boolean", "default": False},
"conditions": {"type": "object"},
"type": {"enum": list(ACTION_TYPES.keys())},
"args": {"type": "object"}}}
"options": {"type": "object"}}}
def __init__(self, config, rec=True):
super().__init__(config)
if rec:
if "conditions" in self:
self["conditions"] = ConditionsConfig(self["conditions"])
self["action"] = self.ACTION_TYPES[self["type"]](self["args"])
self["action"] = self.ACTION_TYPES[self["type"]](self["options"])
class RuleConfig(BaseConfig):

View File

@@ -60,7 +60,7 @@
# Section: conditions
# Notes: Optional conditions to process the rule.
# If multiple conditions are set, they all
# have to be true to process the rule.
# have to be true for the rule to be processed.
#
"conditions": {
# Option: local

View File

@@ -0,0 +1,221 @@
# This is an example /etc/pyquarantine/pyquarantine.conf file.
# Copy it into place before use.
#
# The file is in JSON format.
#
# The global option 'log' can be overriden per rule or per modification.
#
{
# Section: global
# Notes: Global options.
#
"global": {
# Option: socket
# Type: String
# Notes: The socket used to communicate with the MTA.
#
# Examples:
# unix:/path/to/socket a named pipe
# inet:8899 listen on ANY interface
# inet:8899@localhost listen on a specific interface
# inet6:8899 listen on ANY interface
# inet6:8899@[2001:db8:1234::1] listen on a specific interface
# Value: [ SOCKET ]
"socket": "inet:8898@127.0.0.1",
# Option: local_addrs
# Type: List
# Notes: A list of local hosts and networks.
# Value: [ LIST ]
#
"local_addrs": ["fe80::/64", "::1/128", "127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
# Option: loglevel
# Type: String
# Notes: Set loglevel for rules and actions.
# Value: [ error | warning | info | debug ]
#
"loglevel": "info",
# Option: pretend
# Type: Bool
# Notes: Just pretend to do the actions, for test purposes.
# Value: [ true | false ]
#
"pretend": true
},
# Section: rules
# Notes: Rules and related actions.
#
"rules": [
{
# Option: name
# Type: String
# Notes: Name of the rule.
# Value: [ NAME ]
#
"name": "myrule",
# Section: conditions
# Notes: Optional conditions to process the rule.
# If multiple conditions are set, they all
# have to be true to process the rule.
#
"conditions": {
# Option: local
# Type: Bool
# Notes: Condition wheter the senders host address is listed in local_addrs.
# Value: [ true | false ]
#
"local": false,
# Option: hosts
# Type: String
# Notes: Condition wheter the senders host address is listed in this list.
# Value: [ LIST ]
#
"hosts": [ "127.0.0.1" ],
# Option: envfrom
# Type: String
# Notes: Condition wheter the envelop-from address matches this regular expression.
# Value: [ REGEX ]
#
"envfrom": "^.+@mypartner\\.com$",
# Option: envto
# Type: String
# Notes: Condition wheter the envelop-to address matches this regular expression.
# Value: [ REGEX ]
#
"envto": "^postmaster@.+$"
},
# Section: actions
# Notes: Actions of the rule.
#
"actions": [
{
# Option: name
# Type: String
# Notes: Name of the modification.
# Value: [ NAME ]
#
"name": "add_test_header",
# Option: type
# Type: String
# Notes: Type of the modification.
# Value: [ add_header | del_header | mod_header ]
#
"type": "add_header",
# Option: field
# Type: String
# Notes: Name of the header.
# Value: [ NAME ]
#
"field": "X-Test-Header",
# Option: value
# Type: String
# Notes: Value of the header.
# Value: [ VALUE ]
#
"value": "true"
}, {
"name": "modify_subject",
"type": "mod_header",
# Option: field
# Type: String
# Notes: Regular expression to match against header lines (e.g. Subject: Test-Subject).
# Value: [ REGEX ]
#
"field": "^Subject$",
# Option: search
# Type: String
# Notes: Regular expression to match against the headers value.
# Values: [ VALUE ]
#
"search": "(?P<subject>.*)",
# Option: value
# Type: String
# Notes: New value of the header.
# Values: [ VALUE ]
"value": "[EXTERNAL] \\g<subject>"
}, {
"name": "delete_received_header",
"type": "del_header",
# Option: field
# Type: String
# Notes: Regular expression to match against header lines (e.g. Subject: Test-Subject).
# Value: [ REGEX ]
#
"field": "^Received$"
}, {
"name": "add_disclaimer",
"type": "add_disclaimer",
# Option: action
# Type: String
# Notes: Action to perform with the disclaimer.
# Value: [ append | prepend ]
#
"action": "prepend",
# Option: html_template
# Type: String
# Notes: Path to a file which contains the html representation of the disclaimer.
# Value: [ FILE_PATH ]
#
"html_template": "/etc/pyquarantine/templates/disclaimer_html.template",
# Option: text_template
# Type: String
# Notes: Path to a file which contains the text representation of the disclaimer.
# Value: [ FILE_PATH ]
#
"text_template": "/etc/pyquarantine/templates/disclaimer_text.template",
# Option: error_policy
# Type: String
# Notes: Set what should be done if the modification fails (e.g. no message body present).
# Value: [ wrap | ignore | reject ]
#
"error_policy": "wrap"
}, {
"name": "store_message",
"type": "store",
# Option: storage_type
# Type: String
# Notes: The storage type used to store e-mails.
# Value: [ file ]
"storage_type": "file",
# Option: directory
# Type: String
# Notes: Directory used to store e-mails.
# Value: [ file ]
"directory": "/mnt/messages",
# Option: original
# Type: Bool
# Notes: If set to true, store the message as received by the MTA instead of storing the current state
# of the message, that may was modified already by other actions.
# Value: [ true | false ]
"original": true
}
]
}
]
}

View File

@@ -390,14 +390,14 @@ class Modify:
self.cfg = cfg
self.logger = logging.getLogger(cfg["name"])
self.logger.setLevel(cfg.get_loglevel(debug))
cfg["args"]["pretend"] = cfg["pretend"]
cfg["options"]["pretend"] = cfg["pretend"]
self._modification = self.MODIFICATION_TYPES[cfg["type"]](
**cfg["args"])
**cfg["options"])
self._headersonly = self._modification._headersonly
def __str__(self):
cfg = []
for key, value in self.cfg["args"].items():
for key, value in self.cfg["options"].items():
cfg.append(f"{key}={value}")
class_name = type(self._modification).__name__
return f"{class_name}(" + ", ".join(cfg) + ")"

View File

@@ -332,16 +332,16 @@ class Notify:
self.logger = logging.getLogger(cfg["name"])
self.logger.setLevel(cfg.get_loglevel(debug))
nodification_type = cfg["args"]["type"]
del cfg["args"]["type"]
cfg["args"]["pretend"] = cfg["pretend"]
nodification_type = cfg["options"]["type"]
del cfg["options"]["type"]
cfg["options"]["pretend"] = cfg["pretend"]
self._notification = self.NOTIFICATION_TYPES[nodification_type](
**cfg["args"])
**cfg["options"])
self._headersonly = self._notification._headersonly
def __str__(self):
cfg = []
for key, value in self.cfg["args"].items():
for key, value in self.cfg["options"].items():
cfg.append(f"{key}={value}")
class_name = type(self._notification).__name__
return f"{class_name}(" + ", ".join(cfg) + ")"

View File

@@ -375,16 +375,16 @@ class Store:
self.logger = logging.getLogger(cfg["name"])
self.logger.setLevel(cfg.get_loglevel(debug))
storage_type = cfg["args"]["type"]
del cfg["args"]["type"]
cfg["args"]["pretend"] = cfg["pretend"]
storage_type = cfg["options"]["type"]
del cfg["options"]["type"]
cfg["options"]["pretend"] = cfg["pretend"]
self._storage = self.STORAGE_TYPES[storage_type](
**cfg["args"])
**cfg["options"])
self._headersonly = self._storage._headersonly
def __str__(self):
cfg = []
for key, value in self.cfg["args"].items():
for key, value in self.cfg["options"].items():
cfg.append(f"{key}={value}")
class_name = type(self._storage).__name__
return f"{class_name}(" + ", ".join(cfg) + ")"
@@ -412,25 +412,25 @@ class Quarantine:
"loglevel": cfg["loglevel"],
"pretend": cfg["pretend"],
"type": "store",
"args": cfg["args"]["store"].get_config()})
"options": cfg["options"]["store"].get_config()})
self._storage = Store(storage_cfg, local_addrs, debug)
self.smtp_host = cfg["args"]["smtp_host"]
self.smtp_port = cfg["args"]["smtp_port"]
self.smtp_host = cfg["options"]["smtp_host"]
self.smtp_port = cfg["options"]["smtp_port"]
self._notification = None
if "notify" in cfg["args"]:
if "notify" in cfg["options"]:
notify_cfg = ActionConfig({
"name": cfg["name"],
"loglevel": cfg["loglevel"],
"pretend": cfg["pretend"],
"type": "notify",
"args": cfg["args"]["notify"].get_config()})
"options": cfg["options"]["notify"].get_config()})
self._notification = Notify(notify_cfg, local_addrs, debug)
self._whitelist = None
if "whitelist" in cfg["args"]:
whitelist_cfg = cfg["args"]["whitelist"]
if "whitelist" in cfg["options"]:
whitelist_cfg = cfg["options"]["whitelist"]
whitelist_cfg["name"] = cfg["name"]
whitelist_cfg["loglevel"] = cfg["loglevel"]
self._whitelist = Conditions(
@@ -439,15 +439,15 @@ class Quarantine:
debug=debug)
self._milter_action = None
if "milter_action" in cfg["args"]:
self._milter_action = cfg["args"]["milter_action"].upper()
if "milter_action" in cfg["options"]:
self._milter_action = cfg["options"]["milter_action"].upper()
assert self._milter_action in ["ACCEPT", "REJECT", "DISCARD"], \
f"invalid milter_action '{cfg['args']['milter_action']}'"
self._reason = None
if self._milter_action == "REJECT":
if "reject_reason" in cfg["args"]:
self._reason = cfg["args"]["reject_reason"]
if "reject_reason" in cfg["options"]:
self._reason = cfg["options"]["reject_reason"]
else:
self._reason = "Message rejected"
@@ -459,9 +459,9 @@ class Quarantine:
if self._whitelist is not None:
cfg.append(f"whitelist={str(self._whitelist)}")
for key in ["milter_action", "reject_reason"]:
if key not in self.cfg["args"]:
if key not in self.cfg["options"]:
continue
value = self.cfg["args"][key]
value = self.cfg["options"][key]
cfg.append(f"{key}={value}")
class_name = type(self).__name__
return f"{class_name}(" + ", ".join(cfg) + ")"