diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..70b8734 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:slim-buster +VOLUME /opt +WORKDIR /discovery + +ENV PYTHONUNBUFFERED 1 +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt +COPY ./src/ . +EXPOSE 443 +ENTRYPOINT [ "python", "./app.py" ] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8cadc20 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3' +services: + builder: + build: . + image: toneprint:latest + dns: 8.8.8.8 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8ab6294..bb66cd8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ -flask \ No newline at end of file +flask +click +requests \ No newline at end of file diff --git a/src/app.py b/src/app.py index 56a7ebe..d4d3c6e 100755 --- a/src/app.py +++ b/src/app.py @@ -1,10 +1,17 @@ #!/usr/bin/env python - +import sys +import logging from flask import Flask, Response, request, abort +from functools import cache +import requests +import click -app = Flask(__name__) -responses_files = { +logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +WEBSERVICE_URL = "https://tp.tcelectronic.com/TonePrintService.svc" +STATIC_XML_FILES = { "GetVersionsAndInfo": "xml/GetVersionsAndInfoResponse.xml", "GetAllToneprintsFullBeta": 'xml/toneprints.xml', "GetAllArtistsFullBeta": "xml/artists.xml", @@ -13,35 +20,92 @@ "GetAllSelectTypes": "xml/selecttypes.xml", "GetAllProductTypesFull": "xml/producttypes.xml" } +ACTIONS_DATA = {} +ACTIONS = ('GetVersionsAndInfo', 'GetAllToneprintsFullBeta', 'GetAllArtistsFullBeta', + 'GetAllProductsFullBeta', 'GetAllEffectsFullBeta', 'GetAllProductTypesFull', 'GetAllSelectTypes') -def get_response(action): - file_path = responses_files.get(action, None) - if file_path: - print(f'File: {file_path} for action: {action}') - with open(file_path) as f: - data = f.read() - return data +app = Flask(__name__) + + +def patch_xml(action, xml_string): + if action == "GetAllArtistsFullBeta": + logger.info(f"Patch xml -> enable [edit artists toneprints]") + xml_string = xml_string.replace("false", "true") + return xml_string + + +def download_xml(action): + payload = f"""<{action} xmlns = "http://tempuri.org/">AX67D3F6A2YK8ZQ3_nothing""" + headers = {'Soapaction': f'"http://tempuri.org/ITonePrintService/{action}"', + 'Content-Type': 'text/xml; charset=utf-8'} + response = requests.post(WEBSERVICE_URL, headers=headers, data=payload) + if response.status_code == 200: + logger.info(f"Response from Server: {response.status_code} - Length: {len(response.text)}") + return response.text else: + logger.error(f"Response error from server: {response.status_code}") + logger.error(response.text) return None +def update_data(static_xml): + global ACTIONS_DATA + logger.info("Update xml") + for action in ACTIONS: + if not static_xml: + logger.info(f"Get xml for action: {action}") + xml = patch_xml(action, download_xml(action)) + if xml: + ACTIONS_DATA[action] = xml + else: + logger.info(f"Get static xml for action: {action}") + with open(STATIC_XML_FILES[action]) as f: + ACTIONS_DATA[action] = f.read() + + +@cache +def get_response(action): + return ACTIONS_DATA.get(action, None) + + @app.route("/TonePrintService.svc", methods=['POST']) def fake_service(): - print("--------------------------------") - print("Headers: ", request.headers) response = Response() action = request.headers.get('Soapaction', '').split('/')[-1].replace('"', '') if action: - print("Action:", action) - response_text = get_response(action) - if response_text: - response.data = response_text + logger.info(f"Request for Action:{action}") + logger.debug(f"Headers: {request.headers}") + response_xml = get_response(action) + if response_xml: + response.data = response_xml return response else: + logger.error(f"Unknown action: {action}") abort(404, 'Unknown action') else: + logger.error("Missing action in request") abort(400, 'Missing action') + +@click.command() +@click.option('-h', '--host', default="0.0.0.0", type=str, help='Listen host', show_default=True) +@click.option('-p', '--port', default=443, type=int, help='Listen port', show_default=True) +@click.option('--cert', default='ssl/cert.pem', type=click.Path(exists=True), help='Certificate File', show_default=True) +@click.option('--key', default='ssl/key.pem', type=click.Path(exists=True), help='Key File', show_default=True) +@click.option('--static-xml',is_flag=True, help="Update XML") +@click.option('--debug',is_flag=True, help="Debug mode") +def main(host, port, cert, key, static_xml, debug): + logger.info("Toneprint Fake Server [starting...]") + logger.info("Host: %s", host) + logger.info("Port: %s", port) + logger.info("Cert: %s", cert) + logger.info("Key: %s", key) + logger.info("Debug: %s", debug) + update_data(static_xml) + app.run(debug=debug, host=host, port=port, ssl_context=(cert, key)) + + if __name__ == "__main__": - app.run(debug=True, port=443, ssl_context=('ssl/cert.pem', 'ssl/key.pem')) \ No newline at end of file + main() +