remove service regsitry, remove unused middleware

This commit is contained in:
Alex Holliday
2026-01-20 22:40:06 +00:00
parent f03ded4109
commit 44079f2eb8
14 changed files with 96 additions and 265 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ export const createApp = ({ services, controllers, envSettings, frontendPath, op
});
// Main app routes
setupRoutes(app, controllers);
setupRoutes(app, controllers, services);
// FE routes
app.get("*", (req, res) => {
+7 -6
View File
@@ -1,4 +1,4 @@
import { verifyJWT } from "../middleware/v1/verifyJWT.js";
import { createVerifyJWT } from "../middleware/v1/verifyJWT.js";
import { authApiLimiter } from "../middleware/v1/rateLimiter.js";
import AuthRoutes from "../routes/v1/authRoute.js";
@@ -15,19 +15,20 @@ import NotificationRoutes from "../routes/v1/notificationRoute.js";
import IncidentRoutes from "../routes/v1/incidentRoute.js";
export const setupRoutes = (app: any, controllers: Record<string, any>) => {
export const setupRoutes = (app: any, controllers: Record<string, any>, services: Record<string, any>) => {
const verifyJWT = createVerifyJWT(services.settingsService);
// V1
const authRoutes = new AuthRoutes(controllers.authController);
const authRoutes = new AuthRoutes(controllers.authController, verifyJWT);
const monitorRoutes = new MonitorRoutes(controllers.monitorController);
const settingsRoutes = new SettingsRoutes(controllers.settingsController);
const checkRoutes = new CheckRoutes(controllers.checkController);
const inviteRoutes = new InviteRoutes(controllers.inviteController);
const inviteRoutes = new InviteRoutes(controllers.inviteController, verifyJWT);
const maintenanceWindowRoutes = new MaintenanceWindowRoutes(controllers.maintenanceWindowController);
const queueRoutes = new QueueRoutes(controllers.queueController);
const logRoutes = new LogRoutes(controllers.logController);
const statusPageRoutes = new StatusPageRoutes(controllers.statusPageController);
const statusPageRoutes = new StatusPageRoutes(controllers.statusPageController, verifyJWT);
const notificationRoutes = new NotificationRoutes(controllers.notificationController);
const diagnosticRoutes = new DiagnosticRoutes(controllers.diagnosticController);
const diagnosticRoutes = new DiagnosticRoutes(controllers.diagnosticController, verifyJWT);
const incidentRoutes = new IncidentRoutes(controllers.incidentController);
app.use("/api/v1/auth", authApiLimiter, authRoutes.getRouter());
+1 -9
View File
@@ -1,4 +1,3 @@
import ServiceRegistry from "../service/system/serviceRegistry.js";
import TranslationService from "../service/system/translationService.js";
import StringService from "../service/system/stringService.js";
import MongoDB from "../db/MongoDB.js";
@@ -46,7 +45,7 @@ import { games, GameDig } from "gamedig";
import jmespath from "jmespath";
// DB Modules
import { NormalizeData, NormalizeDataUptimeDetails } from "../utils/dataUtils.js";
import { NormalizeData } from "../utils/dataUtils.js";
import { GenerateAvatarImage } from "../utils/imageProcessing.js";
import { ParseBoolean } from "../utils/utils.js";
@@ -140,9 +139,6 @@ export const initializeServices = async ({
envSettings: any;
settingsService: any;
}): Promise<InitializedSerivces> => {
const serviceRegistry = new ServiceRegistry({ logger });
(ServiceRegistry as any).instance = serviceRegistry;
const translationService = new TranslationService(logger);
await translationService.initialize();
@@ -335,9 +331,5 @@ export const initializeServices = async ({
incidentsRepository,
};
Object.values(services).forEach((service) => {
ServiceRegistry.register(service.serviceName, service);
});
return services;
};
@@ -1,7 +1,3 @@
// import { NormalizeData } from "../../../utils/dataUtils.js";
// import ServiceRegistry from "../../../service/system/serviceRegistry.js";
// import StringService from "../../../service/system/stringService.js";
const SERVICE_NAME = "statusPageModule";
class StatusPageModule {
+2 -5
View File
@@ -1,12 +1,9 @@
import { logger } from "../../utils/logger.js";
import ServiceRegistry from "../../service/system/serviceRegistry.js";
import StringService from "../../service/system/stringService.js";
const handleErrors = (error, req, res, next) => {
const status = error.status || 500;
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
const message = error.message || stringService.authIncorrectPassword;
const service = error.service || stringService.unknownService;
const message = error.message || "Server error";
const service = error.service || "unknownService";
logger.error({
message: message,
service: service,
-57
View File
@@ -1,57 +0,0 @@
import jwt from "jsonwebtoken";
const TOKEN_PREFIX = "Bearer ";
const SERVICE_NAME = "allowedRoles";
import ServiceRegistry from "../../service/system/serviceRegistry.js";
import StringService from "../../service/system/stringService.js";
import SettingsService from "../../service/system/settingsService.js";
const isAllowed = (allowedRoles) => {
return (req, res, next) => {
const token = req.headers["authorization"];
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
// If no token is pressent, return an error
if (!token) {
const error = new Error(stringService.noAuthToken);
error.status = 401;
error.service = SERVICE_NAME;
next(error);
return;
}
// If the token is improperly formatted, return an error
if (!token.startsWith(TOKEN_PREFIX)) {
const error = new Error(stringService.invalidAuthToken);
error.status = 400;
error.service = SERVICE_NAME;
next(error);
return;
}
// Parse the token
try {
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
var decoded = jwt.verify(parsedToken, jwtSecret);
const userRoles = decoded.role;
// Check if the user has the required role
if (userRoles.some((role) => allowedRoles.includes(role))) {
next();
return;
} else {
const error = new Error(stringService.insufficientPermissions);
error.status = 403;
error.service = SERVICE_NAME;
next(error);
return;
}
} catch (error) {
error.status = 401;
error.method = "isAllowed";
error.service = SERVICE_NAME;
next(error);
return;
}
};
};
export { isAllowed };
+29
View File
@@ -0,0 +1,29 @@
import type { Request, Response, NextFunction } from "express";
const SERVICE_NAME = "allowedRoles";
import { AppError } from "@/utils/AppError.js";
import type { UserRole } from "@/types/index.js";
const isAllowed = (allowedRoles: UserRole[]) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
const user = req.user;
if (!user) {
throw new AppError({ message: "Unauthorized", status: 403, service: SERVICE_NAME });
}
const userRoles = req.user?.role || [];
// Check if the user has the required role
if (userRoles.some((role) => allowedRoles.includes(role))) {
next();
return;
} else {
throw new AppError({ message: "Unauthorized", status: 403, service: SERVICE_NAME });
}
} catch (error) {
next(error);
return;
}
};
};
export { isAllowed };
+43 -42
View File
@@ -1,51 +1,52 @@
import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
import ServiceRegistry from "../../service/system/serviceRegistry.js";
import SettingsService from "../../service/system/settingsService.js";
import StringService from "../../service/system/stringService.js";
import { AppError } from "@/utils/AppError.js";
import { Settings } from "@/types/settings.js";
const SERVICE_NAME = "verifyJWT";
const TOKEN_PREFIX = "Bearer ";
const verifyJWT = (req: Request, res: Response, next: NextFunction) => {
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
const token = req.headers["authorization"];
// Make sure a token is provided
if (!token) {
const error: any = new Error(stringService.noAuthToken);
error.status = 401;
error.service = SERVICE_NAME;
next(error);
return;
}
// Make sure it is properly formatted
if (!token.startsWith(TOKEN_PREFIX)) {
const error: any = new Error(stringService.invalidAuthToken); // Instantiate a new Error object for improperly formatted token
error.status = 401;
error.service = SERVICE_NAME;
error.method = "verifyJWT";
next(error);
return;
}
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
// Verify the token's authenticity
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
jwt.verify(parsedToken, jwtSecret, (err: any, decoded: any) => {
if (err) {
const errorMessage = err.name === "TokenExpiredError" ? stringService.expiredAuthToken : stringService.invalidAuthToken;
err.details = { msg: errorMessage };
err.status = 401;
err.service = SERVICE_NAME;
err.method = "verifyJWT";
next(err);
export const createVerifyJWT = (settingsService: { getSettings: () => Settings }) => {
return (req: Request, res: Response, next: NextFunction) => {
const token = req.headers["authorization"];
// Make sure a token is provided
if (!token) {
const error = new AppError({ message: "No token provided", status: 401, service: SERVICE_NAME });
next(error);
return;
}
// Make sure it is properly formatted
if (!token.startsWith(TOKEN_PREFIX)) {
const error = new AppError({ message: "Invalid token format", status: 401, service: SERVICE_NAME, method: "verifyJWT" });
next(error);
return;
} else {
// Token is valid, carry on
req.user = decoded;
next();
}
});
};
export { verifyJWT };
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
// Verify the token's authenticity
const { jwtSecret } = settingsService.getSettings();
if (!jwtSecret) {
const error = new AppError({ message: "JWT secret not configured", status: 500, service: SERVICE_NAME });
next(error);
return;
}
jwt.verify(parsedToken, jwtSecret, (err: any, decoded: any) => {
if (err) {
const error = new AppError({
message: "Failed to authenticate token",
details: err,
status: 401,
service: SERVICE_NAME,
method: "verifyJWT",
});
next(error);
return;
} else {
// Token is valid, carry on
req.user = decoded;
next();
}
});
};
};
@@ -1,59 +0,0 @@
import { logger } from "../../utils/logger.js";
import ServiceRegistry from "../../service/system/serviceRegistry.js";
import StringService from "../../service/system/stringService.js";
import { ObjectId } from "mongodb";
const SERVICE_NAME = "verifyOwnership";
const verifyOwnership = (Model, paramName) => {
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
return async (req, res, next) => {
const userId = req.user._id;
let documentId = req.params[paramName];
try {
if (typeof documentId === "string") {
documentId = ObjectId.createFromHexString(documentId);
}
const doc = await Model.findById(documentId);
//If the document is not found, return a 404 error
if (!doc) {
logger.error({
message: stringService.verifyOwnerNotFound,
service: SERVICE_NAME,
method: "verifyOwnership",
});
const error = new Error(stringService.verifyOwnerNotFound);
error.status = 404;
throw error;
}
// Special case for User model, as it will not have a `userId` field as other docs will
if (Model.modelName === "User") {
if (userId.toString() !== doc._id.toString()) {
const error = new Error(stringService.verifyOwnerUnauthorized);
error.status = 403;
throw error;
}
next();
return;
}
// If the userID does not match the document's userID, return a 403 error
if (userId.toString() !== doc.userId.toString()) {
const error = new Error("Unauthorized");
error.status = 403;
throw error;
}
next();
return;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "verifyOwnership";
next(error);
return;
}
};
};
export { verifyOwnership };
@@ -1,66 +0,0 @@
const jwt = require("jsonwebtoken");
const logger = require("../../utils/logger.js");
const SERVICE_NAME = "verifyAdmin";
const TOKEN_PREFIX = "Bearer ";
import ServiceRegistry from "../service/serviceRegistry.js";
import SettingsService from "../service/settingsService.js";
import StringService from "../service/stringService.js";
/**
* Verifies the JWT token
* @function
* @param {express.Request} req
* @param {express.Response} res
* @param {express.NextFunction} next
* @returns {express.Response}
*/
const verifySuperAdmin = (req, res, next) => {
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
const token = req.headers["authorization"];
// Make sure a token is provided
if (!token) {
const error = new Error(stringService.noAuthToken);
error.status = 401;
error.service = SERVICE_NAME;
next(error);
return;
}
// Make sure it is properly formatted
if (!token.startsWith(TOKEN_PREFIX)) {
const error = new Error(stringService.invalidAuthToken); // Instantiate a new Error object for improperly formatted token
error.status = 400;
error.service = SERVICE_NAME;
error.method = "verifySuperAdmin";
next(error);
return;
}
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
// verify admin role is present
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
if (err) {
logger.error({
message: err.message,
service: SERVICE_NAME,
method: "verifySuperAdmin",
stack: err.stack,
details: stringService.invalidAuthToken,
});
return res.status(401).json({ success: false, msg: stringService.invalidAuthToken });
}
if (decoded.role.includes("superadmin") === false) {
logger.error({
message: stringService.invalidAuthToken,
service: SERVICE_NAME,
method: "verifySuperAdmin",
stack: err.stack,
});
return res.status(401).json({ success: false, msg: stringService.unauthorized });
}
next();
});
};
module.exports = { verifySuperAdmin };
+3 -4
View File
@@ -1,18 +1,17 @@
import { Router } from "express";
import { verifyJWT } from "../../middleware/v1/verifyJWT.js";
import { isAllowed } from "../../middleware/v1/isAllowed.js";
import multer from "multer";
const upload = multer();
class AuthRoutes {
constructor(authController) {
constructor(authController, verifyJWT) {
this.router = Router();
this.authController = authController;
this.initRoutes();
this.initRoutes(verifyJWT);
}
initRoutes() {
initRoutes(verifyJWT) {
this.router.post("/register", upload.single("profileImage"), this.authController.registerUser);
this.router.post("/login", this.authController.loginUser);
+4 -4
View File
@@ -1,14 +1,14 @@
import { Router } from "express";
import { verifyJWT } from "../../middleware/v1/verifyJWT.js";
import { isAllowed } from "../../middleware/v1/isAllowed.js";
class DiagnosticRoutes {
constructor(diagnosticController) {
constructor(diagnosticController, verifyJWT) {
this.router = Router();
this.diagnosticController = diagnosticController;
this.initRoutes();
this.initRoutes(verifyJWT);
}
initRoutes() {
initRoutes(verifyJWT) {
this.router.get("/system", verifyJWT, isAllowed(["admin", "superadmin"]), this.diagnosticController.getSystemStats);
}
+3 -4
View File
@@ -1,15 +1,14 @@
import { Router } from "express";
import { verifyJWT } from "../../middleware/v1/verifyJWT.js";
import { isAllowed } from "../../middleware/v1/isAllowed.js";
class InviteRoutes {
constructor(inviteController) {
constructor(inviteController, verifyJWT) {
this.router = Router();
this.inviteController = inviteController;
this.initRoutes();
this.initRoutes(verifyJWT);
}
initRoutes() {
initRoutes(verifyJWT) {
this.router.post("/send", verifyJWT, isAllowed(["admin", "superadmin"]), this.inviteController.sendInviteEmail);
this.router.post("/verify", this.inviteController.verifyInviteToken);
this.router.post("/", verifyJWT, isAllowed(["admin", "superadmin"]), this.inviteController.getInviteToken);
+3 -4
View File
@@ -1,16 +1,15 @@
import { Router } from "express";
import { verifyJWT } from "../../middleware/v1/verifyJWT.js";
import multer from "multer";
const upload = multer();
class StatusPageRoutes {
constructor(statusPageController) {
constructor(statusPageController, verifyJWT) {
this.router = Router();
this.statusPageController = statusPageController;
this.initRoutes();
this.initRoutes(verifyJWT);
}
initRoutes() {
initRoutes(verifyJWT) {
this.router.get("/", this.statusPageController.getStatusPage);
this.router.get("/team", verifyJWT, this.statusPageController.getStatusPagesByTeamId);