summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/index.html22
-rw-r--r--src/login.html23
-rw-r--r--src/main.css63
-rw-r--r--src/main.js229
-rw-r--r--src/register.html25
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