~cadence/crumpet

f192b5b1f53f4ed97b228be220da64526acd4cd2 — Cadence Ember 7 months ago a571e2c
Support server usage
1 files changed, 85 insertions(+), 3 deletions(-)

M crumpet.py
M crumpet.py => crumpet.py +85 -3
@@ 1,26 1,33 @@
import cherrypy
from cherrypy.lib.static import serve_file
import hashlib
import mimetypes
import os
import pathlib
import random
import re
import requests
import shelve
import shutil
import subprocess
import sys
from threading import Lock
import time

content_host = "https://cadence.moe"

mimetypes.types_map[".js"] = "text/javascript" # serve correct type for javascript modules; mimetypes module has application/javascript normally

tokens = {}
tokens_lock = Lock()

db = None
def init_database():
	global db
	db = shelve.open("crumpet_server_config", writeback=False)
	db.setdefault("game_directory", None)
	db.setdefault("customlevels_directory", None)
	db.setdefault("is_installed", True)
	db.setdefault("is_public_server", False)

try:
	init_database()


@@ 121,6 128,10 @@ class Crumpet:
	def _cp_dispatch(self, vpath):
		if vpath[:2] == ["api", "rtw"]:
			vpath[:2] = []

			if vpath[0] == "fetchimages":
				vpath[0] = "images_server"

			return self

		return vpath


@@ 152,6 163,12 @@ class Crumpet:
	@cherrypy.tools.json_in()
	@cherrypy.tools.json_out()
	def save_game_directory(self):
		if db["is_public_server"]:
			return {
				"status": "failure",
				"message": "This server cannot be configured."
			}

		try:
			root = cherrypy.request.json
		except AttributeError:


@@ 189,6 206,12 @@ class Crumpet:
	@cherrypy.tools.json_in()
	@cherrypy.tools.json_out()
	def save_customlevels_directory(self):
		if db["is_public_server"]:
			return {
				"status": "failure",
				"message": "This server cannot be configured."
			}

		try:
			root = cherrypy.request.json
		except AttributeError:


@@ 217,8 240,57 @@ class Crumpet:
		}

	@cherrypy.expose
	def token(self):
		if not db["is_public_server"]:
			cherrypy.response.status = 403
			return ""

		r = str(random.random()).split(".")[1]
		with tokens_lock:
			tokens[r] = time.time() + 60 # one minute from now
		return r

	@cherrypy.expose
	def images_server(self, *suffix, token, hash, **kwargs):
		print(token, hash)

		if not db["is_public_server"]:
			cherrypy.response.status = 403
			return ""

		if not token or not hash:
			cherrypy.response.status = 400
			return "Must supply token and hash"

		with tokens_lock:
			print(tokens)
			if token not in tokens:
				cherrypy.response.status = 403
				return "Invalid token"

			if tokens[token] < time.time():
				cherrypy.response.status = 403
				return "Expired token"

		h = hash_file("res2.dat")
		h.update(bytes(token, "utf-8"))
		patched_hash = h.hexdigest()

		if hash != patched_hash:
			cherrypy.response.status = 403
			return "Hash does not match"

		return serve_file(pathlib.Path(__file__).parent.joinpath("images.zip").absolute(), "application/zip")

	@cherrypy.expose
	@cherrypy.tools.json_out()
	def request_images(self, *path_components):
		if db["is_public_server"]:
			return {
				"status": "failure",
				"message": "This server cannot be configured."
			}

		# Request a token
		token_request = requests.get(content_host + "/api/rtw/token")
		token = token_request.content


@@ 264,8 336,12 @@ class Crumpet:
	@cherrypy.expose
	@cherrypy.tools.json_in()
	def download(self):
		if not db["is_installed"]:
			return restricted_message()
		if db["is_public_server"]:
			return {
				"status": "failure",
				"message": "This is a public server, and you cannot store levels on it."
			}

		root = cherrypy.request.json
		level_data = bytearray(root["data"])
		filename = root["filename"]


@@ 276,6 352,12 @@ class Crumpet:
	@cherrypy.expose
	@cherrypy.tools.json_out()
	def load(self, filename):
		if db["is_public_server"]:
			return {
				"status": "failure",
				"message": "This is a public server, and you cannot store levels on it."
			}

		with open_level(filename, "rb") as fd:
			level_data = fd.read()
		return list(level_data)