PengLogin/index.js
2025-09-06 00:27:38 +02:00

239 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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';
import cookieParser from 'cookie-parser';
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(req, res, next) {
const token = req.cookies.auth_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.use(cookieParser());
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', authenticateToken, (req, res) => {
res.status(200).json({ user: req.user });
});
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'});
} 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}`);
}
);