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({
@@ -146,7 +146,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
const oldSecretVersion = await SecretVersion.findOne({
secret: secretId,
version
});
}).select('+secretBlindIndex')
if (!oldSecretVersion) throw new Error('Failed to find secret version');
@@ -155,6 +155,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
type,
user,
environment,
secretBlindIndex,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -174,6 +175,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
type,
user,
environment,
...(secretBlindIndex ? { secretBlindIndex } : {}),
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -197,6 +199,7 @@ export const rollbackSecretVersion = async (req: Request, res: Response) => {
user,
environment,
isDeleted: false,
...(secretBlindIndex ? { secretBlindIndex } : {}),
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -173,6 +173,7 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
}
}
*/
let secrets;
try {
const { workspaceId } = req.params;
@@ -182,7 +183,10 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
const secretSnapshot = await SecretSnapshot.findOne({
workspace: workspaceId,
version
}).populate<{ secretVersions: ISecretVersion[]}>('secretVersions');
}).populate<{ secretVersions: ISecretVersion[]}>({
path: 'secretVersions',
select: '+secretBlindIndex'
});
if (!secretSnapshot) throw new Error('Failed to find secret snapshot');
@@ -259,7 +263,7 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
);
// add secret versions
await SecretVersion.insertMany(
const secretV = await SecretVersion.insertMany(
secrets.map(({
_id,
version,
+1 -1
View File
@@ -157,7 +157,7 @@ const getAuthSTDPayload = async ({
}, {
new: true
})
.select('+encryptedKey +iv +tag').populate('user serviceAccount');
.select('+encryptedKey +iv +tag');
if (!serviceTokenData) throw ServiceTokenDataNotFoundError({ message: 'Failed to find service token data' });
+2
View File
@@ -1,5 +1,6 @@
import mongoose from 'mongoose';
import { EESecretService } from '../ee/services';
import { SecretService } from '../services';
import { getLogger } from '../utils/logger';
/**
@@ -22,6 +23,7 @@ const initDatabaseHelper = async ({
getLogger("database").info("Database connection established");
await EESecretService.initSecretVersioning();
await SecretService.initSecretBlindIndexDataHelper();
} catch (err) {
getLogger("database").error(`Unable to establish Database connection due to the error.\n${err}`);
}
+97 -73
View File
@@ -11,6 +11,7 @@ import {
} from '../interfaces/middleware';
import {
User,
Workspace,
ServiceAccount,
ServiceTokenData,
Secret,
@@ -26,7 +27,8 @@ import {
validateUserClientForSecrets
} from '../helpers/user';
import {
validateServiceTokenDataClientForSecrets, validateServiceTokenDataClientForWorkspace
validateServiceTokenDataClientForSecrets,
validateServiceTokenDataClientForWorkspace
} from '../helpers/serviceTokenData';
import {
validateServiceAccountClientForSecrets,
@@ -63,7 +65,8 @@ import {
EELogService
} from '../ee/services';
import {
getAuthDataPayloadIdObj
getAuthDataPayloadIdObj,
getAuthDataPayloadUserObj
} from '../utils/auth';
/**
@@ -217,6 +220,46 @@ const validateClientForSecrets = async ({
});
}
/**
* Initialize secret blind index data by setting previously
* un-initialized projects to have secret blind index data
* (Ensures that all projects have associated blind index data)
*/
const initSecretBlindIndexDataHelper = async () => {
const workspaceIdsBlindIndexed = await SecretBlindIndexData.distinct('workspace');
const workspaceIdsToBlindIndex = await Workspace.distinct('_id', {
_id: {
$nin: workspaceIdsBlindIndexed
}
});
const secretBlindIndexDataToInsert = workspaceIdsToBlindIndex.map((workspaceToBlindIndex) => {
const salt = crypto.randomBytes(16).toString('base64');
const {
ciphertext: encryptedSaltCiphertext,
iv: saltIV,
tag: saltTag
} = encryptSymmetric({
plaintext: salt,
key: getEncryptionKey()
});
const secretBlindIndexData = new SecretBlindIndexData({
workspace: workspaceToBlindIndex,
encryptedSaltCiphertext,
saltIV,
saltTag
})
return secretBlindIndexData;
});
if (secretBlindIndexDataToInsert.length > 0) {
await SecretBlindIndexData.insertMany(secretBlindIndexDataToInsert);
}
}
/**
* Create secret blind index data containing encrypted blind index [salt]
* for workspace with id [workspaceId]
@@ -283,7 +326,7 @@ const getSecretBlindIndexSaltHelper = async ({
* Generate blind index for secret with name [secretName]
* and salt [salt]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {String} obj.secretName - name of secret to generate blind index for
* @param {String} obj.salt - base64-salt
*/
const generateSecretBlindIndexWithSaltHelper = async ({
@@ -312,8 +355,8 @@ const getSecretBlindIndexSaltHelper = async ({
* Generate blind index for secret with name [secretName]
* for workspace with id [workspaceId]
* @param {Object} obj
* @param {Object} obj.secretName - name of secret to generate blind index for
* @param {Object} obj.workspaceId - id of workspace that secret belongs to
* @param {Stringj} obj.secretName - name of secret to generate blind index for
* @param {Types.ObjectId} obj.workspaceId - id of workspace that secret belongs to
*/
const generateSecretBlindIndexHelper = async ({
secretName,
@@ -367,11 +410,11 @@ const createSecretHelper = async ({
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
secretValueTag,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
}: CreateSecretParams) => {
// preliminary OK
// pending check for other types of clients
const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
@@ -380,7 +423,8 @@ const createSecretHelper = async ({
const exists = await Secret.exists({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
type
type,
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
});
if (exists) throw BadRequestError({
@@ -400,12 +444,6 @@ const createSecretHelper = async ({
if (!exists) throw BadRequestError({
message: 'Failed to create personal secret override for no corresponding shared secret'
});
// TODO: adapt to other client types
if (!(authData.authPayload instanceof User)) throw BadRequestError({
message: 'Failed to create personal secret override for no specified user'
});
}
// create secret
@@ -414,16 +452,17 @@ const createSecretHelper = async ({
workspace: new Types.ObjectId(workspaceId),
environment,
type,
...(type === SECRET_PERSONAL && (authData.authPayload instanceof User) ? {
user: authData.authPayload._id
} : {}),
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {}),
secretBlindIndex,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
secretValueTag,
secretCommentCiphertext,
secretCommentIV,
secretCommentTag
}).save();
const secretVersion = new SecretVersion({
@@ -431,11 +470,10 @@ const createSecretHelper = async ({
version: secret.version,
workspace: secret.workspace,
type,
...(type === SECRET_PERSONAL && authData.authPayload instanceof User ? {
user: authData.authPayload._id
} : {}),
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {}),
environment: secret.environment,
isDeleted: false,
secretBlindIndex,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
@@ -475,7 +513,7 @@ const createSecretHelper = async ({
if (postHogClient) {
postHogClient.capture({
event: 'secrets added',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData
}),
properties: {
@@ -504,21 +542,17 @@ const getSecretsHelper = async ({
environment,
authData
}: GetSecretsParams) => {
// preliminary OK
// pending check for other types of clients
let secrets: ISecret[] = [];
if (authData.authPayload instanceof User) {
// case: get personal secrets first
secrets = await Secret.find({
workspace: new Types.ObjectId(workspaceId),
environment,
type: SECRET_PERSONAL,
user: authData.authPayload._id
});
}
// get personal secrets first
secrets = await Secret.find({
workspace: new Types.ObjectId(workspaceId),
environment,
type: SECRET_PERSONAL,
...getAuthDataPayloadUserObj(authData)
});
// concat with shared secrets
secrets = secrets.concat(await Secret.find({
workspace: new Types.ObjectId(workspaceId),
environment,
@@ -549,7 +583,7 @@ const getSecretsHelper = async ({
if (postHogClient) {
postHogClient.capture({
event: 'secrets pulled',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData
}),
properties: {
@@ -582,38 +616,31 @@ const getSecretHelper = async ({
type,
authData
}: GetSecretParams) => {
// preliminary OK
// pending check for other types of clients
const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
});
let secret;
let secret: ISecret | null = null;
if (authData.authPayload instanceof User) {
// case: find any personal secret matching criteria
// try getting personal secret first (if exists)
secret = await Secret.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
type: type ?? SECRET_PERSONAL,
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {})
});
if (!secret) {
// case: failed to find personal secret matching criteria
// -> find shared secret matching criteria
secret = await Secret.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
type: type ?? SECRET_PERSONAL,
...(type === SECRET_PERSONAL ? {
user: authData.authPayload._id
} : {})
type: SECRET_SHARED
});
if (!secret) {
// case: failed to find personal secret matching criteria
// -> find shared secret matching criteria
secret = await Secret.findOne({
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
type: SECRET_SHARED
});
}
}
if (!secret) throw SecretNotFoundError();
@@ -639,7 +666,7 @@ const getSecretHelper = async ({
if (postHogClient) {
postHogClient.capture({
event: 'secrets pull',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData
}),
properties: {
@@ -678,8 +705,6 @@ const updateSecretHelper = async ({
secretValueIV,
secretValueTag
}: UpdateSecretParams) => {
// preliminary OK
// pending check for other types of clients
const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
@@ -688,6 +713,7 @@ const updateSecretHelper = async ({
let secret: ISecret | null = null;
if (type === SECRET_SHARED) {
// case: update shared secret
secret = await Secret.findOneAndUpdate(
{
secretBlindIndex,
@@ -705,14 +731,15 @@ const updateSecretHelper = async ({
new: true
}
);
} else if (type === SECRET_PERSONAL && authData.authPayload instanceof User) {
} else {
// case: update personal secret
secret = await Secret.findOneAndUpdate(
{
secretBlindIndex,
workspace: new Types.ObjectId(workspaceId),
environment,
type,
user: authData.authPayload._id
...getAuthDataPayloadUserObj(authData)
},
{
secretValueCiphertext,
@@ -733,11 +760,10 @@ const updateSecretHelper = async ({
version: secret.version,
workspace: secret.workspace,
type,
...(type === SECRET_PERSONAL && authData.authPayload instanceof User ? {
user: authData.authPayload._id
} : {}),
...(type === SECRET_PERSONAL ? getAuthDataPayloadUserObj(authData) : {}),
environment: secret.environment,
isDeleted: false,
secretBlindIndex,
secretKeyCiphertext: secret.secretKeyCiphertext,
secretKeyIV: secret.secretKeyIV,
secretKeyTag: secret.secretKeyTag,
@@ -777,7 +803,7 @@ const updateSecretHelper = async ({
if (postHogClient) {
postHogClient.capture({
event: 'secrets modified',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData
}),
properties: {
@@ -810,9 +836,6 @@ const deleteSecretHelper = async ({
type,
authData
}: DeleteSecretParams) => {
// preliminary OK
// pending check for other types of clients
const secretBlindIndex = await generateSecretBlindIndexHelper({
secretName,
workspaceId: new Types.ObjectId(workspaceId)
@@ -840,13 +863,13 @@ const deleteSecretHelper = async ({
workspaceId: new Types.ObjectId(workspaceId),
environment
});
} else if (type === SECRET_PERSONAL && authData.authPayload instanceof User) {
} else {
secret = await Secret.findOneAndDelete({
secretBlindIndex,
workspaceId: new Types.ObjectId(workspaceId),
environment,
type,
user: authData.authPayload._id
...getAuthDataPayloadUserObj(authData)
});
if (secret) {
@@ -887,7 +910,7 @@ const deleteSecretHelper = async ({
if (postHogClient) {
postHogClient.capture({
event: 'secrets deleted',
distinctId: TelemetryService.getDistinctId({
distinctId: await TelemetryService.getDistinctId({
authData
}),
properties: {
@@ -909,6 +932,7 @@ const deleteSecretHelper = async ({
export {
validateClientForSecret,
validateClientForSecrets,
initSecretBlindIndexDataHelper,
createSecretBlindIndexDataHelper,
getSecretBlindIndexSaltHelper,
generateSecretBlindIndexWithSaltHelper,
-1
View File
@@ -111,7 +111,6 @@ const validateClientForServiceTokenData = async ({
environment?: string;
requiredPermissions?: string[];
}) => {
if (!serviceTokenData.workspace.equals(workspaceId)) {
// case: invalid workspaceId passed
throw UnauthorizedRequestError({
@@ -13,6 +13,9 @@ export interface CreateSecretParams {
secretValueCiphertext: string;
secretValueIV: string;
secretValueTag: string;
secretCommentCiphertext?: string;
secretCommentIV?: string;
secretCommentTag?: string;
}
export interface GetSecretsParams {
+2 -1
View File
@@ -33,7 +33,8 @@ const serviceTokenDataSchema = new Schema<IServiceTokenData>(
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
ref: 'User',
required: true
},
serviceAccount: {
type: Schema.Types.ObjectId,
+35 -5
View File
@@ -10,6 +10,8 @@ import { secretsController } from '../../controllers/v3';
import {
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT,
ADMIN,
MEMBER,
PERMISSION_WRITE_SECRETS,
@@ -25,7 +27,12 @@ router.get(
query('tagSlugs'),
validateRequest,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY]
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
@@ -48,9 +55,17 @@ router.post(
body('secretValueCiphertext').exists().isString().trim(),
body('secretValueIV').exists().isString().trim(),
body('secretValueTag').exists().isString().trim(),
body('secretCommentCiphertext').optional().isString().trim(),
body('secretCommentIV').optional().isString().trim(),
body('secretCommentTag').optional().isString().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY]
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
@@ -70,7 +85,12 @@ router.get(
query('type').optional().isIn([SECRET_SHARED, SECRET_PERSONAL]),
validateRequest,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY]
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
@@ -93,7 +113,12 @@ router.patch(
body('secretValueTag').exists().isString().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY]
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
@@ -113,7 +138,12 @@ router.delete(
body('type').exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
validateRequest,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT, AUTH_MODE_API_KEY]
acceptedAuthModes: [
AUTH_MODE_JWT,
AUTH_MODE_API_KEY,
AUTH_MODE_SERVICE_TOKEN,
AUTH_MODE_SERVICE_ACCOUNT
]
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
+12
View File
@@ -11,6 +11,7 @@ import {
DeleteSecretParams
} from '../interfaces/services/SecretService';
import {
initSecretBlindIndexDataHelper,
createSecretBlindIndexDataHelper,
getSecretBlindIndexSaltHelper,
generateSecretBlindIndexWithSaltHelper,
@@ -23,6 +24,17 @@ import {
} from '../helpers/secrets';
class SecretService {
/**
*
* @param param0 h
* @returns
*/
static async initSecretBlindIndexDataHelper() {
return await initSecretBlindIndexDataHelper();
}
/**
* Create secret blind index data containing encrypted blind index salt
* for workspace with id [workspaceId]
+10 -6
View File
@@ -16,6 +16,7 @@ import {
ServiceTokenData
} from '../models';
import {
AccountNotFoundError,
BadRequestError
} from '../utils/errors';
@@ -50,20 +51,23 @@ class Telemetry {
return postHogClient;
}
static getDistinctId ({
static getDistinctId = async ({
authData
}: {
authData: AuthData;
}) {
let distinctId: any = '';
}) => {
let distinctId = '';
if (authData.authPayload instanceof User) {
distinctId = authData.authPayload.email;
} else if (authData.authPayload instanceof ServiceAccount) {
distinctId = `sa.${authData.authPayload._id.toString()}`;
} else if (authData.authPayload instanceof ServiceTokenData) {
if (authData.authPayload.user instanceof User) {
distinctId = authData.authPayload?.user.email;
} else if (authData.authPayload?.serviceAccount) {
if (authData.authPayload.user) {
const user = await User.findById(authData.authPayload.user, 'email');
if (!user) throw AccountNotFoundError();
distinctId = user.email;
} else if (authData.authPayload.serviceAccount) {
distinctId = distinctId = `sa.${authData.authPayload.serviceAccount.toString()}`;
}
}
+32 -4
View File
@@ -2,9 +2,17 @@ import { AuthData } from '../interfaces/middleware';
import {
User,
ServiceAccount,
ServiceTokenData
ServiceTokenData,
ServiceToken
} from '../models';
// TODO: find a more optimal folder structure to store these types of functions
/**
* Returns an object containing the id of the authentication data payload
* @param {AuthData} authData - authentication data object
* @returns
*/
const getAuthDataPayloadIdObj = (authData: AuthData) => {
if (authData.authPayload instanceof User) {
return { userId: authData.authPayload._id };
@@ -17,10 +25,30 @@ const getAuthDataPayloadIdObj = (authData: AuthData) => {
if (authData.authPayload instanceof ServiceTokenData) {
return { serviceTokenDataId: authData.authPayload._id };
}
return {};
};
/**
* Returns an object containing the user associated with the authentication data payload
* @param {AuthData} authData - authentication data object
* @returns
*/
const getAuthDataPayloadUserObj = (authData: AuthData) => {
if (authData.authPayload instanceof User) {
return { user: authData.authPayload._id };
}
if (authData.authPayload instanceof ServiceAccount) {
return { user: authData.authPayload.user };
}
if (authData.authPayload instanceof ServiceTokenData) {
return { user: authData.authPayload.user };
}
}
export {
getAuthDataPayloadIdObj
getAuthDataPayloadIdObj,
getAuthDataPayloadUserObj
}