add list condition
This commit is contained in:
@@ -12,7 +12,6 @@
|
||||
# along with pyquarantine. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from sys import version_info
|
||||
import encodings
|
||||
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ def inject_body_part(part, content, subtype="plain"):
|
||||
boundary = part.get_boundary()
|
||||
p_subtype = part.get_content_subtype()
|
||||
part.clear_content()
|
||||
if text_content != None:
|
||||
if text_content is not None:
|
||||
part.set_content(text_content)
|
||||
part.add_alternative(content, subtype=subtype)
|
||||
else:
|
||||
|
||||
@@ -271,6 +271,7 @@ def release(quarantines, args):
|
||||
f"{args.quarantine}: released message with id {args.quarantine_id} "
|
||||
f"for {rcpts}")
|
||||
|
||||
|
||||
def copy(quarantines, args):
|
||||
logger = logging.getLogger(__name__)
|
||||
quarantine = _get_quarantine(quarantines, args.quarantine, args.debug)
|
||||
@@ -279,6 +280,7 @@ def copy(quarantines, args):
|
||||
f"{args.quarantine}: sent a copy of message with id {args.quarantine_id} "
|
||||
f"to {args.recipient}")
|
||||
|
||||
|
||||
def delete(quarantines, args):
|
||||
storage = _get_quarantine(quarantines, args.quarantine, args.debug).storage
|
||||
storage.delete(args.quarantine_id, args.recipient)
|
||||
@@ -455,7 +457,7 @@ def main():
|
||||
dest="syslog",
|
||||
help="Disable syslog messages.",
|
||||
action="store_false")
|
||||
quar_copy_parser_grp.add_argument(
|
||||
quar_copy_parser.add_argument(
|
||||
"-t", "--to",
|
||||
dest="recipient",
|
||||
help="Release email for one recipient address.")
|
||||
|
||||
@@ -62,14 +62,12 @@ class Conditions:
|
||||
else:
|
||||
setattr(self, arg, cfg[arg])
|
||||
|
||||
self.allowlist = cfg["allowlist"] if "allowlist" in cfg else None
|
||||
if self.allowlist is not None:
|
||||
self.allowlist["name"] = f"{cfg['name']}: allowlist"
|
||||
self.allowlist["loglevel"] = cfg["loglevel"]
|
||||
if self.allowlist["type"] == "db":
|
||||
self.allowlist = DatabaseList(self.allowlist, debug)
|
||||
self.list = cfg["list"] if "list" in cfg else None
|
||||
if self.list is not None:
|
||||
if self.list["type"] == "db":
|
||||
self.list = DatabaseList(self.list, debug)
|
||||
else:
|
||||
raise RuntimeError("invalid allowlist type")
|
||||
raise RuntimeError("invalid list type")
|
||||
|
||||
def __str__(self):
|
||||
cfg = []
|
||||
@@ -77,12 +75,12 @@ class Conditions:
|
||||
"var", "metavar"):
|
||||
if arg in self.cfg:
|
||||
cfg.append(f"{arg}={self.cfg[arg]}")
|
||||
if self.allowlist is not None:
|
||||
cfg.append(f"allowlist={self.allowlist}")
|
||||
if self.list is not None:
|
||||
cfg.append(f"list={self.list}")
|
||||
return "Conditions(" + ", ".join(cfg) + ")"
|
||||
|
||||
def get_allowlist(self):
|
||||
return self.allowlist
|
||||
def get_list(self):
|
||||
return self.list
|
||||
|
||||
def match_host(self, host):
|
||||
logger = CustomLogger(
|
||||
@@ -123,28 +121,6 @@ class Conditions:
|
||||
|
||||
return True
|
||||
|
||||
def get_wl_rcpts(self, mailfrom, rcpts, logger):
|
||||
if not self.allowlist:
|
||||
return {}
|
||||
|
||||
wl_rcpts = []
|
||||
for rcpt in rcpts:
|
||||
if self.allowlist.check(mailfrom, rcpt, logger):
|
||||
wl_rcpts.append(rcpt)
|
||||
|
||||
return wl_rcpts
|
||||
|
||||
def update_msginfo_from_match(self, milter, match):
|
||||
if self.metavar is None:
|
||||
return
|
||||
|
||||
named_subgroups = match.groupdict(default=None)
|
||||
for group, value in named_subgroups.items():
|
||||
if value is None:
|
||||
continue
|
||||
name = f"{self.metavar}_{group}"
|
||||
milter.msginfo["vars"][name] = value
|
||||
|
||||
def match(self, milter):
|
||||
logger = CustomLogger(
|
||||
self.logger, {"qid": milter.qid, "name": self.cfg["name"]})
|
||||
@@ -200,4 +176,14 @@ class Conditions:
|
||||
if self.var not in milter.msginfo["vars"]:
|
||||
return False
|
||||
|
||||
if self.list is not None:
|
||||
envfrom = milter.msginfo["mailfrom"]
|
||||
envto = milter.msginfo["rcpts"]
|
||||
if not isinstance(envto, list):
|
||||
envto = [envto]
|
||||
|
||||
for to in envto:
|
||||
if not self.list.check(envfrom, to, logger):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -22,7 +22,7 @@ __all__ = [
|
||||
"RewriteLinksConfig",
|
||||
"StoreConfig",
|
||||
"NotifyConfig",
|
||||
"AllowListConfig",
|
||||
"ListConfig",
|
||||
"QuarantineConfig",
|
||||
"ActionConfig",
|
||||
"RuleConfig",
|
||||
@@ -89,7 +89,7 @@ class BaseConfig:
|
||||
return self._config
|
||||
|
||||
|
||||
class AllowListConfig(BaseConfig):
|
||||
class ListConfig(BaseConfig):
|
||||
JSON_SCHEMA = {
|
||||
"type": "object",
|
||||
"required": ["type"],
|
||||
@@ -121,14 +121,14 @@ class ConditionsConfig(BaseConfig):
|
||||
"headers": {"type": "array",
|
||||
"items": {"type": "string"}},
|
||||
"var": {"type": "string"},
|
||||
"allowlist": {"type": "object"}}}
|
||||
"list": {"type": "object"}}}
|
||||
|
||||
def __init__(self, config, rec=True):
|
||||
super().__init__(config)
|
||||
if not rec:
|
||||
return
|
||||
if "allowlist" in self:
|
||||
self["allowlist"] = AllowListConfig(self["allowlist"])
|
||||
if "list" in self:
|
||||
self["list"] = ListConfig(self["list"])
|
||||
|
||||
|
||||
class AddHeaderConfig(BaseConfig):
|
||||
@@ -257,8 +257,7 @@ class QuarantineConfig(BaseConfig):
|
||||
if "notify" in self:
|
||||
self["notify"] = NotifyConfig(self["notify"])
|
||||
if "allowlist" in self:
|
||||
self["allowlist"] = ConditionsConfig(
|
||||
{"allowlist": self["allowlist"]}, rec)
|
||||
self["allowlist"] = ListConfig(self["allowlist"])
|
||||
|
||||
|
||||
class ActionConfig(BaseConfig):
|
||||
|
||||
@@ -223,7 +223,7 @@ class EMailNotification(BaseNotification):
|
||||
logger.debug(
|
||||
f"removing attribute '{attribute}' "
|
||||
f"from tag '{element.name}'")
|
||||
del(element.attrs[attribute])
|
||||
del element.attrs[attribute]
|
||||
return soup
|
||||
|
||||
def notify(self, msg, qid, mailfrom, recipients, logger,
|
||||
|
||||
@@ -31,8 +31,8 @@ from time import gmtime
|
||||
|
||||
from pyquarantine import mailer
|
||||
from pyquarantine.base import CustomLogger, MilterMessage
|
||||
from pyquarantine.conditions import Conditions
|
||||
from pyquarantine.config import ActionConfig
|
||||
from pyquarantine.list import DatabaseList
|
||||
from pyquarantine.notify import Notify
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ class FileMailStorage(BaseMailStorage):
|
||||
|
||||
metafile, _ = self._get_file_paths(storage_id)
|
||||
|
||||
if type(recipients) == str:
|
||||
if isinstance(recipients, str):
|
||||
recipients = [recipients]
|
||||
|
||||
for recipient in recipients:
|
||||
@@ -430,13 +430,11 @@ class Quarantine:
|
||||
|
||||
self._allowlist = None
|
||||
if "allowlist" in cfg["options"]:
|
||||
allowlist_cfg = cfg["options"]["allowlist"]
|
||||
allowlist_cfg["name"] = cfg["name"]
|
||||
allowlist_cfg["loglevel"] = cfg["loglevel"]
|
||||
self._allowlist = Conditions(
|
||||
allowlist_cfg,
|
||||
local_addrs=[],
|
||||
debug=debug)
|
||||
allowlist = cfg["options"]["allowlist"]
|
||||
if allowlist["type"] == "db":
|
||||
self._allowlist = DatabaseList(allowlist, debug)
|
||||
else:
|
||||
raise RuntimeError("invalid allowlist type")
|
||||
|
||||
self._milter_action = None
|
||||
if "milter_action" in cfg["options"]:
|
||||
@@ -482,9 +480,7 @@ class Quarantine:
|
||||
|
||||
@property
|
||||
def allowlist(self):
|
||||
if self._allowlist is None:
|
||||
return None
|
||||
return self._allowlist.get_allowlist()
|
||||
return self._allowlist
|
||||
|
||||
@property
|
||||
def milter_action(self):
|
||||
@@ -512,7 +508,7 @@ class Quarantine:
|
||||
|
||||
def release(self, storage_id, recipients=None):
|
||||
metadata, msg = self.storage.get_mail(storage_id)
|
||||
if recipients and type(recipients) == str:
|
||||
if recipients and isinstance(recipients, str):
|
||||
recipients = [recipients]
|
||||
else:
|
||||
recipients = metadata["recipients"]
|
||||
@@ -552,14 +548,18 @@ class Quarantine:
|
||||
def execute(self, milter):
|
||||
logger = CustomLogger(
|
||||
self.logger, {"name": self.cfg["name"], "qid": milter.qid})
|
||||
|
||||
rcpts = milter.msginfo["rcpts"]
|
||||
wl_rcpts = []
|
||||
allowed_rcpts = []
|
||||
if self._allowlist:
|
||||
wl_rcpts = self._allowlist.get_wl_rcpts(
|
||||
milter.msginfo["mailfrom"], rcpts, logger)
|
||||
if wl_rcpts:
|
||||
logger.info(f"allowed recipients: {wl_rcpts}")
|
||||
rcpts = [rcpt for rcpt in rcpts if rcpt not in wl_rcpts]
|
||||
allowed_rcpts = []
|
||||
for rcpt in rcpts:
|
||||
if self._allowlist.check(
|
||||
milter.msginfo["mailfrom"], rcpt, logger):
|
||||
allowed_rcpts.append(rcpt)
|
||||
if allowed_rcpts:
|
||||
logger.info(f"allowed recipients: {allowed_rcpts}")
|
||||
rcpts = [rcpt for rcpt in rcpts if rcpt not in allowed_rcpts]
|
||||
if not rcpts:
|
||||
# all recipients allowed
|
||||
return
|
||||
@@ -573,7 +573,7 @@ class Quarantine:
|
||||
if self._notification is not None:
|
||||
self._notification.execute(milter)
|
||||
|
||||
milter.msginfo["rcpts"].extend(wl_rcpts)
|
||||
milter.msginfo["rcpts"].extend(allowed_rcpts)
|
||||
|
||||
if self._milter_action is not None:
|
||||
milter.delrcpt(rcpts)
|
||||
|
||||
Reference in New Issue
Block a user