import express from 'express'; import sqlite3 from 'sqlite3'; import { open } from 'sqlite'; import bcrypt from 'bcrypt'; import nodemailer from 'nodemailer'; import dotenv from 'dotenv'; import fs, { stat } from 'fs'; dotenv.config(); const transporter = nodemailer.createTransport({ host: 'email.thepenguinontheweb.tech', port: 587, secure: false, // false pour STARTTLS auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASS } }); function sendMail(to, subject, html) { const mailOptions = { from: process.env.EMAIL_USER, to: to, subject: subject, html: html }; return transporter.sendMail(mailOptions) .then(() => console.log('Email sent successfully')) .catch(error => console.error('Error sending email:', error)); } const db = await open({ filename: './db/database.db', driver: sqlite3.Database }); function initializeDatabase() { db.exec(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, historyToDefault INTEGER DEFAULT 0 ); `); db.exec(` CREATE TABLE IF NOT EXISTS verify ( id INTEGER PRIMARY KEY, token TEXT NOT NULL UNIQUE, username TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, createdAt DATETIME DEFAULT CURRENT_TIMESTAMP ); `); } initializeDatabase(); const app = express(); const port = 20909; app.use(express.json()); app.use(express.static('public')); app.get('/login', (req, res) => { res.sendFile('index.html', { root: 'public' }); } ); app.get('/register', (req, res) => { res.sendFile('register.html', { root: 'public' }); } ); app.get('/', (req, res) => { // redirect to login page res.redirect('/login'); } ); app.post('/api/login', (req, res) => { const { username, password } = req.body; if (!username || !password) { return res.status(400).json({ message: 'Username and password are required' }); } db.get('SELECT * FROM users WHERE username = ? OR email = ?', [username, username]) .then(user => { if (!user) { return res.status(401).json({ message: 'Invalid username or password' }); } // Check password (replace with real password check logic) const isPasswordValid = bcrypt.compareSync(password, user.password); if (!isPasswordValid) { return res.status(401).json({ message: 'Invalid username or password' }); } res.status(200).json({ message: 'Login successful' }); }) .catch(err => { console.error('Database error:', err); res.status(500).json({ message: 'Internal server error' }); }); } ); app.post('/api/register', (req, res) => { const { username, email, password } = req.body; if (!username || !email || !password) { return res.status(400).json({ message: 'Username, email, and password are required' }); } const hashedPassword = bcrypt.hashSync(password, 10); let isAlreadyRegistered = false; db.get('SELECT * FROM users WHERE username = ? OR email = ?', [username, email]) .then(user => { if (user) { isAlreadyRegistered = true; return res.status(409).json({ message: 'Username or email already exists' }); } }) .catch(err => { console.error('Database error:', err); return res.status(500).json({ message: 'Internal server error' }); }); if (isAlreadyRegistered) { return; } db.get('SELECT * FROM verify WHERE username = ? OR email = ?', [username, email]) .then(verify => { if (verify) { // Verify if the last verification token is still valid if (Date.now() - new Date(verify.createdAt).getTime() < 24 * 60 * 60 * 1000) { isAlreadyRegistered = true; return res.status(409).json({ message: 'Verification already sent, please check your email' }); } else { // If the token is expired, delete it db.run('DELETE FROM verify WHERE id = ?', [verify.id]) .catch(err => { console.error('Database error:', err); return res.status(500).json({ message: 'Internal server error' }); }); } } }) .catch(err => { console.error('Database error:', err); return res.status(500).json({ message: 'Internal server error' }); }); if (isAlreadyRegistered) { return; } const verificationToken = Math.random().toString(36).substring(2, 15); db.run('INSERT INTO verify (token, username, email, password) VALUES (?, ?, ?, ?)', [verificationToken, username, email, hashedPassword]) .then(() => { // read the email template const emailTemplate = fs.readFileSync('mailFile/mail.html', 'utf8'); // replace placeholders in the email template const emailContent = emailTemplate.replace('{{verification_link}}', `${process.env.URL}/verify?token=${verificationToken}`); sendMail(email, 'Welcome to Our Service', emailContent); res.status(201).json({ message: 'email send' }); }) .catch(err => { console.error('Database error:', err); return res.status(500).json({ message: 'Internal server error' }); }); } ); app.get('/verify', (req, res) => { const { token } = req.query; if (!token) { return res.status(400).json({ message: 'Token is required' }); } res.sendFile('verify.html', { root: 'public' }); } ); app.post('/api/verify', (req, res) => { const { token } = req.body; if (!token) { return res.status(400).json({ message: 'Token is required' }); } db.get('SELECT * FROM verify WHERE token = ?', [token]) .then(verify => { if (!verify) { return res.status(404).json({ message: 'Invalid or expired token' }); } // Insert user into users table db.run('INSERT INTO users (username, email, password) VALUES (?, ?, ?)', [verify.username, verify.email, verify.password]) .then(() => { // Delete the verification record db.run('DELETE FROM verify WHERE id = ?', [verify.id]) .then(() => { res.status(200).json({ message: 'Email verified successfully' }); }) .catch(err => { console.error('Database error:', err); res.status(500).json({ message: 'Internal server error' }); }); }) .catch(err => { console.error('Database error:', err); res.status(500).json({ message: 'Internal server error' }); }); }) .catch(err => { console.error('Database error:', err); res.status(500).json({ message: 'Internal server error' }); }); } ); app.listen(port, "127.0.0.1", () => { console.log(`Server is running on localhost:${port}`); } );