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