Enable all auth clients for secrets v3, remove serviceTokenData .populate in middleware, make secret versions and rollbacks compatible with blind indexing

This commit is contained in:
Tuan Dang
2023-04-19 15:38:13 +03:00
parent acb90ee0f7
commit ad5852fe3a
21 changed files with 313 additions and 133 deletions
@@ -8,6 +8,8 @@ import { BadRequestError, InternalServerError, UnauthorizedRequestError, Validat
import { AnyBulkWriteOperation } from 'mongodb';
import { SECRET_PERSONAL, SECRET_SHARED } from "../../variables";
import { TelemetryService } from '../../services';
import { User } from "../../models";
import { AccountNotFoundError } from '../../utils/errors';
/**
* Create secret for workspace with id [workspaceId] and environment [environment]
@@ -340,15 +342,18 @@ export const getSecrets = async (req: Request, res: Response) => {
const { workspaceId } = req.params;
let userId: Types.ObjectId | undefined = undefined // used for getting personal secrets for user
let userEmail: Types.ObjectId | undefined = undefined // used for posthog
let userEmail: string | undefined = undefined // used for posthog
if (req.user) {
userId = req.user._id;
userEmail = req.user.email;
}
if (req.serviceTokenData) {
userId = req.serviceTokenData.user._id
userEmail = req.serviceTokenData.user.email;
userId = req.serviceTokenData.user;
const user = await User.findById(req.serviceTokenData.user, 'email');
if (!user) throw AccountNotFoundError();
userEmail = user.email;
}
const [err, secrets] = await to(Secret.find(
+46 -26
View File
@@ -374,8 +374,14 @@ export const createSecrets = async (req: Request, res: Response) => {
listOfSecretsToCreate = [req.body.secrets];
}
// get secret blind index salt
const salt = await SecretService.getSecretBlindIndexSalt({
workspaceId: new Types.ObjectId(workspaceId)
});
type secretsToCreateType = {
type: string;
secretName?: string;
secretKeyCiphertext: string;
secretKeyIV: string;
secretKeyTag: string;
@@ -388,25 +394,10 @@ export const createSecrets = async (req: Request, res: Response) => {
tags: string[]
}
const secretsToInsert: ISecret[] = listOfSecretsToCreate.map(({
type,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag,
tags
}: secretsToCreateType) => {
return ({
version: 1,
workspace: new Types.ObjectId(workspaceId),
const secretsToInsert: ISecret[] = await Promise.all(
listOfSecretsToCreate.map(async ({
type,
user: (req.user && type === SECRET_PERSONAL) ? req.user : undefined,
environment,
secretName,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -417,11 +408,38 @@ export const createSecrets = async (req: Request, res: Response) => {
secretCommentIV,
secretCommentTag,
tags
});
});
}: secretsToCreateType) => {
let secretBlindIndex;
if (secretName) {
secretBlindIndex = await SecretService.generateSecretBlindIndexWithSalt({
secretName,
salt
});
}
return ({
version: 1,
workspace: new Types.ObjectId(workspaceId),
type,
...(secretBlindIndex ? { secretBlindIndex } : {}),
user: (req.user && type === SECRET_PERSONAL) ? req.user : undefined,
environment,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag,
tags
});
})
);
const newlyCreatedSecrets: ISecret[] = (await Secret.insertMany(secretsToInsert)).map((insertedSecret) => insertedSecret.toObject());
setTimeout(async () => {
// trigger event - push secrets
await EventService.handleEvent({
@@ -440,6 +458,7 @@ export const createSecrets = async (req: Request, res: Response) => {
type,
user,
environment,
secretBlindIndex,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -453,6 +472,7 @@ export const createSecrets = async (req: Request, res: Response) => {
type,
user,
environment,
secretBlindIndex,
isDeleted: false,
secretKeyCiphertext,
secretKeyIV,
@@ -492,7 +512,7 @@ export const createSecrets = async (req: Request, res: Response) => {
if (postHogClient) {
postHogClient.capture({
event: 'secrets added',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData: req.authData
}),
properties: {
@@ -607,7 +627,7 @@ export const getSecrets = async (req: Request, res: Response) => {
// case: client authorization is via service token
if (req.serviceTokenData) {
const userId = req.serviceTokenData.user._id
const userId = req.serviceTokenData.user;
const secretQuery: any = {
workspace: workspaceId,
@@ -667,7 +687,7 @@ export const getSecrets = async (req: Request, res: Response) => {
if (postHogClient) {
postHogClient.capture({
event: 'secrets pulled',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData: req.authData
}),
properties: {
@@ -889,7 +909,7 @@ export const updateSecrets = async (req: Request, res: Response) => {
if (postHogClient) {
postHogClient.capture({
event: 'secrets modified',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData: req.authData
}),
properties: {
@@ -1023,7 +1043,7 @@ export const deleteSecrets = async (req: Request, res: Response) => {
if (postHogClient) {
postHogClient.capture({
event: 'secrets deleted',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData: req.authData
}),
properties: {
@@ -11,9 +11,11 @@ import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissi
import {
PERMISSION_READ_SECRETS,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN
} from '../../variables';
import { getSaltRounds } from '../../config';
import { BadRequestError } from '../../utils/errors';
/**
* Return service token data associated with service token on request
@@ -48,7 +50,15 @@ export const getServiceTokenData = async (req: Request, res: Response) => {
}
*/
return res.status(200).json(req.serviceTokenData);
if (!(req.authData.authPayload instanceof ServiceTokenData)) throw BadRequestError({
message: 'Failed accepted client validation for service token data'
});
const serviceTokenData = await ServiceTokenData
.findById(req.authData.authPayload._id)
.populate('user');
return res.status(200).json(serviceTokenData);
}
/**
@@ -132,7 +132,7 @@ export const pullSecrets = async (req: Request, res: Response) => {
if (req.user) {
userId = req.user._id.toString();
} else if (req.serviceTokenData) {
userId = req.serviceTokenData.user._id
userId = req.serviceTokenData.user.toString();
}
// validate environment
const workspaceEnvs = req.membership.workspace.environments;
@@ -70,7 +70,10 @@ export const createSecret = async (req: Request, res: Response) => {
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
secretValueTag,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
} = req.body;
const secret = await SecretService.createSecret({
@@ -84,7 +87,12 @@ export const createSecret = async (req: Request, res: Response) => {
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
secretValueTag,
...((secretCommentCiphertext && secretCommentIV && secretCommentTag) ? {
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
} : {})
});
await EventService.handleEvent({