schoolbox-ws/static/index.html

208 lines
No EOL
5.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
width: 100%;
height: 100%;
margin: 2em;
display: grid;
grid-template-columns: max-content auto;
gap: 2em;
}
.labelgrid {
display: grid;
grid-template-columns: min-content auto;
column-gap: 1em;
}
.buttongrid {
display: flex;
flex-direction: row;
flex-basis: 0;
width: 100%;
padding-top: 5px;
}
.buttongrid>* {
width: 0;
flex-grow: 1;
}
#text {
display: none;
}
#votebuttons {
display: none;
}
</style>
</head>
<body>
<div>
<div class="labelgrid">
<label for="id"> ID</label>
<input id="id" />
<label for="passcode"> passcode</label>
<input id="passcode" />
<label for="pin"> pin</label>
<input id="pin" />
<label for="auth"> authenticated</label>
<input id="auth" type=checkbox onclick="return false" />
</div>
<div class="buttongrid" id="authbuttons">
<button onclick="startRegistration()">registrate</button>
<button onclick="startAuthentication()">authenticate</button>
</div>
<div class="buttongrid" id="votebuttons">
<button onclick="vote(1)">1</button>
<button onclick="vote(2)">2</button>
<button onclick="vote(3)">3</button>
<button onclick="vote(4)">4</button>
<button onclick="vote(5)">5</button>
</div>
</div>
<div>
<h1 id="text"></h1>
<div id="logger"></div>
</div>
<script>
function preventDefault(e) {alert(); e.preventDefault()}
function toHex(data) {
return Array.from(data).map((b) => ("00" + b.toString(16)).slice(-2)).join(
"",
);
}
async function generateHMAC(key, message) {
const encoder = new TextEncoder();
const keyData = encoder.encode(key);
const messageData = encoder.encode(message);
const cryptoKey = await crypto.subtle.importKey(
"raw",
keyData,
{name: "HMAC", hash: {name: "SHA-256"}},
false,
["sign"],
);
const signature = await crypto.subtle.sign(
"HMAC",
cryptoKey,
messageData,
);
return toHex(new Uint8Array(signature));
}
function log(text) {
logger.innerHTML += text + "<br>";
}
function disableAuthBtns() {
document.querySelectorAll("#authbuttons").forEach(v => v.disabled = false);
}
const id = document.querySelector("#id");
const pass = document.querySelector("#passcode");
const pin = document.querySelector("#pin");
const logger = document.querySelector("#logger")
const text = document.querySelector("#text")
const votebuttons = document.querySelector("#votebuttons")
const auth = document.querySelector("#auth")
function websock() {
let socket = new WebSocket("ws://localhost:8000/ws");
socket.sendln = (...e) => {
log("device: " + e.join("\n"));
socket.send(...e)
}
socket.addEventListener("message", async (event) => {
log("server: " + event.data);
let data = JSON.parse(event.data);
switch (data.c) {
case "ping": {
socket.sendln(JSON.stringify({c: "pong"}));
break
}
case "reg_pin": {
pin.value = data.d.pin;
break
}
case "reg_ok": {
id.value = data.d.id;
pass.value = data.d.password;
socket.close();
pin.value = "";
log("### closing and reopening socket");
websock()
break
}
case "auth_nonce": {
const signature = await generateHMAC(pass.value, data.d.nonce)
console.log(pass.value, data.value, signature)
socket.sendln(JSON.stringify({c: "auth_validate", d: {signature}}));
break
}
case "auth_ok": {
auth.checked = true;
disableAuthBtns()
break;
}
case "session_start": {
text.style.display = "block";
votebuttons.style.display = "flex";
text.innerText = data.d.text;
break;
}
case "session_stop": {
text.style.display = "none";
votebuttons.style.display = "none";
text.innerText = "";
break;
}
}
});
socket.addEventListener("close", () => {
auth.checked = false;
disableAuthBtns()
window.startRegistration = undefined;
window.startAuthentication = undefined;
text.innerText = ""
})
socket.addEventListener("open", () => {
window.startRegistration = () => {
socket.sendln(JSON.stringify({c: "reg_start"}))
}
window.startAuthentication = () => {
socket.sendln(JSON.stringify({c: "auth_start", d: {id: id.value}}))
}
window.vote = (num) => {
socket.sendln(JSON.stringify({c: "session_vote", d: {vote: num}}))
}
})
}
websock()
</script>
</body>
</html>