From c70b900fe20f74d20c76ece6a0ca27a30d8fda53 Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Tue, 16 Feb 2021 17:24:26 +0100 Subject: [PATCH] Add support for config file --- Dockerfile | 4 +++- README.md | 10 +++++++--- gmnd/__init__.py | 52 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9cf344b..ac1f557 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,9 +15,11 @@ RUN openssl req \ -extensions san \ -config openssl.conf FROM python:3 AS deploy-stage +RUN pip install pyyaml WORKDIR /app COPY ./gmnd/__init__.py . COPY ./content content +COPY config.yml . COPY --from=build-stage /app/certs certs EXPOSE 1965 -CMD ["python", "__init__.py"] +CMD ["python", "__init__.py", "--file", "config.yml" ] diff --git a/README.md b/README.md index 47aa32e..8a5fcfb 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,19 @@ # gMNd gMNd is my gemini server, which is written in python. -Currently it only serves static files. You can build and run it from the supplied Dockerfile if you so whish +Currently it only serves static files. You can build and run it from the supplied Dockerfile if you so whish: ``` docker build -t gmnd:latest . ``` -By just running it, it will create self signed certs and serve example content from this repo +By just running it, it will create self signed certs and serve example content from this repo: ``` docker run -p 1965:1965 gmnd ``` -A slightly more interesting thing it can do is serve your own content, in this example from /tm/content on your host machine +A slightly more interesting thing it can do is serve your own content, in this example from /tmp/content on your host machine: ``` docker run --mount type=bind,source="/tmp/content,target=/app/content" -p 1965:1965 gmnd ``` +Or even supply your own certificates from the outside, in this example in /usr/local/certs: +``` +docker run --mount type=bind,source="/tmp/content,target=/app/content" --mount type=bind,source="/usr/local/certs,target=/app/certs" -p 1965:1965 gmnd +``` diff --git a/gmnd/__init__.py b/gmnd/__init__.py index 60ed570..c40acf5 100644 --- a/gmnd/__init__.py +++ b/gmnd/__init__.py @@ -7,22 +7,48 @@ import sys from socket import AF_INET, SHUT_RDWR, SO_REUSEADDR, SOCK_STREAM, SOL_SOCKET from urllib.parse import urlparse +import yaml + class gMNd: def __init__(self, options={}): + self.allow_dir_list = options.get('allow_dir_list', False) self.base_path = options.get('base_path', './content') - self.logg_level = options.get('logg_level', logging.INFO) + self.config_file = options.get('config_file', None) self.listen_addr = options.get('listen_addr', '127.0.0.1') - self.allow_dir_list = options.get('allow_dir_list', False) self.listen_port = options.get('listen_port', 1965) + self.logg_level = options.get('logg_level', logging.INFO) self.server_cert = options.get('server_cert', './certs/cert.pem') self.server_key = options.get('server_key', './certs/cert.key') logging.basicConfig(stream=sys.stderr, level=self.logg_level) + if self.config_file: + if os.path.isfile(self.config_file): + self.read_config() + else: + logging.warning("Config file supplied, but it is not a file") self.bindsocket = socket.socket() self.bindsocket.bind((self.listen_addr, self.listen_port)) self.bindsocket.listen(5) + def read_config(self): + with open(self.config_file) as configfile: + config_dict = yaml.load(configfile, Loader=yaml.FullLoader) + if 'allow_dir_list' in config_dict: + self.allow_dir_list = config_dict['allow_dir_list'] + if 'base_path' in config_dict: + self.base_path = config_dict['base_path'] + if 'listen_addr' in config_dict: + self.listen_addr = config_dict['listen_addr'] + if 'listen_port' in config_dict: + self.listen_port = config_dict['listen_port'] + if 'logg_level' in config_dict: + self.logg_level = config_dict['logg_level'] + if 'server_cert' in config_dict: + self.server_cert = config_dict['server_cert'] + if 'server_key' in config_dict: + self.server_key = config_dict['server_key'] + def run(self): while True: logging.debug("Waiting for client") @@ -37,14 +63,14 @@ class gMNd: conn.getpeercert())) try: request = conn.recv() - logging.debug(request) + logging.debug("Full request: {}".format(request)) url = urlparse(request) scheme = url.scheme.decode() netloc = url.netloc.decode() path = url.path.decode().rstrip() - logging.debug(scheme) - logging.debug(netloc) - logging.debug(path) + logging.debug("Scheme: {}".format(scheme)) + logging.debug("Netloc: {}".format(netloc)) + logging.debug("Path: {}".format(path)) header = get_header() body = b"" @@ -52,8 +78,8 @@ class gMNd: if not path.endswith(".gmi"): header = get_header( '20', - mimetypes.guess_type( - self.base_path + path)[0].encode()) + mimetypes.guess_type(self.base_path + + path)[0].encode()) cfile = open(self.base_path + path) body = cfile.read().encode() cfile.close() @@ -63,7 +89,7 @@ class gMNd: '/index.gmi') body = cfile.read().encode() cfile.close() - logging.debug(body) + logging.debug("Body: {}".format(body)) elif os.path.isdir(self.base_path + path) and self.allow_dir_list: body = self.get_dir_list(path) @@ -111,8 +137,8 @@ def get_header(status='20', meta=b"text/gemini"): if __name__ == "__main__": - server = gMNd({ - 'allow_dir_list': True, - 'listen_addr': '0.0.0.0' - }) + options = {} + if (sys.argv[1] == "-f" or sys.argv[1] == "--file") and sys.argv[2]: + options['config_file'] = sys.argv[2] + server = gMNd(options) server.run()