mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(rbac): made new permission check for v3 secrets and v2 batch
This commit is contained in:
@@ -35,7 +35,17 @@ import { isValidScope } from "../../helpers/secrets";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
import { getAllImportedSecrets } from "../../services/SecretImportService";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import { BatchSecretsV2, GetSecretsV2 } from "../../validation";
|
import {
|
||||||
|
BatchSecretsV2,
|
||||||
|
GetSecretsV2,
|
||||||
|
validateServiceTokenDataClientForWorkspace
|
||||||
|
} from "../../validation";
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
getUserProjectPermissions
|
||||||
|
} from "../../services/ProjectRoleService";
|
||||||
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Peform a batch of any specified CUD secret operations
|
* Peform a batch of any specified CUD secret operations
|
||||||
@@ -68,17 +78,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
const folders = await Folder.findOne({ workspace: workspaceId, environment });
|
||||||
|
|
||||||
if (req.authData.authPayload instanceof ServiceTokenData) {
|
if (req.authData.authPayload instanceof ServiceTokenData) {
|
||||||
const isValidScopeAccess = isValidScope(
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
req.authData.authPayload,
|
serviceTokenData: req.authData.authPayload,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
environment,
|
environment,
|
||||||
secretPath || "/"
|
secretPath,
|
||||||
);
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
// in service token when not giving secretpath folderid must be root
|
|
||||||
// this is to avoid giving folderid when service tokens are used
|
|
||||||
if ((!secretPath && folderId !== "root") || (secretPath && !isValidScopeAccess)) {
|
|
||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secretPath) {
|
if (secretPath) {
|
||||||
@@ -94,6 +100,22 @@ export const batchSecrets = async (req: Request, res: Response) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.user?._id) {
|
||||||
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Delete,
|
||||||
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for await (const request of requests) {
|
for await (const request of requests) {
|
||||||
// do a validation
|
// do a validation
|
||||||
|
|
||||||
@@ -977,17 +999,17 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
const postHogClient = await TelemetryService.getPostHogClient();
|
const postHogClient = await TelemetryService.getPostHogClient();
|
||||||
|
|
||||||
// reduce the number of events captured
|
// reduce the number of events captured
|
||||||
let shouldRecordK8Event = false
|
let shouldRecordK8Event = false;
|
||||||
if (req.authData.userAgent == K8_USER_AGENT_NAME) {
|
if (req.authData.userAgent == K8_USER_AGENT_NAME) {
|
||||||
const randomNumber = Math.random();
|
const randomNumber = Math.random();
|
||||||
if (randomNumber > 0.9) {
|
if (randomNumber > 0.9) {
|
||||||
shouldRecordK8Event = true
|
shouldRecordK8Event = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postHogClient) {
|
if (postHogClient) {
|
||||||
const shouldCapture = req.authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
|
const shouldCapture = req.authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
|
||||||
const approximateForNoneCapturedEvents = secrets.length * 10
|
const approximateForNoneCapturedEvents = secrets.length * 10;
|
||||||
|
|
||||||
if (shouldCapture) {
|
if (shouldCapture) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
@@ -1111,10 +1133,10 @@ export const updateSecrets = async (req: Request, res: Response) => {
|
|||||||
tags,
|
tags,
|
||||||
...(secretCommentCiphertext !== undefined && secretCommentIV && secretCommentTag
|
...(secretCommentCiphertext !== undefined && secretCommentIV && secretCommentTag
|
||||||
? {
|
? {
|
||||||
secretCommentCiphertext,
|
secretCommentCiphertext,
|
||||||
secretCommentIV,
|
secretCommentIV,
|
||||||
secretCommentTag
|
secretCommentTag
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
getUserProjectPermissions
|
getUserProjectPermissions
|
||||||
} from "../../services/ProjectRoleService";
|
} from "../../services/ProjectRoleService";
|
||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
import { validateServiceTokenDataClientForWorkspace } from "../../validation";
|
||||||
|
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return secrets for workspace with id [workspaceId] and environment
|
* Return secrets for workspace with id [workspaceId] and environment
|
||||||
@@ -40,12 +42,22 @@ export const getSecretsRaw = async (req: Request, res: Response) => {
|
|||||||
secretPath = scope.secretPath;
|
secretPath = scope.secretPath;
|
||||||
environment = scope.environment;
|
environment = scope.environment;
|
||||||
workspaceId = serviceTokenDetails.workspace.toString();
|
workspaceId = serviceTokenDetails.workspace.toString();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_READ_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secrets = await SecretService.getSecrets({
|
const secrets = await SecretService.getSecrets({
|
||||||
@@ -108,12 +120,20 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
|
|||||||
params: { secretName }
|
params: { secretName }
|
||||||
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
|
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_READ_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.getSecret({
|
const secret = await SecretService.getSecret({
|
||||||
@@ -148,12 +168,20 @@ export const createSecretRaw = async (req: Request, res: Response) => {
|
|||||||
body: { secretPath, environment, workspaceId, type, secretValue, secretComment }
|
body: { secretPath, environment, workspaceId, type, secretValue, secretComment }
|
||||||
} = await validateRequest(reqValidator.CreateSecretRawV3, req);
|
} = await validateRequest(reqValidator.CreateSecretRawV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = await BotService.getWorkspaceKeyWithBot({
|
const key = await BotService.getWorkspaceKeyWithBot({
|
||||||
@@ -223,12 +251,20 @@ export const updateSecretByNameRaw = async (req: Request, res: Response) => {
|
|||||||
body: { secretValue, environment, secretPath, type, workspaceId }
|
body: { secretValue, environment, secretPath, type, workspaceId }
|
||||||
} = await validateRequest(reqValidator.UpdateSecretByNameRawV3, req);
|
} = await validateRequest(reqValidator.UpdateSecretByNameRawV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = await BotService.getWorkspaceKeyWithBot({
|
const key = await BotService.getWorkspaceKeyWithBot({
|
||||||
@@ -279,12 +315,20 @@ export const deleteSecretByNameRaw = async (req: Request, res: Response) => {
|
|||||||
body: { environment, secretPath, type, workspaceId }
|
body: { environment, secretPath, type, workspaceId }
|
||||||
} = await validateRequest(reqValidator.DeleteSecretByNameRawV3, req);
|
} = await validateRequest(reqValidator.DeleteSecretByNameRawV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { secret } = await SecretService.deleteSecret({
|
const { secret } = await SecretService.deleteSecret({
|
||||||
@@ -327,12 +371,20 @@ export const getSecrets = async (req: Request, res: Response) => {
|
|||||||
query: { secretPath, environment, workspaceId, include_imports: includeImports,folderId }
|
query: { secretPath, environment, workspaceId, include_imports: includeImports,folderId }
|
||||||
} = await validateRequest(reqValidator.GetSecretsV3, req);
|
} = await validateRequest(reqValidator.GetSecretsV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_READ_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secrets = await SecretService.getSecrets({
|
const secrets = await SecretService.getSecrets({
|
||||||
@@ -377,12 +429,20 @@ export const getSecretByName = async (req: Request, res: Response) => {
|
|||||||
params: { secretName }
|
params: { secretName }
|
||||||
} = await validateRequest(reqValidator.GetSecretByNameV3, req);
|
} = await validateRequest(reqValidator.GetSecretByNameV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_READ_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.getSecret({
|
const secret = await SecretService.getSecret({
|
||||||
@@ -425,12 +485,20 @@ export const createSecret = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
} = await validateRequest(reqValidator.CreateSecretV3, req);
|
} = await validateRequest(reqValidator.CreateSecretV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.createSecret({
|
const secret = await SecretService.createSecret({
|
||||||
@@ -487,12 +555,20 @@ export const updateSecretByName = async (req: Request, res: Response) => {
|
|||||||
params: { secretName }
|
params: { secretName }
|
||||||
} = await validateRequest(reqValidator.UpdateSecretByNameV3, req);
|
} = await validateRequest(reqValidator.UpdateSecretByNameV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.updateSecret({
|
const secret = await SecretService.updateSecret({
|
||||||
@@ -531,12 +607,20 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
|
|||||||
params: { secretName }
|
params: { secretName }
|
||||||
} = await validateRequest(reqValidator.DeleteSecretByNameV3, req);
|
} = await validateRequest(reqValidator.DeleteSecretByNameV3, req);
|
||||||
|
|
||||||
if (req.user._id) {
|
if (req.user?._id) {
|
||||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
ProjectPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
await validateServiceTokenDataClientForWorkspace({
|
||||||
|
serviceTokenData: req.authData.authPayload as IServiceTokenData,
|
||||||
|
workspaceId: new Types.ObjectId(workspaceId),
|
||||||
|
environment,
|
||||||
|
secretPath,
|
||||||
|
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { secret } = await SecretService.deleteSecret({
|
const { secret } = await SecretService.deleteSecret({
|
||||||
|
|||||||
@@ -504,11 +504,6 @@ export const getSecretsHelper = async ({
|
|||||||
}: GetSecretsParams) => {
|
}: GetSecretsParams) => {
|
||||||
let secrets: ISecret[] = [];
|
let secrets: ISecret[] = [];
|
||||||
// if using service token filter towards the folderId by secretpath
|
// if using service token filter towards the folderId by secretpath
|
||||||
if (authData.authPayload instanceof ServiceTokenData) {
|
|
||||||
if (!isValidScope(authData.authPayload, environment, secretPath)) {
|
|
||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!folderId) {
|
if (!folderId) {
|
||||||
folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||||
@@ -575,11 +570,11 @@ export const getSecretsHelper = async ({
|
|||||||
const postHogClient = await TelemetryService.getPostHogClient();
|
const postHogClient = await TelemetryService.getPostHogClient();
|
||||||
|
|
||||||
// reduce the number of events captured
|
// reduce the number of events captured
|
||||||
let shouldRecordK8Event = false
|
let shouldRecordK8Event = false;
|
||||||
if (authData.userAgent == K8_USER_AGENT_NAME) {
|
if (authData.userAgent == K8_USER_AGENT_NAME) {
|
||||||
const randomNumber = Math.random();
|
const randomNumber = Math.random();
|
||||||
if (randomNumber > 0.9) {
|
if (randomNumber > 0.9) {
|
||||||
shouldRecordK8Event = true
|
shouldRecordK8Event = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,7 +583,7 @@ export const getSecretsHelper = async ({
|
|||||||
|
|
||||||
if (postHogClient && atLeastOneNonSignUpSecret) {
|
if (postHogClient && atLeastOneNonSignUpSecret) {
|
||||||
const shouldCapture = authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
|
const shouldCapture = authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
|
||||||
const approximateForNoneCapturedEvents = secrets.length * 10
|
const approximateForNoneCapturedEvents = secrets.length * 10;
|
||||||
|
|
||||||
if (shouldCapture) {
|
if (shouldCapture) {
|
||||||
postHogClient.capture({
|
postHogClient.capture({
|
||||||
@@ -633,11 +628,7 @@ export const getSecretHelper = async ({
|
|||||||
});
|
});
|
||||||
let secret: ISecret | null = null;
|
let secret: ISecret | null = null;
|
||||||
// if using service token filter towards the folderId by secretpath
|
// if using service token filter towards the folderId by secretpath
|
||||||
if (authData.authPayload instanceof ServiceTokenData) {
|
|
||||||
if (!isValidScope(authData.authPayload, environment, secretPath)) {
|
|
||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||||
|
|
||||||
// try getting personal secret first (if exists)
|
// try getting personal secret first (if exists)
|
||||||
@@ -751,12 +742,6 @@ export const updateSecretHelper = async ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let secret: ISecret | null = null;
|
let secret: ISecret | null = null;
|
||||||
// if using service token filter towards the folderId by secretpath
|
|
||||||
if (authData.authPayload instanceof ServiceTokenData) {
|
|
||||||
if (!isValidScope(authData.authPayload, environment, secretPath)) {
|
|
||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||||
|
|
||||||
if (type === SECRET_SHARED) {
|
if (type === SECRET_SHARED) {
|
||||||
@@ -916,12 +901,6 @@ export const deleteSecretHelper = async ({
|
|||||||
workspaceId: new Types.ObjectId(workspaceId)
|
workspaceId: new Types.ObjectId(workspaceId)
|
||||||
});
|
});
|
||||||
|
|
||||||
// if using service token filter towards the folderId by secretpath
|
|
||||||
if (authData.authPayload instanceof ServiceTokenData) {
|
|
||||||
if (!isValidScope(authData.authPayload, environment, secretPath)) {
|
|
||||||
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
|
||||||
|
|
||||||
let secrets: ISecret[] = [];
|
let secrets: ISecret[] = [];
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ router.post(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body"
|
|
||||||
}),
|
|
||||||
secretsController.batchSecrets
|
secretsController.batchSecrets
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
import {
|
import {
|
||||||
requireAuth,
|
requireAuth,
|
||||||
requireBlindIndicesEnabled,
|
requireBlindIndicesEnabled,
|
||||||
requireE2EEOff,
|
requireE2EEOff
|
||||||
requireWorkspaceAuth,
|
|
||||||
validateRequest
|
|
||||||
} from "../../middleware";
|
} from "../../middleware";
|
||||||
import { body, param, query } from "express-validator";
|
|
||||||
import { secretsController } from "../../controllers/v3";
|
import { secretsController } from "../../controllers/v3";
|
||||||
import {
|
import {
|
||||||
ADMIN,
|
AuthMode
|
||||||
AuthMode,
|
|
||||||
MEMBER,
|
|
||||||
PERMISSION_READ_SECRETS,
|
|
||||||
PERMISSION_WRITE_SECRETS,
|
|
||||||
SECRET_PERSONAL,
|
|
||||||
SECRET_SHARED
|
|
||||||
} from "../../variables";
|
} from "../../variables";
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
@@ -32,12 +23,6 @@ router.get(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "query",
|
|
||||||
locationEnvironment: "query",
|
|
||||||
requiredPermissions: [PERMISSION_READ_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "query"
|
locationWorkspaceId: "query"
|
||||||
}),
|
}),
|
||||||
@@ -52,12 +37,6 @@ router.post(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
@@ -72,12 +51,6 @@ router.patch(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
@@ -92,12 +65,6 @@ router.delete(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
@@ -109,20 +76,9 @@ router.delete(
|
|||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
query("workspaceId").exists().isString().trim(),
|
|
||||||
query("environment").exists().isString().trim(),
|
|
||||||
query("folderId").optional().isString().trim(),
|
|
||||||
query("secretPath").default("/").isString().trim(),
|
|
||||||
validateRequest,
|
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "query",
|
|
||||||
locationEnvironment: "query",
|
|
||||||
requiredPermissions: [PERMISSION_READ_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "query"
|
locationWorkspaceId: "query"
|
||||||
}),
|
}),
|
||||||
@@ -134,12 +90,6 @@ router.post(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
@@ -151,12 +101,6 @@ router.get(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "query",
|
|
||||||
locationEnvironment: "query",
|
|
||||||
requiredPermissions: [PERMISSION_READ_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "query"
|
locationWorkspaceId: "query"
|
||||||
}),
|
}),
|
||||||
@@ -168,12 +112,6 @@ router.patch(
|
|||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
@@ -182,21 +120,9 @@ router.patch(
|
|||||||
|
|
||||||
router.delete(
|
router.delete(
|
||||||
"/:secretName",
|
"/:secretName",
|
||||||
param("secretName").exists().isString().trim(),
|
|
||||||
body("workspaceId").exists().isString().trim(),
|
|
||||||
body("environment").exists().isString().trim(),
|
|
||||||
body("secretPath").default("/").isString().trim(),
|
|
||||||
body("type").exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
|
|
||||||
validateRequest,
|
|
||||||
requireAuth({
|
requireAuth({
|
||||||
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
|
||||||
}),
|
}),
|
||||||
requireWorkspaceAuth({
|
|
||||||
acceptedRoles: [ADMIN, MEMBER],
|
|
||||||
locationWorkspaceId: "body",
|
|
||||||
locationEnvironment: "body",
|
|
||||||
requiredPermissions: [PERMISSION_WRITE_SECRETS]
|
|
||||||
}),
|
|
||||||
requireBlindIndicesEnabled({
|
requireBlindIndicesEnabled({
|
||||||
locationWorkspaceId: "body"
|
locationWorkspaceId: "body"
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { validateUserClientForWorkspace } from "./user";
|
|||||||
import { ActorType } from "../ee/models";
|
import { ActorType } from "../ee/models";
|
||||||
import { AuthData } from "../interfaces/middleware";
|
import { AuthData } from "../interfaces/middleware";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { isValidScope } from "../helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate authenticated clients for service token with id [serviceTokenId] based
|
* Validate authenticated clients for service token with id [serviceTokenId] based
|
||||||
@@ -62,11 +63,13 @@ export const validateServiceTokenDataClientForWorkspace = async ({
|
|||||||
serviceTokenData,
|
serviceTokenData,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
|
secretPath = "/",
|
||||||
requiredPermissions
|
requiredPermissions
|
||||||
}: {
|
}: {
|
||||||
serviceTokenData: IServiceTokenData;
|
serviceTokenData: IServiceTokenData;
|
||||||
workspaceId: Types.ObjectId;
|
workspaceId: Types.ObjectId;
|
||||||
environment?: string;
|
environment?: string;
|
||||||
|
secretPath?: string;
|
||||||
requiredPermissions?: string[];
|
requiredPermissions?: string[];
|
||||||
}) => {
|
}) => {
|
||||||
if (!serviceTokenData.workspace.equals(workspaceId)) {
|
if (!serviceTokenData.workspace.equals(workspaceId)) {
|
||||||
@@ -78,7 +81,6 @@ export const validateServiceTokenDataClientForWorkspace = async ({
|
|||||||
|
|
||||||
if (environment) {
|
if (environment) {
|
||||||
// case: environment is specified
|
// case: environment is specified
|
||||||
|
|
||||||
if (!serviceTokenData.scopes.find(({ environment: tkEnv }) => tkEnv === environment)) {
|
if (!serviceTokenData.scopes.find(({ environment: tkEnv }) => tkEnv === environment)) {
|
||||||
// case: invalid environment passed
|
// case: invalid environment passed
|
||||||
throw UnauthorizedRequestError({
|
throw UnauthorizedRequestError({
|
||||||
@@ -86,6 +88,10 @@ export const validateServiceTokenDataClientForWorkspace = async ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isValidScope(serviceTokenData, environment, secretPath)) {
|
||||||
|
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
|
||||||
|
}
|
||||||
|
|
||||||
requiredPermissions?.forEach((permission) => {
|
requiredPermissions?.forEach((permission) => {
|
||||||
if (!serviceTokenData.permissions.includes(permission)) {
|
if (!serviceTokenData.permissions.includes(permission)) {
|
||||||
throw UnauthorizedRequestError({
|
throw UnauthorizedRequestError({
|
||||||
|
|||||||
Reference in New Issue
Block a user