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.
286 lines
7.4 KiB
JavaScript
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();
|
|
}
|