schoolbox-ws/manual/manual.typ

152 lines
4.7 KiB
Typst

#import "@preview/ilm:1.4.1": *
#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge, shapes
#show link: underline
#show link: set text(fill: blue)
#set text(lang: "en")
#show: ilm.with(
title: [SchoolBOX WS],
author: "Jurn Wubben",
date: datetime.today(),
abstract: [Websocket comminucation between the SchoolBox device and the associated server.],
figure-index: (enabled: false),
table-index: (enabled: false),
listing-index: (enabled: false)
)
= Messages
== Heartbeat
=== Server
- ```json
{"c": "ping"}
```<ping>
- ```json
{"e": 0, "info": "Pong missed"}
```<pongmissed>
=== Device
- ```json
{"c": "pong"}
```<pong>
== Registration
=== Server
- ```json
{"c": "reg_pin", "d": {"pin": 1234}} // Pin is a random integer. Length doesn't really matter, as long as it fits on the screen.
```<reg_pin>
- ```json
{"c": "reg_ok"}
```<reg_ok>
=== Device
- ```json
{"c": "reg_start"}
```<reg_start>
== Authentication
=== Server
- ```json
{"c": "auth_nonce", "d": {"nonce": "random_string"}} // Should be a long, random generated string.
```<auth_nonce>
- ```json
{"c": "auth_ok"}
```<auth_ok>
- ```json
{"e": 1, "info": "Invalid packet, wrong ID."}
```<auth_error_id>
- ```json
{"e": 2, "info": "Invalid signature."} // the info doesn't matter
```<auth_error_sig>
- ```json
{"e": 3, "info": "Logged in at other place."} // the info doesn't matter
```<auth_error_takeover>
=== Device
- ```json
{"c": "auth_start", "d": {"id": "id"}} // Id that is provided with registration.
```<auth_start>
- ```json
{"c": "auth_validate", "d": {"signature": "HMAC hash of nonce"}}
```<auth_validate>
- The HMAC is a SHA256 with the password as the key, and the nonce as the data.
- The returned signature is encoded as hex.
- #link("https://git.jsw.tf/jsw/schoolbox-ws/src/commit/6acc935609d5c0de52aa752b69ccbaea84301b87/src/auth.ts#L9-L32")[Example implementation in JS.]
== Session
=== Server
- ```json
{"c": "session_start", "d": {"text": "Question?"}}
```<session_start>
- ```json
{"c": "session_stop"}
```<session_stop>
=== Device
- ```json
{"c": "session_vote", "d": {"vote": 1}} // Vote is an integer in the range of 1..5
```<session_vote>
= General flow
#let arrLine = (arr) => {
for (i, el) in arr.enumerate() {
if i == 0 or i == arr.len() {
continue
}
edge(arr.at(i - 1), el, "-|>")
}
}
#let l = link;
#align(center, diagram(
node-stroke: 1pt,
node((1,0), [New connection], corner-radius: 2pt, extrude: (0, 3), name: <flow_new>),
node((3, 0), l(<ping>)[ping], name: <flow_ping>),
node((3, 1), l(<pong>)[pong], stroke: blue, name: <flow_pong>),
node((0,1), l(<reg_start>)[reg_start], name: <flow_reg_start>, stroke: blue),
node((0,2), l(<reg_pin>)[reg_pin], name: <flow_reg_pin>),
node((0,3), l(<reg_ok>)[reg_ok], name: <flow_reg_ok>),
node((0,4), [Disconnect], name: <flow_disconnect>, corner-radius: 2pt, extrude: (0, 3)),
node((2,1), l(<auth_start>)[auth_start], name: <flow_auth_start>, stroke: blue),
node((1,1), l(<auth_error_id>)[auth error id], name: <flow_auth_error_id>),
node((2,2), l(<auth_nonce>)[auth_nonce], name: <flow_auth_nonce>),
node((1,3), l(<auth_error_sig>)[auth error signature], name: <flow_auth_error_sig>),
node((2,3), l(<auth_validate>)[auth_validate], name: <flow_auth_validate>, stroke: blue),
node((2,4), l(<auth_ok>)[auth_ok], name: <flow_auth_ok>),
node((1,5), [Logged in], corner-radius: 2pt, extrude: (0, 3), name: <flow_loggedin>),
edge(<flow_ping>, <flow_pong>, "<|-|>", label: [Every 30s]),
edge(<flow_new>, "l", <flow_reg_start>, "-|>"),
edge(<flow_new>, "r", <flow_auth_start>, "-|>"),
edge(<flow_auth_start>, <flow_auth_error_id>, "-|>"),
edge(<flow_auth_error_id>, <flow_auth_start>, "-|>", bend: 18deg),
edge(<flow_auth_validate>, <flow_auth_error_sig>, "-|>"),
edge(<flow_auth_error_sig>, <flow_auth_start>, "-|>", bend: 23deg),
edge(<flow_auth_ok>, "d", <flow_loggedin>, "-|>"),
arrLine((<flow_reg_start>, <flow_reg_pin>, <flow_reg_ok>, <flow_disconnect>)),
arrLine((<flow_auth_start>, <flow_auth_nonce>, <flow_auth_validate>, <flow_auth_ok>)),
node((0,6), l(<session_start>)[session_start], name: <flow_session_start>),
node((0,7), l(<session_vote>)[session_vote], name: <flow_session_vote>),
node((0,8), l(<session_stop>)[session_stop], name: <flow_session_stop>),
node((2, 6), l(<auth_error_takeover>)[auth takeover error], corner-radius: 2pt, extrude: (0, 3), name: <flow_session_takeover>),
edge(<flow_loggedin>, "l", <flow_session_start>, "-|>"),
edge(<flow_session_start>, <flow_session_vote>, "-|>"),
edge(<flow_session_vote>, <flow_session_stop>, "-|>"),
edge((0, 7), (0, 7), "--|>", bend: 300deg, loop-angle: 200deg),
edge(<flow_session_stop>, "r", <flow_loggedin>, "-|>"),
edge(<flow_loggedin>, "r", <flow_session_takeover>, "-|>")
))