196 lines
5.7 KiB
JavaScript
196 lines
5.7 KiB
JavaScript
const express = require('express');
|
|
const session = require('express-session');
|
|
const port = 3000;
|
|
const app = express();
|
|
const cookieParser = require('cookie-parser');
|
|
|
|
const path = require('path');
|
|
const { insertUser, isUserExists, db } = require('./backend/db.js');
|
|
const { initializeSocket } = require('./backend/socket.js');
|
|
|
|
const bcrypt = require('bcrypt');
|
|
const saltRounds = 10;
|
|
const { Server } = require('socket.io');
|
|
const { createServer } = require('node:http');
|
|
const server = createServer(app);
|
|
const io = initializeSocket(server);
|
|
const jwt = require('jsonwebtoken');
|
|
const jwtSecret = process.env.JWT_SECRET;
|
|
|
|
require('dotenv').config();
|
|
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({
|
|
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)
|
|
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);
|
|
})
|
|
|
|
// serving the login page
|
|
app.get('/login', (req, res) => {
|
|
const token = req.cookies.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('/auth/user', (req, res) => {
|
|
const token = req.cookies.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});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// serving the chat page if logged in
|
|
app.get('/', (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'));
|
|
});
|
|
});
|
|
|
|
|
|
// 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.trim();
|
|
let password = req.body.password.trim();
|
|
|
|
try {
|
|
// Check if user exists
|
|
const exists = await isUserExists(username);
|
|
if (exists) {
|
|
console.log('User already exists');
|
|
return res.status(500).send('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).send("Account successfully created <a href=/login>Login screen</a>");
|
|
} catch (err) {
|
|
console.error('Error inserting data:', err);
|
|
return res.status(500).send('Error inserting data');
|
|
}
|
|
}
|
|
|
|
// login function
|
|
async function loginUser(req, res) {
|
|
let username = req.body.username.trim();
|
|
let password = req.body.password.trim();
|
|
|
|
if (username && password) {
|
|
try {
|
|
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.send('Incorrect Username or Password!');
|
|
}
|
|
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.send(`
|
|
<p>Login successful!</p>
|
|
<p>Redirecting to chat...</p>
|
|
<script>
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 1500);
|
|
</script>
|
|
`);
|
|
} else {
|
|
res.send('Incorrect Username or Password!');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error executing query', error);
|
|
res.status(500).send('Error executing query');
|
|
}
|
|
} else {
|
|
res.send('Please enter Username and Password!');
|
|
}
|
|
res.end();
|
|
} |