mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: all the services are now working with secrets v2 architecture
This commit is contained in:
@@ -115,6 +115,22 @@ export async function up(knex: Knex): Promise<void> {
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
if (await knex.schema.hasTable(TableName.IntegrationAuth)) {
|
||||
const hasEncryptedAccess = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedAccess");
|
||||
const hasEncryptedAccessId = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedAccessId");
|
||||
const hasEncryptedRefresh = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedRefresh");
|
||||
const hasEncryptedAwsIamAssumRole = await knex.schema.hasColumn(
|
||||
TableName.IntegrationAuth,
|
||||
"encryptedAwsAssumeIamRoleArn"
|
||||
);
|
||||
await knex.schema.alterTable(TableName.IntegrationAuth, (t) => {
|
||||
if (!hasEncryptedAccess) t.binary("encryptedAccess");
|
||||
if (!hasEncryptedAccessId) t.binary("encryptedAccessId");
|
||||
if (!hasEncryptedRefresh) t.binary("encryptedRefresh");
|
||||
if (!hasEncryptedAwsIamAssumRole) t.binary("hasEncryptedAwsIamAssumRole");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
@@ -131,4 +147,20 @@ export async function down(knex: Knex): Promise<void> {
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretVersionV2);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretVersionV2Tag);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretVersionV2);
|
||||
|
||||
if (await knex.schema.hasTable(TableName.IntegrationAuth)) {
|
||||
const hasEncryptedAccess = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedAccess");
|
||||
const hasEncryptedAccessId = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedAccessId");
|
||||
const hasEncryptedRefresh = await knex.schema.hasColumn(TableName.IntegrationAuth, "encryptedRefresh");
|
||||
const hasEncryptedAwsIamAssumRole = await knex.schema.hasColumn(
|
||||
TableName.IntegrationAuth,
|
||||
"encryptedAwsAssumeIamRoleArn"
|
||||
);
|
||||
await knex.schema.alterTable(TableName.IntegrationAuth, (t) => {
|
||||
if (hasEncryptedAccess) t.dropColumn("encryptedAccess");
|
||||
if (hasEncryptedAccessId) t.dropColumn("encryptedAccessId");
|
||||
if (hasEncryptedRefresh) t.dropColumn("encryptedRefresh");
|
||||
if (hasEncryptedAwsIamAssumRole) t.dropColumn("hasEncryptedAwsIamAssumRole");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { zodBuffer } from "@app/lib/zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const IntegrationAuthsSchema = z.object({
|
||||
@@ -32,7 +34,11 @@ export const IntegrationAuthsSchema = z.object({
|
||||
updatedAt: z.date(),
|
||||
awsAssumeIamRoleArnCipherText: z.string().nullable().optional(),
|
||||
awsAssumeIamRoleArnIV: z.string().nullable().optional(),
|
||||
awsAssumeIamRoleArnTag: z.string().nullable().optional()
|
||||
awsAssumeIamRoleArnTag: z.string().nullable().optional(),
|
||||
encryptedAccess: zodBuffer.nullable().optional(),
|
||||
encryptedAccessId: zodBuffer.nullable().optional(),
|
||||
encryptedRefresh: zodBuffer.nullable().optional(),
|
||||
hasEncryptedAwsIamAssumRole: zodBuffer.nullable().optional()
|
||||
});
|
||||
|
||||
export type TIntegrationAuths = z.infer<typeof IntegrationAuthsSchema>;
|
||||
|
||||
@@ -16,6 +16,7 @@ export type TSecretApprovalRequestSecretDALFactory = ReturnType<typeof secretApp
|
||||
export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
||||
const secretApprovalRequestSecretOrm = ormify(db, TableName.SecretApprovalRequestSecret);
|
||||
const secretApprovalRequestSecretTagOrm = ormify(db, TableName.SecretApprovalRequestSecretTag);
|
||||
const secretApprovalRequestSecretV2TagOrm = ormify(db, TableName.SecretApprovalRequestSecretTagV2);
|
||||
const secretApprovalRequestSecretV2Orm = ormify(db, TableName.SecretApprovalRequestSecretV2);
|
||||
|
||||
const bulkUpdateNoVersionIncrement = async (data: TSecretApprovalRequestsSecrets[], tx?: Knex) => {
|
||||
@@ -359,6 +360,7 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => {
|
||||
findByRequestId,
|
||||
findByRequestIdBridgeSecretV2,
|
||||
bulkUpdateNoVersionIncrement,
|
||||
insertApprovalSecretTags: secretApprovalRequestSecretTagOrm.insertMany
|
||||
insertApprovalSecretTags: secretApprovalRequestSecretTagOrm.insertMany,
|
||||
insertApprovalSecretV2Tags: secretApprovalRequestSecretV2TagOrm.insertMany
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ import { groupBy, pick, unique } from "@app/lib/fn";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { EnforcementLevel } from "@app/lib/types";
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
||||
@@ -28,13 +29,6 @@ import {
|
||||
fnSecretBulkUpdate,
|
||||
getAllNestedSecretReferences
|
||||
} from "@app/services/secret/secret-fns";
|
||||
import {
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
fnSecretBulkDelete as fnSecretV2BridgeBulkDelete,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge,
|
||||
secretEncryptionHelper
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
import { TSecretQueueFactory } from "@app/services/secret/secret-queue";
|
||||
import { SecretOperations } from "@app/services/secret/secret-types";
|
||||
import { TSecretVersionDALFactory } from "@app/services/secret/secret-version-dal";
|
||||
@@ -44,6 +38,16 @@ import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-fold
|
||||
import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
||||
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
||||
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import {
|
||||
fnSecretBulkDelete as fnSecretV2BridgeBulkDelete,
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge,
|
||||
secretEncryptionHelper
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||
@@ -63,10 +67,6 @@ import {
|
||||
TSecretApprovalDetailsDTO,
|
||||
TStatusChangeDTO
|
||||
} from "./secret-approval-request-types";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
|
||||
type TSecretApprovalRequestServiceFactoryDep = {
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
@@ -730,7 +730,7 @@ export const secretApprovalRequestServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
await snapshotService.performSnapshot(folderId, shouldUseSecretV2Bridge);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
const [folder] = await folderDAL.findSecretPathByFolderIds(projectId, [folderId]);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||
await secretQueueService.syncSecrets({
|
||||
|
||||
@@ -10,15 +10,11 @@ import { logger } from "@app/lib/logger";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { QueueName, TQueueServiceFactory } from "@app/queue";
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
import { TSecretDALFactory } from "@app/services/secret/secret-dal";
|
||||
import { fnSecretBulkInsert, fnSecretBulkUpdate } from "@app/services/secret/secret-fns";
|
||||
import {
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
import { TSecretQueueFactory, uniqueSecretQueueKey } from "@app/services/secret/secret-queue";
|
||||
import { SecretOperations } from "@app/services/secret/secret-types";
|
||||
import { TSecretVersionDALFactory } from "@app/services/secret/secret-version-dal";
|
||||
@@ -28,13 +24,17 @@ import { ReservedFolders } from "@app/services/secret-folder/secret-folder-types
|
||||
import { TSecretImportDALFactory } from "@app/services/secret-import/secret-import-dal";
|
||||
import { fnSecretsFromImports, fnSecretsV2FromImports } from "@app/services/secret-import/secret-import-fns";
|
||||
import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
||||
|
||||
import { MAX_REPLICATION_DEPTH } from "./secret-replication-constants";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import {
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
import { MAX_REPLICATION_DEPTH } from "./secret-replication-constants";
|
||||
|
||||
type TSecretReplicationServiceFactoryDep = {
|
||||
secretDAL: Pick<
|
||||
|
||||
@@ -17,9 +17,13 @@ import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
import { TSecretDALFactory } from "@app/services/secret/secret-dal";
|
||||
import { TSecretVersionDALFactory } from "@app/services/secret/secret-version-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TTelemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
|
||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
@@ -39,10 +43,6 @@ import {
|
||||
secretRotationPreSetFn
|
||||
} from "./secret-rotation-queue-fn";
|
||||
import { TSecretRotationData, TSecretRotationDbFn, TSecretRotationEncData } from "./secret-rotation-queue-types";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
export type TSecretRotationQueueFactory = ReturnType<typeof secretRotationQueueFactory>;
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ import { TSecretVersionTagDALFactory } from "@app/services/secret/secret-version
|
||||
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
||||
import { TSecretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal";
|
||||
import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
|
||||
import { TLicenseServiceFactory } from "../license/license-service";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
@@ -23,11 +26,8 @@ import {
|
||||
import { TSnapshotDALFactory } from "./snapshot-dal";
|
||||
import { TSnapshotFolderDALFactory } from "./snapshot-folder-dal";
|
||||
import { TSnapshotSecretDALFactory } from "./snapshot-secret-dal";
|
||||
import { getFullFolderPath } from "./snapshot-service-fns";
|
||||
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
|
||||
import { TSnapshotSecretV2DALFactory } from "./snapshot-secret-v2-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal";
|
||||
import { getFullFolderPath } from "./snapshot-service-fns";
|
||||
|
||||
type TSecretSnapshotServiceFactoryDep = {
|
||||
snapshotDAL: TSnapshotDALFactory;
|
||||
@@ -167,14 +167,15 @@ export const secretSnapshotServiceFactory = ({
|
||||
return snapshotDetails;
|
||||
};
|
||||
|
||||
const performSnapshot = async (folderId: string, shouldUseSecretV2Bridge: boolean) => {
|
||||
const performSnapshot = async (folderId: string) => {
|
||||
try {
|
||||
if (!licenseService.isValidLicense) throw new InternalServerError({ message: "Invalid license" });
|
||||
const folder = await folderDAL.findById(folderId);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||
const shouldUseSecretV2Bridge = folder.projectVersion === 3;
|
||||
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const snapshot = await snapshotDAL.transaction(async (tx) => {
|
||||
const folder = await folderDAL.findById(folderId, tx);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||
|
||||
const secretVersions = await secretVersionV2BridgeDAL.findLatestVersionByFolderId(folderId, tx);
|
||||
const folderVersions = await folderVersionDAL.findLatestVersionByFolderId(folderId, tx);
|
||||
const newSnapshot = await snapshotDAL.create(
|
||||
@@ -208,9 +209,6 @@ export const secretSnapshotServiceFactory = ({
|
||||
}
|
||||
|
||||
const snapshot = await snapshotDAL.transaction(async (tx) => {
|
||||
const folder = await folderDAL.findById(folderId, tx);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||
|
||||
const secretVersions = await secretVersionDAL.findLatestVersionByFolderId(folderId, tx);
|
||||
const folderVersions = await folderVersionDAL.findLatestVersionByFolderId(folderId, tx);
|
||||
const newSnapshot = await snapshotDAL.create(
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from "./array";
|
||||
export * from "./dates";
|
||||
export * from "./object";
|
||||
export * from "./string";
|
||||
export * from "./undefined";
|
||||
|
||||
3
backend/src/lib/fn/undefined.ts
Normal file
3
backend/src/lib/fn/undefined.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const executeIfDefined = <T, R>(func: (input: T) => R, input: T | undefined): R | undefined => {
|
||||
return input === undefined ? undefined : func(input);
|
||||
};
|
||||
@@ -11,6 +11,8 @@ import { BadRequestError } from "@app/lib/errors";
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
|
||||
import { TIntegrationDALFactory } from "../integration/integration-dal";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { TProjectBotDALFactory } from "../project-bot/project-bot-dal";
|
||||
import { TProjectBotServiceFactory } from "../project-bot/project-bot-service";
|
||||
import { getApps } from "./integration-app-list";
|
||||
@@ -55,6 +57,7 @@ type TIntegrationAuthServiceFactoryDep = {
|
||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
export type TIntegrationAuthServiceFactory = ReturnType<typeof integrationAuthServiceFactory>;
|
||||
@@ -64,7 +67,8 @@ export const integrationAuthServiceFactory = ({
|
||||
integrationAuthDAL,
|
||||
integrationDAL,
|
||||
projectBotDAL,
|
||||
projectBotService
|
||||
projectBotService,
|
||||
kmsService
|
||||
}: TIntegrationAuthServiceFactoryDep) => {
|
||||
const listIntegrationAuthByProjectId = async ({
|
||||
actorId,
|
||||
@@ -145,18 +149,38 @@ export const integrationAuthServiceFactory = ({
|
||||
};
|
||||
}
|
||||
|
||||
const key = await projectBotService.getBotKey(projectId);
|
||||
if (tokenExchange.refreshToken) {
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.refreshToken, key);
|
||||
updateDoc.refreshIV = refreshEncToken.iv;
|
||||
updateDoc.refreshTag = refreshEncToken.tag;
|
||||
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
|
||||
}
|
||||
if (tokenExchange.accessToken) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.accessToken, key);
|
||||
updateDoc.accessIV = accessEncToken.iv;
|
||||
updateDoc.accessTag = accessEncToken.tag;
|
||||
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(projectId);
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
if (tokenExchange.refreshToken) {
|
||||
const refreshEncToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenExchange.refreshToken)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedRefresh = refreshEncToken;
|
||||
}
|
||||
if (tokenExchange.accessToken) {
|
||||
const accessToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenExchange.accessToken)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedAccess = accessToken;
|
||||
}
|
||||
} else {
|
||||
if (!botKey) throw new BadRequestError({ message: "Bot key not found" });
|
||||
if (tokenExchange.refreshToken) {
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.refreshToken, botKey);
|
||||
updateDoc.refreshIV = refreshEncToken.iv;
|
||||
updateDoc.refreshTag = refreshEncToken.tag;
|
||||
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
|
||||
}
|
||||
if (tokenExchange.accessToken) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenExchange.accessToken, botKey);
|
||||
updateDoc.accessIV = accessEncToken.iv;
|
||||
updateDoc.accessTag = accessEncToken.tag;
|
||||
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||
}
|
||||
}
|
||||
return integrationAuthDAL.transaction(async (tx) => {
|
||||
const doc = await integrationAuthDAL.findOne({ projectId, integration }, tx);
|
||||
@@ -212,109 +236,210 @@ export const integrationAuthServiceFactory = ({
|
||||
: {})
|
||||
};
|
||||
|
||||
const key = await projectBotService.getBotKey(projectId);
|
||||
if (refreshToken) {
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integration,
|
||||
refreshToken,
|
||||
url,
|
||||
updateDoc.metadata as Record<string, string>
|
||||
);
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, key);
|
||||
updateDoc.refreshIV = refreshEncToken.iv;
|
||||
updateDoc.refreshTag = refreshEncToken.tag;
|
||||
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, key);
|
||||
updateDoc.accessIV = accessEncToken.iv;
|
||||
updateDoc.accessTag = accessEncToken.tag;
|
||||
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||
updateDoc.accessExpiresAt = tokenDetails.accessExpiresAt;
|
||||
}
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(projectId);
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
if (refreshToken) {
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integration,
|
||||
refreshToken,
|
||||
url,
|
||||
updateDoc.metadata as Record<string, string>
|
||||
);
|
||||
const refreshEncToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenDetails.refreshToken)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedRefresh = refreshEncToken;
|
||||
|
||||
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
|
||||
if (accessToken) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessToken, key);
|
||||
const accessEncToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenDetails.accessToken)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedAccess = accessEncToken;
|
||||
updateDoc.accessExpiresAt = tokenDetails.accessExpiresAt;
|
||||
}
|
||||
|
||||
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
|
||||
if (accessToken) {
|
||||
const accessEncToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(accessToken)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedAccess = accessEncToken;
|
||||
}
|
||||
if (accessId) {
|
||||
const accessEncToken = secretManagerEncryptor({
|
||||
plainText: Buffer.from(accessId)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.encryptedAccessId = accessEncToken;
|
||||
}
|
||||
if (awsAssumeIamRoleArn) {
|
||||
const awsAssumeIamRoleArnEncrypted = secretManagerEncryptor({
|
||||
plainText: Buffer.from(awsAssumeIamRoleArn)
|
||||
}).cipherTextBlob;
|
||||
updateDoc.hasEncryptedAwsIamAssumRole = awsAssumeIamRoleArnEncrypted;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!botKey) throw new BadRequestError({ message: "Bot key not found" });
|
||||
if (refreshToken) {
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integration,
|
||||
refreshToken,
|
||||
url,
|
||||
updateDoc.metadata as Record<string, string>
|
||||
);
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
|
||||
updateDoc.refreshIV = refreshEncToken.iv;
|
||||
updateDoc.refreshTag = refreshEncToken.tag;
|
||||
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
|
||||
updateDoc.accessIV = accessEncToken.iv;
|
||||
updateDoc.accessTag = accessEncToken.tag;
|
||||
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||
|
||||
updateDoc.accessExpiresAt = tokenDetails.accessExpiresAt;
|
||||
}
|
||||
if (accessId) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessId, key);
|
||||
updateDoc.accessIdIV = accessEncToken.iv;
|
||||
updateDoc.accessIdTag = accessEncToken.tag;
|
||||
updateDoc.accessIdCiphertext = accessEncToken.ciphertext;
|
||||
}
|
||||
if (awsAssumeIamRoleArn) {
|
||||
const awsAssumeIamRoleArnEnc = encryptSymmetric128BitHexKeyUTF8(awsAssumeIamRoleArn, key);
|
||||
updateDoc.awsAssumeIamRoleArnCipherText = awsAssumeIamRoleArnEnc.ciphertext;
|
||||
updateDoc.awsAssumeIamRoleArnIV = awsAssumeIamRoleArnEnc.iv;
|
||||
updateDoc.awsAssumeIamRoleArnTag = awsAssumeIamRoleArnEnc.tag;
|
||||
|
||||
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
|
||||
if (accessToken) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessToken, botKey);
|
||||
updateDoc.accessIV = accessEncToken.iv;
|
||||
updateDoc.accessTag = accessEncToken.tag;
|
||||
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||
}
|
||||
if (accessId) {
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessId, botKey);
|
||||
updateDoc.accessIdIV = accessEncToken.iv;
|
||||
updateDoc.accessIdTag = accessEncToken.tag;
|
||||
updateDoc.accessIdCiphertext = accessEncToken.ciphertext;
|
||||
}
|
||||
if (awsAssumeIamRoleArn) {
|
||||
const awsAssumeIamRoleArnEnc = encryptSymmetric128BitHexKeyUTF8(awsAssumeIamRoleArn, botKey);
|
||||
updateDoc.awsAssumeIamRoleArnCipherText = awsAssumeIamRoleArnEnc.ciphertext;
|
||||
updateDoc.awsAssumeIamRoleArnIV = awsAssumeIamRoleArnEnc.iv;
|
||||
updateDoc.awsAssumeIamRoleArnTag = awsAssumeIamRoleArnEnc.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return integrationAuthDAL.create(updateDoc);
|
||||
};
|
||||
|
||||
// helper function
|
||||
const getIntegrationAccessToken = async (integrationAuth: TIntegrationAuths, botKey: string) => {
|
||||
const getIntegrationAccessToken = async (
|
||||
integrationAuth: TIntegrationAuths,
|
||||
shouldUseSecretV2Bridge: boolean,
|
||||
botKey?: string
|
||||
) => {
|
||||
let accessToken: string | undefined;
|
||||
let accessId: string | undefined;
|
||||
// this means its not access token based
|
||||
if (
|
||||
integrationAuth.integration === Integrations.AWS_SECRET_MANAGER &&
|
||||
integrationAuth.awsAssumeIamRoleArnCipherText
|
||||
(shouldUseSecretV2Bridge
|
||||
? integrationAuth.hasEncryptedAwsIamAssumRole
|
||||
: integrationAuth.awsAssumeIamRoleArnCipherText)
|
||||
) {
|
||||
return { accessToken: "", accessId: "" };
|
||||
}
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const { decryptor: secretManagerDecryptor, encryptor: secretManagerEncryptor } =
|
||||
await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId: integrationAuth.projectId
|
||||
});
|
||||
if (integrationAuth.encryptedAccess) {
|
||||
accessToken = secretManagerDecryptor({ cipherTextBlob: integrationAuth.encryptedAccess }).toString();
|
||||
}
|
||||
|
||||
if (integrationAuth.accessTag && integrationAuth.accessIV && integrationAuth.accessCiphertext) {
|
||||
accessToken = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: integrationAuth.accessCiphertext,
|
||||
iv: integrationAuth.accessIV,
|
||||
tag: integrationAuth.accessTag,
|
||||
key: botKey
|
||||
});
|
||||
}
|
||||
if (integrationAuth.encryptedRefresh) {
|
||||
const refreshToken = secretManagerDecryptor({ cipherTextBlob: integrationAuth.encryptedRefresh }).toString();
|
||||
|
||||
if (integrationAuth.refreshCiphertext && integrationAuth.refreshIV && integrationAuth.refreshTag) {
|
||||
const refreshToken = decryptSymmetric128BitHexKeyUTF8({
|
||||
key: botKey,
|
||||
ciphertext: integrationAuth.refreshCiphertext,
|
||||
iv: integrationAuth.refreshIV,
|
||||
tag: integrationAuth.refreshTag
|
||||
});
|
||||
if (integrationAuth.accessExpiresAt && integrationAuth.accessExpiresAt < new Date()) {
|
||||
// refer above it contains same logic except not saving
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integrationAuth.integration,
|
||||
refreshToken,
|
||||
integrationAuth?.url,
|
||||
integrationAuth.metadata as Record<string, string>
|
||||
);
|
||||
const encryptedRefresh = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenDetails.refreshToken)
|
||||
}).cipherTextBlob;
|
||||
const encryptedAccess = secretManagerEncryptor({
|
||||
plainText: Buffer.from(tokenDetails.accessToken)
|
||||
}).cipherTextBlob;
|
||||
accessToken = tokenDetails.accessToken;
|
||||
await integrationAuthDAL.updateById(integrationAuth.id, {
|
||||
accessExpiresAt: tokenDetails.accessExpiresAt,
|
||||
encryptedRefresh,
|
||||
encryptedAccess
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!accessToken) throw new BadRequestError({ message: "Missing access token" });
|
||||
|
||||
if (integrationAuth.accessExpiresAt && integrationAuth.accessExpiresAt < new Date()) {
|
||||
// refer above it contains same logic except not saving
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integrationAuth.integration,
|
||||
refreshToken,
|
||||
integrationAuth?.url,
|
||||
integrationAuth.metadata as Record<string, string>
|
||||
);
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
|
||||
accessToken = tokenDetails.accessToken;
|
||||
await integrationAuthDAL.updateById(integrationAuth.id, {
|
||||
refreshIV: refreshEncToken.iv,
|
||||
refreshTag: refreshEncToken.tag,
|
||||
refreshCiphertext: refreshEncToken.ciphertext,
|
||||
accessExpiresAt: tokenDetails.accessExpiresAt,
|
||||
accessIV: accessEncToken.iv,
|
||||
accessTag: accessEncToken.tag,
|
||||
accessCiphertext: accessEncToken.ciphertext
|
||||
if (integrationAuth.encryptedAccessId) {
|
||||
accessId = secretManagerDecryptor({
|
||||
cipherTextBlob: integrationAuth.encryptedAccessId
|
||||
}).toString();
|
||||
}
|
||||
|
||||
// the old bot key is else
|
||||
} else {
|
||||
if (!botKey) throw new BadRequestError({ message: "bot key is missing" });
|
||||
if (integrationAuth.accessTag && integrationAuth.accessIV && integrationAuth.accessCiphertext) {
|
||||
accessToken = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: integrationAuth.accessCiphertext,
|
||||
iv: integrationAuth.accessIV,
|
||||
tag: integrationAuth.accessTag,
|
||||
key: botKey
|
||||
});
|
||||
}
|
||||
|
||||
if (integrationAuth.refreshCiphertext && integrationAuth.refreshIV && integrationAuth.refreshTag) {
|
||||
const refreshToken = decryptSymmetric128BitHexKeyUTF8({
|
||||
key: botKey,
|
||||
ciphertext: integrationAuth.refreshCiphertext,
|
||||
iv: integrationAuth.refreshIV,
|
||||
tag: integrationAuth.refreshTag
|
||||
});
|
||||
|
||||
if (integrationAuth.accessExpiresAt && integrationAuth.accessExpiresAt < new Date()) {
|
||||
// refer above it contains same logic except not saving
|
||||
const tokenDetails = await exchangeRefresh(
|
||||
integrationAuth.integration,
|
||||
refreshToken,
|
||||
integrationAuth?.url,
|
||||
integrationAuth.metadata as Record<string, string>
|
||||
);
|
||||
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
|
||||
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
|
||||
accessToken = tokenDetails.accessToken;
|
||||
await integrationAuthDAL.updateById(integrationAuth.id, {
|
||||
refreshIV: refreshEncToken.iv,
|
||||
refreshTag: refreshEncToken.tag,
|
||||
refreshCiphertext: refreshEncToken.ciphertext,
|
||||
accessExpiresAt: tokenDetails.accessExpiresAt,
|
||||
accessIV: accessEncToken.iv,
|
||||
accessTag: accessEncToken.tag,
|
||||
accessCiphertext: accessEncToken.ciphertext
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!accessToken) throw new BadRequestError({ message: "Missing access token" });
|
||||
|
||||
if (integrationAuth.accessIdTag && integrationAuth.accessIdIV && integrationAuth.accessIdCiphertext) {
|
||||
accessId = decryptSymmetric128BitHexKeyUTF8({
|
||||
key: botKey,
|
||||
ciphertext: integrationAuth.accessIdCiphertext,
|
||||
iv: integrationAuth.accessIdIV,
|
||||
tag: integrationAuth.accessIdTag
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!accessToken) throw new BadRequestError({ message: "Missing access token" });
|
||||
|
||||
if (integrationAuth.accessIdTag && integrationAuth.accessIdIV && integrationAuth.accessIdCiphertext) {
|
||||
accessId = decryptSymmetric128BitHexKeyUTF8({
|
||||
key: botKey,
|
||||
ciphertext: integrationAuth.accessIdCiphertext,
|
||||
iv: integrationAuth.accessIdIV,
|
||||
tag: integrationAuth.accessIdTag
|
||||
});
|
||||
}
|
||||
return { accessId, accessToken };
|
||||
};
|
||||
|
||||
@@ -339,8 +464,8 @@ export const integrationAuthServiceFactory = ({
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken, accessId } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken, accessId } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
const apps = await getApps({
|
||||
integration: integrationAuth.integration,
|
||||
accessToken,
|
||||
@@ -371,8 +496,8 @@ export const integrationAuthServiceFactory = ({
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
const teams = await getTeams({
|
||||
integration: integrationAuth.integration,
|
||||
accessToken,
|
||||
@@ -400,8 +525,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
if (appId) {
|
||||
const { data } = await request.get<TVercelBranches[]>(
|
||||
@@ -441,8 +566,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (accountId) {
|
||||
const { data } = await request.get<TChecklyGroups[]>(`${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups`, {
|
||||
headers: {
|
||||
@@ -468,8 +593,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: accessToken
|
||||
@@ -505,8 +630,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: accessToken
|
||||
@@ -537,8 +662,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
const { data } = await request.get<{ results: Array<{ id: string; name: string }> }>(
|
||||
`${IntegrationUrls.QOVERY_API_URL}/organization`,
|
||||
{
|
||||
@@ -571,8 +696,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessId, accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessId, accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
const kms = new AWS.KMS({
|
||||
region,
|
||||
@@ -629,8 +754,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (orgId) {
|
||||
const { data } = await request.get<{ results: Array<{ id: string; name: string }> }>(
|
||||
`${IntegrationUrls.QOVERY_API_URL}/organization/${orgId}/project`,
|
||||
@@ -665,8 +790,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (projectId && projectId !== "none") {
|
||||
// TODO: fix
|
||||
const { data } = await request.get<{ results: { id: string; name: string }[] }>(
|
||||
@@ -706,8 +831,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (environmentId) {
|
||||
const { data } = await request.get<{ results: { id: string; name: string }[] }>(
|
||||
`${IntegrationUrls.QOVERY_API_URL}/environment/${environmentId}/application`,
|
||||
@@ -746,8 +871,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (environmentId) {
|
||||
const { data } = await request.get<{ results: { id: string; name: string }[] }>(
|
||||
`${IntegrationUrls.QOVERY_API_URL}/environment/${environmentId}/container`,
|
||||
@@ -786,8 +911,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (environmentId) {
|
||||
const { data } = await request.get<{ results: { id: string; name: string }[] }>(
|
||||
`${IntegrationUrls.QOVERY_API_URL}/environment/${environmentId}/job`,
|
||||
@@ -825,8 +950,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
const { data } = await request.get<THerokuPipelineCoupling[]>(
|
||||
`${IntegrationUrls.HEROKU_API_URL}/pipeline-couplings`,
|
||||
@@ -865,8 +990,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (appId) {
|
||||
const query = `
|
||||
query GetEnvironments($projectId: String!, $after: String, $before: String, $first: Int, $isEphemeral: Boolean, $last: Int) {
|
||||
@@ -933,8 +1058,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
|
||||
if (appId && appId !== "") {
|
||||
const query = `
|
||||
@@ -1007,8 +1132,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
const workspaces: TBitbucketWorkspace[] = [];
|
||||
let hasNextPage = true;
|
||||
let workspaceUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/workspaces`;
|
||||
@@ -1056,8 +1181,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
const secretGroups: { name: string; groupId: string }[] = [];
|
||||
|
||||
if (appId) {
|
||||
@@ -1124,8 +1249,8 @@ export const integrationAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(integrationAuth.projectId);
|
||||
const { accessToken } = await getIntegrationAccessToken(integrationAuth, shouldUseSecretV2Bridge, botKey);
|
||||
if (appId) {
|
||||
const {
|
||||
data: { buildType }
|
||||
|
||||
@@ -312,12 +312,14 @@ export const secretFolderDALFactory = (db: TDbClient) => {
|
||||
const folder = await (tx || db.replicaNode())(TableName.SecretFolder)
|
||||
.where({ [`${TableName.SecretFolder}.id` as "id"]: id })
|
||||
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
|
||||
.join(TableName.Project, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
|
||||
.select(selectAllTableCols(TableName.SecretFolder))
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||
db.ref("name").withSchema(TableName.Environment).as("envName"),
|
||||
db.ref("projectId").withSchema(TableName.Environment)
|
||||
db.ref("projectId").withSchema(TableName.Environment),
|
||||
db.ref("version").withSchema(TableName.Project).as("projectVersion")
|
||||
)
|
||||
.first();
|
||||
if (folder) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services
|
||||
import { getReplicationFolderName } from "@app/ee/services/secret-replication/secret-replication-service";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { TProjectDALFactory } from "../project/project-dal";
|
||||
import { TProjectBotServiceFactory } from "../project-bot/project-bot-service";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
@@ -16,8 +18,9 @@ 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 { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretImportDALFactory } from "./secret-import-dal";
|
||||
import { fnSecretsFromImports } from "./secret-import-fns";
|
||||
import { fnSecretsFromImports, fnSecretsV2FromImports } from "./secret-import-fns";
|
||||
import {
|
||||
TCreateSecretImportDTO,
|
||||
TDeleteSecretImportDTO,
|
||||
@@ -31,12 +34,14 @@ type TSecretImportServiceFactoryDep = {
|
||||
secretImportDAL: TSecretImportDALFactory;
|
||||
folderDAL: TSecretFolderDALFactory;
|
||||
secretDAL: Pick<TSecretDALFactory, "find">;
|
||||
secretV2BridgeDAL: Pick<TSecretV2BridgeDALFactory, "find">;
|
||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus">;
|
||||
projectEnvDAL: TProjectEnvDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" });
|
||||
@@ -52,7 +57,9 @@ export const secretImportServiceFactory = ({
|
||||
secretDAL,
|
||||
secretQueueService,
|
||||
licenseService,
|
||||
projectBotService
|
||||
projectBotService,
|
||||
secretV2BridgeDAL,
|
||||
kmsService
|
||||
}: TSecretImportServiceFactoryDep) => {
|
||||
const createImport = async ({
|
||||
environment,
|
||||
@@ -489,7 +496,23 @@ export const secretImportServiceFactory = ({
|
||||
)
|
||||
);
|
||||
|
||||
const botKey = await projectBotService.getBotKey(projectId);
|
||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
const importedSecrets = await fnSecretsV2FromImports({
|
||||
allowedImports,
|
||||
folderDAL,
|
||||
secretDAL: secretV2BridgeDAL,
|
||||
secretImportDAL,
|
||||
decryptor: (value) =>
|
||||
value ? secretManagerEncryptor({ plainText: value }).cipherTextBlob.toString() : undefined
|
||||
});
|
||||
return importedSecrets;
|
||||
}
|
||||
|
||||
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
||||
|
||||
const importedSecrets = await fnSecretsFromImports({ allowedImports, folderDAL, secretDAL, secretImportDAL });
|
||||
|
||||
@@ -4,11 +4,11 @@ import { TableName, TSecretFolders, TSecretsV2 } from "@app/db/schemas";
|
||||
import { groupBy } from "@app/lib/fn";
|
||||
import { logger } from "@app/lib/logger";
|
||||
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal";
|
||||
import { TFnSecretBulkDelete, TFnSecretBulkInsert, TFnSecretBulkUpdate } from "./secret-v2-bridge-types";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
|
||||
const INTERPOLATION_SYNTAX_REG = /\${([^}]+)}/g;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||
|
||||
import { ActorType } from "../auth/auth-type";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TSecretQueueFactory } from "../secret/secret-queue";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
@@ -22,7 +23,6 @@ import { fnSecretsV2FromImports } from "../secret-import/secret-import-fns";
|
||||
import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal";
|
||||
import {
|
||||
secretEncryptionHelper,
|
||||
fnSecretBulkDelete,
|
||||
fnSecretBulkInsert,
|
||||
fnSecretBulkUpdate,
|
||||
@@ -51,10 +51,7 @@ import { TSecretVersionV2TagDALFactory } from "./secret-version-tag-dal";
|
||||
type TSecretV2BridgeServiceFactoryDep = {
|
||||
secretDAL: TSecretV2BridgeDALFactory;
|
||||
secretVersionDAL: TSecretVersionV2DALFactory;
|
||||
kmsService: Pick<
|
||||
TKmsServiceFactory,
|
||||
"getProjectSecretManagerKmsDataKey" | "encryptWithInputKey" | "decryptWithInputKey"
|
||||
>;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
secretVersionTagDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
|
||||
secretTagDAL: TSecretTagDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
@@ -69,7 +66,7 @@ type TSecretV2BridgeServiceFactoryDep = {
|
||||
secretApprovalRequestDAL: Pick<TSecretApprovalRequestDALFactory, "create" | "transaction">;
|
||||
secretApprovalRequestSecretDAL: Pick<
|
||||
TSecretApprovalRequestSecretDALFactory,
|
||||
"insertMany" | "insertApprovalSecretTags"
|
||||
"insertV2Bridge" | "insertApprovalSecretV2Tags"
|
||||
>;
|
||||
snapshotService: Pick<TSecretSnapshotServiceFactory, "performSnapshot">;
|
||||
};
|
||||
@@ -150,8 +147,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
|
||||
const { secretName, type, ...el } = inputSecret;
|
||||
const references = getAllNestedSecretReferences(inputSecret.secretValue);
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
const secret = await secretDAL.transaction((tx) =>
|
||||
fnSecretBulkInsert({
|
||||
@@ -161,8 +160,12 @@ export const secretV2BridgeServiceFactory = ({
|
||||
version: 1,
|
||||
type,
|
||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue),
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedValue: el.secretValue
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||
: undefined,
|
||||
reminderNote: el.secretReminderNote,
|
||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||
key: secretName,
|
||||
@@ -179,7 +182,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
})
|
||||
);
|
||||
|
||||
await snapshotService.performSnapshot(folderId, true);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
await secretQueueService.syncSecrets({
|
||||
secretPath,
|
||||
actorId,
|
||||
@@ -274,14 +277,16 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const tags = inputSecret.tagIds ? await secretTagDAL.find({ projectId, $in: { id: inputSecret.tagIds } }) : [];
|
||||
if ((inputSecret.tagIds || []).length !== tags.length) throw new BadRequestError({ message: "Tag not found" });
|
||||
|
||||
const { secretName, secretValue, secretComment } = inputSecret;
|
||||
const { secretName, secretValue } = inputSecret;
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
const encryptedValue =
|
||||
typeof secretValue !== "undefined"
|
||||
? {
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretValue) as Buffer,
|
||||
encryptedValue: secretManagerEncryptor({ plainText: Buffer.from(secretValue) }).cipherTextBlob,
|
||||
references: getAllNestedSecretReferences(secretValue)
|
||||
}
|
||||
: {};
|
||||
@@ -294,7 +299,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
filter: { id: secretId },
|
||||
data: {
|
||||
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretComment),
|
||||
encryptedComment: inputSecret.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(inputSecret.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
reminderNote: inputSecret.secretReminderNote,
|
||||
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
||||
key: inputSecret.newSecretName || secretName,
|
||||
@@ -319,7 +326,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
projectId
|
||||
});
|
||||
|
||||
await snapshotService.performSnapshot(folderId, true);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
await secretQueueService.syncSecrets({
|
||||
actor,
|
||||
actorId,
|
||||
@@ -385,7 +392,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
})
|
||||
);
|
||||
|
||||
await snapshotService.performSnapshot(folderId, true);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
await secretQueueService.syncSecrets({
|
||||
actor,
|
||||
actorId,
|
||||
@@ -394,12 +401,18 @@ export const secretV2BridgeServiceFactory = ({
|
||||
environmentSlug: folder.environment.slug
|
||||
});
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
return reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||
...deletedSecret[0],
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, deletedSecret[0].encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, deletedSecret[0].encryptedComment)
|
||||
value: deletedSecret[0].encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: deletedSecret[0].encryptedValue }).toString()
|
||||
: undefined,
|
||||
comment: deletedSecret[0].encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: deletedSecret[0].encryptedComment }).toString()
|
||||
: undefined
|
||||
});
|
||||
};
|
||||
|
||||
@@ -463,8 +476,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
actorId
|
||||
);
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
if (includeImports) {
|
||||
const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId));
|
||||
@@ -486,15 +501,19 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secretDAL,
|
||||
folderDAL,
|
||||
secretImportDAL,
|
||||
decryptor: (value) => secretEncryptionHelper.decryptValue(secretManagerDecryptor, value)
|
||||
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined)
|
||||
});
|
||||
|
||||
return {
|
||||
secrets: secrets.map((secret) =>
|
||||
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
||||
...secret,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||
value: secret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString()
|
||||
: undefined,
|
||||
comment: secret.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString()
|
||||
: undefined
|
||||
})
|
||||
),
|
||||
imports: importedSecrets
|
||||
@@ -505,8 +524,12 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secrets: secrets.map((secret) =>
|
||||
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
||||
...secret,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||
value: secret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString()
|
||||
: undefined,
|
||||
comment: secret.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString()
|
||||
: undefined
|
||||
})
|
||||
)
|
||||
};
|
||||
@@ -553,8 +576,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secretType = SecretType.Shared;
|
||||
}
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
|
||||
const secret = await (version === undefined
|
||||
? secretDAL.findOneWithTags({
|
||||
@@ -571,9 +596,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
key: secretName
|
||||
})
|
||||
.then((el) => SecretsV2Schema.parse({ ...el, id: el.secretId })));
|
||||
|
||||
const interpolateInlineSecretReference = interpolateSecrets({
|
||||
projectId,
|
||||
decryptSecret: (encryptedValue) => secretEncryptionHelper.decryptValue(secretManagerDecryptor, encryptedValue),
|
||||
decryptSecret: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined),
|
||||
secretDAL,
|
||||
folderDAL
|
||||
});
|
||||
@@ -600,17 +626,17 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secretDAL,
|
||||
folderDAL,
|
||||
secretImportDAL,
|
||||
decryptor: (value) => secretEncryptionHelper.decryptValue(secretManagerDecryptor, value)
|
||||
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined)
|
||||
});
|
||||
|
||||
for (let i = importedSecrets.length - 1; i >= 0; i -= 1) {
|
||||
for (let j = 0; j < importedSecrets[i].secrets.length; j += 1) {
|
||||
if (secretName === importedSecrets[i].secrets[j].key) {
|
||||
const importedSecret = importedSecrets[i].secrets[j];
|
||||
let secretValue = secretEncryptionHelper.decryptValue(
|
||||
secretManagerDecryptor,
|
||||
importedSecret.encryptedValue
|
||||
);
|
||||
let secretValue = importedSecret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: importedSecret.encryptedValue }).toString()
|
||||
: undefined;
|
||||
|
||||
if (expandSecretReferences && secretValue) {
|
||||
const secretReferenceExpandedString = {
|
||||
[importedSecret.key]: { value: secretValue }
|
||||
@@ -623,7 +649,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
return reshapeBridgeSecret(projectId, importedSecrets[i].environment, importedSecrets[i].secretPath, {
|
||||
...importedSecret,
|
||||
value: secretValue,
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, importedSecret.encryptedComment)
|
||||
comment: importedSecret.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: importedSecret.encryptedComment }).toString()
|
||||
: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -631,7 +659,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
}
|
||||
if (!secret) throw new BadRequestError({ message: "Secret not found" });
|
||||
|
||||
let secretValue = secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue);
|
||||
let secretValue = secret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString()
|
||||
: undefined;
|
||||
if (expandSecretReferences && secretValue) {
|
||||
const secretReferenceExpandedString = {
|
||||
[secret.key]: { value: secretValue }
|
||||
@@ -644,7 +674,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
return reshapeBridgeSecret(projectId, environment, path, {
|
||||
...secret,
|
||||
value: secretValue,
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||
comment: secret.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString()
|
||||
: undefined
|
||||
});
|
||||
};
|
||||
|
||||
@@ -693,15 +725,19 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
||||
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { encryptor: secretManagerEncryptor, decryptor: secretManagerDecryptor } =
|
||||
await kmsService.createCipherPairWithDataKey({ type: KmsDataKey.SecretManager, projectId });
|
||||
|
||||
const newSecrets = await secretDAL.transaction(async (tx) =>
|
||||
fnSecretBulkInsert({
|
||||
inputSecrets: inputSecrets.map((el) => ({
|
||||
version: 1,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue),
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
encryptedValue: el.secretValue
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||
: undefined,
|
||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||
key: el.secretKey,
|
||||
tagIds: el.tagIds,
|
||||
@@ -717,7 +753,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
})
|
||||
);
|
||||
|
||||
await snapshotService.performSnapshot(folderId, true);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
await secretQueueService.syncSecrets({
|
||||
actor,
|
||||
actorId,
|
||||
@@ -726,12 +762,13 @@ export const secretV2BridgeServiceFactory = ({
|
||||
environmentSlug: folder.environment.slug
|
||||
});
|
||||
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
return newSecrets.map((el) =>
|
||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||
...el,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||
value: el.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString() : undefined,
|
||||
comment: el.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
||||
: undefined
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -799,8 +836,8 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
||||
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { encryptor: secretManagerEncryptor, decryptor: secretManagerDecryptor } =
|
||||
await kmsService.createCipherPairWithDataKey({ type: KmsDataKey.SecretManager, projectId });
|
||||
|
||||
const secrets = await secretDAL.transaction(async (tx) =>
|
||||
fnSecretBulkUpdate({
|
||||
@@ -811,7 +848,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const encryptedValue =
|
||||
typeof el.secretValue !== "undefined"
|
||||
? {
|
||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue) as Buffer,
|
||||
encryptedValue: secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob,
|
||||
references: getAllNestedSecretReferences(el.secretValue)
|
||||
}
|
||||
: {};
|
||||
@@ -819,7 +856,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
filter: { id: originalSecret.id, type: SecretType.Shared },
|
||||
data: {
|
||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||
encryptedComment: el.secretComment
|
||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
||||
: undefined,
|
||||
reminderNote: el.secretReminderNote,
|
||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||
key: el.newSecretName || el.secretKey,
|
||||
@@ -834,7 +873,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secretVersionTagDAL
|
||||
})
|
||||
);
|
||||
await snapshotService.performSnapshot(folderId, true);
|
||||
await snapshotService.performSnapshot(folderId);
|
||||
await secretQueueService.syncSecrets({
|
||||
actor,
|
||||
actorId,
|
||||
@@ -843,12 +882,13 @@ export const secretV2BridgeServiceFactory = ({
|
||||
environmentSlug: folder.environment.slug
|
||||
});
|
||||
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
return secrets.map((el) =>
|
||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||
...el,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||
value: el.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString() : undefined,
|
||||
comment: el.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
||||
: undefined
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -917,13 +957,17 @@ export const secretV2BridgeServiceFactory = ({
|
||||
environmentSlug: folder.environment.slug
|
||||
});
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
return secretsDeleted.map((el) =>
|
||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||
...el,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||
comment: secretEncryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||
value: el.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: el.encryptedValue }).toString() : undefined,
|
||||
comment: el.encryptedComment
|
||||
? secretManagerDecryptor({ cipherTextBlob: el.encryptedComment }).toString()
|
||||
: undefined
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -977,8 +1021,10 @@ export const secretV2BridgeServiceFactory = ({
|
||||
if (!hasRole(ProjectMembershipRole.Admin))
|
||||
throw new BadRequestError({ message: "Only admins are allowed to take this action" });
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
await secretDAL.transaction(async (tx) => {
|
||||
const secrets = await secretDAL.findAllProjectSecretValues(projectId, tx);
|
||||
await secretDAL.upsertSecretReferences(
|
||||
@@ -987,9 +1033,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
.map(({ id, encryptedValue }) => ({
|
||||
secretId: id,
|
||||
references: encryptedValue
|
||||
? getAllNestedSecretReferences(
|
||||
secretEncryptionHelper.decryptValue(secretManagerDecryptor, encryptedValue) as string
|
||||
)
|
||||
? getAllNestedSecretReferences(secretManagerDecryptor({ cipherTextBlob: encryptedValue }).toString())
|
||||
: []
|
||||
})),
|
||||
tx
|
||||
@@ -1067,11 +1111,15 @@ export const secretV2BridgeServiceFactory = ({
|
||||
});
|
||||
}
|
||||
|
||||
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
const decryptedSourceSecrets = sourceSecrets.map((secret) => ({
|
||||
...secret,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue)
|
||||
value: secret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString()
|
||||
: undefined
|
||||
}));
|
||||
|
||||
let isSourceUpdated = false;
|
||||
@@ -1090,7 +1138,9 @@ export const secretV2BridgeServiceFactory = ({
|
||||
const decryptedDestinationSecrets = destinationSecretsFromDB.map((secret) => {
|
||||
return {
|
||||
...secret,
|
||||
value: secretEncryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue)
|
||||
value: secret.encryptedValue
|
||||
? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString()
|
||||
: undefined
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1151,33 +1201,25 @@ export const secretV2BridgeServiceFactory = ({
|
||||
tx
|
||||
);
|
||||
|
||||
// TODO(akhilmhdh-sev2): fix this
|
||||
// const commits = locallyCreatedSecrets.concat(locallyUpdatedSecrets).map((doc) => {
|
||||
// const { operation } = doc;
|
||||
// const localSecret = destinationSecretsGroupedByKey[doc.key]?.[0];
|
||||
//
|
||||
// return {
|
||||
// op: operation,
|
||||
// requestId: approvalRequestDoc.id,
|
||||
// metadata: doc.metadata,
|
||||
// secretKeyIV: doc.secretKeyIV,
|
||||
// secretKeyTag: doc.secretKeyTag,
|
||||
// secretKeyCiphertext: doc.secretKeyCiphertext,
|
||||
// secretValueIV: doc.secretValueIV,
|
||||
// secretValueTag: doc.secretValueTag,
|
||||
// secretValueCiphertext: doc.secretValueCiphertext,
|
||||
// secretBlindIndex: doc.secretBlindIndex,
|
||||
// secretCommentIV: doc.secretCommentIV,
|
||||
// secretCommentTag: doc.secretCommentTag,
|
||||
// secretCommentCiphertext: doc.secretCommentCiphertext,
|
||||
// skipMultilineEncoding: doc.skipMultilineEncoding,
|
||||
// // except create operation other two needs the secret id and version id
|
||||
// ...(operation !== SecretOperations.Create
|
||||
// ? { secretId: localSecret.id, secretVersion: latestSecretVersions[localSecret.id].id }
|
||||
// : {})
|
||||
// };
|
||||
// });
|
||||
await secretApprovalRequestSecretDAL.insertMany([], tx);
|
||||
const commits = locallyCreatedSecrets.concat(locallyUpdatedSecrets).map((doc) => {
|
||||
const { operation } = doc;
|
||||
const localSecret = destinationSecretsGroupedByKey[doc.key]?.[0];
|
||||
|
||||
return {
|
||||
op: operation,
|
||||
requestId: approvalRequestDoc.id,
|
||||
metadata: doc.metadata,
|
||||
key: doc.key,
|
||||
encryptedValue: doc.encryptedValue,
|
||||
encryptedComment: doc.encryptedComment,
|
||||
skipMultilineEncoding: doc.skipMultilineEncoding,
|
||||
// except create operation other two needs the secret id and version id
|
||||
...(operation !== SecretOperations.Create
|
||||
? { secretId: localSecret.id, secretVersion: latestSecretVersions[localSecret.id].id }
|
||||
: {})
|
||||
};
|
||||
});
|
||||
await secretApprovalRequestSecretDAL.insertV2Bridge(commits, tx);
|
||||
} else {
|
||||
// apply changes directly
|
||||
if (locallyCreatedSecrets.length) {
|
||||
@@ -1268,34 +1310,24 @@ export const secretV2BridgeServiceFactory = ({
|
||||
tx
|
||||
);
|
||||
|
||||
// TODO(akhilmhdh-sev2): finish this
|
||||
// const commits = locallyDeletedSecrets.map((doc) => {
|
||||
// const { operation } = doc;
|
||||
// const localSecret = sourceSecretsGroupByKey[doc.key]?.[0];
|
||||
//
|
||||
// return {
|
||||
// op: operation,
|
||||
// keyEncoding: doc.keyEncoding,
|
||||
// algorithm: doc.algorithm,
|
||||
// requestId: approvalRequestDoc.id,
|
||||
// metadata: doc.metadata,
|
||||
// secretKeyIV: doc.secretKeyIV,
|
||||
// secretKeyTag: doc.secretKeyTag,
|
||||
// secretKeyCiphertext: doc.secretKeyCiphertext,
|
||||
// secretValueIV: doc.secretValueIV,
|
||||
// secretValueTag: doc.secretValueTag,
|
||||
// secretValueCiphertext: doc.secretValueCiphertext,
|
||||
// secretBlindIndex: doc.secretBlindIndex,
|
||||
// secretCommentIV: doc.secretCommentIV,
|
||||
// secretCommentTag: doc.secretCommentTag,
|
||||
// secretCommentCiphertext: doc.secretCommentCiphertext,
|
||||
// skipMultilineEncoding: doc.skipMultilineEncoding,
|
||||
// secretId: localSecret.id,
|
||||
// secretVersion: latestSecretVersions[localSecret.id].id
|
||||
// };
|
||||
// });
|
||||
const commits = locallyDeletedSecrets.map((doc) => {
|
||||
const { operation } = doc;
|
||||
const localSecret = sourceSecretsGroupByKey[doc.key]?.[0];
|
||||
|
||||
await secretApprovalRequestSecretDAL.insertMany([], tx);
|
||||
return {
|
||||
op: operation,
|
||||
requestId: approvalRequestDoc.id,
|
||||
metadata: doc.metadata,
|
||||
key: doc.key,
|
||||
encryptedComment: doc.encryptedComment,
|
||||
encryptedValue: doc.encryptedValue,
|
||||
skipMultilineEncoding: doc.skipMultilineEncoding,
|
||||
secretId: localSecret.id,
|
||||
secretVersion: latestSecretVersions[localSecret.id].id
|
||||
};
|
||||
});
|
||||
|
||||
await secretApprovalRequestSecretDAL.insertV2Bridge(commits, tx);
|
||||
} else {
|
||||
// if no secret approval policy is present, we delete directly.
|
||||
await secretDAL.delete(
|
||||
@@ -1313,7 +1345,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
});
|
||||
|
||||
if (isDestinationUpdated) {
|
||||
await snapshotService.performSnapshot(destinationFolder.id, true);
|
||||
await snapshotService.performSnapshot(destinationFolder.id);
|
||||
await secretQueueService.syncSecrets({
|
||||
projectId,
|
||||
secretPath: destinationFolder.path,
|
||||
@@ -1324,7 +1356,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
}
|
||||
|
||||
if (isSourceUpdated) {
|
||||
await snapshotService.performSnapshot(sourceFolder.id, true);
|
||||
await snapshotService.performSnapshot(sourceFolder.id);
|
||||
await secretQueueService.syncSecrets({
|
||||
projectId,
|
||||
secretPath: sourceFolder.path,
|
||||
|
||||
@@ -22,8 +22,14 @@ import {
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { groupBy, unique } from "@app/lib/fn";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import {
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
|
||||
import { ActorAuthMethod, ActorType } from "../auth/auth-type";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { getBotKeyFnFactory } from "../project-bot/project-bot-fns";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
@@ -39,12 +45,6 @@ import {
|
||||
TUpdateManySecretsRawFn,
|
||||
TUpdateManySecretsRawFnFactory
|
||||
} from "./secret-types";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import {
|
||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
||||
|
||||
export const generateSecretBlindIndexBySalt = async (secretName: string, secretBlindIndexDoc: TSecretBlindIndexes) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
@@ -18,6 +18,8 @@ import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
||||
import { TIntegrationDALFactory } from "../integration/integration-dal";
|
||||
import { TIntegrationAuthServiceFactory } from "../integration-auth/integration-auth-service";
|
||||
import { syncIntegrationSecrets } from "../integration-auth/integration-sync-secret";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
import { TOrgDALFactory } from "../org/org-dal";
|
||||
import { TProjectDALFactory } from "../project/project-dal";
|
||||
import { TProjectBotServiceFactory } from "../project-bot/project-bot-service";
|
||||
@@ -25,6 +27,9 @@ import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
import { TSecretImportDALFactory } from "../secret-import/secret-import-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "../secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "../secret-v2-bridge/secret-version-tag-dal";
|
||||
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
|
||||
import { TWebhookDALFactory } from "../webhook/webhook-dal";
|
||||
import { fnTriggerWebhook } from "../webhook/webhook-fns";
|
||||
@@ -36,10 +41,6 @@ import {
|
||||
TRemoveSecretReminderDTO,
|
||||
TSyncSecretsDTO
|
||||
} from "./secret-types";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "../secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "../secret-v2-bridge/secret-version-tag-dal";
|
||||
|
||||
export type TSecretQueueFactory = ReturnType<typeof secretQueueFactory>;
|
||||
type TSecretQueueFactoryDep = {
|
||||
@@ -557,6 +558,10 @@ export const secretQueueFactory = ({
|
||||
}
|
||||
|
||||
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(projectId);
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
projectId
|
||||
});
|
||||
let referencedFolderIds;
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
const secretReferences = await secretV2BridgeDAL.findReferencedSecretReferences(
|
||||
@@ -623,31 +628,44 @@ export const secretQueueFactory = ({
|
||||
projectId: integration.projectId
|
||||
};
|
||||
|
||||
const { accessToken, accessId } = await integrationAuthService.getIntegrationAccessToken(integrationAuth, botKey);
|
||||
const awsAssumeRoleArn =
|
||||
const { accessToken, accessId } = await integrationAuthService.getIntegrationAccessToken(
|
||||
integrationAuth,
|
||||
shouldUseSecretV2Bridge,
|
||||
botKey
|
||||
);
|
||||
let awsAssumeRoleArn = null;
|
||||
if (shouldUseSecretV2Bridge) {
|
||||
if (integrationAuth.awsAssumeIamRoleArnCipherText) {
|
||||
awsAssumeRoleArn = secretManagerDecryptor({
|
||||
cipherTextBlob: Buffer.from(integrationAuth.awsAssumeIamRoleArnCipherText)
|
||||
}).toString();
|
||||
}
|
||||
} else if (
|
||||
integrationAuth.awsAssumeIamRoleArnTag &&
|
||||
integrationAuth.awsAssumeIamRoleArnIV &&
|
||||
integrationAuth.awsAssumeIamRoleArnCipherText
|
||||
? decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: integrationAuth.awsAssumeIamRoleArnCipherText,
|
||||
iv: integrationAuth.awsAssumeIamRoleArnIV,
|
||||
tag: integrationAuth.awsAssumeIamRoleArnTag,
|
||||
key: botKey
|
||||
})
|
||||
: null;
|
||||
) {
|
||||
awsAssumeRoleArn = decryptSymmetric128BitHexKeyUTF8({
|
||||
ciphertext: integrationAuth.awsAssumeIamRoleArnCipherText,
|
||||
iv: integrationAuth.awsAssumeIamRoleArnIV,
|
||||
tag: integrationAuth.awsAssumeIamRoleArnTag,
|
||||
key: botKey as string
|
||||
});
|
||||
}
|
||||
|
||||
const secrets = shouldUseSecretV2Bridge
|
||||
? await getIntegrationSecretsV2({
|
||||
environment,
|
||||
projectId,
|
||||
folderId: folder.id,
|
||||
depth: 1
|
||||
depth: 1,
|
||||
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : "")
|
||||
})
|
||||
: await getIntegrationSecrets({
|
||||
environment,
|
||||
projectId,
|
||||
folderId: folder.id,
|
||||
key: botKey,
|
||||
key: botKey as string,
|
||||
depth: 1
|
||||
});
|
||||
const suffixedSecrets: typeof secrets = {};
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services
|
||||
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||
import { TSecretApprovalRequestDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-dal";
|
||||
import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-secret-dal";
|
||||
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import {
|
||||
@@ -73,7 +74,6 @@ import {
|
||||
} from "./secret-types";
|
||||
import { TSecretVersionDALFactory } from "./secret-version-dal";
|
||||
import { TSecretVersionTagDALFactory } from "./secret-version-tag-dal";
|
||||
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
||||
|
||||
type TSecretServiceFactoryDep = {
|
||||
secretDAL: TSecretDALFactory;
|
||||
|
||||
@@ -12,10 +12,10 @@ import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-fold
|
||||
import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal";
|
||||
|
||||
import { ActorType } from "../auth/auth-type";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal";
|
||||
import { TSecretVersionV2DALFactory } from "../secret-v2-bridge/secret-version-dal";
|
||||
import { TSecretVersionV2TagDALFactory } from "../secret-v2-bridge/secret-version-tag-dal";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
|
||||
type TPartialSecret = Pick<TSecrets, "id" | "secretReminderRepeatDays" | "secretReminderNote">;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user