import bcrypt from "bcrypt"; import sqlite3 from "sqlite3"; import { open } from "sqlite"; import express from 'express'; import session from "express-session"; import sfs from "session-file-store"; let FileStore = sfs(session); const app = express(); const PORT = 3333; const SALT_COUNT = 12; const dbPromise = open({ filename: "data.db", driver: sqlite3.Database, }); var fileStoreOptions = {}; app.set('view engine', 'ejs'); app.use( express.urlencoded({ extended: true }), express.static('static'), session({ store: new FileStore(fileStoreOptions), secret: "process.env.SESSION_SECRET", cookie: { maxAge: 60000 }, resave: true, saveUninitialized: true }), ); app.get('/thread/:threadId/', async (req, res) => { try { const db = await dbPromise; const threadId = req.params.threadId; const thread = await db.get('SELECT * FROM Thread WHERE Thread.id=?', threadId); if (!thread) throw ""; const messages = await db.all('SELECT Message.*, User.creationdate as accountCreated, User.username FROM Message LEFT JOIN User WHERE Message.author=User.id AND Message.thread=?', threadId); res.render('pages/thread', { threadinfo: thread, messages: messages, session: req.session }); } catch { res.redirect('back'); } }); app.get('/', async (req, res) => { const db = await dbPromise; const threads = await db.all('SELECT * FROM Thread'); res.render('pages/index', { threads: threads, session: req.session, }); }); app.get("/login", async (req, res) => { if (req.session.logged_in) { return res.redirect('/'); } res.render('pages/login'); }); app.get("/logout", async (req, res) => { req.session.logged_in = false; req.session.user_id = null; res.redirect("/"); }); app.post("/login", async (req, res) => { try { const db = await dbPromise; const { username, password } = req.body; if (!username || !password) { return res.render('pages/login', { error: "Username or password not provided" }); } const user = await db.get(`SELECT password,id FROM User WHERE username = ?`, username); if (!user) return res.render('pages/login', { error: "Incorrect username or password" }); const compared = await bcrypt.compare(password, user.password); if (compared) { req.session.logged_in = true; req.session.user_id = user.id; res.redirect("/"); } else { return res.render('pages/login', { error: "Incorrect username or password" }); } } catch (err) { console.log(err); return res.render('pages/login', { error: "An error ocurred." }); } }); app.post("/register", async (req, res) => { try { const db = await dbPromise; const { username, password } = req.body; if (!username || !password) { return res.render('pages/login', { error: "Username or password not provided" }); } if (username.length < 4) { return res.render('pages/login', { error: "Username must be at least 4 characters long" }); } if (password.length < 6) { return res.render('pages/login', { error: "Password must be at least 6 characters long" }); } const passwordHash = await bcrypt.hash(password, SALT_COUNT); const result = await db.run('INSERT INTO User (username,password,creationdate) VALUES (?,?,unixepoch())', username, passwordHash); const userID = result.lastID; req.session.user_id = userID; req.session.logged_in = true; res.redirect("/"); } catch (err) { console.log(err); if (err.errno) { switch (err.errno) { case 19: return res.render('pages/login', { error: "Username already exists" }); break; } } return res.render('pages/login', { error: "An error ocurred." }); } }); app.post("/message/:threadId/", async (req, res) => { try { const threadId = req.params.threadId; const db = await dbPromise; const thread = await db.get('SELECT * FROM Thread WHERE Thread.id=?', threadId); const messageText = req.body.messageText; const subjectText = req.body.subjectText; const userID = req.session.user_id; await db.run("INSERT INTO Message (text,author,subject,creationdate,thread) VALUES (?,?,?,unixepoch(),?);", messageText, userID, subjectText, threadId); } catch (err) { console.error(err); } res.redirect('back'); }); app.post("/newthread", async (req, res) => { try { const db = await dbPromise; const threadName = req.body.threadName; const threadDesc = req.body.threadDesc; const userID = req.session.user_id; await db.run("INSERT INTO Thread (name,author,description,creationdate) VALUES (?,?,?,unixepoch());", threadName, userID, threadDesc); } catch (err) { console.error(err); } res.redirect("/"); }); const setup = async () => { const db = await dbPromise; await db.migrate(); app.listen(PORT, () => { console.log("listening on http://localhost:" + PORT); }); }; setup();