diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 610a814..0000000 --- a/docs/api.md +++ /dev/null @@ -1,215 +0,0 @@ -MOTHv3 API -========== - -MOTH, by design, uses a small number of API endpoints. - -Whenever possible, -we decided to push complexity into the client, -keeping the server as simple as we could make it. -After all, -this is a hacking contest. -If a participant finds a vulnerability in code running on their own machine, -the people running the server don't care. - -Specification -============= - -You make requests as HTTP GET query arguments: - - https://server/path/elements/api/v3/endpoint?var1=val1&var2=val2 - -The server returns a -[JSend](https://labs.omniti.com/labs/jsend) response: - - { - "status": "success", - "data": "Any JS data type here" - } - - -Client State -============ - -The client (or user interacting with the client) needs to remember only one thing: - -* teamId: the team ID used to register - -A naive client, -like the one we used from 2009-2018, -can ask the user to type in the team ID for every submission. -This is fine. - - -Endpoints -========= - -RegisterTeam(teamId, teamName) -------------------------------- - -Register a team name with a team hash. - -### Parameters - -* teamId: Team's unique identifier (usually a hex value) -* teamName: Team's human-readable name - -On success, no data is returned. -On failure, message contains an English explanation of why. - - -### Example - - https://server/api/v3/RegisterTeam?teamId=8b1292ca&teamName=Lexical+Pedants - - { - "status": "success", - "data": null - } - - -GetState() ----------- - -Return all current state of the puzzle server. - -### Parameters - -None - - -### Return data - -* puzzles: dictionary mapping from category to one of the following: - * list of point values currently open - * URL to puzzle root (intended for token-based puzzles) -* teams: mapping from anonymized team ID to team name -* log: list of (timestamp, team number, category, points) -* notices: list of HTML broadcast notices to display to the user -* now: current server time (unix epoch) - - -### Example - - https://server/api/v3/GetState - - { - "status": "success", - "data": { - "puzzles": { - "sequence": [1, 2], - "codebreaking": [10], - "wopr": "https://appspot.com/dooted-bagel-8372/entry" - }, - "teams": { - "0": "Zelda", - "1": "Defender" - }, - "log": [ - [1526478368, "0", "sequence", 1], - [1526478524, "1", "sequence", 1], - [1526478536, "0", "nocode", 1] - ], - "notices": [ - "WOPR category is now open", - "Event closes at 18:00 today, and will resume tomorrow at 08:00" - ], - "now": 1527170088 - } - } - - -GetPuzzle(category, points) --------------------- - -Return a puzzle. - -### Parameters - -* category: name of category to fetch from -* points: point value of the puzzle to fetch - - -### Return data - -* authors: List of puzzle authors -* hashes: list of djbhash values of acceptable answers -* files: dictionary of puzzle-associated filenames and their URLs -* body: HTML body of the puzzle - - -### Example - - https://server/api/v3/GetPuzzle?category=sequence&points=1 - - { - "status": "success", - "data": { - "authors": ["neale"], - "hashes": [177627], - "files": { - "happy.png": "https://cdn/assets/0904cf3a437a348bea2c49d56a3087c26a01a63c.png" - }, - "body": "
1 2 3 4 5 _\n
\n"
- }
-
-
-
-SubmitAnswer(teamId, category, points, answer)
-----------------------
-
-Submit an answer to a puzzle.
-
-### Parameters
-
-* teamId: Team ID (optional: if ommitted, answer is verified but no points are awarded)
-* category: category name of puzzle
-* points: point value of puzzle
-* answer: attempted answer
-
-
-### Return Data
-
-* epilog: HTML to display upon successfully answering the puzzle
-
-
-### Example
-
- https://server/api/v3/SubmitAnswer?teamId=8b1292ca&category=sequence&points=1&answer=6
-
- {
- "status": "success",
- "data": {
- "epilog": "That's right: in base 10, 5 + 1 = 6."
- }
- }
-
-SubmitToken(teamId, token)
----------------------
-
-Submit a token for points
-
-### Parameters
-
-* teamId: Team ID
-* token: Token being submitted
-
-
-### Return data
-
-* category: category for which this token awarded points
-* points: number of points awarded
-* epilog: HTML to display upon successfully answering the puzzle
-
-
-### Example
-
- https://server/api/v3/SubmitToken?teamId=8b1292ca&token=wat:30:xylep-radar-nanox
-
- {
- "status": "success",
- "data": {
- "category": "wat",
- "points": 30,
- "epilog": ""
- }
- }
diff --git a/tools/fake-server.py b/tools/fake-server.py
deleted file mode 100755
index 340b43b..0000000
--- a/tools/fake-server.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#! /usr/bin/python3
-
-from aiohttp import web
-import time
-
-async def fake_register(request):
- teamId = request.query.get("teamId")
- teamName = request.query.get("teamName")
- if teamId == "ffff" and teamName == "dirtbags":
- resp = {
- "status": "success",
- "data": None,
- }
- elif teamId and teamName:
- resp = {
- "status": "error",
- "message": "Query was correctly formed but I'm feeling cranky"
- }
- else:
- resp = {
- "status": "fail",
- "data": "You must send teamId and teamName",
- }
- return web.json_response(resp)
-
-async def fake_state(request):
- resp = {
- "status": "success",
- "data": {
- "puzzles": {
- "sequence": [1, 2],
- "codebreaking": [10],
- "wopr": "https://appspot.com/dooted-bagel-8372/entry"
- },
- "teams": {
- "0": "Zelda",
- "1": "Defender"
- },
- "log": [
- [1526478368, "0", "sequence", 1],
- [1526478524, "1", "sequence", 1],
- [1526478536, "0", "nocode", 1]
- ],
- "notices": [
- "WOPR category is now open",
- "Event closes at 18:00 today, and will resume tomorrow at 08:00"
- ],
- "now": int(time.time()),
- }
- }
- return web.json_response(resp)
-
-async def fake_getpuzzle(request):
- category = request.query.get("category")
- points = request.query.get("points")
- if category == "sequence" and points == "1":
- resp = {
- "status": "success",
- "data": {
- "authors": ["neale"],
- "hashes": [177627],
- "files": {
- "happy.png": "https://cdn/assets/0904cf3a437a348bea2c49d56a3087c26a01a63c.png"
- },
- "body": "1 2 3 4 5 _\n
\n",
- }
- }
- elif category and points:
- resp = {
- "status": "error",
- "message": "Query was correctly formed but I'm feeling cranky"
- }
- else:
- resp = {
- "status": "fail",
- "data": "You must send category and points"
- }
- return web.json_response(resp)
-
-async def fake_submitanswer(request):
- teamId = request.query.get("teamId")
- category = request.query.get("category")
- points = request.query.get("points")
- answer = request.query.get("answer")
- if category == "sequence" and points == "1" and answer == "6":
- resp = {
- "status": "success",
- "data": {
- "epilog": "Now you know the answer, and knowing is half the battle. Go Joe!"
- }
- }
- elif category and points and answer:
- resp = {
- "status": "error",
- "message": "Query was correctly formed but I'm feeling cranky"
- }
- else:
- resp = {
- "status": "fail",
- "data": "You must send category and points"
- }
- return web.json_response(resp)
-
-async def fake_submittoken(request):
- teamId = request.query.get("teamId")
- token = request.query.get("token")
- if token == "wat:30:xylep-radar-nanox":
- resp = {
- "status": "success",
- "data": {
- "category": "wat",
- "points": 30,
- "epilog": ""
- }
- }
- elif category and points and answer:
- resp = {
- "status": "error",
- "message": "Query was correctly formed but I'm feeling cranky"
- }
- else:
- resp = {
- "status": "fail",
- "data": "You must send category and points"
- }
- return web.json_response(resp)
-
-if __name__ == "__main__":
- app = web.Application()
- app.router.add_route("GET", "/api/v3/RegisterTeam", fake_register)
- app.router.add_route("GET", "/api/v3/GetState", fake_state)
- app.router.add_route("GET", "/api/v3/GetPuzzle", fake_getpuzzle)
- app.router.add_route("GET", "/api/v3/SubmitAnswer", fake_submitanswer)
- app.router.add_route("GET", "/api/v3/SubmitToken", fake_submittoken)
- web.run_app(app)