From 7ebd467d8f104756f67c17a0b920df3db4e329ec Mon Sep 17 00:00:00 2001 From: Benjamin Date: Wed, 22 Feb 2023 20:12:13 +0100 Subject: [PATCH] Add first version --- .editorconfig | 12 +++ .gitignore | 175 ++++++++++++++++++++++++++++++++++++++++ .vscode/extensions.json | 5 ++ app.py | 62 ++++++++++++++ backend.py | 8 ++ settings.py | 8 ++ 6 files changed, 270 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 app.py create mode 100644 backend.py create mode 100644 settings.py diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f256bd2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = tab +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07964a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +### Python https://github.com/github/gitignore 8e67b9420cb6796e5eeca72682babdb06627ec8c +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### VisualStudioCode https://github.com/github/gitignore bf3f140cfabe05651c4338ad6e2ca173299f93df +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..e2e2139 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "EditorConfig.EditorConfig" + ] +} diff --git a/app.py b/app.py new file mode 100644 index 0000000..32e7775 --- /dev/null +++ b/app.py @@ -0,0 +1,62 @@ +import json +import hashlib +import hmac +from backend import handle_data +from settings import * + +def app(environ, start_response): + try: + data: dict = get_data(environ.copy()) + except Exception as e: + start_response('400', [ + ('Content-Type', 'text/plain') + ]) + return iter([str(e).encode()]) + + try: + logging: str = handle_data(data) + except Exception as e: + start_response('500', [ + ('Content-Type', 'text/plain') + ]) + return iter([str(e).encode()]) + + start_response('200 OK', [ + ('Content-Type', 'text/plain') + ]) + + return iter([logging.encode()]) + +def get_data(environ): + if environ['REQUEST_METHOD'] == 'POST': + if 'application/json' != environ.get('CONTENT_TYPE'): + raise Exception('Error: Content-Type is not application/json: ' + environ.get('CONTENT_TYPE')) + + try: + request_body_size = int(environ.get('CONTENT_LENGTH', 0)) + except (ValueError): + request_body_size = 0 + + if 0 == request_body_size: + raise Exception('Error: Content-Length is 0') + + request_body = environ.get('wsgi.input').read(request_body_size) + + signature = environ.get('HTTP_X_GITEA_SIGNATURE') + + if not signature: + raise Exception('Error: Missing signature') + + signature_actual = hmac.new(SECRET_KEY.encode(), request_body, hashlib.sha256).hexdigest() + + if signature_actual != signature: + raise Exception('Error: Signature could not be validated') + + try: + data = json.loads(request_body) + except json.decoder.JSONDecodeError as e: + raise Exception('Error: Could not parse the JSON body: %s' % e) + + return data + else: + raise Exception('Error: Request is not POST: ' + environ.get('REQUEST_METHOD')) diff --git a/backend.py b/backend.py new file mode 100644 index 0000000..9755069 --- /dev/null +++ b/backend.py @@ -0,0 +1,8 @@ +""" +Here you can perform your actions, depending on the information given in the +data dictionary. The returned string will be the plain-text body of the response +to the web-hook request. +""" + +def handle_data(data: dict) -> str: + return "Done" diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..9882680 --- /dev/null +++ b/settings.py @@ -0,0 +1,8 @@ +import os + +''' +This variable stores the secret key (as a string) for calculating the signature +to compare it with the one in the request. This secret key must be equal to the +one set in the web-hook settings. +''' +SECRET_KEY = os.environ['WEBHOOK_KEY']