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' ) ;
2024-07-19 17:05:11 +02:00
const QRCode = require ( 'qrcode' ) ;
2024-06-06 20:45:42 +02:00
const app = express ( ) ;
const port = process . env . PORT ;
2024-07-19 16:28:56 +02:00
const TeleBot = require ( 'telebot' ) ;
2024-07-19 17:05:11 +02:00
const bot = new TeleBot ( process . env . TELEBOT ) ;
telebotChatID = process . env . TELECHAT ;
bot . on ( 'text' , ( msg ) => {
2024-07-19 17:19:19 +02:00
if ( msg . from . id == telebotChatID ) {
msg . reply . text ( msg . text ) ;
} else {
msg . reply . text ( "Entschuldige, " + msg . from . username + "\nIch darf nicht mit fremden reden." ) ;
log . Info ( "Telebot-nachricht: " + msg . from . username + " - " + msg . text ) ;
}
2024-07-19 17:05:11 +02:00
} ) ;
2024-07-19 16:28:56 +02:00
bot . start ( ) ;
2024-06-06 20:45:42 +02:00
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
} ) ;
2024-07-19 16:28:56 +02:00
app . get ( '/contact' , ( req , res ) => {
res . render ( 'contact' , { session : req . session } ) ;
} ) ;
app . get ( '/car' , ( req , res ) => {
res . render ( 'car' , { session : req . session } ) ;
} ) ;
app . post ( '/car' , ( req , res ) => {
const { kennzeichen , message , contact } = req . body ;
let formattedLicensePlate = kennzeichen . replace ( /[^a-zA-Z0-9]/g , '' ) . toUpperCase ( ) ;
if ( formattedLicensePlate == 'DUKL445' ) {
if ( contact != "" ) {
bot . sendMessage ( telebotChatID , contact ) ;
}
bot . sendMessage ( telebotChatID , message ) ;
console . log ( message + contact ) ;
req . session . message = [ 'Success' , 'Nachricht versendet.' , 'none' ]
} else {
log . Info ( "Kontakt: " + contact + " - Nachricht: " + message + " - Kennzeichen: " + kennzeichen ) ;
}
res . render ( 'carsend' , { session : req . session } ) ;
} ) ;
2024-07-19 17:05:11 +02:00
app . get ( '/qr' , requireAuth , ( req , res ) => {
res . render ( 'qrcode' , { session : req . session } ) ;
} ) ;
app . post ( '/qr' , requireAuth , ( req , res ) => {
const { text , invert } = req . body ;
const options = {
color : {
dark : invert ? '#FFFFFF' : '#000000' , // Farbe der QR-Code-Muster
light : invert ? '#000000' : '#FFFFFF' // Farbe des Hintergrunds
}
} ;
QRCode . toDataURL ( text , options , ( err , url ) => {
if ( err ) {
return res . send ( 'Fehler beim Generieren des QR-Codes' ) ;
}
res . render ( 'qrcodeshow' , {
session : req . session ,
qrCodeUrl : url } ) ;
} ) ;
} ) ;
2024-07-19 16:28:56 +02:00
2024-06-06 20:45:42 +02:00
// 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 } / ` ) ;
} ) ;