From c2189bf826d861d677a3de6a5fc66c99f747bff9 Mon Sep 17 00:00:00 2001 From: Slawek Koszewski Date: Sat, 27 Dec 2025 13:40:42 +0100 Subject: [PATCH] Implemented set,delete,list proxy for MIAB API. --- app.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/app.py b/app.py index 6c344db..ecdd07d 100755 --- a/app.py +++ b/app.py @@ -1,12 +1,90 @@ #!/usr/bin/env python3 -from flask import Flask +from flask import Flask, Response, request, jsonify +from flask_httpauth import HTTPBasicAuth +from base64 import b64encode +from requests import get, put, delete +from os import getenv + +# Define global variables for MIAB host and auth header, to be set during authentication +MIAB_HOST = getenv('MIAB_HOST', 'localhost') +MIAB_AUTH_HEADER = '' app = Flask('dns-updater') +auth = HTTPBasicAuth() -@app.route('/api/dnsupdate') -def api_root(): - return "Welcome to the DNS Updater API" +# Verify username and password by attempting to access a dummy DNS record +@auth.verify_password +def verify(username, password): + global MIAB_AUTH_HEADER, MIAB_HOST + MIAB_AUTH_HEADER = "Basic " + b64encode(f"{username}:{password}".encode()).decode() + result = get(f'https://{MIAB_HOST}/admin/dns/custom/test/A', headers={'Authorization': MIAB_AUTH_HEADER}) + if result.status_code != 200: + return False + + return True + +@app.route('/api/setrecord//', methods=['GET'], defaults={'rtype': 'A'}) +@app.route('/api/setrecord///', methods=['GET']) +@app.route('/api/setrecord/', methods=['PUT'], defaults={'rtype': 'A'}) +@app.route('/api/setrecord//', methods=['PUT']) +@auth.login_required +def set_record(qname, rtype, value = None): + global MIAB_HOST, MIAB_AUTH_HEADER + + # Use request data as value for PUT method + if request.method == 'PUT': + value = request.data.decode() + + url = f'https://{MIAB_HOST}/admin/dns/custom/{qname}/{rtype}' + resp = put(url, headers={'Authorization': MIAB_AUTH_HEADER, 'Content-Type': 'text/plain'}, data=value) + + # Propagate 400-499 as is, 500+ as 502 + if resp.status_code != 200: + if 400 <= resp.status_code < 500: + status = resp.status_code + elif resp.status_code >= 500: + status = 502 + else: + status = 500 + return Response(f'Error: {resp.status_code} {resp.text}\n', status=status) + + # Success + return f'OK, created record name = {qname}, type = {rtype.upper()}, value = {value}\n' + +@app.route('/api/deleterecord//', methods=['GET', 'DELETE']) +@auth.login_required +def delete_record(qname, rtype): + global MIAB_HOST, MIAB_AUTH_HEADER + url = f'https://{MIAB_HOST}/admin/dns/custom/{qname}/{rtype}' + resp = delete(url, headers={'Authorization': MIAB_AUTH_HEADER, 'Content-Type': 'text/plain'}, data='') + + # Propagate 400-499 as is, 500+ as 502 + if resp.status_code != 200: + if 400 <= resp.status_code < 500: + status = resp.status_code + elif resp.status_code >= 500: + status = 502 + else: + status = 500 + return Response(f'Error: {resp.status_code} {resp.text}\n', status=status) + + # Success + return f'OK, deleted record name = {qname}, type = {rtype.upper()}\n' + +@app.route('/api/listrecords', methods=['GET'], defaults={'qname': None, 'rtype': None}) +@app.route('/api/listrecords/', methods=['GET'], defaults={'rtype': None}) +@app.route('/api/listrecords//', methods=['GET']) +@auth.login_required +def list_records(qname, rtype): + global MIAB_HOST, MIAB_AUTH_HEADER + url = f'https://{MIAB_HOST}/admin/dns/custom' + if qname: + url += f'/{qname}' + if rtype: + url += f'/{rtype}' + resp = get(url, headers={'Authorization': MIAB_AUTH_HEADER}) + return jsonify(resp.json()) if __name__ == '__main__': - app.run(host='0.0.0.0', port=8080) + app.run(debug=True, host='0.0.0.0', port=8080)