mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Finish preliminary v3/secrets/raw endpoints
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user