W5 done
This commit is contained in:
parent
0e2c114a84
commit
2c5995be3f
13 changed files with 632 additions and 0 deletions
6
w5/.dockerignore
Normal file
6
w5/.dockerignore
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
node_modules
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
users.json
|
||||||
BIN
w5/Cat_poster_1.png
Normal file
BIN
w5/Cat_poster_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 MiB |
12
w5/Dockerfile
Normal file
12
w5/Dockerfile
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM node:16.13.2-alpine3.14
|
||||||
|
|
||||||
|
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
|
||||||
|
WORKDIR /home/node/app
|
||||||
|
|
||||||
|
COPY --chown=node:node . .
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
EXPOSE 9889/tcp
|
||||||
|
|
||||||
|
CMD [ "node", "." ]
|
||||||
3
w5/helloworld.js
Normal file
3
w5/helloworld.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
console.log("Hello, World!");
|
||||||
12
w5/package.json
Normal file
12
w5/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "w5",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "webserver.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ."
|
||||||
|
},
|
||||||
|
"author": "nuark",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
54
w5/router.js
Normal file
54
w5/router.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} method
|
||||||
|
* @param {String} path
|
||||||
|
*/
|
||||||
|
export function route(method, path) {
|
||||||
|
return `route::${method}::${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Router {
|
||||||
|
/** @type {Map.<Route, Function<http.IncomingMessage, http.ServerResponse, String, Object>>} */
|
||||||
|
routes = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Route} route
|
||||||
|
* @param {Function.<http.IncomingMessage, http.ServerResponse, String, Object>} func
|
||||||
|
*/
|
||||||
|
addRoute(route, func) {
|
||||||
|
if (this.routes.has(route)) {
|
||||||
|
throw new Error(`Route ${route} already exists!`);
|
||||||
|
}
|
||||||
|
this.routes.set(route, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Route} route
|
||||||
|
* @returns Function for dispatchng this route
|
||||||
|
*/
|
||||||
|
dispatch(route) {
|
||||||
|
if (this.routes.has(route)) {
|
||||||
|
return this.routes.get(route);
|
||||||
|
}
|
||||||
|
return this.returnError(404, "Not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Number} code
|
||||||
|
* @param {String} message
|
||||||
|
* @param {String} contentType
|
||||||
|
*/
|
||||||
|
returnError(code, message, contentType="text/plain") {
|
||||||
|
return (req, res) => {
|
||||||
|
res.setHeader("Content-Type", contentType);
|
||||||
|
res.statusCode = code;
|
||||||
|
res.write(message);
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
13
w5/templates/dashboard.html
Normal file
13
w5/templates/dashboard.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dashboard</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Hello, {{user.name}} you are {{user.status}}</h2>
|
||||||
|
<button onclick="javascript:(location += '/logout')">Log out</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
52
w5/templates/login.html
Normal file
52
w5/templates/login.html
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Login page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="errors"></div>
|
||||||
|
<h3>Login page</h3>
|
||||||
|
<form action="/login" method="post" name="login">
|
||||||
|
<label for="login">Login</label>
|
||||||
|
<input type="text" name="login" id="login" required />
|
||||||
|
<br />
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="password" id="password" required />
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<button id="login">Login</button>
|
||||||
|
<br />
|
||||||
|
<a href="/register">No accoount? Register here!</a>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
const init = function () {
|
||||||
|
const btn = document.querySelector("button#login");
|
||||||
|
btn.addEventListener("click", async () => {
|
||||||
|
btn.textContent = "Loading...";
|
||||||
|
let formData = Array.from(document.forms.login, e => [e.name, encodeURIComponent(e.value)].join("=")).join("&");
|
||||||
|
try {
|
||||||
|
const jsonData = await (
|
||||||
|
await fetch("/login", {
|
||||||
|
method: "post",
|
||||||
|
body: formData,
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
if (jsonData.ok) {
|
||||||
|
location = "/dashboard";
|
||||||
|
} else {
|
||||||
|
alert(jsonData.message);
|
||||||
|
btn.textContent = "Login";
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(e.message);
|
||||||
|
btn.textContent = "Login";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
60
w5/templates/register.html
Normal file
60
w5/templates/register.html
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Registration page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="errors"></div>
|
||||||
|
<h3>Registration page</h3>
|
||||||
|
<form action="/register" method="post" name="register">
|
||||||
|
<label for="login">Login</label>
|
||||||
|
<input type="text" name="login" id="login" required />
|
||||||
|
<br />
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" name="password" id="password" required />
|
||||||
|
|
||||||
|
<label for="passwordRepeated">Repeat password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="passwordRepeated"
|
||||||
|
id="passwordRepeated"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<button id="register">Register</button>
|
||||||
|
<br />
|
||||||
|
<a href="/login">Already have an accoount? Login here!</a>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
const init = function () {
|
||||||
|
const btn = document.querySelector("button#register");
|
||||||
|
btn.addEventListener("click", async () => {
|
||||||
|
btn.textContent = "Loading...";
|
||||||
|
let formData = Array.from(document.forms.register, e => [e.name, encodeURIComponent(e.value)].join("=")).join("&");
|
||||||
|
try {
|
||||||
|
const jsonData = await (
|
||||||
|
await fetch("/register", {
|
||||||
|
body: formData,
|
||||||
|
method: "post",
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
if (jsonData.ok) {
|
||||||
|
location = "/login";
|
||||||
|
} else {
|
||||||
|
alert(jsonData.message);
|
||||||
|
btn.textContent = "Register";
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(e.message);
|
||||||
|
btn.textContent = "Register";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
90
w5/userdb.js
Normal file
90
w5/userdb.js
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync } from "fs";
|
||||||
|
|
||||||
|
export class User {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} login
|
||||||
|
* @param {String} password
|
||||||
|
* @param {String} status
|
||||||
|
*/
|
||||||
|
constructor(login, password, status) {
|
||||||
|
this.login = login;
|
||||||
|
this.password = password;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UserDB {
|
||||||
|
/** @type {Map.<String, User>} */
|
||||||
|
users = new Map();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
#loadData() {
|
||||||
|
try {
|
||||||
|
const fileData = readFileSync("users.json", "utf-8");
|
||||||
|
const usersData = JSON.parse(fileData);
|
||||||
|
usersData.forEach(user => {
|
||||||
|
this.users.set(
|
||||||
|
user["login"],
|
||||||
|
new User(user["login"], user["password"], user["status"])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (_) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
saveData() {
|
||||||
|
const data = JSON.stringify(Array.from(this.users.keys()).map(k => {
|
||||||
|
const user = this.users.get(k);
|
||||||
|
return {
|
||||||
|
login: user.login,
|
||||||
|
password: user.password,
|
||||||
|
status: user.status
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
writeFileSync("./users.json", data, { encoding: "utf-8", flag: "w+" });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {User} login
|
||||||
|
* @returns Exists user in DB or not
|
||||||
|
*/
|
||||||
|
hasUser(login) {
|
||||||
|
return this.users.has(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {User} user
|
||||||
|
*/
|
||||||
|
putUser(user) {
|
||||||
|
if (this.hasUser(user.login)) {
|
||||||
|
throw new Error(`User ${user.login} exists!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.users.set(user.login, user);
|
||||||
|
this.saveData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} login
|
||||||
|
* @returns User object
|
||||||
|
*/
|
||||||
|
getUser(login) {
|
||||||
|
return this.users.get(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns Users count
|
||||||
|
*/
|
||||||
|
getUsersCount() {
|
||||||
|
return this.users.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
w5/users.json
Normal file
1
w5/users.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[{"login":"nuark","password":"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3","status":"admin"},{"login":"123","password":"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3","status":"user"}]
|
||||||
89
w5/utils.js
Normal file
89
w5/utils.js
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { IncomingMessage, ServerResponse } from "http";
|
||||||
|
import { parse as urlParse } from "querystring";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} filename
|
||||||
|
* @param {Array.<Array.<String, Object>>} params
|
||||||
|
*/
|
||||||
|
export function renderTemplate(res, filename, params = []) {
|
||||||
|
let templateText = readFileSync(filename, "utf-8");
|
||||||
|
params.forEach(el => {
|
||||||
|
const [k, v] = el;
|
||||||
|
templateText = templateText.replace(new RegExp(`\{\{${k}\}\}`, "g"), v);
|
||||||
|
});
|
||||||
|
res.writeHead(200, { "Content-Type": "text/html" });
|
||||||
|
res.write(templateText);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
*/
|
||||||
|
export function getCookies(req) {
|
||||||
|
const list = {};
|
||||||
|
const cookieHeader = req.headers?.cookie;
|
||||||
|
if (!cookieHeader) return list;
|
||||||
|
|
||||||
|
cookieHeader.split(";").forEach(function (cookie) {
|
||||||
|
let [name, ...rest] = cookie.split("=");
|
||||||
|
name = name?.trim();
|
||||||
|
if (!name) return;
|
||||||
|
const value = rest.join("=").trim();
|
||||||
|
if (!value) return;
|
||||||
|
list[name] = decodeURIComponent(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {Object} cookies
|
||||||
|
*/
|
||||||
|
export function setCookies(res, cookies = {}) {
|
||||||
|
res.setHeader(
|
||||||
|
"Set-Cookie",
|
||||||
|
Array.from(Object.keys(cookies))
|
||||||
|
.map(e => `${encodeURIComponent(e)}=${encodeURIComponent(cookies[e])}`)
|
||||||
|
.join(";")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
*/
|
||||||
|
export function redirect(res, path) {
|
||||||
|
res.statusCode = 307;
|
||||||
|
res.setHeader("Location", path);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function consumePostForm(req) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let body = "";
|
||||||
|
req.on("data", function (data) {
|
||||||
|
try {
|
||||||
|
body += data;
|
||||||
|
if (body.length > 1e6) {
|
||||||
|
req.destroy();
|
||||||
|
}
|
||||||
|
} catch (e) { reject(e); }
|
||||||
|
});
|
||||||
|
req.on("end", function () {
|
||||||
|
try {
|
||||||
|
const post = urlParse(body);
|
||||||
|
resolve(post);
|
||||||
|
} catch (e) { reject(e); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
240
w5/webserver.js
Normal file
240
w5/webserver.js
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { createServer, IncomingMessage, ServerResponse } from "http";
|
||||||
|
import { parse as urlParse } from "querystring";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { createHash } from "crypto";
|
||||||
|
import { Router, route } from "./router.js";
|
||||||
|
import { getCookies, renderTemplate, redirect, consumePostForm, setCookies } from "./utils.js";
|
||||||
|
import { User, UserDB } from "./userdb.js";
|
||||||
|
|
||||||
|
const udb = new UserDB();
|
||||||
|
const hasher = (hashable) => createHash("sha256").update(hashable).digest("hex");
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const mainPage = function (req, res, path, params) {
|
||||||
|
res.writeHead(200, { "Content-Type": "text/html" });
|
||||||
|
res.write(
|
||||||
|
`Hello on ${path}!\n You can go on: <br>` +
|
||||||
|
`1. Parameters display (in JSON): <a href="/sparamsAsJson?hello=i&am=JSON">*click*</a><br>` +
|
||||||
|
`2. Parameters display (in TEXT): <a href="/sparamsAsText?why=yes&i=am&a=plain+text">*click*</a><br>` +
|
||||||
|
`3. See some pretty cats: <a href="/showMeACat">*click*</a><br>` +
|
||||||
|
`4. Open dashboard: <a href="/dashboard">*click*</a>`
|
||||||
|
);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const showParameters = function (type) {
|
||||||
|
const contentType = type === "JSON" ? "application/json" : "text/plain";
|
||||||
|
const serializer = type === "JSON" ? JSON.stringify : (obj => Array.from(Object.keys(obj)).map(e => `Key: ${e}; Value: ${obj[e]}`).join("\n"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
return function (req, res, path, params) {
|
||||||
|
res.writeHead(200, { "Content-Type": contentType });
|
||||||
|
res.write(serializer(params));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const showACat = function (req, res, path, params) {
|
||||||
|
res.writeHead(200, { "Content-Type": "image/png" });
|
||||||
|
res.write(readFileSync("./Cat_poster_1.png"));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = new Router();
|
||||||
|
router.addRoute(route("GET", "/"), mainPage);
|
||||||
|
router.addRoute(route("GET", "/sparamsAsJson"), showParameters("JSON"));
|
||||||
|
router.addRoute(route("GET", "/sparamsAsText"), showParameters("TEXT"));
|
||||||
|
router.addRoute(route("GET", "/showMeACat"), showACat);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userRegisterView = (req, res, path, params) => {
|
||||||
|
const cookies = getCookies(req);
|
||||||
|
if (cookies["user"]) return redirect(res, "/dashboard");
|
||||||
|
|
||||||
|
return renderTemplate(res, "./templates/register.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userRegister = async function (req, res, path, params) {
|
||||||
|
const cookies = getCookies(req);
|
||||||
|
if (cookies["user"]) return redirect(res, "/dashboard");
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
ok: true,
|
||||||
|
message: ""
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const post = await consumePostForm(req);
|
||||||
|
console.log(post);
|
||||||
|
const login = post.login;
|
||||||
|
const password = post.password;
|
||||||
|
const passwordRepeated = post.passwordRepeated;
|
||||||
|
const status = udb.getUsersCount() === 0 ? "admin" : "user";
|
||||||
|
if (udb.hasUser(login)) {
|
||||||
|
throw new Error("User already exists!");
|
||||||
|
} else if (password != passwordRepeated) {
|
||||||
|
throw new Error("Passwords must match!");
|
||||||
|
} else {
|
||||||
|
udb.putUser(new User(login, hasher(password), status));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
response.ok = false;
|
||||||
|
response.message = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.statusCode = 200;
|
||||||
|
res.setHeader("Content-Type", "application/json");
|
||||||
|
res.write(JSON.stringify(response));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userLoginView = (req, res, path, params) => {
|
||||||
|
const cookies = getCookies(req);
|
||||||
|
if (cookies["user"]) return redirect(res, "/dashboard");
|
||||||
|
|
||||||
|
return renderTemplate(res, "./templates/login.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userLogin = async function (req, res, path, params) {
|
||||||
|
const cookies = getCookies(req);
|
||||||
|
if (cookies["user"]) return redirect(res, "/dashboard");
|
||||||
|
|
||||||
|
let response = {
|
||||||
|
ok: true,
|
||||||
|
message: ""
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const post = await consumePostForm(req);
|
||||||
|
const login = post.login;
|
||||||
|
const password = hasher(post.password);
|
||||||
|
if (!udb.hasUser(login)) {
|
||||||
|
throw new Error("User not exists!");
|
||||||
|
}
|
||||||
|
const user = udb.getUser(login);
|
||||||
|
if (password !== user.password) {
|
||||||
|
throw new Error("Password doesn't match!");
|
||||||
|
}
|
||||||
|
response["user"] = {
|
||||||
|
login,
|
||||||
|
status: user.status
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
response.ok = false;
|
||||||
|
response.message = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.statusCode = 200;
|
||||||
|
res.setHeader("Content-Type", "application/json");
|
||||||
|
if (response.ok) {
|
||||||
|
setCookies(res, {
|
||||||
|
user: JSON.stringify(response["user"])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res.write(JSON.stringify(response));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userDashboardView = function (req, res, path, params) {
|
||||||
|
const cookies = getCookies(req);
|
||||||
|
if (!cookies["user"]) return redirect(res, "/login");
|
||||||
|
|
||||||
|
const user = JSON.parse(cookies["user"]);
|
||||||
|
return renderTemplate(res, "./templates/dashboard.html", [
|
||||||
|
["user.name", user.login],
|
||||||
|
["user.status", user.status],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sadly, not working(
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} params
|
||||||
|
*/
|
||||||
|
const userDashboardLogout = function (req, res, path, params) {
|
||||||
|
let cookies = getCookies(req);
|
||||||
|
if (cookies["user"]) {
|
||||||
|
cookies["user"] = "";
|
||||||
|
setCookies(res, cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect(res, "/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
router.addRoute(route("GET", "/register"), userRegisterView);
|
||||||
|
router.addRoute(route("POST", "/register"), userRegister);
|
||||||
|
router.addRoute(route("GET", "/login"), userLoginView);
|
||||||
|
router.addRoute(route("POST", "/login"), userLogin);
|
||||||
|
router.addRoute(route("GET", "/dashboard"), userDashboardView);
|
||||||
|
router.addRoute(route("GET", "/dashboard/logout"), userDashboardLogout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {ServerResponse} res
|
||||||
|
*/
|
||||||
|
const requestDispatcher = function (req, res) {
|
||||||
|
const [path, params] = req.url.includes("?") ? req.url.split("?", 2) : [req.url, ""];
|
||||||
|
const parsedParams = urlParse(params);
|
||||||
|
router.dispatch(route(req.method, path))(req, res, path, parsedParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
createServer(requestDispatcher).listen(9889);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue