Files
web-chat/index.js
slawk0 bf8da0606c Remove unused files and improve code clarity
Deleted obsolete files, including icon.png and index.html. Refactored JavaScript code in signup.js and socket.js for better readability by adjusting indentation and format. Updated environment variables in .env and streamlined several routes and functions in index.js.
2024-10-14 15:40:08 +02:00

286 lines
7.4 KiB
JavaScript

require("dotenv").config();
const express = require("express");
const session = require("express-session");
const port = process.env.APP_PORT;
const app = express();
const cookieParser = require("cookie-parser");
const path = require("path");
const {
insertUser,
isUserExists,
changePassword,
db,
} = require("./backend/db.js");
const { initializeSocket } = require("./backend/socket.js");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const { createServer } = require("node:http");
const server = createServer(app);
const jwt = require("jsonwebtoken");
const { decode } = require("jsonwebtoken");
const { json } = require("express");
const jwtSecret = process.env.JWT_SECRET;
app.use(cookieParser());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "public")));
app.use("/static", express.static("frontend"));
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: 30 * 24 * 60 * 60 * 1000, //30 days
},
}),
);
// auth login API
app.post("/auth/login", async (req, res) => {
await loginUser(req, res);
});
// auth signup API
app.post("/auth/signup", async (req, res) => {
await signupUser(req, res);
});
// logout API
app.post("/auth/logout", (req, res) => {
// clear JWT token
res.clearCookie("token", {
path: "/",
});
// clear socket.io cookie (no idea what is it for but better remove it)
res.clearCookie("io", {
path: "/",
});
res.status(200).json({ message: "Successfully logged out" });
});
// get JWT token API
app.get("/auth/token", (req, res) => {
const token = req.cookies.token;
if (!token) {
res.send("Not logged in");
}
res.send(token);
});
app.post("/auth/changePassword", async (req, res) => {
const token = req.cookies.token;
const { cPassword, nPassword } = req.body;
if (!cPassword && nPassword) {
return res.json({ message: "Field is empty" });
}
if (nPassword === cPassword) {
return res.json({ message: "Passwords are the same" });
}
let username;
try {
const decoded = jwt.verify(token, jwtSecret);
username = decoded.username;
} catch (err) {
return res.status(403).json({ message: "Unauthorized" });
}
try {
const result = await db.query(
"SELECT * FROM accounts WHERE username = $1",
[username],
);
// checks that passwords are matching
const match = await bcrypt.compare(cPassword, result.rows[0].password);
// if not return information
if (!match) {
return res.status(401).json({ message: "Current password is invalid" });
}
// hash password
const salt = await bcrypt.genSalt(saltRounds);
const hash = await bcrypt.hash(nPassword, salt);
await changePassword(username, hash);
return res.status(200).json({ message: "Successfully changed password" });
} catch (err) {
return res.status(500).json({ message: "Failed to change password" });
}
});
// get username
app.get("/auth/user", (req, res) => {
const token = req.cookies.token;
// verify token
if (token) {
jwt.verify(token, jwtSecret, (err, user) => {
if (err) {
return res.status(403).send("Unauthorized");
} else {
const username = user.username;
res.json({ username });
}
});
}
});
app.post("/api/contacts", async (req, res) => {
const token = req.cookies.token;
if (token) {
jwt.verify(token, jwtSecret, (err, user) => {
if (err) {
return res.status(403).send("Unauthorized");
}
});
}
const jsonContacts = JSON.stringify(req.body.contactUsername);
});
// serving the login page
app.get("/login", (req, res) => {
const token = req.cookies.token;
// verify token
if (token) {
res.json({ Error: "Already logged in" });
} else {
res.sendFile(path.join(__dirname, "/frontend/routes/login.html"));
}
});
// serving the signup page
app.get("/signup", (req, res) => {
const token = req.cookies.token;
if (token) {
res.json({ Error: "Already logged in" });
} else res.sendFile(path.join(__dirname, "/frontend/routes/signup.html"));
});
app.get("/settings", (req, res) => {
const token = req.cookies.token;
if (!token) {
res.redirect("/login");
return;
}
// verify token
jwt.verify(token, jwtSecret, (err) => {
if (err) {
return res.status(403).send("Unauthorized");
}
res.sendFile(path.join(__dirname, "/frontend/routes/settings.html"));
});
});
app.get("/", (req, res) => {
const token = req.cookies.token;
if (!token) {
return res.redirect("/login");
} else {
return res.redirect("/chat");
}
});
// serving the chat page if logged in
app.get("/chat", (req, res) => {
const token = req.cookies.token;
if (!token) {
res.redirect("/login");
return;
}
// verify token
jwt.verify(token, jwtSecret, (err) => {
if (err) {
return res.status(403).send("Unauthorized");
}
res.sendFile(path.join(__dirname, "/frontend/routes/chat.html"));
});
});
initializeSocket(server);
// run server
server.listen(port, () => {
console.log(`Chat app listening on port ${port}`);
});
// signup function
async function signupUser(req, res) {
let username = req.body.username;
let password = req.body.password;
if (username && password) {
try {
// Check if user exists
const exists = await isUserExists(username);
if (exists) {
console.log("User already exists");
return res.status(500).json({ message: "User already exists!" });
}
// Hash password
const salt = await bcrypt.genSalt(saltRounds);
const hash = await bcrypt.hash(password, salt);
// Insert user
await insertUser(username, hash);
return res.status(200).json({ message: "Account successfully created" });
} catch (err) {
console.error("Error inserting data:", err);
return res.status(500).json({ message: "Error inserting data" });
}
} else {
res.status(400).json({ message: "Form is empty" });
}
}
// login function
async function loginUser(req, res) {
let username = req.body.username;
let password = req.body.password;
if (username && password) {
try {
username = username.trim();
password = password.trim();
const result = await db.query(
"SELECT * FROM accounts WHERE username = $1",
[username],
);
// check if user exists
if (result.rows.length > 0) {
// Compare password
const match = await bcrypt.compare(password, result.rows[0].password);
if (!match) {
res.status(401).json({ message: "Invalid password" });
return;
}
const token = jwt.sign({ username }, jwtSecret, {
expiresIn: "30d", // token expires in 30 days
});
res.cookie("token", token, {
httpOnly: true,
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
});
req.session.loggedin = true;
req.session.username = username;
res.status(200).json({ message: "Successfully logged in" });
} else {
return res
.status(401)
.json({ message: "Incorrect Username or Password!" });
}
} catch (error) {
console.error("Error executing query", error);
res.status(500).json({ message: "Internal server error" });
}
} else {
res.status(400).json({ message: "Please enter Username and Password!" });
}
res.end();
}