Spaces:
Running
Running
File size: 4,985 Bytes
b5757d0 114a9f6 b5757d0 e3a4602 114a9f6 e3a4602 114a9f6 b5757d0 001abd1 61b5f02 001abd1 0c7a171 47dcec6 114a9f6 e3a4602 114a9f6 b5757d0 47dcec6 b5757d0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const { Pool } = require('pg');
const path = require('path');
const app = express();
app.use(express.json());
app.use(cookieParser());
const PORT = 7860;
const SECRET_KEY = process.env.JWT_SECRET || 'fallback_secret';
// Connect to PostgreSQL (Vela)
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false }
});
const authenticateToken = (req, res, next) => {
const token = req.cookies.token;
if (!token) return res.status(401).json({ error: "Unauthorized" });
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.status(403).json({ error: "Forbidden" });
req.user = user;
next();
});
};
// --- AUTH ROUTES ---
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
try {
const result = await pool.query('SELECT * FROM portal_users WHERE username = $1 AND password = $2', [username, password]);
if (result.rows.length === 0) return res.status(401).json({ error: "Invalid credentials" });
const user = result.rows[0];
// Token expires in 8 hours
const token = jwt.sign({ id: user.id, username: user.username, role: user.role }, SECRET_KEY, { expiresIn: '8h' });
// Cookie explicitly expires in 8 hours
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'Strict',
maxAge: 8 * 60 * 60 * 1000
});
res.json({ role: user.role, id: user.id });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.post('/api/logout', (req, res) => {
res.clearCookie('token');
res.json({ success: true });
});
// --- ADMIN ROUTES ---
app.get('/api/admin/users', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const result = await pool.query("SELECT id, username, password, pages FROM portal_users WHERE role = 'user' ORDER BY id ASC");
res.json(result.rows);
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.post('/api/admin/users', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const pagesJson = JSON.stringify(req.body.pages || []);
const result = await pool.query(
'INSERT INTO portal_users (username, password, role, pages) VALUES ($1, $2, $3, $4) RETURNING id, username, password, pages',
[req.body.username, req.body.password, 'user', pagesJson]
);
res.json(result.rows[0]);
} catch (err) {
res.status(500).json({ error: "Database error. Username might already exist." });
}
});
app.delete('/api/admin/users/:id', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
await pool.query('DELETE FROM portal_users WHERE id = $1', [req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.put('/api/admin/users/:id/pages', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
const pagesJson = JSON.stringify(req.body.pages || []);
await pool.query('UPDATE portal_users SET pages = $1 WHERE id = $2', [pagesJson, req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
app.put('/api/admin/users/:id/password', authenticateToken, async (req, res) => {
if (req.user.role !== 'admin') return res.status(403).json({ error: "Admin only" });
try {
await pool.query('UPDATE portal_users SET password = $1 WHERE id = $2', [req.body.password, req.params.id]);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
// --- USER ROUTES ---
app.get('/api/user/pages', authenticateToken, async (req, res) => {
try {
const result = await pool.query('SELECT pages FROM portal_users WHERE id = $1', [req.user.id]);
if (result.rows.length === 0) return res.status(404).json({ error: "User not found" });
const userPages = result.rows[0].pages || [];
res.json(userPages);
} catch (err) {
res.status(500).json({ error: "Database error" });
}
});
// Serve React App
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); |