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.
This commit is contained in:
slawk0
2024-10-14 15:40:08 +02:00
parent 03f45fcb93
commit bf8da0606c
7 changed files with 500 additions and 483 deletions

4
.env
View File

@@ -5,6 +5,6 @@ PG_PASSWORD=jebanechaslo
PG_DATABASE=webchat
SESSION_SECRET=changeme
JWT_SECRET=changeme
JWT_SECRET=jkldfsjklsdfjkl
APP_PORT=3000
APP_PORT=4000

View File

@@ -1,27 +1,26 @@
const {Client} = require('pg');
require('dotenv').config();
const { Client } = require("pg");
require("dotenv").config();
const db = new Client({
user: process.env.PG_USER,
password: process.env.PG_PASSWORD,
database: process.env.PG_DATABASE,
host: process.env.PG_HOST,
port: process.env.PG_PORT
port: process.env.PG_PORT,
});
// create connection to database
db.connect()
.then(() => {
console.log('Successfully connected to database');
// if connection is succesful create tables
createTables()
.catch((err) => {
console.error('Error creating tables:', err);
console.log("Successfully connected to database");
// if connection is successful create tables
createTables().catch((err) => {
console.error("Error creating tables:", err);
});
})
.catch((err) => {
console.error('Error connecting to database: ', err);
})
console.error("Error connecting to database: ", err);
});
async function createTables() {
try {
// Create accounts table
@@ -52,9 +51,9 @@ async function createTables() {
)
`);
console.log('Tables created successfully');
console.log("Tables created successfully");
} catch (err) {
console.error('Error creating tables:', err);
console.error("Error creating tables:", err);
throw err;
}
}
@@ -62,18 +61,18 @@ async function createTables() {
// function for checking if user exists
async function isUserExists(username) {
try {
const query = 'SELECT COUNT(*) FROM accounts WHERE username = $1';
const query = "SELECT COUNT(*) FROM accounts WHERE username = $1";
const result = await db.query(query, [username]);
return result.rows[0].count > 0;
} catch (err) {
console.error('Error checking username:', err);
console.error("Error checking username:", err);
throw err;
}
}
// function for signup
// function for putting user data to database
async function insertUser(username, password){
async function insertUser(username, password) {
const query = `
INSERT INTO accounts (username, password)
VALUES ($1, $2)
@@ -82,29 +81,27 @@ async function insertUser(username, password){
try {
const signupData = await db.query(query, [username, password]);
console.log('Account created:', signupData.rows[0].username);
console.log("Account created:", signupData.rows[0].username);
} catch (err) {
console.error('Error inserting data:', err.stack);
console.error("Error inserting data:", err.stack);
throw err;
}
}
async function changePassword(username, password) {
try {
await db.query(
'UPDATE accounts SET password = $1 WHERE username = $2',
[password, username]
);
await db.query("UPDATE accounts SET password = $1 WHERE username = $2", [
password,
username,
]);
} catch (err) {
console.error('Failed to update password')
console.error("Failed to update password");
throw err;
}
}
module.exports = {
db ,
db,
insertUser,
isUserExists,
changePassword
changePassword,
};

View File

@@ -1,39 +1,39 @@
const { Server } = require('socket.io');
const jwt = require('jsonwebtoken');
const { Server } = require("socket.io");
const jwt = require("jsonwebtoken");
const jwtSecret = process.env.JWT_SECRET;
const { db } = require('./db.js');
const {json} = require("express");
const { db } = require("./db.js");
const { json } = require("express");
function initializeSocket(server) {
const io = new Server(server, {
cookie: {
httpOnly: true,
sameSite: "strict",
maxAge: 30 * 24 * 60 * 60 * 1000
}
maxAge: 30 * 24 * 60 * 60 * 1000,
},
});
io.use((socket, next) => {
// user auth
const token = socket.handshake.auth.token;
if(token) {
if (token) {
jwt.verify(token, jwtSecret, (err, user) => {
if(err) {
if (err) {
console.log(err);
return next(new Error('Authentication error'));
return next(new Error("Authentication error"));
}
socket.user = user;
next();
});
} else {
next(new Error('Not logged in'));
next(new Error("Not logged in"));
}
});
// open main socket connection
io.on('connection', (socket) => {
io.on("connection", (socket) => {
if (!socket.user) {
socket.emit('socket error', 'User not authenticated')
socket.emit("socket error", "User not authenticated");
socket.disconnect();
return;
}
@@ -41,41 +41,51 @@ function initializeSocket(server) {
// Join a room with the user's username
socket.join(username);
io.to(username).emit('username', username);
io.to(username).emit("username", username);
// chat message event
socket.on('chat message', async (msgData) => {
socket.on("chat message", async (msgData) => {
const { content, recipient } = msgData;
let insertedId;
try {
// Insert the new message into the database
const result = await db.query('INSERT INTO messages (content, username, recipient) VALUES ($1, $2, $3) RETURNING id', [content, username, recipient]);
const result = await db.query(
"INSERT INTO messages (content, username, recipient) VALUES ($1, $2, $3) RETURNING id",
[content, username, recipient],
);
insertedId = result.rows[0].id;
} catch (err) {
console.error('Error inserting message:', err);
socket.emit('socket error', "Error inserting message, try refreshing the page")
console.error("Error inserting message:", err);
socket.emit(
"socket error",
"Error inserting message, try refreshing the page",
);
return;
}
// Fetch the newly inserted message from the database
try {
const query = 'SELECT id, content, username, recipient FROM messages WHERE id = $1';
const query =
"SELECT id, content, username, recipient FROM messages WHERE id = $1";
const result = await db.query(query, [insertedId]);
if (result.rows.length > 0) {
const newMessage = result.rows[0];
// Emit message to the sender's and recipient's rooms
io.to(username).to(recipient).emit('chat message', { username: newMessage.username, recipient: newMessage.recipient, content: newMessage.content });
io.to(username).to(recipient).emit("chat message", {
username: newMessage.username,
recipient: newMessage.recipient,
content: newMessage.content,
});
}
} catch (err) {
console.error('Error fetching inserted message:', err);
socket.emit('socket error', 'Failed to send message')
console.error("Error fetching inserted message:", err);
socket.emit("socket error", "Failed to send message");
}
});
socket.on('get messages', async (recipient) => {
socket.on("get messages", async (recipient) => {
const username = socket.user.username;
try {
const query = `
@@ -89,20 +99,23 @@ function initializeSocket(server) {
if (result.rows.length > 0) {
//const { username: sender, recipient: receiver, content: content, id: id } = result.rows;
io.to(username).emit('messages history', result.rows);
io.to(username).emit("messages history", result.rows);
} else {
io.to(username).emit('no messages');
io.to(username).emit("no messages");
}
} catch (e) {
console.error('Error retrieving messages:', e);
socket.emit('socket error', 'Error retrieving messages, refresh the page (server error)')
console.error("Error retrieving messages:", e);
socket.emit(
"socket error",
"Error retrieving messages, refresh the page (server error)",
);
}
});
// Contacts socket
socket.on('contacts', async (contactUsername) => {
socket.on("contacts", async (contactUsername) => {
const username = socket.user.username;
const status = (contactUsername.status === "read") ? "read" : "unread";
const status = contactUsername.status === "read" ? "read" : "unread";
// Update contact list in db
try {
@@ -115,80 +128,88 @@ function initializeSocket(server) {
`;
await db.query(query, [username, contactUsername.contact, status]);
} catch (err) {
console.error('Failed to update contacts ', err)
socket.emit('socket error', 'Failed to update contacts (server error)')
console.error("Failed to update contacts ", err);
socket.emit("socket error", "Failed to update contacts (server error)");
}
// Get contact list from db
try {
const query = (`
const query = `
SELECT contact, username, status
FROM contacts
WHERE username = $1
`);
`;
const result = await db.query(query, [username]);
io.to(username).emit('contacts', result.rows);
} catch(err) {
console.error('Failed to get contacts from db');
io.to(username).emit('socket error', 'Failed to get contacts (server error)');
}
})
socket.on('get contacts', async () => {
const username = socket.user.username;
try {
const query = (`
SELECT contact, username, status
FROM contacts
WHERE username = $1
`);
const result = await db.query(query, [username]);
io.to(username).emit('contacts', result.rows);
} catch(err) {
console.error('Failed to get contacts from db');
io.to(username).emit('socket error', 'Failed to get contacts (server error)');
}
})
socket.on('delete contact', async (contactUsername) => {
const username = socket.user.username;
try {
const query = ('DELETE FROM contacts WHERE (username = $1 AND contact = $2)');
await db.query(query, [username, contactUsername]);
} catch(err) {
console.error('Failed to remove contact from db');
io.to(username).emit('socket error', 'Failed to remove contact (server error)');
}
})
socket.on('status', async (username) => {
const userUsername = socket.user.username;
const status = 'unread';
try {
const query = (
'UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3'
io.to(username).emit("contacts", result.rows);
} catch (err) {
console.error("Failed to get contacts from db");
io.to(username).emit(
"socket error",
"Failed to get contacts (server error)",
);
await db.query(query, [status, userUsername, username]);
io.to(userUsername).emit('status', username);
} catch(err) {
console.error('Failed to update unread status:', err);
}
})
});
socket.on('read', async(contactUsername) => {
const userUsername = socket.user.username;
const status = 'read';
socket.on("get contacts", async () => {
const username = socket.user.username;
try {
const query = ('UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3');
await db.query(query, [status, userUsername, contactUsername]);
io.to(userUsername).emit('status', contactUsername);
} catch(err) {
console.error('Failed to update unread status:', err)
const query = `
SELECT contact, username, status
FROM contacts
WHERE username = $1
`;
const result = await db.query(query, [username]);
io.to(username).emit("contacts", result.rows);
} catch (err) {
console.error("Failed to get contacts from db");
io.to(username).emit(
"socket error",
"Failed to get contacts (server error)",
);
}
})
});
socket.on("delete contact", async (contactUsername) => {
const username = socket.user.username;
try {
const query =
"DELETE FROM contacts WHERE (username = $1 AND contact = $2)";
await db.query(query, [username, contactUsername]);
} catch (err) {
console.error("Failed to remove contact from db");
io.to(username).emit(
"socket error",
"Failed to remove contact (server error)",
);
}
});
socket.on("status", async (username) => {
const userUsername = socket.user.username;
const status = "unread";
try {
const query =
"UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3";
await db.query(query, [status, userUsername, username]);
io.to(userUsername).emit("status", username);
} catch (err) {
console.error("Failed to update unread status:", err);
}
});
socket.on("read", async (contactUsername) => {
const userUsername = socket.user.username;
const status = "read";
try {
const query =
"UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3";
await db.query(query, [status, userUsername, contactUsername]);
io.to(userUsername).emit("status", contactUsername);
} catch (err) {
console.error("Failed to update unread status:", err);
}
});
// disconnect event
socket.on('disconnect', () => {
socket.on("disconnect", () => {
console.log(socket.id, " disconnected");
return "Disconnected";
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1009 B

View File

@@ -1,11 +1,11 @@
window.onload = () => {
document.getElementById('username').focus();
}
document.getElementById("username").focus();
};
function showPasswd() {
let x = document.getElementById("password");
let y = document.getElementById("sPassword");
if(x.type == "password"){
if (x.type == "password") {
x.type = "text";
y.type = "text";
} else {
@@ -14,34 +14,35 @@ function showPasswd() {
}
}
document.getElementById('signupForm').addEventListener('submit',async function (event) {
document
.getElementById("signupForm")
.addEventListener("submit", async function (event) {
event.preventDefault();
const messageBox = document.getElementById('messageBox');
const username = document.getElementById('username').value.trim();
const messageBox = document.getElementById("messageBox");
const username = document.getElementById("username").value.trim();
const password = document.getElementById("password").value.trim();
const sPassword = document.getElementById("sPassword").value.trim();
const jsonData = JSON.stringify({ username, password });
if(password !== sPassword){
messageBox.innerText = "Passwords don't match!"
if (password !== sPassword) {
messageBox.innerText = "Passwords don't match!";
return;
}
const response = await fetch ('/auth/signup', {
method: 'POST',
const response = await fetch("/auth/signup", {
method: "POST",
headers: {
'Content-Type': 'application/json'
"Content-Type": "application/json",
},
body: jsonData
body: jsonData,
});
console.log(jsonData);
const result = await response.json();
if(response.ok) {
if (response.ok) {
messageBox.innerText = result.message;
messageBox.style.color = 'green';
messageBox.style.color = "green";
} else {
messageBox.innerText = result.message;
messageBox.style.color = 'red';
messageBox.style.color = "red";
}
})
});

View File

@@ -1,13 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>LOGGED IN!!!</h1>
</body>
</html>

201
index.js
View File

@@ -1,130 +1,139 @@
require('dotenv').config();
const express = require('express');
const session = require('express-session');
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 cookieParser = require("cookie-parser");
const path = require('path');
const { insertUser, isUserExists, changePassword, db } = require('./backend/db.js');
const { initializeSocket } = require('./backend/socket.js');
const path = require("path");
const {
insertUser,
isUserExists,
changePassword,
db,
} = require("./backend/db.js");
const { initializeSocket } = require("./backend/socket.js");
const bcrypt = require('bcrypt');
const bcrypt = require("bcrypt");
const saltRounds = 10;
const { createServer } = require('node:http');
const { createServer } = require("node:http");
const server = createServer(app);
const jwt = require('jsonwebtoken');
const {decode} = require("jsonwebtoken");
const {json} = require("express");
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('/socket.io', express.static('node_modules/socket.io/client-dist'));
app.use(session({
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
}
}));
maxAge: 30 * 24 * 60 * 60 * 1000, //30 days
},
}),
);
// auth login API
app.post('/auth/login', async (req, res) => {
app.post("/auth/login", async (req, res) => {
await loginUser(req, res);
});
// auth signup API
app.post('/auth/signup', async (req, res) => {
app.post("/auth/signup", async (req, res) => {
await signupUser(req, res);
});
// logout API
app.post('/auth/logout', (req, res) => {
app.post("/auth/logout", (req, res) => {
// clear JWT token
res.clearCookie('token', {
path: '/'
res.clearCookie("token", {
path: "/",
});
// clear socket.io cookie (no idea what is it for but better remove it)
res.clearCookie('io', {
path: '/'
res.clearCookie("io", {
path: "/",
});
res.status(200).json({ message: 'Successfully logged out' });
res.status(200).json({ message: "Successfully logged out" });
});
// get JWT token API
app.get('/auth/token', (req, res) => {
app.get("/auth/token", (req, res) => {
const token = req.cookies.token;
if(!token){
res.send('Not logged in');
if (!token) {
res.send("Not logged in");
}
res.send(token);
});
app.post('/auth/changePassword', async (req, res) => {
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 (!cPassword && nPassword) {
return res.json({ message: "Field is empty" });
}
if(nPassword === cPassword) {
return res.json({ message: 'Passwords are the same' })
if (nPassword === cPassword) {
return res.json({ message: "Passwords are the same" });
}
let username;
try {
const decoded = jwt.verify(token, jwtSecret);
username = username = decoded.username;
username = decoded.username;
} catch (err) {
return res.status(403).json({ message: 'Unauthorized'});
return res.status(403).json({ message: "Unauthorized" });
}
try {
const result = await db.query('SELECT * FROM accounts WHERE username = $1', [username]);
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' })
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' });
return res.status(200).json({ message: "Successfully changed password" });
} catch (err) {
return res.status(500).json({ message: 'Failed to change password' });
return res.status(500).json({ message: "Failed to change password" });
}
});
// get username
app.get('/auth/user', (req, res) => {
app.get("/auth/user", (req, res) => {
const token = req.cookies.token;
// verify token
if(token) {
if (token) {
jwt.verify(token, jwtSecret, (err, user) => {
if(err) {
return res.status(403).send('Unauthorized');
if (err) {
return res.status(403).send("Unauthorized");
} else {
const username = user.username;
res.json({username});
res.json({ username });
}
});
}
});
app.post('/api/contacts', async(req, res) => {
app.post("/api/contacts", async (req, res) => {
const token = req.cookies.token;
if(token) {
if (token) {
jwt.verify(token, jwtSecret, (err, user) => {
if(err) {
return res.status(403).send('Unauthorized');
if (err) {
return res.status(403).send("Unauthorized");
}
});
}
@@ -132,68 +141,66 @@ app.post('/api/contacts', async(req, res) => {
});
// serving the login page
app.get('/login', (req, res) => {
app.get("/login", (req, res) => {
const token = req.cookies.token;
// verify token
if (token) {
res.json({ Error: 'Already logged in' });
res.json({ Error: "Already logged in" });
} else {
res.sendFile(path.join(__dirname, '/frontend/routes/login.html'));
res.sendFile(path.join(__dirname, "/frontend/routes/login.html"));
}
});
// serving the signup page
app.get('/signup', (req, res) => {
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'));
if (token) {
res.json({ Error: "Already logged in" });
} else res.sendFile(path.join(__dirname, "/frontend/routes/signup.html"));
});
app.get('/settings', (req, res) => {
app.get("/settings", (req, res) => {
const token = req.cookies.token;
if(!token) {
res.redirect('/login');
if (!token) {
res.redirect("/login");
return;
}
// verify token
jwt.verify(token, jwtSecret, (err) => {
if (err) {
return res.status(403).send('Unauthorized');
return res.status(403).send("Unauthorized");
}
res.sendFile(path.join(__dirname, '/frontend/routes/settings.html'))
res.sendFile(path.join(__dirname, "/frontend/routes/settings.html"));
});
})
});
app.get('/', (req, res) => {
app.get("/", (req, res) => {
const token = req.cookies.token;
if(!token) {
return res.redirect('/login');
if (!token) {
return res.redirect("/login");
} else {
return res.redirect('/chat');
return res.redirect("/chat");
}
})
});
// serving the chat page if logged in
app.get('/chat', (req, res) => {
app.get("/chat", (req, res) => {
const token = req.cookies.token;
if(!token) {
res.redirect('/login');
if (!token) {
res.redirect("/login");
return;
}
// verify token
jwt.verify(token, jwtSecret, (err) => {
if (err) {
return res.status(403).send('Unauthorized');
return res.status(403).send("Unauthorized");
}
res.sendFile(path.join(__dirname, '/frontend/routes/chat.html'));
res.sendFile(path.join(__dirname, "/frontend/routes/chat.html"));
});
});
initializeSocket(server)
initializeSocket(server);
// run server
server.listen(port, () => {
@@ -205,13 +212,13 @@ async function signupUser(req, res) {
let username = req.body.username;
let password = req.body.password;
if(username && 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!' });
console.log("User already exists");
return res.status(500).json({ message: "User already exists!" });
}
// Hash password
@@ -222,17 +229,16 @@ async function signupUser(req, res) {
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' });
console.error("Error inserting data:", err);
return res.status(500).json({ message: "Error inserting data" });
}
} else {
res.status(400).json({ message: 'Form is empty'})
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;
@@ -241,34 +247,39 @@ async function loginUser(req, res) {
username = username.trim();
password = password.trim();
const result = await db.query('SELECT * FROM accounts WHERE username = $1', [username]);
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'});
res.status(401).json({ message: "Invalid password" });
return;
}
const token = jwt.sign({ username }, jwtSecret, {
expiresIn: '30d' // token expires in 30 days
expiresIn: "30d", // token expires in 30 days
});
res.cookie('token', token, {
res.cookie("token", token, {
httpOnly: true,
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
});
req.session.loggedin = true;
req.session.username = username;
res.status(200).json({ message: 'Successfully logged in' });
res.status(200).json({ message: "Successfully logged in" });
} else {
return res.status(401).json({ message: 'Incorrect Username or Password!'})
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' });
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.status(400).json({ message: "Please enter Username and Password!" });
}
res.end();
}