@addon24/eslint-config
Version:
ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types
181 lines (158 loc) • 6.18 kB
JavaScript
/**
* ESLint-Regel: Admin Controller Security
* Stellt sicher, dass alle Admin-Controller die erforderlichen Security Guards verwenden müssen.
* Alle Controller im Admin-Ordner müssen @UseGuards(AuthGuard, AdminGuard) verwenden.
*/
/** @type {import('eslint').Rule.RuleModule} */
const adminControllerSecurityRule = {
meta: {
type: "problem",
docs: {
description: "Admin-Controller müssen AuthGuard und AdminGuard verwenden",
category: "Security",
recommended: true,
},
schema: [],
messages: {
missingAuthGuardImport: "Admin-Controller müssen AuthGuard importieren: import AuthGuard from '@/guards/AuthGuard'",
missingAdminGuardImport: "Admin-Controller müssen AdminGuard importieren: import AdminGuard from '@/guards/AdminGuard'",
missingUseGuardsImport: "Admin-Controller müssen UseGuards importieren: import { UseGuards } from '@nestjs/common'",
missingUseGuardsDecorator: "Admin-Controller müssen @UseGuards(AuthGuard, AdminGuard) als Klassen-Decorator verwenden",
incorrectGuardsOrder: "@UseGuards muss exakt 'AuthGuard, AdminGuard' in dieser Reihenfolge enthalten",
missingApiBearerAuth: "Admin-Controller müssen @ApiBearerAuth() Decorator verwenden",
},
},
create(context) {
const filename = context.getFilename();
// Prüfe, ob es sich um einen Admin-Controller handelt
const isAdminController = filename.includes("/Admin/") &&
filename.endsWith("Controller.ts") &&
!filename.includes("BaseController") &&
!filename.includes(".test.") &&
!filename.includes(".spec.");
if (!isAdminController) return {};
let hasAuthGuardImport = false;
let hasAdminGuardImport = false;
let hasUseGuardsImport = false;
let hasCorrectUseGuardsDecorator = false;
let hasApiBearerAuthDecorator = false;
let classNode = null;
return {
// Prüfe Import-Statements
ImportDeclaration(node) {
if (node.source.value === "@/guards/AuthGuard") {
// Prüfe auf default import
const defaultImport = node.specifiers.find(spec =>
spec.type === "ImportDefaultSpecifier" && spec.local.name === "AuthGuard"
);
if (defaultImport) {
hasAuthGuardImport = true;
}
}
if (node.source.value === "@/guards/AdminGuard") {
// Prüfe auf default import
const defaultImport = node.specifiers.find(spec =>
spec.type === "ImportDefaultSpecifier" && spec.local.name === "AdminGuard"
);
if (defaultImport) {
hasAdminGuardImport = true;
}
}
if (node.source.value === "@nestjs/common") {
// Prüfe auf UseGuards import
const useGuardsImport = node.specifiers.find(spec =>
spec.type === "ImportSpecifier" && spec.imported.name === "UseGuards"
);
if (useGuardsImport) {
hasUseGuardsImport = true;
}
}
},
// Prüfe Klassen-Decorators
ClassDeclaration(node) {
classNode = node;
if (node.decorators) {
for (const decorator of node.decorators) {
// Prüfe @UseGuards Decorator
if (decorator.expression.type === "CallExpression" &&
decorator.expression.callee.type === "Identifier" &&
decorator.expression.callee.name === "UseGuards") {
const args = decorator.expression.arguments;
if (args.length === 2 &&
args[0].type === "Identifier" && args[0].name === "AuthGuard" &&
args[1].type === "Identifier" && args[1].name === "AdminGuard") {
hasCorrectUseGuardsDecorator = true;
}
}
// Prüfe @ApiBearerAuth Decorator
if (decorator.expression.type === "CallExpression" &&
decorator.expression.callee.type === "Identifier" &&
decorator.expression.callee.name === "ApiBearerAuth") {
hasApiBearerAuthDecorator = true;
}
}
}
},
// Validierung am Ende der Datei
"Program:exit"(node) {
if (!classNode) return;
// Prüfe alle erforderlichen Importe
if (!hasAuthGuardImport) {
context.report({
node: classNode,
messageId: "missingAuthGuardImport",
});
}
if (!hasAdminGuardImport) {
context.report({
node: classNode,
messageId: "missingAdminGuardImport",
});
}
if (!hasUseGuardsImport) {
context.report({
node: classNode,
messageId: "missingUseGuardsImport",
});
}
// Prüfe @UseGuards Decorator
if (!hasCorrectUseGuardsDecorator) {
// Finde UseGuards Decorator, um spezifische Fehlermeldung zu geben
let foundIncorrectUseGuards = false;
if (classNode.decorators) {
for (const decorator of classNode.decorators) {
if (decorator.expression.type === "CallExpression" &&
decorator.expression.callee.type === "Identifier" &&
decorator.expression.callee.name === "UseGuards") {
foundIncorrectUseGuards = true;
context.report({
node: decorator,
messageId: "incorrectGuardsOrder",
});
break;
}
}
}
if (!foundIncorrectUseGuards) {
context.report({
node: classNode,
messageId: "missingUseGuardsDecorator",
});
}
}
// Prüfe @ApiBearerAuth Decorator
if (!hasApiBearerAuthDecorator) {
context.report({
node: classNode,
messageId: "missingApiBearerAuth",
});
}
},
};
},
};
export default {
rules: {
"admin-controller-security": adminControllerSecurityRule,
},
};