243 lines
6.8 KiB
JavaScript
243 lines
6.8 KiB
JavaScript
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';
|
||
import jwt from 'jsonwebtoken';
|
||
|
||
dotenv.config();
|
||
|
||
const transporter = nodemailer.createTransport({
|
||
host: process.env.SMTP_HOST,
|
||
port: process.env.SMTP_PORT,
|
||
secure: process.env.SMTP_SECURE === 'true', // false for 587, true for 465
|
||
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));
|
||
}
|
||
|
||
function authenticateToken(token) {
|
||
if (!token) return res.sendStatus(401);
|
||
|
||
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
|
||
if (err) return res.sendStatus(403);
|
||
req.user = user;
|
||
next();
|
||
});
|
||
}
|
||
|
||
|
||
|
||
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,
|
||
admin BOOLEAN DEFAULT 0,
|
||
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');
|
||
}
|
||
);
|
||
|
||
// Exemple d'utilisation :
|
||
app.get('/api/loginToken', async (req, res) => {
|
||
|
||
if (!req.cookies) return res.sendStatus(401);
|
||
|
||
if (!req.cookies.auth_token) return res.sendStatus(401);
|
||
|
||
const token = req.cookies.auth_token;
|
||
|
||
authenticateToken(token);
|
||
});
|
||
|
||
app.post('/api/login', async (req, res) => {
|
||
const { username, password } = req.body;
|
||
|
||
if (!username || !password) {
|
||
return res.status(400).json({ message: 'Username and password are required' });
|
||
}
|
||
|
||
try {
|
||
const user = await db.get('SELECT * FROM users WHERE username = ? OR email = ?', [username, username]);
|
||
|
||
if (!user) {
|
||
return res.status(401).json({ message: 'Invalid username or password' });
|
||
}
|
||
|
||
const isPasswordValid = bcrypt.compareSync(password, user.password);
|
||
if (!isPasswordValid) {
|
||
return res.status(401).json({ message: 'Invalid username or password' });
|
||
}
|
||
|
||
// Générer le token JWT
|
||
const token = jwt.sign(
|
||
{ id: user.id, username: user.username, email: user.email, historyToDefault: user.historyToDefault, admin: user.admin },
|
||
process.env.JWT_SECRET, // à définir dans ton .env
|
||
{ expiresIn: process.env.JWT_EXPIRATION }
|
||
);
|
||
|
||
res.cookie("auth_token", token,
|
||
{
|
||
httpOnly: true,
|
||
sameSite: 'Strict'
|
||
}
|
||
)
|
||
|
||
// res.status(200).json({ message: 'Login successful', token });
|
||
} catch (err) {
|
||
console.error('Database error:', err);
|
||
res.status(500).json({ message: 'Internal server error' });
|
||
}
|
||
});
|
||
|
||
app.post('/api/register', async (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);
|
||
|
||
try {
|
||
// Check if user already exists in users table
|
||
const user = await db.get('SELECT * FROM users WHERE username = ? OR email = ?', [username, email]);
|
||
if (user) {
|
||
return res.status(409).json({ message: 'Username or email already exists' });
|
||
}
|
||
|
||
// Check if user is already in verify table
|
||
const verify = await db.get('SELECT * FROM verify WHERE username = ? OR email = ?', [username, email]);
|
||
if (verify) {
|
||
// If token is still valid
|
||
if (Date.now() - new Date(verify.createdAt).getTime() < 24 * 60 * 60 * 1000) {
|
||
return res.status(409).json({ message: 'Verification already sent, please check your email' });
|
||
} else {
|
||
// If token is expired, delete it
|
||
await db.run('DELETE FROM verify WHERE id = ?', [verify.id]);
|
||
}
|
||
}
|
||
|
||
// Insert new verification token
|
||
const verificationToken = Math.random().toString(36).substring(2, 15);
|
||
await db.run('INSERT INTO verify (token, username, email, password) VALUES (?, ?, ?, ?)', [verificationToken, username, email, hashedPassword]);
|
||
|
||
// read the email template
|
||
const emailTemplate = fs.readFileSync('mailFile/mail.html', 'utf8');
|
||
const emailContent = emailTemplate.replace('{{verification_link}}', `${process.env.URL}/verify?token=${verificationToken}`);
|
||
|
||
sendMail(email, 'Welcome to Our Service', emailContent);
|
||
return res.status(201).json({ message: 'email send' });
|
||
|
||
} catch (err) {
|
||
await db.run('DELETE FROM verify WHERE username = ? OR email = ?', [username, email]);
|
||
|
||
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', async (req, res) => {
|
||
const { token } = req.body;
|
||
|
||
if (!token) {
|
||
return res.status(400).json({ message: 'Token is required' });
|
||
}
|
||
|
||
try {
|
||
const verify = await db.get('SELECT * FROM verify WHERE token = ?', [token]);
|
||
|
||
if (!verify) {
|
||
return res.status(404).json({ message: 'Invalid or expired token' });
|
||
}
|
||
|
||
// Check if the token is still valid (24 hours)
|
||
if (Date.now() - new Date(verify.createdAt).getTime() > 24 * 60 * 60 * 1000) {
|
||
return res.status(410).json({ message: 'Token has expired' });
|
||
}
|
||
|
||
// Insert user into users table
|
||
await db.run('INSERT INTO users (username, email, password) VALUES (?, ?, ?)', [verify.username, verify.email, verify.password])
|
||
|
||
await db.run('DELETE FROM verify WHERE id = ?', [verify.id]);
|
||
|
||
res.status(200).json({ message: 'Account verified successfully' });
|
||
} catch (err) {
|
||
console.error('Database error:', err);
|
||
return res.status(500).json({ message: 'Internal server error' });
|
||
}
|
||
}
|
||
);
|
||
|
||
app.listen(port, "127.0.0.1", () => {
|
||
console.log(`Server is running on localhost:${port}`);
|
||
}
|
||
); |