feat(rbac): added new validation to all routes and permission check to most

This commit is contained in:
Akhil Mohan
2023-09-08 21:22:36 +05:30
parent 520a553ea1
commit 549121f44e
78 changed files with 4518 additions and 3499 deletions
+8 -19
View File
@@ -5,7 +5,8 @@ import { requireMfaAuth, validateRequest } from "../../middleware";
import { authController } from "../../controllers/v2";
import { authLimiter } from "../../helpers/rateLimiter";
router.post( // TODO: deprecate (moved to api/v3/auth/login1)
router.post(
// TODO: deprecate (moved to api/v3/auth/login1)
"/login1",
authLimiter,
body("email").isString().trim().notEmpty().toLowerCase(),
@@ -14,7 +15,8 @@ router.post( // TODO: deprecate (moved to api/v3/auth/login1)
authController.login1
);
router.post( // TODO: deprecate (moved to api/v3/auth/login1)
router.post(
// TODO: deprecate (moved to api/v3/auth/login1)
"/login2",
authLimiter,
body("email").isString().trim().notEmpty().toLowerCase(),
@@ -23,22 +25,9 @@ router.post( // TODO: deprecate (moved to api/v3/auth/login1)
authController.login2
);
router.post(
"/mfa/send",
authLimiter,
body("email").isString().trim().notEmpty().isEmail(),
validateRequest,
authController.sendMfaToken
);
//remove above ones after depreciation
router.post("/mfa/send", authLimiter, authController.sendMfaToken);
router.post(
"/mfa/verify",
authLimiter,
requireMfaAuth,
body("email").isString().trim().notEmpty(),
body("mfaToken").isString().trim().notEmpty(),
validateRequest,
authController.verifyMfaToken
);
router.post("/mfa/verify", authLimiter, requireMfaAuth, authController.verifyMfaToken);
export default router;
export default router;
+7 -46
View File
@@ -1,48 +1,22 @@
import express from "express";
const router = express.Router();
import { body, param } from "express-validator";
import { environmentController } from "../../controllers/v2";
import {
requireAuth,
requireWorkspaceAuth,
validateRequest,
} from "../../middleware";
import {
ADMIN,
AuthMode,
MEMBER
} from "../../variables";
import { requireAuth } from "../../middleware";
import { AuthMode } from "../../variables";
router.post(
"/:workspaceId/environments",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("environmentSlug").exists().trim(),
body("environmentName").exists().trim(),
validateRequest,
environmentController.createWorkspaceEnvironment
);
router.put(
"/:workspaceId/environments",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("environmentSlug").exists().trim(),
body("environmentName").exists().trim(),
body("oldEnvironmentSlug").exists().trim(),
validateRequest,
environmentController.renameWorkspaceEnvironment
);
@@ -67,30 +41,17 @@ router.patch(
router.delete(
"/:workspaceId/environments",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("environmentSlug").exists().trim(),
validateRequest,
environmentController.deleteWorkspaceEnvironment
);
router.get(
"/:workspaceId/environments",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
validateRequest,
environmentController.getAllAccessibleEnvironmentsOfWorkspace
);
export default router;
export default router;
+11 -39
View File
@@ -1,14 +1,12 @@
import express from "express";
const router = express.Router();
import { Types } from "mongoose";
import {
requireAuth,
requireSecretsAuth,
requireWorkspaceAuth,
validateRequest
} from "../../middleware";
import { validateClientForSecrets } from "../../validation";
import { body, query } from "express-validator";
import { body } from "express-validator";
import { secretsController } from "../../controllers/v2";
import {
ADMIN,
@@ -19,9 +17,9 @@ import {
SECRET_PERSONAL,
SECRET_SHARED
} from "../../variables";
import { BatchSecretRequest } from "../../types/secret";
router.post( // TODO endpoint: strongly consider deprecation in favor of a single operation experience on dashboard
router.post(
// TODO endpoint: strongly consider deprecation in favor of a single operation experience on dashboard
"/batch",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
@@ -30,33 +28,11 @@ router.post( // TODO endpoint: strongly consider deprecation in favor of a singl
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body"
}),
body("workspaceId").exists().isString().trim(),
body("folderId").default("root").isString().trim(),
body("environment").exists().isString().trim(),
body("secretPath").optional().isString().trim(),
body("requests")
.exists()
.custom(async (requests: BatchSecretRequest[], { req }) => {
if (Array.isArray(requests)) {
const secretIds = requests
.map((request) => request.secret._id)
.filter((secretId) => secretId !== undefined);
if (secretIds.length > 0) {
req.secrets = await validateClientForSecrets({
authData: req.authData,
secretIds: secretIds.map((secretId: string) => new Types.ObjectId(secretId)),
requiredPermissions: []
});
}
}
return true;
}),
validateRequest,
secretsController.batchSecrets
);
router.post( // TODO endpoint: deprecate (moved to POST api/v3/secrets)
router.post(
// TODO endpoint: deprecate (moved to POST api/v3/secrets)
"/",
body("workspaceId").exists().isString().trim(),
body("environment").exists().isString().trim(),
@@ -117,15 +93,9 @@ router.post( // TODO endpoint: deprecate (moved to POST api/v3/secrets)
secretsController.createSecrets
);
router.get( // TODO endpoint: deprecate (moved to GET api/v3/secrets)
router.get(
// TODO endpoint: deprecate (moved to GET api/v3/secrets)
"/",
query("workspaceId").exists().trim(),
query("environment").exists().trim(),
query("tagSlugs"),
query("folderId").default("root").isString().trim(),
query("secretPath").optional().isString().trim(),
query("include_imports").optional().default(false).isBoolean(),
validateRequest,
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}),
@@ -138,7 +108,8 @@ router.get( // TODO endpoint: deprecate (moved to GET api/v3/secrets)
secretsController.getSecrets
);
router.patch( // TODO endpoint: deprecate (moved to PATCH api/v3/secrets)
router.patch(
// TODO endpoint: deprecate (moved to PATCH api/v3/secrets)
"/",
body("secrets")
.exists()
@@ -173,7 +144,8 @@ router.patch( // TODO endpoint: deprecate (moved to PATCH api/v3/secrets)
secretsController.updateSecrets
);
router.delete( // TODO endpoint: deprecate (moved to DELETE api/v3/secrets)
router.delete(
// TODO endpoint: deprecate (moved to DELETE api/v3/secrets)
"/",
body("secretIds")
.exists()
+2 -43
View File
@@ -1,18 +1,9 @@
import express from "express";
const router = express.Router();
import {
requireAuth,
requireServiceTokenDataAuth,
requireWorkspaceAuth,
validateRequest
requireAuth
} from "../../middleware";
import { body, param } from "express-validator";
import {
ADMIN,
AuthMode,
MEMBER,
PERMISSION_WRITE_SECRETS
} from "../../variables";
import { AuthMode } from "../../variables";
import { serviceTokenDataController } from "../../controllers/v2";
router.get(
@@ -28,33 +19,6 @@ router.post(
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
body("name").exists().isString().trim(),
body("workspaceId").exists().isString().trim(),
body("scopes").exists().isArray(),
body("scopes.*.environment").exists().isString().trim(),
body("scopes.*.secretPath").exists().isString().trim(),
body("encryptedKey").exists().isString().trim(),
body("iv").exists().isString().trim(),
body("tag").exists().isString().trim(),
body("expiresIn").exists().isNumeric(), // measured in ms
body("permissions")
.isArray({ min: 1 })
.custom((value: string[]) => {
const allowedPermissions = ["read", "write"];
const invalidValues = value.filter((v) => !allowedPermissions.includes(v));
if (invalidValues.length > 0) {
throw new Error(`permissions contains invalid values: ${invalidValues.join(", ")}`);
}
return true;
}),
validateRequest,
serviceTokenDataController.createServiceTokenData
);
@@ -63,11 +27,6 @@ router.delete(
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
requireServiceTokenDataAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
param("serviceTokenDataId").exists().trim(),
validateRequest,
serviceTokenDataController.deleteServiceTokenData
);
+5 -31
View File
@@ -1,56 +1,30 @@
import express from "express";
const router = express.Router();
import { body, param } from "express-validator";
import { tagController } from "../../controllers/v2";
import {
requireAuth,
requireWorkspaceAuth,
validateRequest,
} from "../../middleware";
import {
ADMIN,
AuthMode,
MEMBER
} from "../../variables";
import { requireAuth } from "../../middleware";
import { AuthMode } from "../../variables";
router.get(
"/:workspaceId/tags",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
validateRequest,
tagController.getWorkspaceTags
);
router.delete(
"/tags/:tagId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
acceptedAuthModes: [AuthMode.JWT]
}),
param("tagId").exists().trim(),
validateRequest,
tagController.deleteWorkspaceTag
);
router.post(
"/:workspaceId/tags",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [MEMBER, ADMIN],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("name").exists().trim(),
body("tagColor").exists().trim(),
body("slug").exists().trim(),
validateRequest,
tagController.createWorkspaceTag
);
+52 -79
View File
@@ -1,114 +1,87 @@
import express from "express";
const router = express.Router();
import {
requireAuth,
validateRequest,
} from "../../middleware";
import { body, param } from "express-validator";
import { requireAuth } from "../../middleware";
import { usersController } from "../../controllers/v2";
import { AuthMode } from "../../variables";
import {
AuthMethod
} from "../../models";
router.get(
"/me",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
usersController.getMe
"/me",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
usersController.getMe
);
router.patch(
"/me/mfa",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
body("isMfaEnabled").exists().isBoolean(),
validateRequest,
usersController.updateMyMfaEnabled
"/me/mfa",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
usersController.updateMyMfaEnabled
);
router.patch(
"/me/name",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
body("firstName").exists().isString(),
body("lastName").isString(),
validateRequest,
usersController.updateName
"/me/name",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
usersController.updateName
);
router.put(
"/me/auth-methods",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
body("authMethods").exists().isArray({
min: 1,
}).custom((authMethods: AuthMethod[]) => {
return authMethods.every(provider => [
AuthMethod.EMAIL,
AuthMethod.GOOGLE,
AuthMethod.GITHUB
].includes(provider))
}),
validateRequest,
usersController.updateAuthMethods,
"/me/auth-methods",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
usersController.updateAuthMethods
);
router.get(
"/me/organizations",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
usersController.getMyOrganizations
"/me/organizations",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
usersController.getMyOrganizations
);
router.get(
"/me/api-keys",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.getMyAPIKeys
"/me/api-keys",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.getMyAPIKeys
);
router.post(
"/me/api-keys",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
body("name").exists().isString().trim(),
body("expiresIn").isNumeric(),
validateRequest,
usersController.createAPIKey
"/me/api-keys",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.createAPIKey
);
router.delete(
"/me/api-keys/:apiKeyDataId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
param("apiKeyDataId").exists().trim(),
validateRequest,
usersController.deleteAPIKey
"/me/api-keys/:apiKeyDataId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.deleteAPIKey
);
router.get(
"/me/sessions",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.getMySessions
"/me/sessions",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.getMySessions
);
router.delete(
"/me/sessions",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.deleteMySessions
"/me/sessions",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
usersController.deleteMySessions
);
export default router;
export default router;
+76 -127
View File
@@ -1,147 +1,96 @@
import express from "express";
const router = express.Router();
import { body, param, query } from "express-validator";
import {
requireAuth,
requireMembershipAuth,
requireWorkspaceAuth,
validateRequest,
} from "../../middleware";
import {
ADMIN,
AuthMode,
MEMBER
} from "../../variables";
import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware";
import { ADMIN, AuthMode, MEMBER } from "../../variables";
import { workspaceController } from "../../controllers/v2";
router.post( // TODO endpoint: deprecate (moved to POST v3/secrets)
"/:workspaceId/secrets",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
body("secrets").exists(),
body("keys").exists(),
body("environment").exists().trim().notEmpty(),
body("channel"),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.pushWorkspaceSecrets
);
router.get( // TODO endpoint: deprecate (moved to GET v3/secrets)
"/:workspaceId/secrets",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
query("environment").exists().trim(),
query("channel"),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.pullSecrets
);
router.get( // TODO endpoint: consider moving to v3/users/me/workspaces/:workspaceId/key
"/:workspaceId/encrypted-key",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.getWorkspaceKey
router.post(
// TODO endpoint: deprecate (moved to POST v3/secrets)
"/:workspaceId/secrets",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params"
}),
body("secrets").exists(),
body("keys").exists(),
body("environment").exists().trim().notEmpty(),
body("channel"),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.pushWorkspaceSecrets
);
router.get(
"/:workspaceId/service-token-data",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.getWorkspaceServiceTokenData
// TODO endpoint: deprecate (moved to GET v3/secrets)
"/:workspaceId/secrets",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params"
}),
query("environment").exists().trim(),
query("channel"),
param("workspaceId").exists().trim(),
validateRequest,
workspaceController.pullSecrets
);
router.get( // new - TODO: rewire dashboard to this route
"/:workspaceId/memberships",
param("workspaceId").exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
workspaceController.getWorkspaceMemberships
router.get(
// TODO endpoint: consider moving to v3/users/me/workspaces/:workspaceId/key
"/:workspaceId/encrypted-key",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
workspaceController.getWorkspaceKey
);
router.patch( // TODO - rewire dashboard to this route
"/:workspaceId/memberships/:membershipId",
param("workspaceId").exists().trim(),
param("membershipId").exists().trim(),
body("role").exists().isString().trim().isIn([ADMIN, MEMBER]),
validateRequest,
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
locationWorkspaceId: "params",
}),
requireMembershipAuth({
acceptedRoles: [ADMIN],
locationMembershipId: "params",
}),
workspaceController.updateWorkspaceMembership
router.get(
"/:workspaceId/service-token-data",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
workspaceController.getWorkspaceServiceTokenData
);
router.delete( // TODO - rewire dashboard to this route
"/:workspaceId/memberships/:membershipId",
param("workspaceId").exists().trim(),
param("membershipId").exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
locationWorkspaceId: "params",
}),
requireMembershipAuth({
acceptedRoles: [ADMIN],
locationMembershipId: "params",
}),
workspaceController.deleteWorkspaceMembership
router.get(
// new - TODO: rewire dashboard to this route
"/:workspaceId/memberships",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
workspaceController.getWorkspaceMemberships
);
router.patch(
"/:workspaceId/auto-capitalization",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("autoCapitalization").exists().trim().notEmpty(),
validateRequest,
workspaceController.toggleAutoCapitalization
// TODO - rewire dashboard to this route
"/:workspaceId/memberships/:membershipId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
workspaceController.updateWorkspaceMembership
);
router.delete(
// TODO - rewire dashboard to this route
"/:workspaceId/memberships/:membershipId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}),
workspaceController.deleteWorkspaceMembership
);
router.patch(
"/:workspaceId/auto-capitalization",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
workspaceController.toggleAutoCapitalization
);
export default router;