mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Add non-e2ee option for getSecret, getSecrets, start createSecret
This commit is contained in:
@@ -6,8 +6,6 @@ import {
|
||||
EventService
|
||||
} from '../../services';
|
||||
import { eventPushSecrets } from '../../events';
|
||||
import { getAuthDataPayloadIdObj } from '../../utils/auth';
|
||||
import { BadRequestError } from '../../utils/errors';
|
||||
|
||||
/**
|
||||
* Get secrets for workspace with id [workspaceId] and environment
|
||||
@@ -68,9 +66,11 @@ export const createSecret = async (req: Request, res: Response) => {
|
||||
secretKeyCiphertext,
|
||||
secretKeyIV,
|
||||
secretKeyTag,
|
||||
secretValue,
|
||||
secretValueCiphertext,
|
||||
secretValueIV,
|
||||
secretValueTag,
|
||||
secretComment,
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag
|
||||
@@ -85,14 +85,14 @@ export const createSecret = async (req: Request, res: Response) => {
|
||||
secretKeyCiphertext,
|
||||
secretKeyIV,
|
||||
secretKeyTag,
|
||||
secretValue,
|
||||
secretValueCiphertext,
|
||||
secretValueIV,
|
||||
secretValueTag,
|
||||
...((secretCommentCiphertext && secretCommentIV && secretCommentTag) ? {
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag
|
||||
} : {})
|
||||
secretComment,
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag
|
||||
});
|
||||
|
||||
await EventService.handleEvent({
|
||||
|
||||
@@ -86,6 +86,18 @@ export const createBot = async ({
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return whether or not workspace with id [workspaceId] is end-to-end encrypted
|
||||
* @param {Types.ObjectId} workspaceId - id of workspace to check
|
||||
*/
|
||||
export const getIsWorkspaceE2EEHelper = async (workspaceId: Types.ObjectId) => {
|
||||
const botKey = await BotKey.exists({
|
||||
workspace: workspaceId
|
||||
});
|
||||
|
||||
return botKey ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return decrypted secrets for workspace with id [workspaceId]
|
||||
* and [environment] using bot
|
||||
@@ -101,7 +113,7 @@ export const getSecretsBotHelper = async ({
|
||||
environment: string;
|
||||
}) => {
|
||||
const content = {} as any;
|
||||
const key = await getKey({ workspaceId: workspaceId.toString() });
|
||||
const key = await getKey({ workspaceId: workspaceId });
|
||||
const secrets = await Secret.find({
|
||||
workspace: workspaceId,
|
||||
environment,
|
||||
@@ -136,7 +148,7 @@ export const getSecretsBotHelper = async ({
|
||||
* @param {String} obj.workspaceId - id of workspace
|
||||
* @returns {String} key - decrypted workspace key
|
||||
*/
|
||||
export const getKey = async ({ workspaceId }: { workspaceId: string }) => {
|
||||
export const getKey = async ({ workspaceId }: { workspaceId: Types.ObjectId }) => {
|
||||
const encryptionKey = await getEncryptionKey();
|
||||
const rootEncryptionKey = await getRootEncryptionKey();
|
||||
|
||||
@@ -201,7 +213,7 @@ export const encryptSymmetricHelper = async ({
|
||||
workspaceId: Types.ObjectId;
|
||||
plaintext: string;
|
||||
}) => {
|
||||
const key = await getKey({ workspaceId: workspaceId.toString() });
|
||||
const key = await getKey({ workspaceId: workspaceId });
|
||||
const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8({
|
||||
plaintext,
|
||||
key,
|
||||
@@ -233,7 +245,7 @@ export const decryptSymmetricHelper = async ({
|
||||
iv: string;
|
||||
tag: string;
|
||||
}) => {
|
||||
const key = await getKey({ workspaceId: workspaceId.toString() });
|
||||
const key = await getKey({ workspaceId: workspaceId });
|
||||
const plaintext = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext,
|
||||
iv,
|
||||
|
||||
@@ -6,7 +6,12 @@ import {
|
||||
UpdateSecretParams,
|
||||
DeleteSecretParams,
|
||||
} from '../interfaces/services/SecretService';
|
||||
import { Secret, ISecret, SecretBlindIndexData } from '../models';
|
||||
import {
|
||||
ISecret,
|
||||
Secret,
|
||||
SecretBlindIndexData,
|
||||
BotKey
|
||||
} from '../models';
|
||||
import { SecretVersion } from '../ee/models';
|
||||
import {
|
||||
BadRequestError,
|
||||
@@ -32,7 +37,7 @@ import {
|
||||
decryptSymmetric128BitHexKeyUTF8,
|
||||
} from '../utils/crypto';
|
||||
import { getEncryptionKey, client, getRootEncryptionKey } from '../config';
|
||||
import { TelemetryService } from '../services';
|
||||
import { BotService, TelemetryService } from '../services';
|
||||
import { EESecretService, EELogService } from '../ee/services';
|
||||
import {
|
||||
getAuthDataPayloadIdObj,
|
||||
@@ -237,6 +242,23 @@ 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
|
||||
@@ -256,14 +278,17 @@ export const createSecretHelper = async ({
|
||||
secretKeyCiphertext,
|
||||
secretKeyIV,
|
||||
secretKeyTag,
|
||||
secretValue,
|
||||
secretValueCiphertext,
|
||||
secretValueIV,
|
||||
secretValueTag,
|
||||
secretComment,
|
||||
secretCommentCiphertext,
|
||||
secretCommentIV,
|
||||
secretCommentTag,
|
||||
folderId,
|
||||
}: CreateSecretParams) => {
|
||||
|
||||
const secretBlindIndex = await generateSecretBlindIndexHelper({
|
||||
secretName,
|
||||
workspaceId: new Types.ObjectId(workspaceId),
|
||||
@@ -298,6 +323,52 @@ 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,
|
||||
@@ -410,7 +481,7 @@ export const getSecretsHelper = async ({
|
||||
environment,
|
||||
type: SECRET_PERSONAL,
|
||||
...getAuthDataPayloadUserObj(authData),
|
||||
});
|
||||
}).lean();
|
||||
|
||||
// concat with shared secrets
|
||||
secrets = secrets.concat(
|
||||
@@ -421,7 +492,7 @@ export const getSecretsHelper = async ({
|
||||
secretBlindIndex: {
|
||||
$nin: secrets.map((secret) => secret.secretBlindIndex),
|
||||
},
|
||||
})
|
||||
}).lean()
|
||||
);
|
||||
|
||||
// (EE) create (audit) log
|
||||
@@ -458,8 +529,45 @@ 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
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -492,7 +600,7 @@ export const getSecretHelper = async ({
|
||||
environment,
|
||||
type: type ?? SECRET_PERSONAL,
|
||||
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {}),
|
||||
});
|
||||
}).lean();
|
||||
|
||||
if (!secret) {
|
||||
// case: failed to find personal secret matching criteria
|
||||
@@ -502,7 +610,7 @@ export const getSecretHelper = async ({
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
environment,
|
||||
type: SECRET_SHARED,
|
||||
});
|
||||
}).lean();
|
||||
}
|
||||
|
||||
if (!secret) throw SecretNotFoundError();
|
||||
@@ -541,8 +649,36 @@ 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
|
||||
|
||||
return secret;
|
||||
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
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
0
backend/src/interfaces/services/BotService/index.ts
Normal file
0
backend/src/interfaces/services/BotService/index.ts
Normal file
@@ -8,12 +8,14 @@ export interface CreateSecretParams {
|
||||
folderId?: string;
|
||||
type: "shared" | "personal";
|
||||
authData: AuthData;
|
||||
secretKeyCiphertext: string;
|
||||
secretKeyIV: string;
|
||||
secretKeyTag: string;
|
||||
secretValueCiphertext: string;
|
||||
secretValueIV: string;
|
||||
secretValueTag: string;
|
||||
secretKeyCiphertext?: string;
|
||||
secretKeyIV?: string;
|
||||
secretKeyTag?: string;
|
||||
secretValue?: string;
|
||||
secretValueCiphertext?: string;
|
||||
secretValueIV?: string;
|
||||
secretValueTag?: string;
|
||||
secretComment?: string;
|
||||
secretCommentCiphertext?: string;
|
||||
secretCommentIV?: string;
|
||||
secretCommentTag?: string;
|
||||
|
||||
@@ -48,12 +48,14 @@ router.post(
|
||||
body('workspaceId').exists().isString().trim(),
|
||||
body('environment').exists().isString().trim(),
|
||||
body('type').exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
|
||||
body('secretKeyCiphertext').exists().isString().trim(),
|
||||
body('secretKeyIV').exists().isString().trim(),
|
||||
body('secretKeyTag').exists().isString().trim(),
|
||||
body('secretValueCiphertext').exists().isString().trim(),
|
||||
body('secretValueIV').exists().isString().trim(),
|
||||
body('secretValueTag').exists().isString().trim(),
|
||||
body('secretKeyCiphertext').optional().isString().trim(),
|
||||
body('secretKeyIV').optional().isString().trim(),
|
||||
body('secretKeyTag').optional().isString().trim(),
|
||||
body('secretValue').optional().isString().trim(),
|
||||
body('secretValueCiphertext').optional().isString().trim(),
|
||||
body('secretValueIV').optional().isString().trim(),
|
||||
body('secretValueTag').optional().isString().trim(),
|
||||
body('secretComment').optional().isString().trim(),
|
||||
body('secretCommentCiphertext').optional().isString().trim(),
|
||||
body('secretCommentIV').optional().isString().trim(),
|
||||
body('secretCommentTag').optional().isString().trim(),
|
||||
|
||||
@@ -2,13 +2,31 @@ import { Types } from 'mongoose';
|
||||
import {
|
||||
getSecretsBotHelper,
|
||||
encryptSymmetricHelper,
|
||||
decryptSymmetricHelper
|
||||
decryptSymmetricHelper,
|
||||
getKey,
|
||||
getIsWorkspaceE2EEHelper
|
||||
} from '../helpers/bot';
|
||||
|
||||
// rename the functions here
|
||||
// refactor the interface situation here
|
||||
|
||||
/**
|
||||
* Class to handle bot actions
|
||||
*/
|
||||
class BotService {
|
||||
static async getIsWorkspaceE2EE(workspaceId: Types.ObjectId) {
|
||||
return await getIsWorkspaceE2EEHelper(workspaceId);
|
||||
}
|
||||
|
||||
static async getWorkspaceKeyWithBot({
|
||||
workspaceId
|
||||
}: {
|
||||
workspaceId: Types.ObjectId;
|
||||
}) {
|
||||
return await getKey({
|
||||
workspaceId
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return decrypted secrets for workspace with id [workspaceId] and
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { Types } from 'mongoose';
|
||||
import {
|
||||
ISecret
|
||||
} from '../models';
|
||||
import {
|
||||
CreateSecretParams,
|
||||
GetSecretsParams,
|
||||
|
||||
Reference in New Issue
Block a user