email: rspamd: Simplify installing configuration

Existing implementation expects configuration files installed by FreedomBox to
be edited at the top and the bottom. When re-installing, it tries to keep the
edited parts while reinstalling the FreedomBox managed section in the middle to
be overwritten with (new) FreedomBox defaults.

Instead, simply ship the two files to rspamd configuration directories. These
can be easily overridden by the user if they desire due to flexible
configuration file priorities by rspamd.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2022-02-08 11:46:32 -08:00 committed by James Valleroy
parent 3b5091cbc3
commit 6e2c24c9e4
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
4 changed files with 0 additions and 100 deletions

View File

@ -3,14 +3,12 @@
import glob
import logging
import re
import subprocess
from django.utils.translation import gettext_lazy as _
from plinth import actions
from plinth.modules.email import interproc, lock, postconf
from plinth.modules.email.modconf import ConfigInjector
from . import models
@ -73,12 +71,6 @@ egress_filter_cleanup_options = {
'nested_header_checks': ''
}
# Rspamd config
rspamd_re = re.compile('#[ ]*--[ ]*([A-Z]{3,5})[ ]+FREEDOMBOX CONFIG$')
rspamd_format = '#-- {} FREEDOMBOX CONFIG'
rspamd_mutex = lock.Mutex('rspamd-config')
logger = logging.getLogger(__name__)
@ -116,20 +108,6 @@ def action_set_filter():
with postconf.mutex.lock_all():
fix_filter(check_filter())
injector = ConfigInjector(rspamd_re, rspamd_format)
with rspamd_mutex.lock_all():
# XXX Maybe use globbing?
_inject_rspamd_config(injector, 'override', 'options.inc')
_inject_rspamd_config(injector, 'local', 'milter_headers.conf')
def _inject_rspamd_config(injector, type, name):
template_path = '/etc/plinth/rspamd-config/%s_%s' % (type, name)
config_path = '/etc/rspamd/%s.d/%s' % (type, name)
logger.info('Opening Rspamd config file %s', config_path)
injector.do_template_file(template_path, config_path)
def _compile_sieve():
sieve_list = glob.glob('/etc/dovecot/freedombox-sieve-after/*.sieve')

View File

@ -1,78 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Generic config modifying utilities"""
import contextlib
import io
import re
from . import interproc
class ConfigInjector:
def __init__(self, match, generate):
self.re_pattern = re.compile(match)
self.boundary_fmt = generate + '\n'
def do_file_des(self, template, config, scratch):
"""Write modified config to the `scratch` stream"""
if not isinstance(template, io.TextIOBase):
raise TypeError('Not a text IO stream: template')
self._inject_config3(template, config, scratch)
def _inject_config3(self, template, config, scratch):
# Copy the original config up to header line
for line in config:
match = self.re_pattern.match(line.strip())
if match and match.group(1) == 'BEGIN':
break
scratch.write(line)
if not line.endswith('\n'): # in case no new line was at the eof
scratch.write('\n')
# Write header line
scratch.write(self.boundary_fmt.format('BEGIN'))
# Write template to scratch
for line in template:
scratch.write(line)
# in case no new line was at the eof
if not line.endswith('\n'):
scratch.write('\n')
# Write footer line
scratch.write(self.boundary_fmt.format('END'))
# Find the trailer line in config
for line in config:
match = self.re_pattern.match(line.strip())
if match and match.group(1) == 'END':
break
# Copy the original
for line in config:
scratch.write(line) # keep original file ending style
def do_template_file(self, template_path, config_path):
with open(template_path, 'r') as template:
with self._open_config(config_path) as (config, scratch):
self._inject_config3(template, config, scratch)
def do_template_string(self, template_string, config_path):
with self._open_config(config_path) as (config, scratch):
self._inject_config3([template_string], config, scratch)
@contextlib.contextmanager
def _open_config(self, config_path):
with open(config_path, 'a+') as config:
with interproc.atomically_rewrite(config_path) as scratch:
config.seek(0)
yield config, scratch
def has_header_line(self, config_path):
with open(config_path, 'r') as config_fd:
return self._has_header_line(config_fd)
def _has_header_line(self, config_fd):
for line in config_fd:
match = self.re_pattern.match(line.strip())
if match and match.group(1) == 'BEGIN':
return True
return False