110 lines
2.7 KiB
Python
Executable File
110 lines
2.7 KiB
Python
Executable File
import json
|
|
|
|
from flask import render_template, request, send_from_directory, make_response
|
|
|
|
from .app import app, db
|
|
from .models import Server
|
|
from .tasks import update_server
|
|
from .util import check_ban, check_request_json, get_addr_info, get_geo_continent, verify_announce
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return app.send_static_file("index.html")
|
|
|
|
|
|
@app.route("/list")
|
|
def server_list():
|
|
# We have to make sure that the list isn't cached,
|
|
# since the list isn't really static.
|
|
return send_from_directory(app.static_folder, "list.json", max_age=0)
|
|
|
|
|
|
@app.route("/geoip")
|
|
def geoip():
|
|
continent = get_geo_continent(request.remote_addr)
|
|
|
|
resp = make_response({
|
|
"continent": continent, # null on error
|
|
})
|
|
resp.cache_control.max_age = 7 * 86400
|
|
resp.cache_control.private = True
|
|
|
|
return resp
|
|
|
|
|
|
@app.route("/announce", methods=["GET", "POST"])
|
|
def announce():
|
|
announce_ip = request.remote_addr
|
|
if announce_ip.startswith("::ffff:"):
|
|
announce_ip = announce_ip[7:]
|
|
|
|
if announce_ip in app.config["BANNED_IPS"]:
|
|
return "Banned.", 403
|
|
|
|
data = request.values["json"]
|
|
|
|
if len(data) > 8192:
|
|
return "JSON data is too big.", 413
|
|
|
|
try:
|
|
obj = json.loads(data)
|
|
except json.JSONDecodeError as e:
|
|
return "Failed to decode JSON: " + e.msg, 400
|
|
|
|
if not isinstance(obj, dict):
|
|
return "JSON data is not an object.", 400
|
|
|
|
action = obj.get("action")
|
|
if action not in ("start", "update", "delete"):
|
|
return "Action field is invalid or missing.", 400
|
|
|
|
obj["ip"] = announce_ip
|
|
if not obj.get("address"):
|
|
obj["address"] = announce_ip
|
|
obj.setdefault("port", 30000)
|
|
|
|
if check_ban(announce_ip, obj["address"], obj["port"]):
|
|
return "Banned", 403
|
|
|
|
server = Server.find_from_json(obj)
|
|
|
|
if action == "delete":
|
|
if not server:
|
|
return "Server not found."
|
|
server.set_offline()
|
|
db.session.commit()
|
|
return "Removed from server list."
|
|
|
|
# Delete message does not require most fields
|
|
error_str = check_request_json(obj)
|
|
if error_str is not None:
|
|
return "Invalid JSON data: " + error_str, 400
|
|
|
|
if action == "update" and not server:
|
|
if app.config["ALLOW_UPDATE_WITHOUT_OLD"]:
|
|
action = "start"
|
|
else:
|
|
return "Server to update not found.", 404
|
|
|
|
addr_info = get_addr_info(obj["address"], obj["port"])
|
|
|
|
if addr_info is None:
|
|
return f"Failed to resolve server address {obj['address']!r}.", 400
|
|
|
|
valid = False
|
|
if "world_uuid" not in obj:
|
|
valid = verify_announce(addr_info, obj["address"], obj["ip"])
|
|
|
|
if not valid and server and server.address_verification_required:
|
|
return render_template("address_verification_failed.txt",
|
|
announce_ip=announce_ip,
|
|
valid_addresses=[data[4][0] for data in addr_info]), 400
|
|
obj["address_verified"] = valid
|
|
|
|
obj["addr_info"] = addr_info
|
|
|
|
update_server.delay(obj)
|
|
|
|
return "Done.", 202
|