Source: app.js

  1. /**
  2. * Diese Datei initialisiert und konfiguriert den Server, einschließlich Middleware, Routen, Datenbankverbindungen und Sicherheitskonfigurationen für eine vollständige Backend-Anwendung.
  3. *
  4. * @file app.js - Express Server Hauptanwendung
  5. * @author Farah, Ayoub, Luca, Miray, Ilyass, Lennart
  6. * @copyright 2024
  7. * @requires cors
  8. * @requires express
  9. * @requires body-parser
  10. * @requires path
  11. * @requires express-session
  12. * @requires ./sequelize.config
  13. */
  14. const cors = require("cors");
  15. const express = require("express");
  16. const app = express();
  17. const bodyParser = require("body-parser");
  18. const path = require("path");
  19. const session = require("express-session");
  20. const sequelize = require("./sequelize.config.js");
  21. // Import routes
  22. const authRoutes = require('./backend/routes/authRoutes');
  23. const docUploadRoutes = require("./backend/routes/docUploadRoutes");
  24. const foldersRoutes = require("./backend/routes/foldersRoutes");
  25. const semanticSearchRoutes = require('./backend/routes/semanticSearchRoutes');
  26. const adminRoutes = require('./backend/routes/adminRoutes');
  27. const passwordResetRoutes = require('./backend/models/passwordReset');
  28. const {registerUser, verifyUserCode} = require ('./backend/models/userRegistrationToDB.js');
  29. const monitorRoutes = require('./backend/routes/monitorRoutes.js');
  30. // Import models
  31. const User = require("./database/User");
  32. const Folder = require("./database/Folder");
  33. const File = require("./database/File");
  34. const UserRole = require("./database/UserRole");
  35. const UserRoleMapping = require("./database/UserRoleMapping");
  36. const PORT = process.env.PORT || 3000;
  37. /**
  38. * CORS-Konfiguration
  39. * @name CORSConfiguration
  40. * @memberof module:middleware
  41. * @property {string} origin - Erlaubte Origin für CORS
  42. * @property {string[]} methods - Erlaubte HTTP-Methoden
  43. * @property {boolean} credentials - Erlaubt Credentials in CORS-Requests
  44. */
  45. app.use(
  46. cors({
  47. origin: "http://localhost:5173",
  48. methods: ["POST", "PUT", "GET", "DELETE", "OPTIONS", "HEAD"],
  49. credentials: true,
  50. })
  51. );
  52. // Basic security headers
  53. app.use((req, res, next) => {
  54. res.setHeader(
  55. 'Content-Security-Policy',
  56. "default-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; img-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' localhost:* ws://localhost:*"
  57. );
  58. next();
  59. });
  60. /**
  61. * Body-Parser Konfiguration für JSON-Verarbeitung
  62. * @name BodyParserConfiguration
  63. * @memberof module:middleware
  64. */
  65. app.use(express.json());
  66. /**
  67. * Session-Konfiguration für Express
  68. * @name SessionConfiguration
  69. * @memberof module:middleware
  70. * @property {string} name - Name der Session-ID
  71. * @property {string} secret - Geheimer Schlüssel für Session-Verschlüsselung
  72. * @property {boolean} resave - Verhindert das Neu-Speichern unmodifizierter Sessions
  73. * @property {boolean} saveUninitialized - Verhindert Speichern nicht initialisierter Sessions
  74. * @property {Object} cookie - Cookie-Konfigurationen
  75. */
  76. app.use(
  77. session({
  78. name: "userId",
  79. secret: "your_secret_key",
  80. resave: false,
  81. saveUninitialized: false,
  82. cookie: {
  83. sameSite: false,
  84. secure: false,
  85. httpOnly: true,
  86. maxAge: 24 * 60 * 60 * 1000,
  87. },
  88. })
  89. );
  90. /**
  91. * Modell-Beziehungsdefinitionen
  92. * @namespace ModelRelationships
  93. * @description Definiert die Beziehungen zwischen den Datenbank-Modellen
  94. * @property {Object} User.hasMany.Folder - Ein-zu-viele Beziehung zwischen User und Folder
  95. * @property {Object} Folder.belongsTo.User - Viele-zu-eins Beziehung zwischen Folder und User
  96. * @property {Object} Folder.hasMany.Folder - Selbstreferenzierende Beziehung für Unterordner
  97. * @property {Object} User.hasMany.File - Ein-zu-viele Beziehung zwischen User und File
  98. * @property {Object} Folder.hasMany.File - Ein-zu-viele Beziehung zwischen Folder und File
  99. * @property {Object} UserRoleMapping - Verknüpfungstabelle zwischen User und UserRole
  100. *
  101. * Datenbank-Initialisierung und Beziehungsdefinition zwischen Models
  102. * @name DatabaseSetup
  103. * @async
  104. * @function
  105. * @throws {Error} Wenn die Datenbankverbindung oder Synchronisation fehlschlägt
  106. */
  107. (async () => {
  108. try {
  109. await sequelize.authenticate();
  110. console.log("Database connection successful.");
  111. // Define Model Relationships
  112. User.hasMany(Folder, { foreignKey: "user_id", onDelete: "CASCADE" });
  113. Folder.belongsTo(User, { foreignKey: "user_id" });
  114. Folder.hasMany(Folder, { foreignKey: "parent_folder_id", as: "subfolders", onDelete: "SET NULL" });
  115. Folder.belongsTo(Folder, { foreignKey: "parent_folder_id", as: "parentFolder" });
  116. User.hasMany(File, { foreignKey: "user_id", onDelete: "CASCADE" });
  117. File.belongsTo(User, { foreignKey: "user_id" });
  118. Folder.hasMany(File, { foreignKey: "folder_id", onDelete: "SET NULL" });
  119. File.belongsTo(Folder, { foreignKey: "folder_id" });
  120. UserRoleMapping.belongsTo(User, { foreignKey: "user_id" });
  121. UserRoleMapping.belongsTo(UserRole, { foreignKey: "role_id" });
  122. User.belongsToMany(UserRole, { through: UserRoleMapping, foreignKey: "user_id" });
  123. UserRole.belongsToMany(User, { through: UserRoleMapping, foreignKey: "role_id" });
  124. await sequelize.sync();
  125. console.log("Database synchronization successful.");
  126. } catch (error) {
  127. console.error("Database error:", error);
  128. }
  129. })();
  130. /**
  131. * Authentifizierungs-Middleware zur Überprüfung der Benutzeranmeldung
  132. * @function authenticateMiddleware
  133. * @param {express.Request} req - Express Request Objekt
  134. * @param {express.Response} res - Express Response Objekt
  135. * @param {express.NextFunction} next - Express Next Middleware Funktion
  136. * @returns {void}
  137. */
  138. const authenticateMiddleware = (req, res, next) => {
  139. if (req.session.userId) {
  140. next();
  141. } else {
  142. res.status(401).json({ message: "Unauthorized: Please log in" });
  143. }
  144. };
  145. app.use('/api/admin', adminRoutes);
  146. /**
  147. * Route zum Abrufen des Admin-Status
  148. * @name get/api/admin/status
  149. * @function
  150. * @memberof module:routes
  151. * @param {express.Request} req - Express Request Objekt
  152. * @param {express.Response} res - Express Response Objekt
  153. */
  154. app.get("/api/admin/status", (req, res) => {
  155. if (req.session.isAdmin) {
  156. res.json({ isAdmin: true });
  157. } else {
  158. res.json({ isAdmin: false });
  159. }
  160. });
  161. /**
  162. * Route zum Abrufen der aktuellen Benutzerinformationen
  163. * @name get/api/current-user
  164. * @function
  165. * @param {express.Request} req - Express Request Objekt
  166. * @param {express.Response} res - Express Response Objekt
  167. * @returns {Object} Objekt mit userId und isAdmin Status
  168. */
  169. app.get("/api/current-user", authenticateMiddleware, (req, res) => {
  170. res.json({
  171. userId: req.session.userId,
  172. isAdmin: req.session.isAdmin || false,
  173. });
  174. });
  175. /**
  176. * Registrierungsroute für neue Benutzer
  177. * @name post/register
  178. * @function
  179. * @async
  180. * @param {express.Request} req - Express Request Objekt mit username, email und password im Body
  181. * @param {express.Response} res - Express Response Objekt
  182. * @throws {Error} Wenn die Registrierung fehlschlägt
  183. */
  184. app.post("/register", async (req, res) => {
  185. console.log("Received registration request:", req.body);
  186. const { username, email, password } = req.body;
  187. try {
  188. const userId = await registerUser(username, email, password);
  189. console.log("User registered successfully:", userId);
  190. res.status(201).json({
  191. message: "User registered successfully. Please log in.",
  192. userId,
  193. });
  194. } catch (error) {
  195. console.error("Error registering user:", error);
  196. if (error.message === "Username or email already exists") {
  197. res.status(400).json({ message: error.message });
  198. } else if (error.message === "Failed to insert user: No ID returned") {
  199. res.status(500).json({
  200. message:
  201. "User was created but an error occurred. Please contact support.",
  202. });
  203. } else {
  204. res.status(500).json({
  205. message: "An unexpected error occurred. Please try again later.",
  206. });
  207. }
  208. }
  209. });
  210. /**
  211. * Verifizierungsroute für Benutzer-Codes
  212. * @name post/api/verify-code
  213. * @function
  214. * @async
  215. * @param {express.Request} req - Express Request Objekt mit email und verificationCode im Body
  216. * @param {express.Response} res - Express Response Objekt
  217. * @throws {Error} Wenn die Verifizierung fehlschlägt
  218. */
  219. app.post('/api/verify-code', async (req, res) => {
  220. const { email, verificationCode } = req.body;
  221. if (!email || !verificationCode) {
  222. return res.status(400).json({ message: 'Email und verification key sind notwendig' });
  223. }
  224. try {
  225. const result = await verifyUserCode(email, verificationCode);
  226. if (result.success) {
  227. res.status(200).json({ message: result.message });
  228. } else {
  229. res.status(400).json({ message: result.message });
  230. }
  231. } catch (error) {
  232. console.error(error);
  233. res.status(500).json({ message: 'An error occurred during verification' });
  234. }
  235. });
  236. // Route Middleware
  237. app.use('/auth', authRoutes);
  238. app.use('/api/admin', adminRoutes);
  239. app.use("/docupload", authenticateMiddleware, docUploadRoutes);
  240. app.use("/folders", authenticateMiddleware, foldersRoutes);
  241. app.use("/search", authenticateMiddleware, semanticSearchRoutes);
  242. app.use("/passwordReset", passwordResetRoutes);
  243. app.use('/monitor', monitorRoutes);
  244. app.use(express.static(path.join(__dirname, "frontend", "dist")));
  245. /**
  246. * Catch-all Route für Client-seitiges Routing
  247. * @name get/*
  248. * @function
  249. * @param {express.Request} req - Express Request Objekt
  250. * @param {express.Response} res - Express Response Objekt
  251. */
  252. app.get("*", (req, res) => {
  253. console.log(`Catch-All Route hit: ${req.url}`);
  254. res.sendFile(path.join(__dirname, "frontend", "dist", "index.html"));
  255. });
  256. /**
  257. * Server-Start Konfiguration
  258. * @name ServerStart
  259. * @function
  260. * @param {number} PORT - Der Port auf dem der Server läuft
  261. * @listens {number} PORT
  262. */
  263. app.listen(PORT, () => {
  264. console.log(`Server running on port ${PORT}`);
  265. });