diff --git a/.env b/.env index 1c7602c..965935b 100644 --- a/.env +++ b/.env @@ -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 diff --git a/backend/db.js b/backend/db.js index 6039e2f..e2cefb8 100644 --- a/backend/db.js +++ b/backend/db.js @@ -1,31 +1,30 @@ -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 +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, }); // 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); - }); - }) - .catch((err) => { - console.error('Error connecting to database: ', err); - }) + .then(() => { + 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); + }); async function createTables() { - try { - // Create accounts table - await db.query(` + try { + // Create accounts table + await db.query(` CREATE TABLE IF NOT EXISTS accounts ( id SERIAL PRIMARY KEY, username VARCHAR(255) UNIQUE NOT NULL, @@ -33,8 +32,8 @@ async function createTables() { ) `); - // Create messages table - await db.query(` + // Create messages table + await db.query(` CREATE TABLE IF NOT EXISTS messages ( id SERIAL PRIMARY KEY, content TEXT NOT NULL, @@ -43,8 +42,8 @@ async function createTables() { ) `); - // Create contacts table - await db.query(` + // Create contacts table + await db.query(` CREATE TABLE IF NOT EXISTS contacts ( username TEXT NOT NULL, contact TEXT NOT NULL, @@ -52,59 +51,57 @@ async function createTables() { ) `); - console.log('Tables created successfully'); - } catch (err) { - console.error('Error creating tables:', err); - throw err; - } + console.log("Tables created successfully"); + } catch (err) { + console.error("Error creating tables:", err); + throw err; + } } // function for checking if user exists async function isUserExists(username) { - try { - 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); - throw err; - } + try { + 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); + throw err; + } } // function for signup // function for putting user data to database -async function insertUser(username, password){ - const query = ` +async function insertUser(username, password) { + const query = ` INSERT INTO accounts (username, password) VALUES ($1, $2) RETURNING *; `; - try { - const signupData = await db.query(query, [username, password]); - console.log('Account created:', signupData.rows[0].username); - } catch (err) { - console.error('Error inserting data:', err.stack); - throw err; - } + try { + const signupData = await db.query(query, [username, password]); + console.log("Account created:", signupData.rows[0].username); + } catch (err) { + 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] - ); - } catch (err) { - console.error('Failed to update password') - throw err; - } - + try { + await db.query("UPDATE accounts SET password = $1 WHERE username = $2", [ + password, + username, + ]); + } catch (err) { + console.error("Failed to update password"); + throw err; + } } module.exports = { - db , - insertUser, - isUserExists, - changePassword + db, + insertUser, + isUserExists, + changePassword, }; - diff --git a/backend/socket.js b/backend/socket.js index f56888a..93a8b74 100644 --- a/backend/socket.js +++ b/backend/socket.js @@ -1,199 +1,220 @@ -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 + const io = new Server(server, { + cookie: { + httpOnly: true, + sameSite: "strict", + maxAge: 30 * 24 * 60 * 60 * 1000, + }, + }); + + io.use((socket, next) => { + // user auth + const token = socket.handshake.auth.token; + if (token) { + jwt.verify(token, jwtSecret, (err, user) => { + if (err) { + console.log(err); + return next(new Error("Authentication error")); } + socket.user = user; + next(); + }); + } else { + next(new Error("Not logged in")); + } + }); + + // open main socket connection + io.on("connection", (socket) => { + if (!socket.user) { + socket.emit("socket error", "User not authenticated"); + socket.disconnect(); + return; + } + const username = socket.user.username; + // Join a room with the user's username + socket.join(username); + + io.to(username).emit("username", username); + + // chat message event + 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], + ); + insertedId = result.rows[0].id; + } catch (err) { + 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 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, + }); + } + } catch (err) { + console.error("Error fetching inserted message:", err); + socket.emit("socket error", "Failed to send message"); + } }); - io.use((socket, next) => { - // user auth - const token = socket.handshake.auth.token; - if(token) { - jwt.verify(token, jwtSecret, (err, user) => { - if(err) { - console.log(err); - return next(new Error('Authentication error')); - } - socket.user = user; - next(); - }); - } else { - next(new Error('Not logged in')); - } - }); - - // open main socket connection - io.on('connection', (socket) => { - if (!socket.user) { - socket.emit('socket error', 'User not authenticated') - socket.disconnect(); - return; - } - const username = socket.user.username; - // Join a room with the user's username - socket.join(username); - - io.to(username).emit('username', username); - - // chat message event - 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]); - insertedId = result.rows[0].id; - - } catch (err) { - 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 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 }); - } - } catch (err) { - console.error('Error fetching inserted message:', err); - socket.emit('socket error', 'Failed to send message') - } - }); - - socket.on('get messages', async (recipient) => { - const username = socket.user.username; - try { - const query = ` + socket.on("get messages", async (recipient) => { + const username = socket.user.username; + try { + const query = ` SELECT id, content, username, recipient FROM messages WHERE (username = $1 AND recipient = $2) OR (username = $2 AND recipient = $1) ORDER BY id ASC `; - const result = await db.query(query, [username, recipient]); + const result = await db.query(query, [username, recipient]); - if (result.rows.length > 0) { - //const { username: sender, recipient: receiver, content: content, id: id } = result.rows; + if (result.rows.length > 0) { + //const { username: sender, recipient: receiver, content: content, id: id } = result.rows; - io.to(username).emit('messages history', result.rows); - } else { - 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)') - } - }); + io.to(username).emit("messages history", result.rows); + } else { + 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)", + ); + } + }); - // Contacts socket - socket.on('contacts', async (contactUsername) => { - const username = socket.user.username; - const status = (contactUsername.status === "read") ? "read" : "unread"; + // Contacts socket + socket.on("contacts", async (contactUsername) => { + const username = socket.user.username; + const status = contactUsername.status === "read" ? "read" : "unread"; - // Update contact list in db - try { - const query = ` + // Update contact list in db + try { + const query = ` INSERT INTO contacts (username, contact, status) SELECT $1, $2, $3 WHERE NOT EXISTS ( SELECT 1 FROM contacts WHERE username = $1 AND contact = $2 ) `; - 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)') - } - // Get contact list from db - try { - const query = (` + 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)"); + } + // Get contact list from db + 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('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' - ); - 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', () => { - return "Disconnected"; - }); + `; + 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)", + ); + } }); - return io; + 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"; + 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", () => { + console.log(socket.id, " disconnected"); + return "Disconnected"; + }); + }); + + return io; } -module.exports = { initializeSocket }; \ No newline at end of file +module.exports = { initializeSocket }; diff --git a/frontend/icons/icon.png b/frontend/icons/icon.png deleted file mode 100644 index d2d02d2..0000000 Binary files a/frontend/icons/icon.png and /dev/null differ diff --git a/frontend/js/signup.js b/frontend/js/signup.js index e0533c7..65fc1fd 100644 --- a/frontend/js/signup.js +++ b/frontend/js/signup.js @@ -1,47 +1,48 @@ 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"){ - x.type = "text"; - y.type = "text"; - } else { - x.type = "password"; - y.type = "password"; - } + let x = document.getElementById("password"); + let y = document.getElementById("sPassword"); + if (x.type == "password") { + x.type = "text"; + y.type = "text"; + } else { + x.type = "password"; + y.type = "password"; + } } -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!" - return; + if (password !== sPassword) { + messageBox.innerText = "Passwords don't match!"; + return; } - - const response = await fetch ('/auth/signup', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: jsonData + const response = await fetch("/auth/signup", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: jsonData, }); - + console.log(jsonData); const result = await response.json(); - if(response.ok) { - messageBox.innerText = result.message; - messageBox.style.color = 'green'; + if (response.ok) { + messageBox.innerText = result.message; + messageBox.style.color = "green"; } else { - messageBox.innerText = result.message; - messageBox.style.color = 'red'; + messageBox.innerText = result.message; + messageBox.style.color = "red"; } -}) + }); diff --git a/frontend/routes/index.html b/frontend/routes/index.html deleted file mode 100644 index 914451a..0000000 --- a/frontend/routes/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - -
- - - -