feat: made raw secret endpoints and normal e2ee ones to be same functionality

This commit is contained in:
=
2024-07-30 23:01:12 +05:30
parent 2cbae96c9a
commit 547be80dcf
9 changed files with 314 additions and 70 deletions
@@ -10,8 +10,10 @@ import { getReplicationFolderName } from "@app/ee/services/secret-replication/se
import { BadRequestError } from "@app/lib/errors";
import { TProjectDALFactory } from "../project/project-dal";
import { TProjectBotServiceFactory } from "../project-bot/project-bot-service";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { TSecretDALFactory } from "../secret/secret-dal";
import { decryptSecretRaw } from "../secret/secret-fns";
import { TSecretQueueFactory } from "../secret/secret-queue";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TSecretImportDALFactory } from "./secret-import-dal";
@@ -29,6 +31,7 @@ type TSecretImportServiceFactoryDep = {
secretImportDAL: TSecretImportDALFactory;
folderDAL: TSecretFolderDALFactory;
secretDAL: Pick<TSecretDALFactory, "find">;
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus">;
projectEnvDAL: TProjectEnvDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
@@ -48,7 +51,8 @@ export const secretImportServiceFactory = ({
projectDAL,
secretDAL,
secretQueueService,
licenseService
licenseService,
projectBotService
}: TSecretImportServiceFactoryDep) => {
const createImport = async ({
environment,
@@ -449,12 +453,61 @@ export const secretImportServiceFactory = ({
return fnSecretsFromImports({ allowedImports, folderDAL, secretDAL, secretImportDAL });
};
const getRawSecretsFromImports = async ({
path: secretPath,
environment,
projectId,
actor,
actorAuthMethod,
actorId,
actorOrgId
}: TGetSecretsFromImportDTO) => {
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
if (!folder) return [];
// this will already order by position
// so anything based on this order will also be in right position
const secretImports = await secretImportDAL.find({ folderId: folder.id, isReplication: false });
const allowedImports = secretImports.filter(({ importEnv, importPath }) =>
permission.can(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, {
environment: importEnv.slug,
secretPath: importPath
})
)
);
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
const importedSecrets = await fnSecretsFromImports({ allowedImports, folderDAL, secretDAL, secretImportDAL });
return importedSecrets.map((el) => ({
...el,
secrets: el.secrets.map((encryptedSecret) =>
decryptSecretRaw({ ...encryptedSecret, workspace: projectId, environment, secretPath }, botKey)
)
}));
};
return {
createImport,
updateImport,
deleteImport,
getImports,
getSecretsFromImports,
getRawSecretsFromImports,
resyncSecretImportReplication,
fnSecretsFromImports
};
+6 -1
View File
@@ -407,7 +407,12 @@ export const decryptSecretRaw = (
id: secret.id,
user: secret.userId,
tags: secret.tags,
skipMultilineEncoding: secret.skipMultilineEncoding
skipMultilineEncoding: secret.skipMultilineEncoding,
secretReminderRepeatDays: secret.secretReminderRepeatDays,
secretReminderNote: secret.secretReminderNote,
metadata: secret.metadata,
createdAt: secret.createdAt,
updatedAt: secret.updatedAt
};
};
+111 -49
View File
@@ -1176,7 +1176,9 @@ export const secretServiceFactory = ({
secretValue,
secretComment,
skipMultilineEncoding,
tagIds
tagIds,
secretReminderNote,
secretReminderRepeatDays
}: TCreateSecretRawDTO) => {
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
@@ -1205,6 +1207,8 @@ export const secretServiceFactory = ({
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag,
skipMultilineEncoding,
secretReminderRepeatDays,
secretReminderNote,
tags: tagIds
});
@@ -1223,12 +1227,19 @@ export const secretServiceFactory = ({
secretPath,
secretValue,
skipMultilineEncoding,
tagIds
tagIds,
secretReminderNote,
secretReminderRepeatDays,
metadata,
secretComment,
newSecretName
}: TUpdateSecretRawDTO) => {
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(newSecretName || secretName, botKey);
const secret = await updateSecret({
secretName,
@@ -1244,7 +1255,17 @@ export const secretServiceFactory = ({
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
skipMultilineEncoding,
tags: tagIds
tags: tagIds,
metadata,
secretReminderRepeatDays,
secretReminderNote,
newSecretName,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag,
secretCommentCiphertext: secretCommentEncrypted.ciphertext
});
await snapshotService.performSnapshot(secret.folderId);
@@ -1283,6 +1304,7 @@ export const secretServiceFactory = ({
const createManySecretsRaw = async ({
actorId,
projectSlug,
projectId: optionalProjectId,
environment,
actor,
actorOrgId,
@@ -1290,9 +1312,16 @@ export const secretServiceFactory = ({
secretPath,
secrets: inputSecrets = []
}: TCreateManySecretRawDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
if (!projectSlug && !optionalProjectId)
throw new BadRequestError({ message: "Must provide either project slug or projectId" });
let projectId = optionalProjectId as string;
// pick either project slug or projectid
if (!optionalProjectId && projectSlug) {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
projectId = project.id;
}
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
@@ -1305,24 +1334,28 @@ export const secretServiceFactory = ({
actorId,
actorOrgId,
actorAuthMethod,
secrets: inputSecrets.map(({ secretComment, secretKey, secretValue, skipMultilineEncoding }) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
return {
secretName: secretKey,
skipMultilineEncoding,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag
};
})
secrets: inputSecrets.map(
({ secretComment, secretKey, metadata, tagIds, secretValue, skipMultilineEncoding }) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
return {
secretName: secretKey,
skipMultilineEncoding,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag,
tags: tagIds,
metadata
};
}
)
});
return secrets.map((secret) =>
@@ -1333,6 +1366,7 @@ export const secretServiceFactory = ({
const updateManySecretsRaw = async ({
actorId,
projectSlug,
projectId: optionalProjectId,
environment,
actor,
actorOrgId,
@@ -1340,9 +1374,15 @@ export const secretServiceFactory = ({
secretPath,
secrets: inputSecrets = []
}: TUpdateManySecretRawDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
if (!projectSlug && !optionalProjectId)
throw new BadRequestError({ message: "Must provide either project slug or projectId" });
let projectId = optionalProjectId as string;
if (!optionalProjectId && projectSlug) {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
projectId = project.id;
}
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
@@ -1355,25 +1395,40 @@ export const secretServiceFactory = ({
actorId,
actorOrgId,
actorAuthMethod,
secrets: inputSecrets.map(({ secretComment, secretKey, secretValue, skipMultilineEncoding }) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
return {
secretName: secretKey,
type: SecretType.Shared,
secrets: inputSecrets.map(
({
secretComment,
secretKey,
secretValue,
skipMultilineEncoding,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag
};
})
tagIds: tags,
newSecretName,
secretReminderNote,
secretReminderRepeatDays
}) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(newSecretName || secretKey, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
return {
secretName: secretKey,
newSecretName,
tags,
secretReminderRepeatDays,
secretReminderNote,
type: SecretType.Shared,
skipMultilineEncoding,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
secretCommentIV: secretCommentEncrypted.iv,
secretCommentTag: secretCommentEncrypted.tag
};
}
)
});
return secrets.map((secret) =>
@@ -1384,6 +1439,7 @@ export const secretServiceFactory = ({
const deleteManySecretsRaw = async ({
actorId,
projectSlug,
projectId: optionalProjectId,
environment,
actor,
actorOrgId,
@@ -1391,9 +1447,15 @@ export const secretServiceFactory = ({
secretPath,
secrets: inputSecrets = []
}: TDeleteManySecretRawDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
if (!projectSlug && !optionalProjectId)
throw new BadRequestError({ message: "Must provide either project slug or projectId" });
let projectId = optionalProjectId as string;
if (!optionalProjectId && projectSlug) {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
projectId = project.id;
}
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
@@ -1406,7 +1468,7 @@ export const secretServiceFactory = ({
actorId,
actorOrgId,
actorAuthMethod,
secrets: inputSecrets.map(({ secretKey }) => ({ secretName: secretKey, type: SecretType.Shared }))
secrets: inputSecrets.map(({ secretKey, type = SecretType.Shared }) => ({ secretName: secretKey, type }))
});
return secrets.map((secret) =>
+23 -4
View File
@@ -160,14 +160,16 @@ export type TGetASecretRawDTO = {
} & Omit<TProjectPermission, "projectId">;
export type TCreateSecretRawDTO = TProjectPermission & {
secretName: string;
secretPath: string;
environment: string;
secretName: string;
secretValue: string;
type: SecretType;
tagIds?: string[];
secretComment?: string;
skipMultilineEncoding?: boolean;
secretReminderRepeatDays?: number | null;
secretReminderNote?: string | null;
};
export type TUpdateSecretRawDTO = TProjectPermission & {
@@ -175,11 +177,16 @@ export type TUpdateSecretRawDTO = TProjectPermission & {
environment: string;
secretName: string;
secretValue?: string;
newSecretName?: string;
secretComment?: string;
type: SecretType;
tagIds?: string[];
skipMultilineEncoding?: boolean;
secretReminderRepeatDays?: number | null;
secretReminderNote?: string | null;
metadata?: {
source?: string;
};
};
export type TDeleteSecretRawDTO = TProjectPermission & {
@@ -191,34 +198,46 @@ export type TDeleteSecretRawDTO = TProjectPermission & {
export type TCreateManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
secretPath: string;
projectSlug: string;
projectId?: string;
projectSlug?: string;
environment: string;
secrets: {
secretKey: string;
secretValue: string;
secretComment?: string;
skipMultilineEncoding?: boolean;
tagIds?: string[];
metadata?: {
source?: string;
};
}[];
};
export type TUpdateManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
secretPath: string;
projectSlug: string;
projectId?: string;
projectSlug?: string;
environment: string;
secrets: {
secretKey: string;
newSecretName?: string;
secretValue: string;
secretComment?: string;
skipMultilineEncoding?: boolean;
tagIds?: string[];
secretReminderRepeatDays?: number | null;
secretReminderNote?: string | null;
}[];
};
export type TDeleteManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
secretPath: string;
projectSlug: string;
projectId?: string;
projectSlug?: string;
environment: string;
secrets: {
secretKey: string;
type?: SecretType;
}[];
};