const express = require('express');
const mysql = require('mysql2/promise');
const app = express();
app.use(express.json());
const pool = mysql.createPool({
host: 'localhost',
user: 'app_user',
password: 'password',
database: 'myapp',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// Input validation middleware
const validateUserId = (req, res, next) => {
const userId = parseInt(req.params.id);
if (isNaN(userId) || userId <= 0) {
return res.status(400).json({ error: 'Invalid user ID' });
}
req.params.id = userId;
next();
};
// SECURE: Parameterized query
app.get('/users/:id', validateUserId, async (req, res) => {
try {
const userId = req.params.id;
const query = 'SELECT id, username, email, department FROM users WHERE id = ?';
const [results] = await pool.execute(query, [userId]);
if (results.length === 0) {
return res.status(404).json({ error: 'User not found' });
}
res.json(results[0]);
} catch (error) {
console.error('Database error:', error);
res.status(500).json({ error: 'Database error' });
}
});
// SECURE: Parameterized query with validation
app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
// Input validation
if (!username || !password) {
return res.status(400).json({ error: 'Username and password required' });
}
if (username.length > 50 || password.length > 100) {
return res.status(400).json({ error: 'Invalid input length' });
}
const query = 'SELECT id, username FROM users WHERE username = ? AND password = ?';
const [results] = await pool.execute(query, [username, password]);
if (results.length > 0) {
res.json({ success: true, user: results[0] });
} else {
res.status(401).json({ success: false, error: 'Invalid credentials' });
}
} catch (error) {
console.error('Login error:', error);
res.status(500).json({ error: 'Login failed' });
}
});
// SECURE: Parameterized query with validation
app.get('/search', async (req, res) => {
try {
const { name, department, status } = req.query;
const params = [];
let sql = "SELECT id, username, email, department, status FROM users WHERE 1=1";
// Validate and build query safely
if (name && typeof name === 'string') {
if (name.length > 100) {
return res.status(400).json({ error: 'Name search term too long' });
}
sql += " AND name LIKE ?";
params.push(`%\${name}%`);
}
if (department) {
const validDepartments = ['IT', 'HR', 'Finance', 'Marketing', 'Sales'];
if (!validDepartments.includes(department)) {
return res.status(400).json({ error: 'Invalid department' });
}
sql += " AND department = ?";
params.push(department);
}
if (status) {
const validStatuses = ['active', 'inactive', 'pending'];
if (!validStatuses.includes(status)) {
return res.status(400).json({ error: 'Invalid status' });
}
sql += " AND status = ?";
params.push(status);
}
const [results] = await pool.execute(sql, params);
res.json(results);
} catch (error) {
console.error('Search error:', error);
res.status(500).json({ error: 'Search failed' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});