AutoZoomAPI/daemon.py

315 lines
11 KiB
Python

# -*- coding: utf-8 -*-
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
import ujson
import os
import random
import shutil
import requests
import string
import traceback
from urllib.parse import parse_qs, urlsplit
def jsonLoad(path):
data = open(path, "r", encoding='utf-8')
out = ujson.load(data)
data.close()
return out
def jsonSave(path, value):
file = open(path, "w", encoding='utf-8')
file.write(ujson.dumps(value, indent=4))
file.close()
def apiKeyInvalid(obj):
obj.send_response(401)
obj.send_header('Content-type', 'application/json; charset=utf-8')
obj.end_headers()
obj.wfile.write(b'{"code":401, "message": "Invalid API key"}')
return
def apiKeyExpired(obj):
obj.send_response(403)
obj.send_header('Content-type', 'application/json; charset=utf-8')
obj.end_headers()
obj.wfile.write(b'{"code":403, "message": "API key expired"}')
return
def badRequest(obj):
obj.send_response(400)
obj.send_header('Content-type', 'application/json; charset=utf-8')
obj.end_headers()
obj.wfile.write(b'{"code":400, "message": "Bad request"}')
return
def okRequest(obj):
obj.send_response(200)
obj.send_header('Content-type', 'application/json; charset=utf-8')
obj.end_headers()
obj.wfile.write(b'{"code":200, "message": "ok"}')
return
def blacklistedRequest(obj):
obj.send_response(403)
obj.send_header('Content-type', 'application/json; charset=utf-8')
obj.end_headers()
obj.wfile.write(b'{"code":403, "message": "Your IP is blacklisted. Make sure you are using correct API address."}')
obj.close_connection
return
def azGenKey(ipaddr):
az_requests = jsonLoad(config["data_location"]+"az_requests.json")
today_day = datetime.now().strftime("%d.%m.%Y")
if ipaddr in az_requests:
if today_day in az_requests[ipaddr]:
if az_requests[ipaddr][today_day] > 4:
return False
else:
az_requests[ipaddr][today_day] = 0
else:
az_requests[ipaddr] = {}
az_requests[ipaddr][today_day] = 0
api_keys = jsonLoad(config["data_location"]+"api_keys.json")
key = ''.join(random.sample(string.ascii_letters + string.digits, 20))
api_keys["autozoom"].append(key)
az_requests[ipaddr][today_day] += 1
jsonSave(config["data_location"]+"api_keys.json", api_keys)
jsonSave(config["data_location"]+"az_requests.json", az_requests)
return key
conffile = open("config.json", "r")
config = ujson.load(conffile)
conffile.close()
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
global config
blacklist = jsonLoad(config["data_location"]+"blacklist.json")
for addr in blacklist:
if addr == str(self.headers["X-Real-IP"]):
blacklistedRequest(self)
keys = jsonLoad(config["data_location"]+"api_keys.json")
expired = jsonLoad(config["data_location"]+"expired_keys.json")
try:
fullpath = config["url"]+self.path
reqpath = urlsplit(fullpath).path
requery = parse_qs(urlsplit(fullpath).query)
if reqpath == "/favicon.ico":
with open("favicon.ico", 'rb') as f:
self.send_response(200)
self.send_header(
"Content-Type", 'application/octet-stream')
self.send_header(
"Content-Disposition", 'attachment; filename="{}"'.format(os.path.basename("favicon.ico")))
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs.st_size))
self.end_headers()
shutil.copyfileobj(f, self.wfile)
f.close()
elif (reqpath == "/azVersion"):
if requery["apikey"][0] == "publickey":
file = open(config["autozoom_location"]+"version.json", "r")
versions = ujson.load(file)
file.close()
output = versions["stable"]
if "branch" in reqpath:
if requery["branch"][0] == "dev":
output = versions["dev"]
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(bytes(ujson.dumps({"version": output}), encoding='utf-8'))
elif requery["apikey"][0] in expired:
apiKeyExpired(self)
else:
apiKeyInvalid(self)
elif (reqpath == "/azChangelog"):
if requery["apikey"][0] == "publickey":
file = open(f'{config["autozoom_location"]}changelogs/{requery["version"][0]}.json', "r")
output = ujson.load(file)[requery["locale"][0]]
file.close()
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(bytes(ujson.dumps({"changelog": output}, ensure_ascii=False), encoding='utf-8'))
elif requery["apikey"][0] in expired:
apiKeyExpired(self)
else:
apiKeyInvalid(self)
elif (reqpath == "/azRequestKey"):
if requery["apikey"][0] == "publickey":
generated_key = azGenKey(str(self.headers["X-Real-IP"]))
if not generated_key:
self.send_response(403)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(b'{"code":403, "message": "Too many new key requests for today. Try again later."}')
else:
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(bytes('{"code":200, "message": "ok", "apikey": "' + generated_key + '"}', encoding='utf-8'))
elif requery["apikey"][0] in expired:
apiKeyExpired(self)
else:
apiKeyInvalid(self)
elif (reqpath == "/update"):
if requery["app"][0] == "autozoom":
if requery["apikey"][0] == "publickey":
filepath = config["autozoom_location"]+"AutoZoomLatest.zip"
with open(filepath, 'rb') as f:
self.send_response(200)
self.send_header("Content-Type", 'application/octet-stream')
self.send_header("Content-Disposition", 'attachment; filename="{}"'.format(os.path.basename(filepath)))
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs.st_size))
self.end_headers()
shutil.copyfileobj(f, self.wfile)
f.close()
else:
apiKeyInvalid(self)
else:
badRequest(self)
else:
badRequest(self)
except Exception as exp:
badRequest(self)
traceback.print_exc()
def do_POST(self):
global config
blacklist = jsonLoad(config["data_location"]+"blacklist.json")
for addr in blacklist:
if addr == str(self.headers["X-Real-IP"]):
blacklistedRequest(self)
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length).decode("utf-8")
keys = jsonLoad(config["data_location"]+"api_keys.json")
expired = jsonLoad(config["data_location"]+"expired_keys.json")
try:
fullpath = config["url"]+self.path
reqpath = urlsplit(fullpath).path
requery = parse_qs(urlsplit(fullpath).query)
data = body
if (reqpath == "/azSendMessage"):
if requery["apikey"][0] in keys["autozoom"]:
keys_storage = jsonLoad(config["data_location"]+"keys_storage.json")
if requery["apikey"][0] in keys_storage:
try:
if "message" in reqpath:
try:
output = requests.post(
url=f'https://api.telegram.org/bot{config["telegram_bot_token"]}/sendMessage?chat_id={keys_storage[requery["apikey"][0]]}&text={requery["message"][0]}'
)
except:
output = requests.post(
url=f'https://api.telegram.org/bot{config["telegram_bot_token"]}/sendMessage',
data={'chat_id': keys_storage[requery["apikey"][0]], 'text': ujson.loads(data)["message"]}
)
else:
output = requests.post(
url=f'https://api.telegram.org/bot{config["telegram_bot_token"]}/sendMessage',
data={'chat_id': keys_storage[requery["apikey"][0]], 'text': ujson.loads(data)["message"]}
)
if output.status_code == requests.codes.ok:
okRequest(self)
else:
badRequest(self)
except:
traceback.print_exc()
badRequest(self)
else:
self.send_response(400)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.end_headers()
self.wfile.write(b'{"code":400, "message": "Bad request. This key might not be linked to Telegram user."}')
elif requery["apikey"][0] in expired:
apiKeyExpired(self)
else:
apiKeyInvalid(self)
else:
badRequest(self)
except Exception as exp:
badRequest(self)
traceback.print_exc()
httpd = HTTPServer((config["address"], config["port"]), SimpleHTTPRequestHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass