This commit is contained in:
Andrew 2022-02-23 02:37:30 +07:00
parent 0e2c114a84
commit 2c5995be3f
13 changed files with 632 additions and 0 deletions

240
w5/webserver.js Normal file
View 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);