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:
parent
8f191cae72
commit
3f2760ba2d
102
lacre/config.py
102
lacre/config.py
|
@ -16,72 +16,86 @@ CONFIG_PATH_ENV = "GPG_MAILGATE_CONFIG"
|
||||||
# List of mandatory configuration parameters. Each item on this list should be
|
# List of mandatory configuration parameters. Each item on this list should be
|
||||||
# a pair: a section name and a parameter name.
|
# a pair: a section name and a parameter name.
|
||||||
MANDATORY_CONFIG_ITEMS = [("relay", "host"),
|
MANDATORY_CONFIG_ITEMS = [("relay", "host"),
|
||||||
("relay", "port")]
|
("relay", "port")]
|
||||||
|
|
||||||
# Global dict to keep configuration parameters. It's hidden behind several
|
# Global dict to keep configuration parameters. It's hidden behind several
|
||||||
# utility functions to make it easy to replace it with ConfigParser object in
|
# utility functions to make it easy to replace it with ConfigParser object in
|
||||||
# the future.
|
# the future.
|
||||||
cfg = dict()
|
cfg = dict()
|
||||||
|
|
||||||
|
|
||||||
def load_config() -> dict:
|
def load_config() -> dict:
|
||||||
"""Parses configuration file.
|
"""Parse configuration file.
|
||||||
|
|
||||||
If environment variable identified by CONFIG_PATH_ENV
|
If environment variable identified by CONFIG_PATH_ENV
|
||||||
variable is set, its value is taken as a configuration file
|
variable is set, its value is taken as a configuration file
|
||||||
path. Otherwise, the default is taken
|
path. Otherwise, the default is taken
|
||||||
('/etc/gpg-mailgate.conf').
|
('/etc/gpg-mailgate.conf').
|
||||||
"""
|
"""
|
||||||
configFile = os.getenv(CONFIG_PATH_ENV, '/etc/gpg-mailgate.conf')
|
configFile = os.getenv(CONFIG_PATH_ENV, '/etc/gpg-mailgate.conf')
|
||||||
|
|
||||||
parser = read_config(configFile)
|
parser = _read_config(configFile)
|
||||||
|
|
||||||
global cfg
|
global cfg
|
||||||
cfg = copy_to_dict(parser)
|
cfg = _copy_to_dict(parser)
|
||||||
return cfg
|
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:
|
return cp
|
||||||
config = dict()
|
|
||||||
|
|
||||||
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:
|
def has_section(section) -> bool:
|
||||||
global cfg
|
return section in cfg
|
||||||
return section in cfg
|
|
||||||
|
|
||||||
def config_item_set(section, key) -> bool:
|
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:
|
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():
|
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
|
Returns a list of missing parameters, so an empty list means
|
||||||
configuration is complete.
|
configuration is complete.
|
||||||
"""
|
"""
|
||||||
missing = []
|
missing = []
|
||||||
for (section, param) in MANDATORY_CONFIG_ITEMS:
|
for (section, param) in MANDATORY_CONFIG_ITEMS:
|
||||||
if not config_item_set(section, param):
|
if not config_item_set(section, param):
|
||||||
missing.append((section, param))
|
missing.append((section, param))
|
||||||
return missing
|
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"]))
|
||||||
|
|
|
@ -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()
|
|
@ -378,7 +378,7 @@ def send_msg( message, recipients ):
|
||||||
recipients = [_f for _f in recipients if _f]
|
recipients = [_f for _f in recipients if _f]
|
||||||
if recipients:
|
if recipients:
|
||||||
LOG.info(f"Sending email to: {recipients!r}")
|
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])
|
smtp = smtplib.SMTP(relay[0], relay[1])
|
||||||
if conf.config_item_equals('relay', 'starttls', 'yes'):
|
if conf.config_item_equals('relay', 'starttls', 'yes'):
|
||||||
smtp.starttls()
|
smtp.starttls()
|
||||||
|
|
Loading…
Reference in New Issue