From 0218745bd32fd6d2e81c39cad5ec67020506df51 Mon Sep 17 00:00:00 2001 From: fabriceBJHost Date: Tue, 1 Jul 2025 16:01:05 +0200 Subject: [PATCH] app ready for testing --- .env.example | 4 +-- config/databases.js | 56 ++++++++++++++++++++++++++++++--- index.js | 10 ++++-- middleware/authMiddleware.js | 52 +++++++++++++++---------------- routes/authRoute.js | 60 ++++++++++++++++++------------------ routes/protectedRoute.js | 16 +++++----- 6 files changed, 125 insertions(+), 73 deletions(-) diff --git a/.env.example b/.env.example index caece3b..350f270 100644 --- a/.env.example +++ b/.env.example @@ -4,5 +4,5 @@ JWT_SECRET=yourSuperSecretKey # Replace with your actual secret key # Database configuration DB_HOST=localhost DB_USER=root -DB_PASSWORD=yourpassword -DB_NAME=jwt_auth \ No newline at end of file +DB_PASSWORD= +DB_NAME=api_isakafo \ No newline at end of file diff --git a/config/databases.js b/config/databases.js index ab61584..ef3a6b5 100644 --- a/config/databases.js +++ b/config/databases.js @@ -2,10 +2,56 @@ const mysql = require('mysql2/promise'); require('dotenv').config(); const pool = mysql.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, }); -module.exports = pool; \ No newline at end of file +/** + * Initialize the database and create necessary tables + * + */ +async function initDB() { + try { + const connection = await pool.getConnection(); + + // Create users table if it doesn't exist + await connection.query(` + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY NOT NULL, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + role VARCHAR(20) DEFAULT 'user', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + `); + + // ajoute une autre table si necessaire + + // add a default admin user if none exists + const [rows] = await connection.query(`SELECT COUNT(*) as count FROM users`); + if (rows[0].count === 0) { + const bcrypt = require('bcryptjs'); + const hashedPassword = await bcrypt.hash('admin123', 10); + + await connection.query( + 'INSERT INTO users (username, password, role) VALUES (?, ?, ?)', + ['admin', hashedPassword, 'admin'] + ); + + console.log('✅ Default admin user created: admin / admin123'); + } + + connection.release(); + console.log('✅ Database initialized'); + } catch (err) { + console.error('❌ Failed to initialize database:', err.message); + } +} + +module.exports = { + pool, + initDB, +}; \ No newline at end of file diff --git a/index.js b/index.js index 66a043e..adbea9e 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ const express = require('express'); const authRoutes = require('./routes/authRoute'); const protectedRoutes = require('./routes/protectedRoute'); require('dotenv').config(); +const { initDB } = require('./config/databases'); const app = express(); @@ -10,6 +11,11 @@ app.use(express.json()); app.use('/api/auth', authRoutes); app.use('/api/protected', protectedRoutes); -app.listen(process.env.PORT, () => { - console.log(`Server running on port ${process.env.PORT}`); +initDB().then(() => { + app.listen(process.env.PORT, () => { + console.log(`Server running on port ${process.env.PORT}`); + }); +}).catch(err => { + console.error('❌ Failed to initialize database:', err.message); }); + diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index ccd22b7..0efb8cf 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -4,39 +4,39 @@ require('dotenv').config(); const activeSessions = {}; // store last activity timestamp for tokens module.exports = (requiredRole = null) => { - return (req, res, next) => { - const authHeader = req.headers.authorization; + return (req, res, next) => { + const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ message: 'No token provided' }); - } + if (!authHeader) { + return res.status(401).json({ message: 'No token provided' }); + } - const token = authHeader.split(' ')[1]; + const token = authHeader.split(' ')[1]; - jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { - if (err) { - return res.status(401).json({ message: 'Invalid token' }); - } + jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { + if (err) { + return res.status(401).json({ message: 'Invalid token' }); + } - // Check token last activity - const lastActivity = activeSessions[token]; - const now = Date.now(); + // Check token last activity + const lastActivity = activeSessions[token]; + const now = Date.now(); - if (lastActivity && now - lastActivity > 30 * 60 * 1000) { - delete activeSessions[token]; - return res.status(401).json({ message: 'Token expired due to inactivity' }); - } + if (lastActivity && now - lastActivity > 30 * 60 * 1000) { + delete activeSessions[token]; + return res.status(401).json({ message: 'Token expired due to inactivity' }); + } - // Update last activity - activeSessions[token] = now; + // Update last activity + activeSessions[token] = now; - req.user = decoded; + req.user = decoded; - if (requiredRole && decoded.role !== requiredRole) { - return res.status(403).json({ message: 'Forbidden. Insufficient role' }); - } + if (requiredRole && decoded.role !== requiredRole) { + return res.status(403).json({ message: 'Forbidden. Insufficient role' }); + } - next(); - }); - }; + next(); + }); + }; }; \ No newline at end of file diff --git a/routes/authRoute.js b/routes/authRoute.js index e912e97..44c45fe 100644 --- a/routes/authRoute.js +++ b/routes/authRoute.js @@ -1,47 +1,47 @@ const express = require('express'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); -const pool = require('../config/databases'); +const { pool } = require('../config/databases'); require('dotenv').config(); const router = express.Router(); router.post('/login', async (req, res) => { - const { username, password } = req.body; + const { username, password } = req.body; - try { - const [rows] = await pool.query( - 'SELECT * FROM users WHERE username = ?', - [username] - ); + try { + const [rows] = await pool.query( + 'SELECT * FROM users WHERE username = ?', + [username] + ); - if (rows.length === 0) { - return res.status(401).json({ message: 'Invalid credentials' }); - } + if (rows.length === 0) { + return res.status(401).json({ message: 'Invalid credentials' }); + } - const user = rows[0]; + const user = rows[0]; - const isMatch = await bcrypt.compare(password, user.password); + const isMatch = await bcrypt.compare(password, user.password); - if (!isMatch) { - return res.status(401).json({ message: 'Invalid credentials' }); - } + if (!isMatch) { + return res.status(401).json({ message: 'Invalid credentials' }); + } + + const payload = { + id: user.id, + username: user.username, + role: user.role, + }; - const payload = { - id: user.id, - username: user.username, - role: user.role, - }; - - const token = jwt.sign(payload, process.env.JWT_SECRET, { - expiresIn: '2h', // max lifespan - }); - - res.json({ token }); - } catch (err) { - console.error(err); - res.status(500).json({ message: 'Server error' }); - } + const token = jwt.sign(payload, process.env.JWT_SECRET, { + expiresIn: '2h', // max lifespan + }); + + res.json({ token }); + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Server error' }); + } }); module.exports = router; diff --git a/routes/protectedRoute.js b/routes/protectedRoute.js index 9572339..328dfad 100644 --- a/routes/protectedRoute.js +++ b/routes/protectedRoute.js @@ -5,18 +5,18 @@ const router = express.Router(); // Open only to logged users router.get('/profile', authMiddleware(), (req, res) => { - res.json({ - message: 'Welcome to your profile!', - user: req.user, - }); + res.json({ + message: 'Welcome to your profile!', + user: req.user, + }); }); // Open only to admins router.get('/admin', authMiddleware('admin'), (req, res) => { - res.json({ - message: 'Welcome, admin!', - user: req.user, - }); + res.json({ + message: 'Welcome, admin!', + user: req.user, + }); }); module.exports = router;