diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index 63aa2d660..8a9350a36 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -2,6 +2,240 @@ import { Request, Response } from "express"; import { Types } from "mongoose"; import { SecretService, EventService } from "../../services"; 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 @@ -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 res */ @@ -58,59 +292,6 @@ export const getSecretByName = async (req: Request, res: Response) => { * @param res */ 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 { workspaceId, @@ -141,13 +322,9 @@ export const createSecret = async (req: Request, res: Response) => { secretValueIV, secretValueTag, secretPath, - ...(secretCommentCiphertext && secretCommentIV && secretCommentTag - ? { - secretCommentCiphertext, - secretCommentIV, - secretCommentTag, - } - : {}), + secretCommentCiphertext, + secretCommentIV, + secretCommentTag }); await EventService.handleEvent({ @@ -164,7 +341,7 @@ export const createSecret = async (req: Request, res: Response) => { secret: secretWithoutBlindIndex, }); }; ->>>>>>> origin + /** * 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) => { const { secretName } = req.params; - const { workspaceId, environment, type, secretPath = "/" } = req.body; + const { + workspaceId, + environment, + type, + secretPath = "/" + } = req.body; const { secret } = await SecretService.deleteSecret({ secretName, diff --git a/backend/src/helpers/secrets.ts b/backend/src/helpers/secrets.ts index 5f72b8f03..d7cc31cda 100644 --- a/backend/src/helpers/secrets.ts +++ b/backend/src/helpers/secrets.ts @@ -37,7 +37,7 @@ import { encryptSymmetric128BitHexKeyUTF8, decryptSymmetric128BitHexKeyUTF8, } from '../utils/crypto'; -import { BotService, TelemetryService } from '../services'; +import { TelemetryService } from '../services'; import { getEncryptionKey, client, getRootEncryptionKey } from "../config"; import { EESecretService, EELogService } from "../ee/services"; import { @@ -46,6 +46,60 @@ import { } from "../utils/auth"; 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] * 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] * @param {Object} obj @@ -280,11 +317,9 @@ export const createSecretHelper = async ({ secretKeyCiphertext, secretKeyIV, secretKeyTag, - secretValue, secretValueCiphertext, secretValueIV, secretValueTag, - secretComment, secretCommentCiphertext, secretCommentIV, 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 const secret = await new Secret({ version: 1, @@ -565,44 +554,7 @@ export const getSecretsHelper = async ({ }); } - 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 - }); - - 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 - })); + return secrets; }; /** @@ -701,35 +653,7 @@ export const getSecretHelper = async ({ }); } - 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 - }); - - const secretValue = decryptSymmetric128BitHexKeyUTF8({ - ciphertext: secret.secretValueCiphertext, - iv: secret.secretValueIV, - tag: secret.secretValueTag, - key - }); - - return ({ - ...secret, - secretName, - secretValue - }); - } - - return ({ - ...secret, - secretName: null, - secretValue: null - }); + return secret; }; /** @@ -919,6 +843,7 @@ export const deleteSecretHelper = async ({ // if using service token filter towards the folderId by secretpath if (authData.authPayload instanceof ServiceTokenData) { const { secretPath: serviceTkScopedSecretPath } = authData.authPayload; + if (secretPath !== serviceTkScopedSecretPath) { throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); } @@ -938,7 +863,7 @@ export const deleteSecretHelper = async ({ workspaceId: new Types.ObjectId(workspaceId), environment, folder: folderId, - }); + }).lean(); secret = await Secret.findOneAndDelete({ secretBlindIndex, @@ -946,7 +871,7 @@ export const deleteSecretHelper = async ({ environment, type, folder: folderId, - }); + }).lean(); await Secret.deleteMany({ secretBlindIndex, @@ -962,7 +887,7 @@ export const deleteSecretHelper = async ({ environment, type, ...getAuthDataPayloadUserObj(authData), - }); + }).lean(); if (secret) { secrets = [secret]; @@ -983,9 +908,7 @@ export const deleteSecretHelper = async ({ secretIds: secrets.map((secret) => secret._id), }); - // (EE) take a secret snapshot - action && - (await EELogService.createLog({ + action && (await EELogService.createLog({ ...getAuthDataPayloadIdObj(authData), workspaceId, actions: [action], @@ -1018,9 +941,9 @@ export const deleteSecretHelper = async ({ }, }); } - - return { + + return ({ secrets, - secret, - }; + secret + }); }; diff --git a/backend/src/interfaces/services/SecretService/index.ts b/backend/src/interfaces/services/SecretService/index.ts index 9fc26738c..678c67711 100644 --- a/backend/src/interfaces/services/SecretService/index.ts +++ b/backend/src/interfaces/services/SecretService/index.ts @@ -7,14 +7,12 @@ export interface CreateSecretParams { environment: string; type: "shared" | "personal"; authData: AuthData; - secretKeyCiphertext?: string; - secretKeyIV?: string; - secretKeyTag?: string; - secretValue?: string; - secretValueCiphertext?: string; - secretValueIV?: string; - secretValueTag?: string; - secretComment?: string; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; secretCommentCiphertext?: string; secretCommentIV?: string; secretCommentTag?: string; diff --git a/backend/src/middleware/requireWorkspaceAuth.ts b/backend/src/middleware/requireWorkspaceAuth.ts index da517b998..a4d65ffd2 100644 --- a/backend/src/middleware/requireWorkspaceAuth.ts +++ b/backend/src/middleware/requireWorkspaceAuth.ts @@ -16,13 +16,15 @@ const requireWorkspaceAuth = ({ locationWorkspaceId, locationEnvironment = undefined, requiredPermissions = [], - requireBlindIndicesEnabled = false + requireBlindIndicesEnabled = false, + requireE2EEOff = true }: { acceptedRoles: Array<'admin' | 'member'>; locationWorkspaceId: req; locationEnvironment?: req | undefined; requiredPermissions?: string[]; requireBlindIndicesEnabled?: boolean; + requireE2EEOff?: boolean; }) => { return async (req: Request, res: Response, next: NextFunction) => { const workspaceId = req[locationWorkspaceId]?.workspaceId; @@ -35,7 +37,8 @@ const requireWorkspaceAuth = ({ environment, acceptedRoles, requiredPermissions, - requireBlindIndicesEnabled + requireBlindIndicesEnabled, + requireE2EEOff }); if (membership) { diff --git a/backend/src/routes/v3/secrets.ts b/backend/src/routes/v3/secrets.ts index 6a3d7af88..1f3e239be 100644 --- a/backend/src/routes/v3/secrets.ts +++ b/backend/src/routes/v3/secrets.ts @@ -20,6 +20,142 @@ import { PERMISSION_READ_SECRETS, } 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( "/", query("workspaceId").exists().isString().trim(), @@ -40,6 +176,7 @@ router.get( locationEnvironment: "query", requiredPermissions: [PERMISSION_READ_SECRETS], requireBlindIndicesEnabled: true, + requireE2EEOff: false }), secretsController.getSecrets ); @@ -74,6 +211,7 @@ router.post( locationEnvironment: "body", requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, + requireE2EEOff: false }), secretsController.createSecret ); @@ -129,6 +267,7 @@ router.patch( locationEnvironment: "body", requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, + requireE2EEOff: false }), secretsController.updateSecretByName ); @@ -155,6 +294,7 @@ router.delete( locationEnvironment: "body", requiredPermissions: [PERMISSION_WRITE_SECRETS], requireBlindIndicesEnabled: true, + requireE2EEOff: false }), secretsController.deleteSecretByName ); diff --git a/backend/src/validation/workspace.ts b/backend/src/validation/workspace.ts index b7a04634f..28c4a20ea 100644 --- a/backend/src/validation/workspace.ts +++ b/backend/src/validation/workspace.ts @@ -13,6 +13,7 @@ import { validateServiceAccountClientForWorkspace } from './serviceAccount'; import { validateUserClientForWorkspace } from './user'; import { validateServiceTokenDataClientForWorkspace } from './serviceTokenData'; import { + BadRequestError, UnauthorizedRequestError, WorkspaceNotFoundError } from '../utils/errors'; @@ -22,6 +23,7 @@ import { AUTH_MODE_SERVICE_TOKEN, AUTH_MODE_API_KEY } from '../variables'; +import { BotService } from '../services'; /** * Validate authenticated clients for workspace with id [workspaceId] based @@ -39,7 +41,8 @@ export const validateClientForWorkspace = async ({ environment, acceptedRoles, requiredPermissions, - requireBlindIndicesEnabled + requireBlindIndicesEnabled, + requireE2EEOff }: { authData: { authMode: string; @@ -50,6 +53,7 @@ export const validateClientForWorkspace = async ({ acceptedRoles: Array<'admin' | 'member'>; requiredPermissions?: string[]; requireBlindIndicesEnabled: boolean; + requireE2EEOff: boolean; }) => { 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' }); } + + 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) { const membership = await validateUserClientForWorkspace({