diff options
-rw-r--r-- | src/index.html | 22 | ||||
-rw-r--r-- | src/login.html | 23 | ||||
-rw-r--r-- | src/main.css | 63 | ||||
-rw-r--r-- | src/main.js | 229 | ||||
-rw-r--r-- | src/register.html | 25 |
5 files changed, 362 insertions, 0 deletions
diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..f9b952b --- /dev/null +++ b/src/index.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href="main.css"> + <script src="main.js" defer></script> + </head> + <body onload="has_session()"> + <div id="content"> + <a href="login.html"> + <button>Login</button> + </a> + <a href="register.html"> + <button>Register</button> + </a> + </div> + <footer> + <center> + <a href="/">POKO</a> + </center> + </footer> + </body> +</html>
\ No newline at end of file diff --git a/src/login.html b/src/login.html new file mode 100644 index 0000000..0b77009 --- /dev/null +++ b/src/login.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href="main.css"> + <script src="main.js" defer></script> + </head> + <body> + <div id="content"> + <form action="javascript:login_form()"> + <label for="id">ID</label> + <input type="text" id="id" minlength="4" maxlength="4" pattern="[0123456789abcedfABCDEF]{4}" required> + <label for="password">Password</label> + <input type="password" id="password" minlength="4" required> + <input type="submit" value="Login"> + </form> + </div> + <footer> + <center> + <a href="/">POKO</a> + </center> + </footer> + </body> +</html>
\ No newline at end of file diff --git a/src/main.css b/src/main.css new file mode 100644 index 0000000..2c53965 --- /dev/null +++ b/src/main.css @@ -0,0 +1,63 @@ +html, body { + margin: 0; + padding: 0; + border: 0; + background-color: grey; +} +footer { + border-top: 2px solid black; + font-weight: bold; +} +footer > center > p { + margin: 0; +} +body { + display: flex; + flex-direction: column; + height: 100vh; + width: 100vw; +} +#content { + flex-grow: 1; + max-width: 70vw; + margin: auto; + display: flex; + flex-direction: column; +} +form { + display: flex; + flex-direction: column; + max-width: 40vw; + align-self: center; +} +form > label { + margin-top: 6px; +} + +input:invalid { + border: 2px dotted red; +} + +bold { + font-weight: bold; + color: red; + background-color: black; +} + +:root { + --primary: #efefef; + --text-primary: #222; +} + +@media (prefers-color-scheme: dark) { + :root { + --primary: #222; + --text-primary: #eee; + } +} + +@media screen and (max-width: 500px) { + #content { + max-width: unset; + } +}
\ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..2b880a2 --- /dev/null +++ b/src/main.js @@ -0,0 +1,229 @@ +// const host = window.location.protocol + "//" + window.location.host; +const server = window.location.protocol + "//" + window.location.hostname + ":8000"; +const host = window.location.protocol + "//" + window.location.host; +const client_id = "POKO Web 0.0" + +async function xhttp_get(url) { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Response status: ${response.status}`); + } + + try { + return new Response(response.status, await response.clone().json()) + } catch { + return new Response(response.status, await response.text()) + } + } catch (error) { + console.error(error.message); + } +} + +async function xhttp_post(url, body) { + try { + const response = await fetch(url, { + method: "POST", + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json", + }, + }); + + try { + return new Response(response.status, await response.clone().json()) + } catch { + return new Response(response.status, await response.text()) + } + + } catch (error) { + console.error(error.message) + } +} + +class Response { + constructor(status, body) { + this.status = status; + this.body = body; + } +} + +async function register() { + const username = document.getElementById("username").value; + const password = document.getElementById("password").value; + const id = document.getElementById("id").value; + + const url = server + "/user/register/" + var body; + if (id == "") { + body = {"name": username, "password": password} + } else { + body = {"name": username, "password": password, "id": id} + } + const req = await xhttp_post(url, body); + + if (req.status == 201) { + await login(req.body.id, password) + window.location.href = host + } else { + alert(req.status + ": " + req.body) + } +} + +function password_validator() { + const password = document.getElementById("password"); +} + +function login_form() { + const id = document.getElementById("id").value; + const password = document.getElementById("password").value; + + login(id, password) +} + +async function login(id, password) { + const url = server + "/user/login" + const body = {"id": id, "password": password, "clientid": client_id}; + const req = await xhttp_post(url, body); + + if (req.status == 200) { + // Set session cookie + set_session(req.body, id) + window.location.href = host; + } else { + alert(req.status + ": " + req.body) + } +} + +function getCookie(cname) { + let name = cname + "="; + let decodedCookie = decodeURIComponent(document.cookie); + let ca = decodedCookie.split(';'); + for(let i = 0; i <ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length, c.length); + } + } + return ""; +} + +function get_session() { + return getCookie("session") +} +function get_id() { + return getCookie("id") +} +function set_session(session, id) { + document.cookie = "session=" + session + "; path=/;"; + document.cookie = "id=" + id + "; path=/;"; +} +function del_session() { + document.cookie = "session=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + document.cookie = "id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; +} + +async function logout() { + const id = get_id(); + const session = get_session(); + + const url = server + "/user/logout" + const body = {"id": id, "session": session}; + const req = await xhttp_post(url, body); + + if (req.status == 200) { + del_session() + window.location.href = host + } else { + alert("Unauthorized") + } +} + +async function has_session() { + const session = get_session(); + const id = get_id(); + + const users = await userlist(); + const content = document.getElementById("content"); + + // If session exists + if (session != "") { + // If ID exists + if (id != "") { + const url = server + "/user/get" + const body = {"id": id, "session": session} + const req = await xhttp_post(url, body); + + if (req.status == 200) { + + const tokens = format_tokovec(req.body.tokovec); + + content.innerHTML = ` + <div id="userinfo"> + <h3>User Info</h3> + <p>Username: ${req.body.name}</p> + <p>ID: ${id}</p> + </div> + <div id="balance"> + <h3>Tokens Balance</h3> + ${tokens} + </div> + <div id="actions"> + <h3>Actions</h3> + <a href="/transfer.html"><button>Transfer</button></a> + <button onclick="logout()">Logout</button> + <button onclick="logout_all()">Logout All //TODO</button> + </div> + <div id="users"> + <h3>Users</h3> + ${users} + </div> + `; + } else if (req.status == 404) { + if (req.body == "Not Authenticated") { + del_session() + } + } + } else { + del_session() + } + } else { + content.innerHTML += users; + } +} + +function format_tokovec(tokovec) { + var out = "" + for (t in tokovec) { + out += ` + <p>${tokovec[t].color}: ${tokovec[t].amount}</p> + ` + } + + return out +} + +async function userlist() { + const url = server + "/user/list" + const req = await xhttp_get(url); + + var out = "" + + try { + if (req.status == 200) { + for (u in req.body) { + const user = req.body[u]; + out += `<p>${user.id} -- ${user.name}` + } + + } else { + return "<p>User list not available</p>" + } + + } catch {} + + return out +}
\ No newline at end of file diff --git a/src/register.html b/src/register.html new file mode 100644 index 0000000..34deb49 --- /dev/null +++ b/src/register.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" href="main.css"> + <script src="main.js" defer></script> + </head> + <body> + <div id="content"> + <form action="javascript:register()"> + <label for="username">Username</label> + <input type="text" id="username" minlength="1" required> + <label for="password">Password<br><bold>DO NOT REUSE A PASSWORD. THIS APPLICATION IS NOT SECURE</bold></label> + <input type="password" id="password" minlength="4" required> + <label for="id">ID (optional)<br>This is what you use to login. Do not lose it. One will be generated if not specified</label> + <input type="text" id="id" minlength="4" maxlength="4" pattern="[0123456789abcedfABCDEF]{4}"> + <input type="submit" value="Register"> + </form> + </div> + <footer> + <center> + <a href="/">POKO</a> + </center> + </footer> + </body> +</html>
\ No newline at end of file |