Create login/register form

This commit is contained in:
Aelita4 2022-08-18 10:57:58 +02:00
parent 78b6c6b687
commit 0c63934a8a
Signed by: Aelita4
GPG Key ID: F8EC95519509D1D5
17 changed files with 3345 additions and 24 deletions

3095
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,22 @@
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"cookie-parser": "^1.4.6",
"ejs": "^3.1.8",
"eslint": "^8.22.0",
"express": "^4.18.1",
"express-session": "^1.17.3",
"mysql": "^2.18.1",
"ping": "^0.4.2",
"typescript": "^4.7.4"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/cookie-parser": "^1.4.3",
"@types/express": "^4.17.13",
"@types/express-session": "^1.17.5",
"@types/mysql": "^2.15.21",
"@types/node": "^18.7.6",
"@types/ping": "^0.4.1"
}

View File

@ -1,6 +1,10 @@
import express, { Request, Response } from 'express';
import * as Ping from 'ping';
import { existsSync, readdirSync, writeFileSync, readFileSync } from 'fs';
import sessions from "express-session"
import cookieParser from "cookie-parser"
import mysql from 'mysql'
import bcrypt from 'bcrypt'
const ping = async (host: string) => {
const result = await Ping.promise.probe(host, {
@ -10,8 +14,28 @@ const ping = async (host: string) => {
return result;
}
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "sshmon"
});
connection.connect();
const app = express();
app.set('views', __dirname + '/../views');
app.set('view engine', 'ejs');
app.use(sessions({
secret: "jkthaljkerhwejhflsbglsrbhsbfgdnbsdktiu34y5i4",
saveUninitialized:true,
cookie: { maxAge: 1000 * 60 * 60 * 24 },
resave: false
}));
app.use(cookieParser());
app.use(express.urlencoded());
const pings = new Map();
if(!existsSync("../data.json")) writeFileSync("../data.json", "[]");
@ -22,16 +46,24 @@ const timeoutDelay = 60000;
const routes = readdirSync("./routes");
routes.forEach(route => {
const file = require(`./routes/${route}`);
app.get(file.url, file.callback.bind(null, { addresses, ping, pings, timeoutDelay }))
console.log(`[${file.method}] ${file.url}`);
switch(file.method) {
case "GET": app.get(file.url, file.callback.bind(null, { addresses, ping, pings, timeoutDelay })); break;
case "POST": app.post(file.url, file.callback.bind(null, { addresses, ping, pings, timeoutDelay })); break;
}
});
app.set('views', __dirname + '/../views');
app.set('view engine', 'ejs');
app.listen(8080, () => console.log('rdy'));
export interface Data {
interface Data {
ping: Function,
pings: Map<string, number>,
addresses: Array<string>,
timeoutDelay: number
};
interface User {
username: string
}
export { connection, bcrypt, User, Data };

View File

@ -2,6 +2,7 @@ import { Request, Response } from 'express';
import { existsSync, writeFileSync, readFileSync } from 'fs'
module.exports = {
method: "GET",
url: "/addIP/:ip",
callback: async (data: any, req: Request, res: Response) => {
if(!existsSync("../data.json")) writeFileSync("../data.json", "[]");

View File

@ -1,6 +1,7 @@
import { Request, Response } from 'express';
module.exports = {
method: "GET",
url: "/downtime/:ip",
callback: async (data: any, req: Request, res: Response) => {
const ip = req.params.ip;

9
src/routes/login.ts Normal file
View File

@ -0,0 +1,9 @@
import { Request, Response } from 'express';
module.exports = {
method: "GET",
url: "/login",
callback: async (data: any, req: Request, res: Response) => {
res.render("pages/login.ejs", { invalid: "" });
}
}

26
src/routes/loginUser.ts Normal file
View File

@ -0,0 +1,26 @@
import { Request, Response } from 'express';
import { connection, bcrypt } from '../index'
module.exports = {
method: "POST",
url: "/loginUser",
callback: async (data: any, req: Request, res: Response) => {
connection.query("SELECT * FROM users WHERE username = ?", req.body.username, async (err, results, fields) => {
if(err) throw err;
if(results.length === 0) res.render("pages/login.ejs", { invalid: "baduserorpass" });
else {
const compare = await bcrypt.compare(req.body.password, results[0].password);
if(compare) {
const session = req.session;
//@ts-ignore
session.user = {}
//@ts-ignore
session.user.username = req.body.username;
res.redirect("/");
} else res.render("pages/login.ejs", { invalid: "baduserorpass" });
}
})
}
}

11
src/routes/logout.ts Normal file
View File

@ -0,0 +1,11 @@
import { Request, Response } from 'express';
module.exports = {
method: "GET",
url: "/logout",
callback: async (data: any, req: Request, res: Response) => {
req.session.destroy(err => {
res.redirect('/login');
});
}
}

View File

@ -1,6 +1,7 @@
import { Request, Response } from 'express';
module.exports = {
method: "GET",
url: "/ping/:ip",
callback: async (data: any, req: Request, res: Response) => {
const ip = req.params.ip;

9
src/routes/register.ts Normal file
View File

@ -0,0 +1,9 @@
import { Request, Response } from 'express';
module.exports = {
method: "GET",
url: "/register",
callback: async (data: any, req: Request, res: Response) => {
res.render("pages/register.ejs", { invalid: "" });
}
}

View File

@ -0,0 +1,32 @@
import e, { Request, Response } from 'express';
import { connection, bcrypt } from '../index'
module.exports = {
method: "POST",
url: "/registerUser",
callback: async (data: any, req: Request, res: Response) => {
if(!req.body.username || !req.body.password) {
res.render("pages/register.ejs", { invalid: "noinput" });
return;
}
if(req.body.password !== req.body.password2) {
res.render("pages/register.ejs", { invalid: "nomatch" });
return;
}
const encryptedPassword = await bcrypt.hash(req.body.password, 10);
connection.query("SELECT * FROM users WHERE username = ?", req.body.username, (err, results, fields) => {
if(err) throw err;
if(results.length > 0) res.render("pages/register.ejs", { invalid: "exists" });
else {
connection.query("INSERT INTO users VALUES (NULL, ?, ?)", [req.body.username, encryptedPassword], (errr, resultss, fieldss) => {
if(errr) throw errr
res.render("pages/register.ejs", { invalid: "created" });
});
}
});
}
}

View File

@ -2,6 +2,7 @@ import { Request, Response } from 'express';
import { existsSync, writeFileSync, readFileSync } from 'fs'
module.exports = {
method: "GET",
url: "/removeIP/:ip",
callback: async (data: any, req: Request, res: Response) => {
if(!existsSync("../data.json")) writeFileSync("../data.json", "[]");

View File

@ -2,12 +2,19 @@ import { Request, Response } from 'express';
import { readFileSync } from 'fs';
module.exports = {
method: "GET",
url: "/",
callback: async (data: any, req: Request, res: Response) => {
data.addresses = JSON.parse(readFileSync("../data.json", {encoding:'utf8', flag:'r'}))
res.render('pages/index.ejs', {
data.addresses = JSON.parse(readFileSync("../data.json", {encoding:'utf8', flag:'r'}));
//@ts-ignore
if(!req.session.user) res.redirect("/login");
else res.render('pages/index.ejs', {
addresses: data.addresses,
timeoutDelay: data.timeoutDelay
timeoutDelay: data.timeoutDelay,
//@ts-ignore
loggedIn: req.session.user ? true : false,
//@ts-ignore
username: req.session.user?.username
});
}
}

View File

@ -2,12 +2,7 @@
<head>
<script>
const addresses = ["<%- addresses.join(`", \"`) %>"];
function clock() {
const x = new Date();
document.getElementById("time").innerHTML = String(x.getHours()).padStart(2, '0') + ":" + String(x.getMinutes()).padStart(2, '0') + ":" + String(x.getSeconds()).padStart(2, '0');
}
async function addIP() {
const addrElement = document.getElementById("addresses");
@ -51,18 +46,11 @@
setTimeout(aaa, <%= timeoutDelay %>)
}
window.onload = async () => {
const x = new Date();
document.getElementById("time").innerHTML = String(x.getHours()).padStart(2, '0') + ":" + String(x.getMinutes()).padStart(2, '0') + ":" + String(x.getSeconds()).padStart(2, '0');
const clockRefresh = 1000;
aaa();
setInterval(clock, clockRefresh);
}
window.onload = aaa;
</script>
</head>
<body>
<div id="time">12:00:00</div>
<%- include("../partials/navbar.ejs", { activeLink: "home", username, loggedIn }) %>
<div id="main"></div>
<div id="eta"></div><br />
<input type="text" name="ipaddr" id="ipaddr" value="">

23
views/pages/login.ejs Normal file
View File

@ -0,0 +1,23 @@
<!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</title>
</head>
<body>
<%- include("../partials/navbar.ejs", { activeLink: "login", loggedIn: false }) %>
<form action="/loginUser" method="post">
<h2>Login</h2>
<div class="input-field">
<input type="text" name="username" id="username" placeholder="Enter Username">
</div>
<div class="input-field">
<input type="password" name="password" id="password" placeholder="Enter Password">
</div>
<input type="submit" value="Login">
<% if(invalid == "baduserorpass") { %><span style="color:red;">Bad username or password</span><% } %>
</form>
</body>
</html>

29
views/pages/register.ejs Normal file
View File

@ -0,0 +1,29 @@
<!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>Register</title>
</head>
<body>
<%- include("../partials/navbar.ejs", { activeLink: "register", loggedIn: false }) %>
<form action="/registerUser" method="post">
<h2>Register</h2>
<div class="input-field">
<input type="text" name="username" id="username" placeholder="Enter Username">
</div>
<div class="input-field">
<input type="password" name="password" id="password" placeholder="Enter Password">
</div>
<div class="input-field">
<input type="password" name="password2" id="password2" placeholder="Confirm Password">
</div>
<input type="submit" value="Register">
<% if(invalid == "exists") { %><span style="color:red;">Account already exists</span>
<% } else if(invalid == "noinput") { %><span style="color:red;">Type in username and password</span>
<% } else if(invalid == "nomatch") { %><span style="color:red;">Passwords don't match</span>
<% } else if(invalid == "created") { %><span style="color:green;">Account created</span><% } %>
</form>
</body>
</html>

52
views/partials/navbar.ejs Normal file
View File

@ -0,0 +1,52 @@
<style>
.topnav {
background-color: #333;
overflow: hidden;
}
.topnav a {
float: left;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
}
.topnav a.hoverable:hover {
background-color: #ddd;
color: black;
}
.topnav a.active {
background-color: #04AA6D;
color: white;
}
.topnav a.right {
float: right;
}
.topnav a.no-pointer {
cursor: default;
}
</style>
<script>
function clock() {
const x = new Date();
document.getElementById("topbar_clock").innerHTML = String(x.getHours()).padStart(2, '0') + ":" + String(x.getMinutes()).padStart(2, '0') + ":" + String(x.getSeconds()).padStart(2, '0');
}
setInterval(clock, 100);
</script>
<div class="topnav">
<a class="no-pointer" id="topbar_clock" href="#">12:00:00</a>
<a class="hoverable<% if(activeLink === "home") { %> active<% } %>" id="topnav_home" href="/">Home</a>
<% if(!loggedIn) { %>
<a class="hoverable right<% if(activeLink === "login") { %> active<% } %>" id="topnav_login" href="/login">Login</a>
<a class="hoverable right<% if(activeLink === "register") { %> active<% } %>" id="topnav_register" href="/register">Register</a>
<% } else { %>
<a class="hoverable right" id="topnav_logout" href="/logout">Log out</a>
<a class="hoverable right" id="topnav_user" href="#"><%- username %></a>
<% } %>
</div>