homeboergmann/app.js

337 lines
11 KiB
JavaScript
Raw Normal View History

2024-06-06 20:45:42 +02:00
const express = require('express');
const session = require('express-session');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const nodemailer = require('nodemailer');
const { Pool } = require('pg');
const path = require('path');
const moment = require('moment');
require('dotenv').config();
const log = require('node-file-logger');
const app = express();
const port = process.env.PORT;
const options = {
folderPath: './logs/',
dateBasedFileNaming: true,
fileNamePrefix: 'DailyLogs_',
fileNameExtension: '.log',
dateFormat: 'YYYY_MM_D',
timeFormat: 'h:mm:ss A',
}
log.SetUserOptions(options);
// Middleware
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: false }));
// Session-Konfiguration
app.use(session({
secret: process.env.SESSIONSECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 1000 * 60 * 60 * 24 * 2 }
}));
// Authentifizierungs-Middleware
const requireAuth = (req, res, next) => {
if (!req.session.userId) {
return res.redirect('/login');
}
next();
};
const requireAdmin = (req, res, next) => {
if (req.session.role !== 'admin') {
return res.status(403).send('Access denied');
}
next();
};
// Email-Konfiguration
const transporter = nodemailer.createTransport({
host: process.env.MAILHOST,
port: 465,
secure: true,
auth: {
user: process.env.MAILUSER,
pass: process.env.MAILPASS
}
});
// Datenbankverbindung
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
// Registrierung
app.post('/register', async (req, res) => {
const { username, email, password } = req.body;
try {
const hashedPassword = await bcrypt.hash(password, 10);
await pool.query('INSERT INTO users (username, email, password) VALUES ($1, $2, $3)', [username, email, hashedPassword]);
const message = 'Registrierung erfolgreich. Ein Admin wird dich in kürze freischalten';
const mailOptions = {
to: 'admin@boergmann.it',
from: 'admin@boergmann.it',
subject: 'Neue Registrierung',
text: `${username} hat sich registriert`
};
transporter.sendMail(mailOptions, (error) => {
if (error) {
console.error('Error sending email:', error);
const message = 'Error sending Mail:' + error;
res.render('error', { session: req.session, message });
}
});
res.render('error', { session: req.session, message });
} catch (error) {
console.error('Error registering user:', error);
const message = 'Error registering user:' + error;
res.render('error', { session: req.session, message });
}
});
// Login
app.post('/login', async (req, res) => {
const { username, password } = req.body;
try {
const userResult = await pool.query("SELECT *, CASE WHEN admin_temp IS NOT NULL AND (now() - admin_temp) > interval '22 hours' THEN 'expired' ELSE 'valid' END AS admin_status FROM users WHERE username = $1", [username]);
if (userResult.rows.length > 0) {
const user = userResult.rows[0];
const match = await bcrypt.compare(password, user.password);
if (match) {
if (user.is_active) {
req.session.userId = user.id;
req.session.userName = user.username;
req.session.activeRiege = 1;
req.session.activeTab = 'geraete';
req.session.message = [title = '', message = '', type = 'none'];
log.Info(username + ' ' + password);
if (user.admin_status === 'expired') {
await pool.query('UPDATE users SET role = $1, admin_temp = NULL WHERE id = $2', ['user', user.id]);
req.session.role = 'user';
} else {
req.session.role = user.role;
}
res.redirect('/');
} else {
res.redirect('/freischaltung')
}
} else {
const message = 'Falscher Benutzername oder falsches Passwort';
res.render('login', { session: req.session, username, message });
}
} else {
const message = 'Falscher Benutzername oder falsches Passwort';
res.render('login', { session: req.session, username, message });
}
} catch (error) {
console.error('Error logging in:', error);
const message = 'Error logging in:' + error;
res.render('error', { session: req.session, message });
}
});
//Wird angezeigt, wenn ein nicht freigeschalteter User sich anmelden will.
app.get('/freischaltung', async (req, res) => {
res.render('freischaltung', { session: req.session });
})
// Logout
app.get('/logout', (req, res) => {
req.session.destroy(err => {
if (err) {
return res.status(500).send('Internal Server Error');
}
res.redirect('/');
});
});
// Benutzer freischalten (nur Admin)
app.post('/userrights', requireAuth, requireAdmin, async (req, res) => {
const { userId, type } = req.body;
try {
if (type === 'activate') {
await pool.query('UPDATE users SET is_active = TRUE WHERE id = $1', [userId]);
const userResult = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);
if (userResult.rows.length > 0) {
if (userResult.rows[0].email) {
const mailOptions = {
to: userResult.rows[0].email,
from: 'admin@boergmann.it',
subject: 'Freischaltung',
text: `Hallo ${userResult.rows[0].username}, du wurdest soeben freigeschaltet.`
};
transporter.sendMail(mailOptions, (error) => {
if (error) {
console.error('Error sending email:', error);
const message = 'Error sending Mail:' + error;
res.render('error', { session: req.session, message });
}
})
}
}
} else if (type === 'admin') {
await pool.query('UPDATE users SET role = $1 WHERE id = $2', ['admin', userId]);
}
else if (type === 'admint') {
await pool.query('UPDATE users SET role = $1, admin_temp = $2 WHERE id = $3', ['admin', moment().toDate(), userId]);
} else if (type === 'delete') {
await pool.query('DELETE FROM users WHERE id = $1', [userId]);
}
res.redirect('/admin');
} catch (error) {
console.error('Error activating user:', error);
const message = 'Error activating user:' + error;
res.render('error', { session: req.session, message });
}
});
// Passwort-Zurücksetzung anfordern
app.post('/send-password', async (req, res) => {
const { email } = req.body;
try {
const userResult = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
if (userResult.rows.length > 0) {
const user = userResult.rows[0];
const token = crypto.randomBytes(20).toString('hex');
const resetLink = `http://tkd.boergmann.it/reset-password/${token}`;
await pool.query('UPDATE users SET reset_password_token = $1, reset_password_expires = $2 WHERE id = $3', [token, selectedDate = moment().add(1, 'd').toDate(), user.id]);
const mailOptions = {
to: user.email,
from: 'admin@boergmann.it',
subject: 'Password Reset',
text: `Click the following link to reset your password: ${resetLink}`
};
transporter.sendMail(mailOptions, (err) => {
if (err) {
console.error('Error sending email:', err);
const message = 'Error sending Mail:' + error;
res.render('error', { session: req.session, message });
} else {
const message = 'Password reset link sent';
res.render('error', { session: req.session, message });
}
});
} else {
const message = 'Email not found';
res.render('error', { session: req.session, message });
}
} catch (error) {
console.error('Error in forgot-password:', error);
const message = 'Error in forgot-password';
res.render('error', { session: req.session, message });
}
});
app.get('/forgot-password', async (req, res) => {
res.render('forgot-password', { session: req.session })
})
// Passwort zurücksetzen
app.get('/reset-password/:token', async (req, res) => {
const { token } = req.params;
try {
const userResult = await pool.query('SELECT * FROM users WHERE reset_password_token = $1 AND reset_password_expires > $2', [token, Date.now()]);
if (userResult.rows.length > 0) {
res.render('reset-password', { token }); // Stelle sicher, dass es eine reset-password.ejs gibt
} else {
const message = 'Token ungültig oder abgelaufen';
res.render('error', { session: req.session, message });
}
} catch (error) {
console.error('Error in reset-password:', error);
const message = 'Error in reset-password';
res.render('error', { session: req.session, message });
}
});
app.post('/reset-password/:token', async (req, res) => {
const { token } = req.params;
const { password } = req.body;
try {
const userResult = await pool.query('SELECT * FROM users WHERE reset_password_token = $1 AND reset_password_expires > $2', [token, Date.now()]);
if (userResult.rows.length > 0) {
const user = userResult.rows[0];
const hashedPassword = await bcrypt.hash(password, 10);
await pool.query('UPDATE users SET password = $1, reset_password_token = NULL, reset_password_expires = NULL WHERE id = $2', [hashedPassword, user.id]);
res.redirect('/login');
} else {
const message = 'Token ungültig oder abgelaufen';
res.render('error', { session: req.session, message });
}
} catch (error) {
console.error('Error in reset-password:', error);
const message = 'Error in reset-password';
res.render('error', { session: req.session, message });
}
});
// Profilseite
app.get('/profile', requireAuth, (req, res) => {
res.render('profile', { session: req.session }); // Stelle sicher, dass es eine profile.ejs gibt
});
app.post('/profile', requireAuth, async (req, res) => {
const { email, password } = req.body;
try {
if (email) {
await pool.query('UPDATE users SET email = $1 WHERE id = $2', [email, req.session.userId]);
}
if (password) {
const hashedPassword = await bcrypt.hash(password, 10);
await pool.query('UPDATE users SET password = $1 WHERE id = $2', [hashedPassword, req.session.userId]);
}
res.redirect('/profile');
} catch (error) {
console.error('Error updating profile:', error);
const message = 'Error updating profile:' + error;
res.render('error', { session: req.session, message });
}
});
// Admin-Seite
app.get('/admin', requireAuth, requireAdmin, async (req, res) => {
const usersResult = await pool.query('SELECT * FROM users');
res.render('admin', { users: usersResult.rows, session: req.session }); // Stelle sicher, dass es eine admin.ejs gibt
});
// Login und Registrierung anzeigen
app.get('/login', (req, res) => {
req.session.message = ['', '', 'none'];
res.render('login', { session: req.session }); // Stelle sicher, dass es eine login.ejs gibt
});
// Registrierung
app.get('/register', (req, res) => {
res.render('register', { session: req.session }); // Stelle sicher, dass es eine register.ejs gibt
});
// Startseite
app.get('/', (req, res) => {
req.session.message = ['', '', 'none']
res.render('index', { session: req.session });
});
2024-06-06 21:56:22 +02:00
//Datenschutz und Impressum
app.get('/impressum', (req, res) => {
req.session.message = ['', '', 'none']
res.render('impressum', { session: req.session });
});
2024-06-06 20:45:42 +02:00
const server = app.listen(port, '0.0.0.0', () => {
log.Info(`Server is running on ${process.env.HOST}:${port}/`);
});