Create skeleton of the Lacre daemon

Also:
- Expose a function to read mail relay configuration.
- Replace tabs with 4 spaces in lacre.config.
This commit is contained in:
Piotr F. Mieszkowski 2022-06-30 21:03:22 +02:00 committed by Gitea
parent 8f191cae72
commit 3f2760ba2d
3 changed files with 93 additions and 45 deletions

View File

@ -16,72 +16,86 @@ CONFIG_PATH_ENV = "GPG_MAILGATE_CONFIG"
# List of mandatory configuration parameters. Each item on this list should be
# a pair: a section name and a parameter name.
MANDATORY_CONFIG_ITEMS = [("relay", "host"),
("relay", "port")]
("relay", "port")]
# Global dict to keep configuration parameters. It's hidden behind several
# utility functions to make it easy to replace it with ConfigParser object in
# the future.
cfg = dict()
def load_config() -> dict:
"""Parses configuration file.
"""Parse configuration file.
If environment variable identified by CONFIG_PATH_ENV
variable is set, its value is taken as a configuration file
path. Otherwise, the default is taken
('/etc/gpg-mailgate.conf').
"""
configFile = os.getenv(CONFIG_PATH_ENV, '/etc/gpg-mailgate.conf')
If environment variable identified by CONFIG_PATH_ENV
variable is set, its value is taken as a configuration file
path. Otherwise, the default is taken
('/etc/gpg-mailgate.conf').
"""
configFile = os.getenv(CONFIG_PATH_ENV, '/etc/gpg-mailgate.conf')
parser = read_config(configFile)
parser = _read_config(configFile)
global cfg
cfg = copy_to_dict(parser)
return cfg
global cfg
cfg = _copy_to_dict(parser)
return cfg
def read_config(fileName) -> RawConfigParser:
cp = RawConfigParser()
cp.read(fileName)
return cp
def _read_config(fileName) -> RawConfigParser:
cp = RawConfigParser()
cp.read(fileName)
def copy_to_dict(confParser) -> dict:
config = dict()
return cp
for sect in confParser.sections():
config[sect] = dict()
for (name, value) in confParser.items(sect):
config[sect][name] = value
return config
def _copy_to_dict(confParser) -> dict:
config = dict()
for sect in confParser.sections():
config[sect] = dict()
for (name, value) in confParser.items(sect):
config[sect][name] = value
return config
def get_item(section, key, empty_value=None):
global cfg
if config_item_set(section, key):
return cfg[section][key]
else:
return empty_value
def get_item(section, key, empty_value = None):
global cfg
if config_item_set(section, key):
return cfg[section][key]
else:
return empty_value
def has_section(section) -> bool:
global cfg
return section in cfg
return section in cfg
def config_item_set(section, key) -> bool:
global cfg
return section in cfg and (key in cfg[section]) and not (cfg[section][key] is None)
return section in cfg and (key in cfg[section]) and not (cfg[section][key] is None)
def config_item_equals(section, key, value) -> bool:
global cfg
return section in cfg and key in cfg[section] and cfg[section][key] == value
return section in cfg and key in cfg[section] and cfg[section][key] == value
def validate_config():
"""Checks whether the configuration is complete.
"""Check if configuration is complete.
Returns a list of missing parameters, so an empty list means
configuration is complete.
"""
missing = []
for (section, param) in MANDATORY_CONFIG_ITEMS:
if not config_item_set(section, param):
missing.append((section, param))
return missing
Returns a list of missing parameters, so an empty list means
configuration is complete.
"""
missing = []
for (section, param) in MANDATORY_CONFIG_ITEMS:
if not config_item_set(section, param):
missing.append((section, param))
return missing
#
# High level access to configuration.
#
def relay_params():
"""Return a (HOST, PORT) tuple identifying the mail relay."""
return (cfg["relay"]["host"], int(cfg["relay"]["port"]))

34
lacre/daemon.py Normal file
View File

@ -0,0 +1,34 @@
"""Lacre Daemon, the Advanced Mail Filter message dispatcher."""
from aiosmtpd.controller import Controller
import lacre.config as conf
# import lacre.mailgate as gate
RESULT_OK = '250 OK'
RESULT_ERROR = '500 Could not process your message'
RESULT_NOT_IMPLEMENTED = '500 Not implemented yet'
class MailEncryptionProxy:
"""A mail handler dispatching to appropriate mail operation."""
async def handle_DATA(self, server, session, envelope):
"""Accept a message and either encrypt it or forward as-is."""
# for now, just return an error because we're not ready to handle mail
return RESULT_NOT_IMPLEMENTED
if __name__ == '__main__':
proxy = MailEncryptionProxy()
host, port = conf.relay_params()
controller = Controller(proxy, hostname=host, port=port)
# starts the controller in a new thread
controller.start()
# _this_ thread now continues operation, so it may be used to control key
# and certificate cache
controller.stop()

View File

@ -378,7 +378,7 @@ def send_msg( message, recipients ):
recipients = [_f for _f in recipients if _f]
if recipients:
LOG.info(f"Sending email to: {recipients!r}")
relay = (conf.get_item('relay', 'host'), int(conf.get_item('relay', 'port')))
relay = conf.relay_params()
smtp = smtplib.SMTP(relay[0], relay[1])
if conf.config_item_equals('relay', 'starttls', 'yes'):
smtp.starttls()