mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 21:27:31 +00:00
feat: testing v2 architecture changes and corrections as needed
This commit is contained in:
@@ -128,7 +128,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
if (!hasEncryptedAccess) t.binary("encryptedAccess");
|
if (!hasEncryptedAccess) t.binary("encryptedAccess");
|
||||||
if (!hasEncryptedAccessId) t.binary("encryptedAccessId");
|
if (!hasEncryptedAccessId) t.binary("encryptedAccessId");
|
||||||
if (!hasEncryptedRefresh) t.binary("encryptedRefresh");
|
if (!hasEncryptedRefresh) t.binary("encryptedRefresh");
|
||||||
if (!hasEncryptedAwsIamAssumRole) t.binary("hasEncryptedAwsIamAssumRole");
|
if (!hasEncryptedAwsIamAssumRole) t.binary("encryptedAwsIamAssumRole");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
if (hasEncryptedAccess) t.dropColumn("encryptedAccess");
|
if (hasEncryptedAccess) t.dropColumn("encryptedAccess");
|
||||||
if (hasEncryptedAccessId) t.dropColumn("encryptedAccessId");
|
if (hasEncryptedAccessId) t.dropColumn("encryptedAccessId");
|
||||||
if (hasEncryptedRefresh) t.dropColumn("encryptedRefresh");
|
if (hasEncryptedRefresh) t.dropColumn("encryptedRefresh");
|
||||||
if (hasEncryptedAwsIamAssumRole) t.dropColumn("hasEncryptedAwsIamAssumRole");
|
if (hasEncryptedAwsIamAssumRole) t.dropColumn("encryptedAwsIamAssumRole");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const IntegrationAuthsSchema = z.object({
|
|||||||
encryptedAccess: zodBuffer.nullable().optional(),
|
encryptedAccess: zodBuffer.nullable().optional(),
|
||||||
encryptedAccessId: zodBuffer.nullable().optional(),
|
encryptedAccessId: zodBuffer.nullable().optional(),
|
||||||
encryptedRefresh: zodBuffer.nullable().optional(),
|
encryptedRefresh: zodBuffer.nullable().optional(),
|
||||||
hasEncryptedAwsIamAssumRole: zodBuffer.nullable().optional()
|
encryptedAwsIamAssumRole: zodBuffer.nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIntegrationAuths = z.infer<typeof IntegrationAuthsSchema>;
|
export type TIntegrationAuths = z.infer<typeof IntegrationAuthsSchema>;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
|
import { decryptSymmetric128BitHexKeyUTF8 } from "@app/lib/crypto";
|
||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { groupBy, pick, unique } from "@app/lib/fn";
|
import { groupBy, pick, unique } from "@app/lib/fn";
|
||||||
|
import { setKnexStringValue } from "@app/lib/knex";
|
||||||
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";
|
||||||
@@ -43,8 +44,7 @@ import {
|
|||||||
fnSecretBulkDelete as fnSecretV2BridgeBulkDelete,
|
fnSecretBulkDelete as fnSecretV2BridgeBulkDelete,
|
||||||
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
fnSecretBulkInsert as fnSecretV2BridgeBulkInsert,
|
||||||
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
fnSecretBulkUpdate as fnSecretV2BridgeBulkUpdate,
|
||||||
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge,
|
getAllNestedSecretReferences as getAllNestedSecretReferencesV2Bridge
|
||||||
secretEncryptionHelper
|
|
||||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
|
} 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";
|
||||||
@@ -1086,8 +1086,14 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
...createdSecrets.map((createdSecret) => ({
|
...createdSecrets.map((createdSecret) => ({
|
||||||
op: SecretOperations.Create,
|
op: SecretOperations.Create,
|
||||||
version: 1,
|
version: 1,
|
||||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, createdSecret.secretComment),
|
encryptedComment: setKnexStringValue(
|
||||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, createdSecret.secretValue),
|
createdSecret.secretComment,
|
||||||
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
|
encryptedValue: setKnexStringValue(
|
||||||
|
createdSecret.secretValue,
|
||||||
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
skipMultilineEncoding: createdSecret.skipMultilineEncoding,
|
skipMultilineEncoding: createdSecret.skipMultilineEncoding,
|
||||||
key: createdSecret.secretKey,
|
key: createdSecret.secretKey,
|
||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
@@ -1152,8 +1158,14 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
return {
|
return {
|
||||||
...latestSecretVersions[secretId],
|
...latestSecretVersions[secretId],
|
||||||
key: newSecretName || secretKey,
|
key: newSecretName || secretKey,
|
||||||
encryptedValue: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretValue) as Buffer,
|
encryptedComment: setKnexStringValue(
|
||||||
encryptedComment: secretEncryptionHelper.encryptValue(secretManagerEncryptor, secretComment) as Buffer,
|
secretComment,
|
||||||
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
|
encryptedValue: setKnexStringValue(
|
||||||
|
secretValue,
|
||||||
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
reminderRepeatDays,
|
reminderRepeatDays,
|
||||||
reminderNote,
|
reminderNote,
|
||||||
metadata,
|
metadata,
|
||||||
|
|||||||
@@ -12,3 +12,12 @@ export const stripUndefinedInWhere = <T extends object>(val: T): Exclude<T, unde
|
|||||||
});
|
});
|
||||||
return copy as Exclude<T, undefined>;
|
return copy as Exclude<T, undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if its undefined its skipped in knex
|
||||||
|
// if its empty string its set as null
|
||||||
|
// else pass to the required one
|
||||||
|
export const setKnexStringValue = <T>(value: string | null | undefined, cb: (arg: string) => T) => {
|
||||||
|
if (typeof value === "undefined") return;
|
||||||
|
if (value === "" || value === null) return null;
|
||||||
|
return cb(value);
|
||||||
|
};
|
||||||
|
|||||||
@@ -694,7 +694,6 @@ export const registerRoutes = async (
|
|||||||
integrationAuthDAL,
|
integrationAuthDAL,
|
||||||
integrationDAL,
|
integrationDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
projectBotDAL,
|
|
||||||
projectBotService,
|
projectBotService,
|
||||||
kmsService
|
kmsService
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ 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 { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
import { KmsDataKey } from "../kms/kms-types";
|
import { KmsDataKey } from "../kms/kms-types";
|
||||||
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";
|
||||||
import { TIntegrationAuthDALFactory } from "./integration-auth-dal";
|
import { TIntegrationAuthDALFactory } from "./integration-auth-dal";
|
||||||
@@ -55,7 +54,6 @@ type TIntegrationAuthServiceFactoryDep = {
|
|||||||
integrationAuthDAL: TIntegrationAuthDALFactory;
|
integrationAuthDAL: TIntegrationAuthDALFactory;
|
||||||
integrationDAL: Pick<TIntegrationDALFactory, "delete">;
|
integrationDAL: Pick<TIntegrationDALFactory, "delete">;
|
||||||
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
projectBotService: Pick<TProjectBotServiceFactory, "getBotKey">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
};
|
};
|
||||||
@@ -66,7 +64,6 @@ export const integrationAuthServiceFactory = ({
|
|||||||
permissionService,
|
permissionService,
|
||||||
integrationAuthDAL,
|
integrationAuthDAL,
|
||||||
integrationDAL,
|
integrationDAL,
|
||||||
projectBotDAL,
|
|
||||||
projectBotService,
|
projectBotService,
|
||||||
kmsService
|
kmsService
|
||||||
}: TIntegrationAuthServiceFactoryDep) => {
|
}: TIntegrationAuthServiceFactoryDep) => {
|
||||||
@@ -126,9 +123,6 @@ export const integrationAuthServiceFactory = ({
|
|||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
||||||
|
|
||||||
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
|
|
||||||
if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" });
|
|
||||||
|
|
||||||
const tokenExchange = await exchangeCode({ integration, code, url });
|
const tokenExchange = await exchangeCode({ integration, code, url });
|
||||||
const updateDoc: TIntegrationAuthsInsert = {
|
const updateDoc: TIntegrationAuthsInsert = {
|
||||||
projectId,
|
projectId,
|
||||||
@@ -217,9 +211,6 @@ export const integrationAuthServiceFactory = ({
|
|||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
||||||
|
|
||||||
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
|
|
||||||
if (!bot) throw new BadRequestError({ message: "Bot must be enabled for oauth2 code token exchange" });
|
|
||||||
|
|
||||||
const updateDoc: TIntegrationAuthsInsert = {
|
const updateDoc: TIntegrationAuthsInsert = {
|
||||||
projectId,
|
projectId,
|
||||||
namespace,
|
namespace,
|
||||||
@@ -278,7 +269,7 @@ export const integrationAuthServiceFactory = ({
|
|||||||
const awsAssumeIamRoleArnEncrypted = secretManagerEncryptor({
|
const awsAssumeIamRoleArnEncrypted = secretManagerEncryptor({
|
||||||
plainText: Buffer.from(awsAssumeIamRoleArn)
|
plainText: Buffer.from(awsAssumeIamRoleArn)
|
||||||
}).cipherTextBlob;
|
}).cipherTextBlob;
|
||||||
updateDoc.hasEncryptedAwsIamAssumRole = awsAssumeIamRoleArnEncrypted;
|
updateDoc.encryptedAwsIamAssumRole = awsAssumeIamRoleArnEncrypted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -338,7 +329,7 @@ export const integrationAuthServiceFactory = ({
|
|||||||
if (
|
if (
|
||||||
integrationAuth.integration === Integrations.AWS_SECRET_MANAGER &&
|
integrationAuth.integration === Integrations.AWS_SECRET_MANAGER &&
|
||||||
(shouldUseSecretV2Bridge
|
(shouldUseSecretV2Bridge
|
||||||
? integrationAuth.hasEncryptedAwsIamAssumRole
|
? integrationAuth.encryptedAwsIamAssumRole
|
||||||
: integrationAuth.awsAssumeIamRoleArnCipherText)
|
: integrationAuth.awsAssumeIamRoleArnCipherText)
|
||||||
) {
|
) {
|
||||||
return { accessToken: "", accessId: "" };
|
return { accessToken: "", accessId: "" };
|
||||||
|
|||||||
@@ -123,7 +123,11 @@ export const integrationDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("keyEncoding").withSchema(TableName.IntegrationAuth).as("keyEncodingAu"),
|
db.ref("keyEncoding").withSchema(TableName.IntegrationAuth).as("keyEncodingAu"),
|
||||||
db.ref("awsAssumeIamRoleArnCipherText").withSchema(TableName.IntegrationAuth),
|
db.ref("awsAssumeIamRoleArnCipherText").withSchema(TableName.IntegrationAuth),
|
||||||
db.ref("awsAssumeIamRoleArnIV").withSchema(TableName.IntegrationAuth),
|
db.ref("awsAssumeIamRoleArnIV").withSchema(TableName.IntegrationAuth),
|
||||||
db.ref("awsAssumeIamRoleArnTag").withSchema(TableName.IntegrationAuth)
|
db.ref("awsAssumeIamRoleArnTag").withSchema(TableName.IntegrationAuth),
|
||||||
|
db.ref("encryptedRefresh").withSchema(TableName.IntegrationAuth),
|
||||||
|
db.ref("encryptedAccess").withSchema(TableName.IntegrationAuth),
|
||||||
|
db.ref("encryptedAccessId").withSchema(TableName.IntegrationAuth),
|
||||||
|
db.ref("encryptedAwsIamAssumRole").withSchema(TableName.IntegrationAuth)
|
||||||
);
|
);
|
||||||
return docs.map(
|
return docs.map(
|
||||||
({
|
({
|
||||||
@@ -152,6 +156,10 @@ export const integrationDALFactory = (db: TDbClient) => {
|
|||||||
awsAssumeIamRoleArnIV,
|
awsAssumeIamRoleArnIV,
|
||||||
awsAssumeIamRoleArnCipherText,
|
awsAssumeIamRoleArnCipherText,
|
||||||
awsAssumeIamRoleArnTag,
|
awsAssumeIamRoleArnTag,
|
||||||
|
encryptedAccess,
|
||||||
|
encryptedRefresh,
|
||||||
|
encryptedAccessId,
|
||||||
|
encryptedAwsIamAssumRole,
|
||||||
...el
|
...el
|
||||||
}) => ({
|
}) => ({
|
||||||
...el,
|
...el,
|
||||||
@@ -183,7 +191,11 @@ export const integrationDALFactory = (db: TDbClient) => {
|
|||||||
accessExpiresAt,
|
accessExpiresAt,
|
||||||
awsAssumeIamRoleArnIV,
|
awsAssumeIamRoleArnIV,
|
||||||
awsAssumeIamRoleArnCipherText,
|
awsAssumeIamRoleArnCipherText,
|
||||||
awsAssumeIamRoleArnTag
|
awsAssumeIamRoleArnTag,
|
||||||
|
encryptedAccess,
|
||||||
|
encryptedRefresh,
|
||||||
|
encryptedAccessId,
|
||||||
|
encryptedAwsIamAssumRole
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ export const secretImportServiceFactory = ({
|
|||||||
|
|
||||||
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
const { botKey, shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.SecretManager,
|
type: KmsDataKey.SecretManager,
|
||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
@@ -507,8 +507,7 @@ export const secretImportServiceFactory = ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
secretDAL: secretV2BridgeDAL,
|
secretDAL: secretV2BridgeDAL,
|
||||||
secretImportDAL,
|
secretImportDAL,
|
||||||
decryptor: (value) =>
|
decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined)
|
||||||
value ? secretManagerEncryptor({ plainText: value }).cipherTextBlob.toString() : undefined
|
|
||||||
});
|
});
|
||||||
return importedSecrets;
|
return importedSecrets;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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";
|
||||||
@@ -204,7 +203,10 @@ export const fnSecretBulkUpdate = async ({
|
|||||||
tags !== undefined ? { tags, secretId: newSecrets[i].id } : []
|
tags !== undefined ? { tags, secretId: newSecrets[i].id } : []
|
||||||
);
|
);
|
||||||
if (secsUpdatedTag.length) {
|
if (secsUpdatedTag.length) {
|
||||||
await secretTagDAL.deleteTagsToSecretV2({ $in: { id: secsUpdatedTag.map(({ secretId }) => secretId) } }, tx);
|
await secretTagDAL.deleteTagsToSecretV2(
|
||||||
|
{ $in: { secrets_v2Id: secsUpdatedTag.map(({ secretId }) => secretId) } },
|
||||||
|
tx
|
||||||
|
);
|
||||||
const newSecretTags = secsUpdatedTag.flatMap(({ tags: secretTags = [], secretId }) =>
|
const newSecretTags = secsUpdatedTag.flatMap(({ tags: secretTags = [], secretId }) =>
|
||||||
secretTags.map((tag) => ({
|
secretTags.map((tag) => ({
|
||||||
[`${TableName.SecretTag}Id` as const]: tag,
|
[`${TableName.SecretTag}Id` as const]: tag,
|
||||||
@@ -552,14 +554,3 @@ export const reshapeBridgeSecret = (
|
|||||||
createdAt: secret.createdAt,
|
createdAt: secret.createdAt,
|
||||||
updatedAt: secret.updatedAt
|
updatedAt: secret.updatedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
export const secretEncryptionHelper = {
|
|
||||||
encryptValue: (encryptor: Awaited<ReturnType<TKmsServiceFactory["encryptWithKmsKey"]>>, value?: string) => {
|
|
||||||
if (typeof value === "undefined") return;
|
|
||||||
return encryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
|
|
||||||
},
|
|
||||||
decryptValue: (decryptor: Awaited<ReturnType<TKmsServiceFactory["decryptWithInputKey"]>>, value?: Buffer | null) => {
|
|
||||||
if (!value) return;
|
|
||||||
return decryptor({ cipherTextBlob: value }).toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-
|
|||||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { groupBy } from "@app/lib/fn";
|
import { groupBy } from "@app/lib/fn";
|
||||||
|
import { setKnexStringValue } from "@app/lib/knex";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
|
|
||||||
@@ -160,9 +161,10 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
version: 1,
|
version: 1,
|
||||||
type,
|
type,
|
||||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||||
encryptedComment: el.secretComment
|
encryptedComment: setKnexStringValue(
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
el.secretComment,
|
||||||
: undefined,
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
encryptedValue: el.secretValue
|
encryptedValue: el.secretValue
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -265,7 +267,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
if (inputSecret.newSecretName) {
|
if (inputSecret.newSecretName) {
|
||||||
const doesNewNameSecretExist = await secretDAL.findOne({
|
const doesNewNameSecretExist = await secretDAL.findOne({
|
||||||
key: inputSecret.secretName,
|
key: inputSecret.newSecretName,
|
||||||
type: SecretType.Shared,
|
type: SecretType.Shared,
|
||||||
folderId
|
folderId
|
||||||
});
|
});
|
||||||
@@ -299,9 +301,10 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
filter: { id: secretId },
|
filter: { id: secretId },
|
||||||
data: {
|
data: {
|
||||||
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
||||||
encryptedComment: inputSecret.secretComment
|
encryptedComment: setKnexStringValue(
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(inputSecret.secretComment) }).cipherTextBlob
|
inputSecret.secretComment,
|
||||||
: undefined,
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
reminderNote: inputSecret.secretReminderNote,
|
reminderNote: inputSecret.secretReminderNote,
|
||||||
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
||||||
key: inputSecret.newSecretName || secretName,
|
key: inputSecret.newSecretName || secretName,
|
||||||
@@ -732,9 +735,10 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
fnSecretBulkInsert({
|
fnSecretBulkInsert({
|
||||||
inputSecrets: inputSecrets.map((el) => ({
|
inputSecrets: inputSecrets.map((el) => ({
|
||||||
version: 1,
|
version: 1,
|
||||||
encryptedComment: el.secretComment
|
encryptedComment: setKnexStringValue(
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
el.secretComment,
|
||||||
: undefined,
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
encryptedValue: el.secretValue
|
encryptedValue: el.secretValue
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
? secretManagerEncryptor({ plainText: Buffer.from(el.secretValue) }).cipherTextBlob
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -821,7 +825,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
const secrets = await secretDAL.findBySecretKeys(
|
const secrets = await secretDAL.findBySecretKeys(
|
||||||
folderId,
|
folderId,
|
||||||
secretsWithNewName.map((el) => ({
|
secretsWithNewName.map((el) => ({
|
||||||
key: el.secretKey,
|
key: el.newSecretName as string,
|
||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
@@ -856,9 +860,10 @@ 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: el.secretComment
|
encryptedComment: setKnexStringValue(
|
||||||
? secretManagerEncryptor({ plainText: Buffer.from(el.secretComment) }).cipherTextBlob
|
el.secretComment,
|
||||||
: undefined,
|
(value) => secretManagerEncryptor({ plainText: Buffer.from(value) }).cipherTextBlob
|
||||||
|
),
|
||||||
reminderNote: el.secretReminderNote,
|
reminderNote: el.secretReminderNote,
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
key: el.newSecretName || el.secretKey,
|
key: el.newSecretName || el.secretKey,
|
||||||
|
|||||||
@@ -635,9 +635,9 @@ export const secretQueueFactory = ({
|
|||||||
);
|
);
|
||||||
let awsAssumeRoleArn = null;
|
let awsAssumeRoleArn = null;
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
if (integrationAuth.awsAssumeIamRoleArnCipherText) {
|
if (integrationAuth.encryptedAwsIamAssumRole) {
|
||||||
awsAssumeRoleArn = secretManagerDecryptor({
|
awsAssumeRoleArn = secretManagerDecryptor({
|
||||||
cipherTextBlob: Buffer.from(integrationAuth.awsAssumeIamRoleArnCipherText)
|
cipherTextBlob: Buffer.from(integrationAuth.encryptedAwsIamAssumRole)
|
||||||
}).toString();
|
}).toString();
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
|||||||
@@ -1,50 +1,39 @@
|
|||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { Button, Modal, ModalContent } from "@app/components/v2";
|
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
import { withProjectPermission } from "@app/hoc";
|
import { withProjectPermission } from "@app/hoc";
|
||||||
import { usePopUp } from "@app/hooks";
|
|
||||||
import {
|
import {
|
||||||
useDeleteIntegration,
|
useDeleteIntegration,
|
||||||
useDeleteIntegrationAuths,
|
useDeleteIntegrationAuths,
|
||||||
useGetCloudIntegrations,
|
useGetCloudIntegrations,
|
||||||
useGetUserWsKey,
|
|
||||||
useGetWorkspaceAuthorizations,
|
useGetWorkspaceAuthorizations,
|
||||||
useGetWorkspaceBot,
|
useGetWorkspaceIntegrations
|
||||||
useGetWorkspaceIntegrations,
|
|
||||||
useUpdateBotActiveStatus
|
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { IntegrationAuth } from "@app/hooks/api/types";
|
import { IntegrationAuth } from "@app/hooks/api/types";
|
||||||
import { ProjectVersion } from "@app/hooks/api/workspace/types";
|
|
||||||
|
|
||||||
import { CloudIntegrationSection } from "./components/CloudIntegrationSection";
|
import { CloudIntegrationSection } from "./components/CloudIntegrationSection";
|
||||||
import { FrameworkIntegrationSection } from "./components/FrameworkIntegrationSection";
|
import { FrameworkIntegrationSection } from "./components/FrameworkIntegrationSection";
|
||||||
import { InfrastructureIntegrationSection } from "./components/InfrastructureIntegrationSection/InfrastructureIntegrationSection";
|
import { InfrastructureIntegrationSection } from "./components/InfrastructureIntegrationSection/InfrastructureIntegrationSection";
|
||||||
import { IntegrationsSection } from "./components/IntegrationsSection";
|
import { IntegrationsSection } from "./components/IntegrationsSection";
|
||||||
import { generateBotKey, redirectForProviderAuth } from "./IntegrationPage.utils";
|
import { redirectForProviderAuth } from "./IntegrationPage.utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
frameworkIntegrations: Array<{ name: string; slug: string; image: string; docsLink: string }>;
|
frameworkIntegrations: Array<{ name: string; slug: string; image: string; docsLink: string }>;
|
||||||
infrastructureIntegrations: Array<{ name: string; slug: string; image: string; docsLink: string }>;
|
infrastructureIntegrations: Array<{
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
image: string;
|
||||||
|
docsLink: string;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IntegrationsPage = withProjectPermission(
|
export const IntegrationsPage = withProjectPermission(
|
||||||
({ frameworkIntegrations, infrastructureIntegrations }: Props) => {
|
({ frameworkIntegrations, infrastructureIntegrations }: Props) => {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
|
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const workspaceId = currentWorkspace?.id || "";
|
const workspaceId = currentWorkspace?.id || "";
|
||||||
const environments = currentWorkspace?.environments || [];
|
const environments = currentWorkspace?.environments || [];
|
||||||
|
|
||||||
const { data: latestWsKey } = useGetUserWsKey(workspaceId);
|
|
||||||
|
|
||||||
const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([
|
|
||||||
"activeBot"
|
|
||||||
] as const);
|
|
||||||
|
|
||||||
const { data: cloudIntegrations, isLoading: isCloudIntegrationsLoading } =
|
const { data: cloudIntegrations, isLoading: isCloudIntegrationsLoading } =
|
||||||
useGetCloudIntegrations();
|
useGetCloudIntegrations();
|
||||||
|
|
||||||
@@ -70,11 +59,6 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
isFetching: isIntegrationFetching
|
isFetching: isIntegrationFetching
|
||||||
} = useGetWorkspaceIntegrations(workspaceId);
|
} = useGetWorkspaceIntegrations(workspaceId);
|
||||||
|
|
||||||
const { data: bot } = useGetWorkspaceBot(workspaceId);
|
|
||||||
|
|
||||||
// mutation
|
|
||||||
const { mutateAsync: updateBotActiveStatus, mutate: updateBotActiveStatusSync } =
|
|
||||||
useUpdateBotActiveStatus();
|
|
||||||
const { mutateAsync: deleteIntegration } = useDeleteIntegration();
|
const { mutateAsync: deleteIntegration } = useDeleteIntegration();
|
||||||
const {
|
const {
|
||||||
mutateAsync: deleteIntegrationAuths,
|
mutateAsync: deleteIntegrationAuths,
|
||||||
@@ -95,12 +79,6 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
isIntegrationsAuthorizedEmpty &&
|
isIntegrationsAuthorizedEmpty &&
|
||||||
isIntegrationsEmpty
|
isIntegrationsEmpty
|
||||||
) {
|
) {
|
||||||
if (bot?.id && currentWorkspace?.version === ProjectVersion.V1)
|
|
||||||
updateBotActiveStatusSync({
|
|
||||||
isActive: false,
|
|
||||||
botId: bot.id,
|
|
||||||
workspaceId
|
|
||||||
});
|
|
||||||
resetDeleteIntegrationAuths();
|
resetDeleteIntegrationAuths();
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
@@ -116,16 +94,6 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
if (!selectedCloudIntegration) return;
|
if (!selectedCloudIntegration) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (bot && !bot.isActive && currentWorkspace?.version === ProjectVersion.V1) {
|
|
||||||
const botKey = generateBotKey(bot.publicKey, latestWsKey!);
|
|
||||||
await updateBotActiveStatus({
|
|
||||||
workspaceId,
|
|
||||||
botKey,
|
|
||||||
isActive: true,
|
|
||||||
botId: bot.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectForProviderAuth(selectedCloudIntegration);
|
redirectForProviderAuth(selectedCloudIntegration);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -135,19 +103,9 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
// function to strat integration for a provider
|
// function to strat integration for a provider
|
||||||
// confirmation to user passing the bot key for provider to get secret access
|
// confirmation to user passing the bot key for provider to get secret access
|
||||||
const handleProviderIntegrationStart = (provider: string) => {
|
const handleProviderIntegrationStart = (provider: string) => {
|
||||||
if (!bot?.isActive) {
|
|
||||||
handlePopUpOpen("activeBot", { provider });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handleProviderIntegration(provider);
|
handleProviderIntegration(provider);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUserAcceptBotCondition = () => {
|
|
||||||
const { provider } = popUp.activeBot?.data as { provider: string };
|
|
||||||
handleProviderIntegration(provider);
|
|
||||||
handlePopUpClose("activeBot");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleIntegrationDelete = async (integrationId: string, cb: () => void) => {
|
const handleIntegrationDelete = async (integrationId: string, cb: () => void) => {
|
||||||
try {
|
try {
|
||||||
await deleteIntegration({ id: integrationId, workspaceId });
|
await deleteIntegration({ id: integrationId, workspaceId });
|
||||||
@@ -195,7 +153,6 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
integrations={integrations}
|
integrations={integrations}
|
||||||
environments={environments}
|
environments={environments}
|
||||||
onIntegrationDelete={({ id }, cb) => handleIntegrationDelete(id, cb)}
|
onIntegrationDelete={({ id }, cb) => handleIntegrationDelete(id, cb)}
|
||||||
isBotActive={bot?.isActive}
|
|
||||||
workspaceId={workspaceId}
|
workspaceId={workspaceId}
|
||||||
/>
|
/>
|
||||||
<CloudIntegrationSection
|
<CloudIntegrationSection
|
||||||
@@ -205,30 +162,6 @@ export const IntegrationsPage = withProjectPermission(
|
|||||||
onIntegrationStart={handleProviderIntegrationStart}
|
onIntegrationStart={handleProviderIntegrationStart}
|
||||||
onIntegrationRevoke={handleIntegrationAuthRevoke}
|
onIntegrationRevoke={handleIntegrationAuthRevoke}
|
||||||
/>
|
/>
|
||||||
<Modal
|
|
||||||
isOpen={popUp.activeBot?.isOpen}
|
|
||||||
onOpenChange={(isOpen) => handlePopUpToggle("activeBot", isOpen)}
|
|
||||||
>
|
|
||||||
<ModalContent
|
|
||||||
title={t("integrations.grant-access-to-secrets") as string}
|
|
||||||
footerContent={
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Button onClick={() => handleUserAcceptBotCondition()}>
|
|
||||||
{t("integrations.grant-access-button") as string}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => handlePopUpClose("activeBot")}
|
|
||||||
variant="outline_bg"
|
|
||||||
colorSchema="secondary"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("integrations.why-infisical-needs-access")}
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
<FrameworkIntegrationSection frameworks={frameworkIntegrations} />
|
<FrameworkIntegrationSection frameworks={frameworkIntegrations} />
|
||||||
<InfrastructureIntegrationSection integrations={infrastructureIntegrations} />
|
<InfrastructureIntegrationSection integrations={infrastructureIntegrations} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-21
@@ -1,4 +1,3 @@
|
|||||||
import Link from "next/link";
|
|
||||||
import { faCalendarCheck } from "@fortawesome/free-regular-svg-icons";
|
import { faCalendarCheck } from "@fortawesome/free-regular-svg-icons";
|
||||||
import { faArrowRight, faRefresh, faWarning, faXmark } from "@fortawesome/free-solid-svg-icons";
|
import { faArrowRight, faRefresh, faWarning, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
@@ -7,8 +6,6 @@ import { integrationSlugNameMapping } from "public/data/frequentConstants";
|
|||||||
|
|
||||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import {
|
import {
|
||||||
Alert,
|
|
||||||
AlertDescription,
|
|
||||||
Button,
|
Button,
|
||||||
DeleteActionModal,
|
DeleteActionModal,
|
||||||
EmptyState,
|
EmptyState,
|
||||||
@@ -29,7 +26,6 @@ type Props = {
|
|||||||
integrations?: TIntegration[];
|
integrations?: TIntegration[];
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
onIntegrationDelete: (integration: TIntegration, cb: () => void) => void;
|
onIntegrationDelete: (integration: TIntegration, cb: () => void) => void;
|
||||||
isBotActive: boolean | undefined;
|
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,7 +34,6 @@ export const IntegrationsSection = ({
|
|||||||
environments = [],
|
environments = [],
|
||||||
isLoading,
|
isLoading,
|
||||||
onIntegrationDelete,
|
onIntegrationDelete,
|
||||||
isBotActive,
|
|
||||||
workspaceId
|
workspaceId
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||||
@@ -59,21 +54,7 @@ export const IntegrationsSection = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isBotActive && Boolean(integrations.length) && (
|
{!isLoading && !integrations.length && (
|
||||||
<div className="px-6 py-4">
|
|
||||||
<Alert hideTitle variant="warning">
|
|
||||||
<AlertDescription>
|
|
||||||
All the active integrations will be disabled. Disable End-to-End Encryption in{" "}
|
|
||||||
<Link href={`/project/${workspaceId}/settings`} passHref>
|
|
||||||
<a className="underline underline-offset-2">project settings </a>
|
|
||||||
</Link>
|
|
||||||
to re-enable it.
|
|
||||||
</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isLoading && !integrations.length && isBotActive && (
|
|
||||||
<div className="mx-6">
|
<div className="mx-6">
|
||||||
<EmptyState
|
<EmptyState
|
||||||
className="rounded-md border border-mineshaft-700 pt-8 pb-4"
|
className="rounded-md border border-mineshaft-700 pt-8 pb-4"
|
||||||
@@ -81,7 +62,7 @@ export const IntegrationsSection = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isLoading && isBotActive && (
|
{!isLoading && (
|
||||||
<div className="flex min-w-max flex-col space-y-4 p-6 pt-0">
|
<div className="flex min-w-max flex-col space-y-4 p-6 pt-0">
|
||||||
{integrations?.map((integration) => (
|
{integrations?.map((integration) => (
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user