change: Api Security and Rate Limiting
This commit is contained in:
parent
311a34f4b9
commit
8b08dda934
9 changed files with 173 additions and 19 deletions
|
@ -1,8 +1,8 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import UserService from "../service/user/userService";
|
||||
import CustomRequestException from "../exceptions/customRequestException";
|
||||
|
||||
export default async function allowSetup(req: Request, res: Response, next: Function) {
|
||||
export default async function allowSetup(req: Request, res: Response, next: NextFunction) {
|
||||
let count = await UserService.count();
|
||||
if (count != 0) {
|
||||
throw new CustomRequestException(405, "service is already set up");
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import BadRequestException from "../exceptions/badRequestException";
|
||||
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
|
||||
import InternalException from "../exceptions/internalException";
|
||||
import { JWTHelper } from "../helpers/jwtHelper";
|
||||
|
||||
export default async function authenticate(req: Request, res: Response, next: Function) {
|
||||
export default async function authenticate(req: Request, res: Response, next: NextFunction) {
|
||||
const bearer = req.headers.authorization?.split(" ")?.[1] ?? undefined;
|
||||
|
||||
if (!bearer) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import BadRequestException from "../exceptions/badRequestException";
|
||||
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
|
||||
import InternalException from "../exceptions/internalException";
|
||||
import { JWTHelper } from "../helpers/jwtHelper";
|
||||
|
||||
export default async function authenticateAPI(req: Request, res: Response, next: Function) {
|
||||
export default async function authenticateAPI(req: Request, res: Response, next: NextFunction) {
|
||||
const bearer = req.headers.authorization?.split(" ")?.[1] ?? undefined;
|
||||
|
||||
if (!bearer) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export default async function detectPWA(req: Request, res: Response, next: Function) {
|
||||
export default async function detectPWA(req: Request, res: Response, next: NextFunction) {
|
||||
const userAgent = req.headers["user-agent"] || "";
|
||||
if ((userAgent.includes("Mobile") && userAgent.includes("Standalone")) || req.headers["x-pwa-client"] === "true") {
|
||||
req.isPWA = true;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { ExceptionBase } from "../exceptions/exceptionsBaseType";
|
||||
import CustomRequestException from "../exceptions/customRequestException";
|
||||
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
|
||||
|
||||
export default function errorHandler(err: ExceptionBase | Error, req: Request, res: Response, next: Function) {
|
||||
export default function errorHandler(err: ExceptionBase | Error, req: Request, res: Response, next: NextFunction) {
|
||||
let status = 500;
|
||||
let msg = "Internal Server Error";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Request, Response } from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import ForbiddenRequestException from "../exceptions/forbiddenRequestException";
|
||||
|
||||
export default async function preventWebapiAccess(req: Request, res: Response, next: Function) {
|
||||
export default async function preventWebapiAccess(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.isWebApiRequest) {
|
||||
throw new ForbiddenRequestException("This route cannot be accessed via webapi");
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import express from "express";
|
||||
import type { Express } from "express";
|
||||
import type { Express, NextFunction, Request, RequestHandler, Response } from "express";
|
||||
import cors from "cors";
|
||||
import helmet from "helmet";
|
||||
import morgan from "morgan";
|
||||
import rateLimit from "express-rate-limit";
|
||||
|
||||
import allowSetup from "../middleware/allowSetup";
|
||||
import authenticate from "../middleware/authenticate";
|
||||
|
@ -20,25 +23,49 @@ import server from "./server";
|
|||
import PermissionHelper from "../helpers/permissionHelper";
|
||||
import preventWebapiAccess from "../middleware/preventWebApiAccess";
|
||||
|
||||
const strictLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 10,
|
||||
message: "Zu viele Anmeldeversuche innerhalb von 15 Minuten. Bitte warten.",
|
||||
});
|
||||
|
||||
const generalLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
max: 500,
|
||||
message: "Zu viele Anfragen innerhalb von 1 Minute. Bitte warten.",
|
||||
});
|
||||
|
||||
function excludePaths(middleware: RequestHandler, excludedPaths: Array<string>) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
if (excludedPaths.includes(req.path)) {
|
||||
return next();
|
||||
}
|
||||
return middleware(req, res, next);
|
||||
};
|
||||
}
|
||||
|
||||
export default (app: Express) => {
|
||||
app.set("query parser", "extended");
|
||||
app.use(cors());
|
||||
app.options("*", cors());
|
||||
app.use(helmet());
|
||||
app.use(morgan("short"));
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
express.urlencoded({
|
||||
extended: true,
|
||||
})
|
||||
);
|
||||
app.use(cors());
|
||||
app.options("*", cors());
|
||||
|
||||
app.use(detectPWA);
|
||||
app.use("/api/public", publicAvailable);
|
||||
app.use("/api/setup", preventWebapiAccess, allowSetup, setup);
|
||||
app.use("/api/reset", preventWebapiAccess, reset);
|
||||
app.use("/api/invite", preventWebapiAccess, invite);
|
||||
app.use("/api/auth", preventWebapiAccess, auth);
|
||||
app.use("/api/setup", strictLimiter, preventWebapiAccess, allowSetup, setup);
|
||||
app.use("/api/reset", strictLimiter, preventWebapiAccess, reset);
|
||||
app.use("/api/invite", strictLimiter, preventWebapiAccess, invite);
|
||||
app.use("/api/auth", strictLimiter, preventWebapiAccess, auth);
|
||||
app.use("/api/webapi", authenticateAPI, webapi);
|
||||
app.use(authenticate);
|
||||
app.use(excludePaths(generalLimiter, ["/synchronize"]));
|
||||
app.use("/api/admin", admin);
|
||||
app.use("/api/user", preventWebapiAccess, user);
|
||||
app.use("/api/server", preventWebapiAccess, PermissionHelper.isAdminMiddleware(), server);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue