mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-28 15:56:39 +00:00
Chungus
This commit is contained in:
@@ -38,13 +38,25 @@ import {
|
||||
verifyUserIsOrgOwner,
|
||||
verifySiteResourceAccess
|
||||
} from "@server/middlewares";
|
||||
import { createStore } from "@server/lib/rateLimitStore";
|
||||
import {
|
||||
verifyCertificateAccess,
|
||||
verifyRemoteExitNodeAccess,
|
||||
verifyIdpAccess,
|
||||
verifyLoginPageAccess
|
||||
} from "@server/middlewares/private";
|
||||
import { createStore } from "@server/lib/private/rateLimitStore";
|
||||
import { ActionsEnum } from "@server/auth/actions";
|
||||
import { createNewt, getNewtToken } from "./newt";
|
||||
import { getOlmToken } from "./olm";
|
||||
import rateLimit, { ipKeyGenerator } from "express-rate-limit";
|
||||
import createHttpError from "http-errors";
|
||||
import * as certificates from "./private/certificates";
|
||||
import * as billing from "@server/routers/private/billing";
|
||||
import { quickStart } from "./auth/privateQuickStart";
|
||||
import { build } from "@server/build";
|
||||
import * as remoteExitNode from "@server/routers/private/remoteExitNode";
|
||||
import * as loginPage from "@server/routers/private/loginPage";
|
||||
import * as orgIdp from "@server/routers/private/orgIdp";
|
||||
|
||||
// Root routes
|
||||
export const unauthenticated = Router();
|
||||
@@ -53,6 +65,45 @@ unauthenticated.get("/", (_, res) => {
|
||||
res.status(HttpCode.OK).json({ message: "Healthy" });
|
||||
});
|
||||
|
||||
if (build === "saas") {
|
||||
unauthenticated.post(
|
||||
"/quick-start",
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 100,
|
||||
keyGenerator: (req) => req.path,
|
||||
handler: (req, res, next) => {
|
||||
const message = `We're too busy right now. Please try again later.`;
|
||||
return next(
|
||||
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
|
||||
);
|
||||
},
|
||||
store: createStore()
|
||||
}),
|
||||
quickStart
|
||||
);
|
||||
}
|
||||
|
||||
if (build !== "oss") {
|
||||
unauthenticated.post(
|
||||
"/remote-exit-node/quick-start",
|
||||
rateLimit({
|
||||
windowMs: 60 * 60 * 1000,
|
||||
max: 5,
|
||||
keyGenerator: (req) =>
|
||||
`${req.path}:${ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only create 5 remote exit nodes every hour. Please try again later.`;
|
||||
return next(
|
||||
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
|
||||
);
|
||||
},
|
||||
store: createStore()
|
||||
}),
|
||||
remoteExitNode.quickStartRemoteExitNode
|
||||
);
|
||||
}
|
||||
|
||||
// Authenticated Root routes
|
||||
export const authenticated = Router();
|
||||
authenticated.use(verifySessionUserMiddleware);
|
||||
@@ -540,7 +591,10 @@ authenticated.post(
|
||||
);
|
||||
authenticated.post(`/supporter-key/hide`, supporterKey.hideSupporterKey);
|
||||
|
||||
unauthenticated.get("/resource/:resourceGuid/auth", resource.getResourceAuthInfo);
|
||||
unauthenticated.get(
|
||||
"/resource/:resourceGuid/auth",
|
||||
resource.getResourceAuthInfo
|
||||
);
|
||||
|
||||
// authenticated.get(
|
||||
// "/role/:roleId/resources",
|
||||
@@ -666,6 +720,46 @@ authenticated.post(
|
||||
idp.updateOidcIdp
|
||||
);
|
||||
|
||||
if (build !== "oss") {
|
||||
authenticated.put(
|
||||
"/org/:orgId/idp/oidc",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createIdp),
|
||||
orgIdp.createOrgOidcIdp
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/idp/:idpId/oidc",
|
||||
verifyOrgAccess,
|
||||
verifyIdpAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateIdp),
|
||||
orgIdp.updateOrgOidcIdp
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
"/org/:orgId/idp/:idpId",
|
||||
verifyOrgAccess,
|
||||
verifyIdpAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteIdp),
|
||||
idp.deleteIdp
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/idp/:idpId",
|
||||
verifyOrgAccess,
|
||||
verifyIdpAccess,
|
||||
verifyUserHasAction(ActionsEnum.getIdp),
|
||||
orgIdp.getOrgIdp
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/idp",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.listIdps),
|
||||
orgIdp.listOrgIdps
|
||||
);
|
||||
}
|
||||
|
||||
authenticated.delete("/idp/:idpId", verifyUserIsServerAdmin, idp.deleteIdp);
|
||||
|
||||
authenticated.get("/idp/:idpId", verifyUserIsServerAdmin, idp.getIdp);
|
||||
@@ -694,6 +788,9 @@ authenticated.get(
|
||||
idp.listIdpOrgPolicies
|
||||
);
|
||||
|
||||
if (build !== "oss") {
|
||||
authenticated.get("/org/:orgId/idp", orgIdp.listOrgIdps); // anyone can see this; it's just a list of idp names and ids
|
||||
}
|
||||
authenticated.get("/idp", idp.listIdps); // anyone can see this; it's just a list of idp names and ids
|
||||
authenticated.get("/idp/:idpId", verifyUserIsServerAdmin, idp.getIdp);
|
||||
|
||||
@@ -826,6 +923,126 @@ authenticated.delete(
|
||||
domain.deleteAccountDomain
|
||||
);
|
||||
|
||||
if (build !== "oss") {
|
||||
authenticated.get(
|
||||
"/org/:orgId/certificate/:domainId/:domain",
|
||||
verifyOrgAccess,
|
||||
verifyCertificateAccess,
|
||||
verifyUserHasAction(ActionsEnum.getCertificate),
|
||||
certificates.getCertificate
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/certificate/:certId/restart",
|
||||
verifyOrgAccess,
|
||||
verifyCertificateAccess,
|
||||
verifyUserHasAction(ActionsEnum.restartCertificate),
|
||||
certificates.restartCertificate
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/billing/create-checkout-session",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.billing),
|
||||
billing.createCheckoutSession
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/billing/create-portal-session",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.billing),
|
||||
billing.createPortalSession
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/billing/subscription",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.billing),
|
||||
billing.getOrgSubscription
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/billing/usage",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.billing),
|
||||
billing.getOrgUsage
|
||||
);
|
||||
|
||||
authenticated.get("/domain/namespaces", domain.listDomainNamespaces);
|
||||
|
||||
authenticated.get(
|
||||
"/domain/check-namespace-availability",
|
||||
domain.checkDomainNamespaceAvailability
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
"/org/:orgId/remote-exit-node",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createRemoteExitNode),
|
||||
remoteExitNode.createRemoteExitNode
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/remote-exit-nodes",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.listRemoteExitNode),
|
||||
remoteExitNode.listRemoteExitNodes
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/remote-exit-node/:remoteExitNodeId",
|
||||
verifyOrgAccess,
|
||||
verifyRemoteExitNodeAccess,
|
||||
verifyUserHasAction(ActionsEnum.getRemoteExitNode),
|
||||
remoteExitNode.getRemoteExitNode
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/pick-remote-exit-node-defaults",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createRemoteExitNode),
|
||||
remoteExitNode.pickRemoteExitNodeDefaults
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
"/org/:orgId/remote-exit-node/:remoteExitNodeId",
|
||||
verifyOrgAccess,
|
||||
verifyRemoteExitNodeAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteRemoteExitNode),
|
||||
remoteExitNode.deleteRemoteExitNode
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
"/org/:orgId/login-page",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createLoginPage),
|
||||
loginPage.createLoginPage
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/login-page/:loginPageId",
|
||||
verifyOrgAccess,
|
||||
verifyLoginPageAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateLoginPage),
|
||||
loginPage.updateLoginPage
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
"/org/:orgId/login-page/:loginPageId",
|
||||
verifyOrgAccess,
|
||||
verifyLoginPageAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteLoginPage),
|
||||
loginPage.deleteLoginPage
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/login-page",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.getLoginPage),
|
||||
loginPage.getLoginPage
|
||||
);
|
||||
}
|
||||
|
||||
// Auth routes
|
||||
export const authRouter = Router();
|
||||
unauthenticated.use("/auth", authRouter);
|
||||
@@ -833,7 +1050,8 @@ authRouter.use(
|
||||
rateLimit({
|
||||
windowMs: config.getRawConfig().rate_limits.auth.window_minutes,
|
||||
max: config.getRawConfig().rate_limits.auth.max_requests,
|
||||
keyGenerator: (req) => `authRouterGlobal:${ipKeyGenerator(req.ip || "")}:${req.path}`,
|
||||
keyGenerator: (req) =>
|
||||
`authRouterGlobal:${ipKeyGenerator(req.ip || "")}:${req.path}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `Rate limit exceeded. You can make ${config.getRawConfig().rate_limits.auth.max_requests} requests every ${config.getRawConfig().rate_limits.auth.window_minutes} minute(s).`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -847,7 +1065,8 @@ authRouter.put(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 15,
|
||||
keyGenerator: (req) => `signup:${ipKeyGenerator(req.ip || "")}:${req.body.email}`,
|
||||
keyGenerator: (req) =>
|
||||
`signup:${ipKeyGenerator(req.ip || "")}:${req.body.email}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only sign up ${15} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -861,7 +1080,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 15,
|
||||
keyGenerator: (req) => `login:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`login:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only log in ${15} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -876,7 +1096,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 900,
|
||||
keyGenerator: (req) => `newtGetToken:${req.body.newtId || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`newtGetToken:${req.body.newtId || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only request a Newt token ${900} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -890,7 +1111,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 900,
|
||||
keyGenerator: (req) => `olmGetToken:${req.body.newtId || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`olmGetToken:${req.body.newtId || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only request an Olm token ${900} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -900,6 +1122,26 @@ authRouter.post(
|
||||
getOlmToken
|
||||
);
|
||||
|
||||
if (build !== "oss") {
|
||||
authRouter.post(
|
||||
"/remoteExitNode/get-token",
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 900,
|
||||
keyGenerator: (req) =>
|
||||
`remoteExitNodeGetToken:${req.body.newtId || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only request an remoteExitNodeToken token ${900} times every ${15} minutes. Please try again later.`;
|
||||
return next(
|
||||
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
|
||||
);
|
||||
},
|
||||
store: createStore()
|
||||
}),
|
||||
remoteExitNode.getRemoteExitNodeToken
|
||||
);
|
||||
}
|
||||
|
||||
authRouter.post(
|
||||
"/2fa/enable",
|
||||
rateLimit({
|
||||
@@ -938,7 +1180,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 15,
|
||||
keyGenerator: (req) => `signup:${req.user?.userId || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`signup:${req.user?.userId || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only disable 2FA ${15} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -952,7 +1195,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 15,
|
||||
keyGenerator: (req) => `signup:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`signup:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only sign up ${15} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -1007,7 +1251,8 @@ authRouter.post(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 15,
|
||||
keyGenerator: (req) => `resetPassword:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`resetPassword:${req.body.email || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only request a password reset ${15} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
@@ -1064,6 +1309,26 @@ authRouter.post(
|
||||
resource.authWithWhitelist
|
||||
);
|
||||
|
||||
if (build !== "oss") {
|
||||
authRouter.post(
|
||||
"/transfer-session-token",
|
||||
rateLimit({
|
||||
windowMs: 1 * 60 * 1000,
|
||||
max: 60,
|
||||
keyGenerator: (req) =>
|
||||
`transferSessionToken:${ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only transfer a session token ${5} times every ${1} minute. Please try again later.`;
|
||||
return next(
|
||||
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
|
||||
);
|
||||
},
|
||||
store: createStore()
|
||||
}),
|
||||
auth.transferSession
|
||||
);
|
||||
}
|
||||
|
||||
authRouter.post(
|
||||
"/resource/:resourceId/access-token",
|
||||
resource.authWithAccessToken
|
||||
@@ -1129,7 +1394,8 @@ authRouter.delete(
|
||||
rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 20, // Allow 10 authentication attempts per 15 minutes per IP
|
||||
keyGenerator: (req) => `securityKeyAuth:${req.user?.userId || ipKeyGenerator(req.ip || "")}`,
|
||||
keyGenerator: (req) =>
|
||||
`securityKeyAuth:${req.user?.userId || ipKeyGenerator(req.ip || "")}`,
|
||||
handler: (req, res, next) => {
|
||||
const message = `You can only delete a security key ${10} times every ${15} minutes. Please try again later.`;
|
||||
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||
|
||||
Reference in New Issue
Block a user