Finish preliminary v3/secrets/raw endpoints

This commit is contained in:
Tuan Dang
2023-06-11 12:11:25 +01:00
parent facabc683b
commit 631eac803e
6 changed files with 475 additions and 217 deletions
+245 -63
View File
@@ -2,6 +2,240 @@ import { Request, Response } from "express";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { SecretService, EventService } from "../../services"; import { SecretService, EventService } from "../../services";
import { eventPushSecrets } from "../../events"; import { eventPushSecrets } from "../../events";
import { BotService } from "../../services";
import { repackageSecretToRaw } from "../../helpers/secrets";
import { encryptSymmetric128BitHexKeyUTF8 } from "../../utils/crypto";
/**
* Return secrets for workspace with id [workspaceId] and environment
* [environment] in plaintext
* @param req
* @param res
*/
export const getSecretsRaw = async (req: Request, res: Response) => {
const workspaceId = req.query.workspaceId as string;
const environment = req.query.environment as string;
const secretPath = req.query.secretPath as string;
const secrets = await SecretService.getSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
authData: req.authData,
});
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId: new Types.ObjectId(workspaceId)
});
return res.status(200).send({
secrets: secrets.map((secret) => {
const rep = repackageSecretToRaw({
secret,
key
});
return rep;
})
});
};
/**
* Return secret with name [secretName] in plaintext
* @param req
* @param res
*/
export const getSecretByNameRaw = async (req: Request, res: Response) => {
const { secretName } = req.params;
const workspaceId = req.query.workspaceId as string;
const environment = req.query.environment as string;
const secretPath = req.query.secretPath as string;
const type = req.query.type as "shared" | "personal" | undefined;
const secret = await SecretService.getSecret({
secretName,
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
secretPath,
authData: req.authData,
});
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId: new Types.ObjectId(workspaceId)
});
return res.status(200).send({
secret: repackageSecretToRaw({
secret,
key
})
});
};
/**
* Create secret with name [secretName] in plaintext
* @param req
* @param res
*/
export const createSecretRaw = async (req: Request, res: Response) => {
const { secretName } = req.params;
const {
workspaceId,
environment,
type,
secretValue,
secretComment,
secretPath = "/"
} = req.body;
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId: new Types.ObjectId(workspaceId)
});
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretName,
key
});
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretValue,
key
});
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretComment,
key
});
const secret = await SecretService.createSecret({
secretName,
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
authData: req.authData,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretPath,
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag
});
await EventService.handleEvent({
event: eventPushSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment,
}),
});
const secretWithoutBlindIndex = secret.toObject();
delete secretWithoutBlindIndex.secretBlindIndex;
return res.status(200).send({
secret: repackageSecretToRaw({
secret: secretWithoutBlindIndex,
key
})
});
}
/**
* Update secret with name [secretName]
* @param req
* @param res
*/
export const updateSecretByNameRaw = async (req: Request, res: Response) => {
const { secretName } = req.params;
const {
workspaceId,
environment,
type,
secretValue,
secretPath = "/",
} = req.body;
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId: new Types.ObjectId(workspaceId)
});
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretValue,
key
});
const secret = await SecretService.updateSecret({
secretName,
workspaceId,
environment,
type,
authData: req.authData,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretPath,
});
await EventService.handleEvent({
event: eventPushSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment,
}),
});
return res.status(200).send({
secret: repackageSecretToRaw({
secret,
key
})
});
};
/**
* Delete secret with name [secretName]
* @param req
* @param res
*/
export const deleteSecretByNameRaw = async (req: Request, res: Response) => {
const { secretName } = req.params;
const {
workspaceId,
environment,
type,
secretPath = "/"
} = req.body;
const { secret } = await SecretService.deleteSecret({
secretName,
workspaceId,
environment,
type,
authData: req.authData,
secretPath,
});
await EventService.handleEvent({
event: eventPushSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment,
}),
});
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId: new Types.ObjectId(workspaceId)
});
return res.status(200).send({
secret: repackageSecretToRaw({
secret,
key
})
});
};
/** /**
* Get secrets for workspace with id [workspaceId] and environment * Get secrets for workspace with id [workspaceId] and environment
@@ -27,7 +261,7 @@ export const getSecrets = async (req: Request, res: Response) => {
}; };
/** /**
* Get secret with name [secretName] * Return secret with name [secretName]
* @param req * @param req
* @param res * @param res
*/ */
@@ -58,59 +292,6 @@ export const getSecretByName = async (req: Request, res: Response) => {
* @param res * @param res
*/ */
export const createSecret = async (req: Request, res: Response) => { export const createSecret = async (req: Request, res: Response) => {
<<<<<<< HEAD
const { secretName } = req.params;
const {
workspaceId,
environment,
type,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValue,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretComment,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
} = req.body;
const secret = await SecretService.createSecret({
secretName,
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
authData: req.authData,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValue,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretComment,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
});
await EventService.handleEvent({
event: eventPushSecrets({
workspaceId: new Types.ObjectId(workspaceId),
environment
})
});
const secretWithoutBlindIndex = secret.toObject();
delete secretWithoutBlindIndex.secretBlindIndex;
return res.status(200).send({
secret: secretWithoutBlindIndex
});
}
=======
const { secretName } = req.params; const { secretName } = req.params;
const { const {
workspaceId, workspaceId,
@@ -141,13 +322,9 @@ export const createSecret = async (req: Request, res: Response) => {
secretValueIV, secretValueIV,
secretValueTag, secretValueTag,
secretPath, secretPath,
...(secretCommentCiphertext && secretCommentIV && secretCommentTag secretCommentCiphertext,
? { secretCommentIV,
secretCommentCiphertext, secretCommentTag
secretCommentIV,
secretCommentTag,
}
: {}),
}); });
await EventService.handleEvent({ await EventService.handleEvent({
@@ -164,7 +341,7 @@ export const createSecret = async (req: Request, res: Response) => {
secret: secretWithoutBlindIndex, secret: secretWithoutBlindIndex,
}); });
}; };
>>>>>>> origin
/** /**
* Update secret with name [secretName] * Update secret with name [secretName]
@@ -214,7 +391,12 @@ export const updateSecretByName = async (req: Request, res: Response) => {
*/ */
export const deleteSecretByName = async (req: Request, res: Response) => { export const deleteSecretByName = async (req: Request, res: Response) => {
const { secretName } = req.params; const { secretName } = req.params;
const { workspaceId, environment, type, secretPath = "/" } = req.body; const {
workspaceId,
environment,
type,
secretPath = "/"
} = req.body;
const { secret } = await SecretService.deleteSecret({ const { secret } = await SecretService.deleteSecret({
secretName, secretName,
+66 -143
View File
@@ -37,7 +37,7 @@ import {
encryptSymmetric128BitHexKeyUTF8, encryptSymmetric128BitHexKeyUTF8,
decryptSymmetric128BitHexKeyUTF8, decryptSymmetric128BitHexKeyUTF8,
} from '../utils/crypto'; } from '../utils/crypto';
import { BotService, TelemetryService } from '../services'; import { TelemetryService } from '../services';
import { getEncryptionKey, client, getRootEncryptionKey } from "../config"; import { getEncryptionKey, client, getRootEncryptionKey } from "../config";
import { EESecretService, EELogService } from "../ee/services"; import { EESecretService, EELogService } from "../ee/services";
import { import {
@@ -46,6 +46,60 @@ import {
} from "../utils/auth"; } from "../utils/auth";
import { getFolderIdFromServiceToken } from "../services/FolderService"; import { getFolderIdFromServiceToken } from "../services/FolderService";
/**
* Returns an object containing secret [secret] but with its value, key, comment decrypted.
*
* Precondition: the workspace for secret [secret] must have E2EE disabled
* @param {ISecret} secret - secret to repackage to raw
* @param {String} key - symmetric key to use to decrypt secret
* @returns
*/
export const repackageSecretToRaw = ({
secret,
key
}:{
secret: ISecret;
key: string;
}) => {
const secretKey = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key
});
const secretValue = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key
});
let secretComment: string = '';
if (secret.secretCommentCiphertext && secret.secretCommentIV && secret.secretCommentTag) {
secretComment = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretCommentCiphertext,
iv: secret.secretCommentIV,
tag: secret.secretCommentTag,
key
});
}
return ({
_id: secret._id,
version: secret.version,
workspace: secret.workspace,
type: secret.type,
environment: secret.environment,
user: secret.user,
secretKey,
secretValue,
secretComment
});
}
/** /**
* Create secret blind index data containing encrypted blind index [salt] * Create secret blind index data containing encrypted blind index [salt]
* for workspace with id [workspaceId] * for workspace with id [workspaceId]
@@ -244,23 +298,6 @@ export const generateSecretBlindIndexHelper = async ({
}); });
}; };
// secretName,
// workspaceId,
// environment,
// type,
// authData,
// secretKeyCiphertext,
// secretKeyIV,
// secretKeyTag,
// secretValue,
// secretValueCiphertext,
// secretValueIV,
// secretValueTag,
// secretCommentCiphertext,
// secretCommentIV,
// secretCommentTag,
// folderId,
/** /**
* Create secret with name [secretName] * Create secret with name [secretName]
* @param {Object} obj * @param {Object} obj
@@ -280,11 +317,9 @@ export const createSecretHelper = async ({
secretKeyCiphertext, secretKeyCiphertext,
secretKeyIV, secretKeyIV,
secretKeyTag, secretKeyTag,
secretValue,
secretValueCiphertext, secretValueCiphertext,
secretValueIV, secretValueIV,
secretValueTag, secretValueTag,
secretComment,
secretCommentCiphertext, secretCommentCiphertext,
secretCommentIV, secretCommentIV,
secretCommentTag, secretCommentTag,
@@ -340,52 +375,6 @@ export const createSecretHelper = async ({
}); });
} }
// can generate secretKeyCiphertext etc. if not E2EE.
const isWorkspaceE2EE = await BotService.getIsWorkspaceE2EE(workspaceId);
if (!isWorkspaceE2EE) {
// if workspace is not end-to-end encrypted, then decrypt
// secret and return it in plaintext
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId
});
if (secretName) {
const encryptedSecretKey = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretName,
key
});
secretKeyCiphertext = encryptedSecretKey.ciphertext;
secretKeyIV = encryptedSecretKey.iv;
secretKeyTag = encryptedSecretKey.tag;
}
if (secretValue) {
const encryptedSecretValue = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretValue,
key
});
secretValueCiphertext = encryptedSecretValue.ciphertext;
secretValueIV = encryptedSecretValue.iv;
secretValueTag = encryptedSecretValue.tag;
}
if (secretComment) {
const encryptedSecretComment = encryptSymmetric128BitHexKeyUTF8({
plaintext: secretComment,
key
});
secretCommentCiphertext = encryptedSecretComment.ciphertext;
secretCommentIV = encryptedSecretComment.iv;
secretCommentTag = encryptedSecretComment.tag;
}
}
// create secret // create secret
const secret = await new Secret({ const secret = await new Secret({
version: 1, version: 1,
@@ -565,44 +554,7 @@ export const getSecretsHelper = async ({
}); });
} }
const isWorkspaceE2EE = await BotService.getIsWorkspaceE2EE(workspaceId); return secrets;
if (!isWorkspaceE2EE) {
// if workspace is not end-to-end encrypted, then decrypt
// secret and return it in plaintext
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId
});
return secrets.map((secret) => {
const secretName = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretKeyCiphertext,
iv: secret.secretKeyIV,
tag: secret.secretKeyTag,
key
});
const secretValue = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key
});
return ({
...secret,
secretName,
secretValue
});
});
}
return secrets.map((secret) => ({
...secret,
secretName: null,
secretValue: null
}));
}; };
/** /**
@@ -701,35 +653,7 @@ export const getSecretHelper = async ({
}); });
} }
const isWorkspaceE2EE = await BotService.getIsWorkspaceE2EE(workspaceId); return secret;
if (!isWorkspaceE2EE) {
// if workspace is not end-to-end encrypted, then decrypt
// secret and return it in plaintext
const key = await BotService.getWorkspaceKeyWithBot({
workspaceId
});
const secretValue = decryptSymmetric128BitHexKeyUTF8({
ciphertext: secret.secretValueCiphertext,
iv: secret.secretValueIV,
tag: secret.secretValueTag,
key
});
return ({
...secret,
secretName,
secretValue
});
}
return ({
...secret,
secretName: null,
secretValue: null
});
}; };
/** /**
@@ -919,6 +843,7 @@ export const deleteSecretHelper = async ({
// 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 (authData.authPayload instanceof ServiceTokenData) {
const { secretPath: serviceTkScopedSecretPath } = authData.authPayload; const { secretPath: serviceTkScopedSecretPath } = authData.authPayload;
if (secretPath !== serviceTkScopedSecretPath) { if (secretPath !== serviceTkScopedSecretPath) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
@@ -938,7 +863,7 @@ export const deleteSecretHelper = async ({
workspaceId: new Types.ObjectId(workspaceId), workspaceId: new Types.ObjectId(workspaceId),
environment, environment,
folder: folderId, folder: folderId,
}); }).lean();
secret = await Secret.findOneAndDelete({ secret = await Secret.findOneAndDelete({
secretBlindIndex, secretBlindIndex,
@@ -946,7 +871,7 @@ export const deleteSecretHelper = async ({
environment, environment,
type, type,
folder: folderId, folder: folderId,
}); }).lean();
await Secret.deleteMany({ await Secret.deleteMany({
secretBlindIndex, secretBlindIndex,
@@ -962,7 +887,7 @@ export const deleteSecretHelper = async ({
environment, environment,
type, type,
...getAuthDataPayloadUserObj(authData), ...getAuthDataPayloadUserObj(authData),
}); }).lean();
if (secret) { if (secret) {
secrets = [secret]; secrets = [secret];
@@ -983,9 +908,7 @@ export const deleteSecretHelper = async ({
secretIds: secrets.map((secret) => secret._id), secretIds: secrets.map((secret) => secret._id),
}); });
// (EE) take a secret snapshot action && (await EELogService.createLog({
action &&
(await EELogService.createLog({
...getAuthDataPayloadIdObj(authData), ...getAuthDataPayloadIdObj(authData),
workspaceId, workspaceId,
actions: [action], actions: [action],
@@ -1018,9 +941,9 @@ export const deleteSecretHelper = async ({
}, },
}); });
} }
return { return ({
secrets, secrets,
secret, secret
}; });
}; };
@@ -7,14 +7,12 @@ export interface CreateSecretParams {
environment: string; environment: string;
type: "shared" | "personal"; type: "shared" | "personal";
authData: AuthData; authData: AuthData;
secretKeyCiphertext?: string; secretKeyCiphertext: string;
secretKeyIV?: string; secretKeyIV: string;
secretKeyTag?: string; secretKeyTag: string;
secretValue?: string; secretValueCiphertext: string;
secretValueCiphertext?: string; secretValueIV: string;
secretValueIV?: string; secretValueTag: string;
secretValueTag?: string;
secretComment?: string;
secretCommentCiphertext?: string; secretCommentCiphertext?: string;
secretCommentIV?: string; secretCommentIV?: string;
secretCommentTag?: string; secretCommentTag?: string;
@@ -16,13 +16,15 @@ const requireWorkspaceAuth = ({
locationWorkspaceId, locationWorkspaceId,
locationEnvironment = undefined, locationEnvironment = undefined,
requiredPermissions = [], requiredPermissions = [],
requireBlindIndicesEnabled = false requireBlindIndicesEnabled = false,
requireE2EEOff = true
}: { }: {
acceptedRoles: Array<'admin' | 'member'>; acceptedRoles: Array<'admin' | 'member'>;
locationWorkspaceId: req; locationWorkspaceId: req;
locationEnvironment?: req | undefined; locationEnvironment?: req | undefined;
requiredPermissions?: string[]; requiredPermissions?: string[];
requireBlindIndicesEnabled?: boolean; requireBlindIndicesEnabled?: boolean;
requireE2EEOff?: boolean;
}) => { }) => {
return async (req: Request, res: Response, next: NextFunction) => { return async (req: Request, res: Response, next: NextFunction) => {
const workspaceId = req[locationWorkspaceId]?.workspaceId; const workspaceId = req[locationWorkspaceId]?.workspaceId;
@@ -35,7 +37,8 @@ const requireWorkspaceAuth = ({
environment, environment,
acceptedRoles, acceptedRoles,
requiredPermissions, requiredPermissions,
requireBlindIndicesEnabled requireBlindIndicesEnabled,
requireE2EEOff
}); });
if (membership) { if (membership) {
+140
View File
@@ -20,6 +20,142 @@ import {
PERMISSION_READ_SECRETS, PERMISSION_READ_SECRETS,
} from "../../variables"; } from "../../variables";
router.get(
"/raw",
query("workspaceId").exists().isString().trim(),
query("workspaceId").exists().isString().trim(),
query("environment").exists().isString().trim(),
query("secretPath").default("/").isString().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "query",
locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS],
requireBlindIndicesEnabled: true,
requireE2EEOff: true
}),
secretsController.getSecretsRaw
);
router.get(
"/raw/:secretName",
param("secretName").exists().isString().trim(),
query("workspaceId").exists().isString().trim(),
query("environment").exists().isString().trim(),
query("secretPath").default("/").isString().trim(),
query("type").optional().isIn([SECRET_SHARED, SECRET_PERSONAL]),
validateRequest,
requireAuth({
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "query",
locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS],
requireBlindIndicesEnabled: true,
requireE2EEOff: true
}),
secretsController.getSecretByNameRaw
);
router.post(
"/raw/:secretName",
body("workspaceId").exists().isString().trim(),
body("environment").exists().isString().trim(),
body("type").exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
body("secretValue").exists().isString().trim(),
body("secretComment").default("").isString().trim(),
body("secretPath").default("/").isString().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true,
requireE2EEOff: true
}),
secretsController.createSecretRaw
);
router.patch(
"/raw/:secretName",
param("secretName").exists().isString().trim(),
body("workspaceId").exists().isString().trim(),
body("environment").exists().isString().trim(),
body("type").exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
body("secretValue").exists().isString().trim(),
body("secretPath").default("/").isString().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true,
requireE2EEOff: true
}),
secretsController.updateSecretByNameRaw
);
router.delete(
"/raw/: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({
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true,
requireE2EEOff: true
}),
secretsController.deleteSecretByNameRaw
);
router.get( router.get(
"/", "/",
query("workspaceId").exists().isString().trim(), query("workspaceId").exists().isString().trim(),
@@ -40,6 +176,7 @@ router.get(
locationEnvironment: "query", locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS], requiredPermissions: [PERMISSION_READ_SECRETS],
requireBlindIndicesEnabled: true, requireBlindIndicesEnabled: true,
requireE2EEOff: false
}), }),
secretsController.getSecrets secretsController.getSecrets
); );
@@ -74,6 +211,7 @@ router.post(
locationEnvironment: "body", locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS], requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true, requireBlindIndicesEnabled: true,
requireE2EEOff: false
}), }),
secretsController.createSecret secretsController.createSecret
); );
@@ -129,6 +267,7 @@ router.patch(
locationEnvironment: "body", locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS], requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true, requireBlindIndicesEnabled: true,
requireE2EEOff: false
}), }),
secretsController.updateSecretByName secretsController.updateSecretByName
); );
@@ -155,6 +294,7 @@ router.delete(
locationEnvironment: "body", locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS], requiredPermissions: [PERMISSION_WRITE_SECRETS],
requireBlindIndicesEnabled: true, requireBlindIndicesEnabled: true,
requireE2EEOff: false
}), }),
secretsController.deleteSecretByName secretsController.deleteSecretByName
); );
+13 -1
View File
@@ -13,6 +13,7 @@ import { validateServiceAccountClientForWorkspace } from './serviceAccount';
import { validateUserClientForWorkspace } from './user'; import { validateUserClientForWorkspace } from './user';
import { validateServiceTokenDataClientForWorkspace } from './serviceTokenData'; import { validateServiceTokenDataClientForWorkspace } from './serviceTokenData';
import { import {
BadRequestError,
UnauthorizedRequestError, UnauthorizedRequestError,
WorkspaceNotFoundError WorkspaceNotFoundError
} from '../utils/errors'; } from '../utils/errors';
@@ -22,6 +23,7 @@ import {
AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_API_KEY AUTH_MODE_API_KEY
} from '../variables'; } from '../variables';
import { BotService } from '../services';
/** /**
* Validate authenticated clients for workspace with id [workspaceId] based * Validate authenticated clients for workspace with id [workspaceId] based
@@ -39,7 +41,8 @@ export const validateClientForWorkspace = async ({
environment, environment,
acceptedRoles, acceptedRoles,
requiredPermissions, requiredPermissions,
requireBlindIndicesEnabled requireBlindIndicesEnabled,
requireE2EEOff
}: { }: {
authData: { authData: {
authMode: string; authMode: string;
@@ -50,6 +53,7 @@ export const validateClientForWorkspace = async ({
acceptedRoles: Array<'admin' | 'member'>; acceptedRoles: Array<'admin' | 'member'>;
requiredPermissions?: string[]; requiredPermissions?: string[];
requireBlindIndicesEnabled: boolean; requireBlindIndicesEnabled: boolean;
requireE2EEOff: boolean;
}) => { }) => {
const workspace = await Workspace.findById(workspaceId); const workspace = await Workspace.findById(workspaceId);
@@ -70,6 +74,14 @@ export const validateClientForWorkspace = async ({
message: 'Failed workspace authorization due to blind indices not being enabled' message: 'Failed workspace authorization due to blind indices not being enabled'
}); });
} }
if (requireE2EEOff) {
const isWorkspaceE2EE = await BotService.getIsWorkspaceE2EE(workspaceId);
if (isWorkspaceE2EE) throw BadRequestError({
message: 'Failed workspace authorization due to end-to-end encryption not being disabled'
});
}
if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) { if (authData.authMode === AUTH_MODE_JWT && authData.authPayload instanceof User) {
const membership = await validateUserClientForWorkspace({ const membership = await validateUserClientForWorkspace({