Moth APIs ======= This document covers the following interfaces: * HTTP Endpoints: what the Moth client sends the Moth server * Puzzle executable: how the transpiler communicates with executables that provide puzzles * Category executable: how the transpiler communicates with executables that provide categories * Provider executable: how Moth communicates with things that provide puzzles (like the transpiler) The Puzzle, Category, and Provider executalbes are all very closely related, since each is a subset of the next. ---- Here's a bad diagram of how this all fits together. I don't know if this is going to help at all. Please submit a merge request with something better. HTTP provider API mothball API 🡗 🡗 🡗 client - mothd - mothball provider - category1.mb - custom provider category API 🡗 - internal transpiler - category2/mkcategory - category3/1/puzzle.md - category3/2/mkpuzzle 🡔 puzzle API # HTTP Endpoints The Moth server accepts standard HTTP `GET` and `POST`. Parameters may be encoded with standard `GET` query parameters (like `GET /endpoint?a=1&b=2`), or with `POST` as `application/x-www-form-encoded` data. ## `/state` Returns the current Moth event state as a JSON object. ### Parameters * `id`: team ID (optional) ### Return ```js { "Config": { "Devel": false // true means this is a development server }, "Messages: "HTML to be rendered as broadcast messages", "TeamNames": { "self": "Requesting team name", // Only if regestered team id is a provided "0": "Team 1 Name", "1": "Team 2 Name" // ... }, "PointsLog": [ [1602679698, "0", "category", 1] // epochTime, teamID, category, points // ... ], "Puzzles": { "category": [1, 2, 3, 6] // list of unlocked puzzles for category // ... } } ``` ### Example HTTP transaction #### Request ``` GET /state HTTP/1.0 ``` #### Response This response has been reflowed for readability: an actual on-wire response would not have newlines or indentation. ``` HTTP/1.0 200 OK Content-Type: application/json {"Config": {"Devel":false}, "Messages":"
Welcome to the event!
Event ends at 19:00!
", "TeamNames":{ "0":"Mike and Jack", "12":"Team 2", "4":"Team 8" }, "PointsLog":[ [1602702696,"0","nocode",1], [1602702705,"0","sequence",1], [1602702787,"0","nocode",2], [1602702831,"0","sequence",2], [1602702839,"4","nocode",3], [1602702896,"0","sequence",8], [1602702900,"4","nocode",4], [1602702913,"0","sequence",16] ], "Puzzles":{ "indy":[12], "nocode":[1,2,3,4,10], "sequence":[1,2,8,16,19], "steg":[1] } } ``` ## `/register` Registers a name to a team ID. This is only required once per team, but user interfaces may find it less confusing to users to present a "login" page. For this reason "this team is already registered" does not return an error. ### Parameters * `id`: team ID * `name`: team name ### Return An object inspired by [JSend](https://github.com/omniti-labs/jsend): ```json { "status": "success/fail/error", "data": { "short": "short description", "description": "long description" } } ``` ### Example HTTP transaction #### Request ``` POST /register HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 26 id=b387ca98&name=dirtbags ``` #### Repsonse ``` HTTP/1.0 200 OK Content-Type: application/json Content-Length=86 {"status":"success","data":{"short":"registered","description":"Team ID registered"}} ``` ## `/answer` Submits an answer for points. If the answer is wrong, no points are awarded 😉 ### Parameters * `id`: team ID * `category`: along with `points`, uniquely identifies a puzzle * `points`: along with `category`, uniquely identifies a puzzle ### Return An object inspired by [JSend](https://github.com/omniti-labs/jsend): ```json { "status": "success/fail/error", "data": { "short": "short description", "description": "long description" } } ``` ### Example HTTP transaction #### Request ``` POST /answer HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 62 id=b387ca98&category=sequence&points=2&answer=achilles+turnip ``` #### Repsonse ``` HTTP/1.0 200 OK Content-Type: application/json Content-Length=83 {"status":"fail","data":{"short":"not accepted","description":"Incorrect answer"}} ``` ## `/content/{category}/{points}/puzzle.json` Retrieves the JSON object describing a puzzle. Parameters are all in the URL for this endpoint, so `curl` and `wget` can be used. ### Parameters * `{category}` (in URL): along with `{points}`, uniquely identifies a puzzle * `{points}` (in URL): along with `{category}`, uniquely identifies a puzzle * `{filename}` (in URL): filename to retrieve ### Return JSON object describing a puzzle. #### JSON Puzzle Object ```js { "Pre": { // Things which appear before the puzzle is solved "Authors": ["Neale Pickett"], // List of puzzle authors, usually rendered as a footnote "Attachments": ["tiger.jpg"], // List of files attached to the puzzle "Scripts": [], // List of scripts which should be included in the HTML render of the puzzle "Body": "Can you find the hidden text?