From 15f47b63f485220bdfd51159a3a6d545e9b1570e Mon Sep 17 00:00:00 2001 From: Bofh Date: Thu, 11 Feb 2021 20:03:31 +0100 Subject: [PATCH] Improved API readability --- igmirror.py | 19 +++++++++++ server.py | 95 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 86 insertions(+), 28 deletions(-) diff --git a/igmirror.py b/igmirror.py index d06e384..b8d8f0f 100644 --- a/igmirror.py +++ b/igmirror.py @@ -562,6 +562,25 @@ def get_random_headers(): def account_exists(acc_id): return os.path.exists('./db/accounts/{}'.format(acc_id)) +def account_config(acc_id, key, value): + if not account_exists(acc_id): + return False, 'Account does not exist: {}'.format(acc_id) + + accdata = db_get('accounts', acc_id) + key = key.strip() + value = value.strip() + + # make sure passwords or cookie cannot be retrieved + if value == '' and not key in ['password', 'cookie']: + if not key in accdata: + return False, 'Key does not exist yet: {}'.format(key) + return True, accdata[key] + + # value has something, so we set it + accdata[key] = value + db_set('accounts', acc_id, accdata) + return True, 'Account configuration saved: {}'.format(key) + def db_set(table, acc_id, accdata): w = open('./db/{}/{}'.format(table, acc_id), 'w') w.write(json.dumps(accdata)) diff --git a/server.py b/server.py index 538caf4..caee59b 100644 --- a/server.py +++ b/server.py @@ -1,29 +1,34 @@ from http.server import BaseHTTPRequestHandler, HTTPServer +from urllib.parse import urlparse import igmirror +import json import sys import os import re class MyServer(BaseHTTPRequestHandler): def do_GET(self): - path = self.path.strip('/') + _ = urlparse(self.path) + qs = _.query + path = _.path.strip().strip('/') parts = path.split('/') if len(parts) == 1: + response(self, 200, 'html') + action = parts[0].lower() - self.send_response(200) - self.send_header("Content-type", "text/html") - self.end_headers() + if False: + pass # list accounts (plain text) - if parts[0] == 'list': + elif action == 'list': accounts = os.listdir('./db/accounts') for acc in sorted(set(accounts)): - self.wfile.write(bytes(acc+'\n', "utf-8")) + echo(self, acc) # lists accounts on a pretty HTML + CSS # making sure there is no XSS possible on account names - elif parts[0] == 'mirrors': + elif action == 'mirrors': html = """ @@ -100,20 +105,16 @@ div.item > div.links > div:nth-child(2) > a { """ html = igmirror.pixelfed_htmlfill_mirrors(html) - self.wfile.write(bytes(html, "utf-8")) + echo(self, html) return if len(parts) == 2: - - self.send_response(200) - self.send_header("Content-type", "application/json") - self.end_headers() - - # a wilcard select all accounts - what = parts[0] + response(self, 200, 'json') + acc_id = parts[0] action = parts[1].lower() - if what == '*': + + if acc_id == '*': if False: pass elif action == 'update': @@ -125,27 +126,65 @@ div.item > div.links > div:nth-child(2) > a { else: # make sure account name contains only safe characters # i think IG usernames can only have this characters: - accname = re.sub(r'[^a-zA-Z0-9_\.]+', '', what) if False: pass + elif action == 'add': - igmirror.add_igaccount(accname) + igmirror.add_igaccount(acc_id) + return echo(self, {'status': 'ok', 'message': 'New mirror account added to Pixelfed!'}) + elif action == 'update': - igmirror.update_igaccount_async(accname) + igmirror.update_igaccount_async(acc_id) + return echo(self, {'status': 'ok', 'message': 'Account update process started asyncronously'}) + elif action == 'login': - igmirror.pixelfed_login(accname, True) + igmirror.pixelfed_login(acc_id, True) + return echo(self, {'status': 'ok', 'message': 'Account logged in to Pixelfed'}) + elif action == 'logout': - igmirror.pixelfed_logout(accname) + igmirror.pixelfed_logout(acc_id) + return echo(self, {'status': 'ok', 'message': 'Account logged out of Pixelfed'}) + elif action == 'nuke': - igmirror.delete_statuses(accname) + igmirror.delete_statuses(acc_id) + return echo(self, {'status': 'ok', 'message': 'Account nuked successfully'}) - self.wfile.write(bytes('{"status": "ok"}', "utf-8")) - return + return echo(self, {'status': 'error', 'message': '2nd parameter action not configured: {}'.format(action)}) - self.send_response(400) - self.send_header("Content-type", "application/json") - self.end_headers() - self.wfile.write(bytes('{"status": "parameters are not correct"}', "utf-8")) + if len(parts) == 3: + response(self, 200, 'json') + acc_id = parts[0] + action = parts[1].lower() + key = parts[2].lower() + + if False: + pass + + elif action == 'cfg': + status, message = igmirror.account_config(acc_id, key, qs) + status = 'ok' if status else 'error' + return echo(self, {'status': status, 'message': message}) + + return echo(self, {'status': 'error', 'message': '2nd parameter action not configured: {}'.format(arg2)}) + + response(self, 400, 'json') + return echo(self, {'status': 'error', 'message': 'Parameters are not correct. Check out the API documentation'}) + +def response(obj, code, typ): + obj.send_response(code) + typ = typ.lower().strip() + if typ == 'html': + obj.send_header('Content-Type', 'text/html') + elif typ == 'json': + obj.send_header('Content-Type', 'application/json') + obj.end_headers() + +def echo(obj, what, newline=True): + if type(what) is dict or type(what) is list: + what = json.dumps(what) + if newline: + what = what + '\n' + obj.wfile.write(bytes(what, "utf-8")) if __name__ == "__main__": addr = '0.0.0.0'