mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 14:27:23 +00:00
feat: changed backend-pg to backend
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName, TIntegrations } from "@app/db/schemas";
|
||||
import { DatabaseError } from "@app/lib/errors";
|
||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||
|
||||
export type TIntegrationDALFactory = ReturnType<typeof integrationDALFactory>;
|
||||
|
||||
export const integrationDALFactory = (db: TDbClient) => {
|
||||
const integrationOrm = ormify(db, TableName.Integration);
|
||||
|
||||
const integrationFindQuery = (tx: Knex, filter: Partial<TIntegrations>) =>
|
||||
tx(TableName.Integration)
|
||||
.where(filter)
|
||||
.join(TableName.Environment, `${TableName.Integration}.envId`, `${TableName.Environment}.id`)
|
||||
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||
.select(tx.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||
.select(tx.ref("projectId").withSchema(TableName.Environment))
|
||||
.select(selectAllTableCols(TableName.Integration));
|
||||
|
||||
const find = async (filter: Partial<TIntegrations>, tx?: Knex) => {
|
||||
try {
|
||||
const docs = await integrationFindQuery(tx || db, filter);
|
||||
return docs.map(({ envId, envSlug, envName, ...el }) => ({
|
||||
...el,
|
||||
environment: {
|
||||
id: envId,
|
||||
slug: envSlug,
|
||||
name: envName
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find by id integrations" });
|
||||
}
|
||||
};
|
||||
|
||||
const findOne = async (filter: Partial<TIntegrations>, tx?: Knex) => {
|
||||
try {
|
||||
const doc = await integrationFindQuery(tx || db, filter).first();
|
||||
if (!doc) return;
|
||||
|
||||
const { envName: name, envSlug: slug, envId: id, ...el } = doc;
|
||||
return { ...el, environment: { id, name, slug } };
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find one integrations" });
|
||||
}
|
||||
};
|
||||
|
||||
const findById = async (id: string, tx?: Knex) => {
|
||||
try {
|
||||
const doc = await integrationFindQuery(tx || db, {
|
||||
[`${TableName.Integration}.id` as "id"]: id
|
||||
}).first();
|
||||
if (!doc) return;
|
||||
|
||||
const { envName: name, envSlug: slug, envId, ...el } = doc;
|
||||
return { ...el, environment: { id: envId, name, slug } };
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find by id integrations" });
|
||||
}
|
||||
};
|
||||
|
||||
const findByProjectId = async (projectId: string, tx?: Knex) => {
|
||||
try {
|
||||
const integrations = await (tx || db)(TableName.Integration)
|
||||
.where(`${TableName.Environment}.projectId`, projectId)
|
||||
.join(
|
||||
TableName.Environment,
|
||||
`${TableName.Integration}.envId`,
|
||||
`${TableName.Environment}.id`
|
||||
)
|
||||
.select(db.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||
.select(db.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||
.select(db.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||
.select(db.ref("projectId").withSchema(TableName.Environment))
|
||||
.select(selectAllTableCols(TableName.Integration));
|
||||
|
||||
return integrations.map(({ envId, envSlug, envName, ...el }) => ({
|
||||
...el,
|
||||
envId,
|
||||
environment: {
|
||||
id: envId,
|
||||
slug: envSlug,
|
||||
name: envName
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "FindByProjectId" });
|
||||
}
|
||||
};
|
||||
|
||||
// used for syncing secrets
|
||||
// this will populate integration auth also
|
||||
const findByProjectIdV2 = async (projectId: string, environment: string, tx?: Knex) => {
|
||||
const docs = await (tx || db)(TableName.Integration)
|
||||
.where(`${TableName.Environment}.projectId`, projectId)
|
||||
.where("isActive", true)
|
||||
.where(`${TableName.Environment}.slug`, environment)
|
||||
.join(TableName.Environment, `${TableName.Integration}.envId`, `${TableName.Environment}.id`)
|
||||
.join(
|
||||
TableName.IntegrationAuth,
|
||||
`${TableName.IntegrationAuth}.id`,
|
||||
`${TableName.Integration}.integrationAuthId`
|
||||
)
|
||||
.select(db.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||
.select(db.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||
.select(db.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||
.select(db.ref("projectId").withSchema(TableName.Environment))
|
||||
.select(selectAllTableCols(TableName.Integration))
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.IntegrationAuth).as("idAu"),
|
||||
db.ref("integration").withSchema(TableName.IntegrationAuth).as("integrationAu"),
|
||||
db.ref("teamId").withSchema(TableName.IntegrationAuth).as("teamIdAu"),
|
||||
db.ref("url").withSchema(TableName.IntegrationAuth).as("urlAu"),
|
||||
db.ref("namespace").withSchema(TableName.IntegrationAuth).as("namespaceAu"),
|
||||
db.ref("accountId").withSchema(TableName.IntegrationAuth).as("accountIdAu"),
|
||||
db.ref("refreshCiphertext").withSchema(TableName.IntegrationAuth).as("refreshCiphertextAu"),
|
||||
db.ref("refreshIV").withSchema(TableName.IntegrationAuth).as("refreshIVAu"),
|
||||
db.ref("refreshTag").withSchema(TableName.IntegrationAuth).as("refreshTagAu"),
|
||||
db
|
||||
.ref("accessIdCiphertext")
|
||||
.withSchema(TableName.IntegrationAuth)
|
||||
.as("accessIdCiphertextAu"),
|
||||
db.ref("accessIdIV").withSchema(TableName.IntegrationAuth).as("accessIdIVAu"),
|
||||
db.ref("accessIdTag").withSchema(TableName.IntegrationAuth).as("accessIdTagAu"),
|
||||
db.ref("accessIV").withSchema(TableName.IntegrationAuth).as("accessIVAu"),
|
||||
db.ref("accessTag").withSchema(TableName.IntegrationAuth).as("accessTagAu"),
|
||||
db.ref("accessCiphertext").withSchema(TableName.IntegrationAuth).as("accessCiphertextAu"),
|
||||
db.ref("accessExpiresAt").withSchema(TableName.IntegrationAuth).as("accessExpiresAtAu"),
|
||||
db.ref("metadata").withSchema(TableName.IntegrationAuth).as("metadataAu"),
|
||||
db.ref("algorithm").withSchema(TableName.IntegrationAuth).as("algorithmAu"),
|
||||
db.ref("keyEncoding").withSchema(TableName.IntegrationAuth).as("keyEncodingAu")
|
||||
);
|
||||
return docs.map(
|
||||
({
|
||||
envId,
|
||||
envName,
|
||||
envSlug,
|
||||
idAu: id,
|
||||
integrationAu: integration,
|
||||
teamIdAu: teamId,
|
||||
urlAu: url,
|
||||
namespaceAu: namespace,
|
||||
accountIdAu: accountId,
|
||||
refreshIVAu: refreshIV,
|
||||
refreshCiphertextAu: refreshCiphertext,
|
||||
refreshTagAu: refreshTag,
|
||||
accessIVAu: accessIV,
|
||||
accessCiphertextAu: accessCiphertext,
|
||||
accessTagAu: accessTag,
|
||||
accessIdIVAu: accessIdIV,
|
||||
accessIdTagAu: accessIdTag,
|
||||
accessIdCiphertextAu: accessIdCiphertext,
|
||||
metadataAu: metadata,
|
||||
algorithmAu: algorithm,
|
||||
keyEncodingAu: keyEncoding,
|
||||
accessExpiresAtAu: accessExpiresAt,
|
||||
...el
|
||||
}) => ({
|
||||
...el,
|
||||
envId,
|
||||
environment: {
|
||||
id: envId,
|
||||
name: envName,
|
||||
slug: envSlug
|
||||
},
|
||||
integrationAuth: {
|
||||
id,
|
||||
integration,
|
||||
teamId,
|
||||
url,
|
||||
namespace,
|
||||
accountId,
|
||||
refreshTag,
|
||||
refreshIV,
|
||||
refreshCiphertext,
|
||||
accessIdCiphertext,
|
||||
accessIdIV,
|
||||
accessIdTag,
|
||||
accessIV,
|
||||
accessCiphertext,
|
||||
accessTag,
|
||||
metadata,
|
||||
algorithm,
|
||||
keyEncoding,
|
||||
accessExpiresAt
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return { ...integrationOrm, find, findOne, findById, findByProjectId, findByProjectIdV2 };
|
||||
};
|
||||
@@ -0,0 +1,180 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/ee/services/permission/project-permission";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
|
||||
import { TIntegrationAuthDALFactory } from "../integration-auth/integration-auth-dal";
|
||||
import { TSecretQueueFactory } from "../secret/secret-queue";
|
||||
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
|
||||
import { TIntegrationDALFactory } from "./integration-dal";
|
||||
import {
|
||||
TCreateIntegrationDTO,
|
||||
TDeleteIntegrationDTO,
|
||||
TUpdateIntegrationDTO
|
||||
} from "./integration-types";
|
||||
|
||||
type TIntegrationServiceFactoryDep = {
|
||||
integrationDAL: TIntegrationDALFactory;
|
||||
integrationAuthDAL: TIntegrationAuthDALFactory;
|
||||
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
secretQueueService: Pick<TSecretQueueFactory, "syncIntegrations">;
|
||||
};
|
||||
|
||||
export type TIntegrationServiceFactory = ReturnType<typeof integrationServiceFactory>;
|
||||
|
||||
export const integrationServiceFactory = ({
|
||||
integrationDAL,
|
||||
integrationAuthDAL,
|
||||
folderDAL,
|
||||
permissionService,
|
||||
secretQueueService
|
||||
}: TIntegrationServiceFactoryDep) => {
|
||||
const createIntegration = async ({
|
||||
app,
|
||||
actor,
|
||||
path,
|
||||
appId,
|
||||
owner,
|
||||
scope,
|
||||
actorId,
|
||||
region,
|
||||
isActive,
|
||||
metadata,
|
||||
secretPath,
|
||||
targetService,
|
||||
targetServiceId,
|
||||
integrationAuthId,
|
||||
sourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId
|
||||
}: TCreateIntegrationDTO) => {
|
||||
const integrationAuth = await integrationAuthDAL.findById(integrationAuthId);
|
||||
if (!integrationAuth) throw new BadRequestError({ message: "Integration auth not found" });
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
integrationAuth.projectId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.Integrations
|
||||
);
|
||||
|
||||
const folder = await folderDAL.findBySecretPath(
|
||||
integrationAuth.projectId,
|
||||
sourceEnvironment,
|
||||
secretPath
|
||||
);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder path not found" });
|
||||
|
||||
const integration = await integrationDAL.create({
|
||||
envId: folder.envId,
|
||||
secretPath,
|
||||
isActive,
|
||||
integrationAuthId,
|
||||
targetEnvironmentId,
|
||||
targetEnvironment,
|
||||
targetServiceId,
|
||||
targetService,
|
||||
metadata,
|
||||
region,
|
||||
scope,
|
||||
owner,
|
||||
appId,
|
||||
path,
|
||||
app,
|
||||
integration: integrationAuth.integration
|
||||
});
|
||||
|
||||
await secretQueueService.syncIntegrations({
|
||||
environment: sourceEnvironment,
|
||||
secretPath,
|
||||
projectId: integrationAuth.projectId
|
||||
});
|
||||
return { integration, integrationAuth };
|
||||
};
|
||||
|
||||
const updateIntegration = async ({
|
||||
actorId,
|
||||
actor,
|
||||
targetEnvironment,
|
||||
app,
|
||||
id,
|
||||
appId,
|
||||
owner,
|
||||
isActive,
|
||||
environment,
|
||||
secretPath
|
||||
}: TUpdateIntegrationDTO) => {
|
||||
const integration = await integrationDAL.findById(id);
|
||||
if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
integration.projectId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSub.Integrations
|
||||
);
|
||||
|
||||
const folder = await folderDAL.findBySecretPath(integration.projectId, environment, secretPath);
|
||||
if (!folder) throw new BadRequestError({ message: "Folder path not found" });
|
||||
|
||||
const updatedIntegration = await integrationDAL.updateById(id, {
|
||||
envId: folder.envId,
|
||||
isActive,
|
||||
app,
|
||||
appId,
|
||||
targetEnvironment,
|
||||
owner,
|
||||
secretPath
|
||||
});
|
||||
|
||||
return updatedIntegration;
|
||||
};
|
||||
|
||||
const deleteIntegration = async ({ actorId, id, actor }: TDeleteIntegrationDTO) => {
|
||||
const integration = await integrationDAL.findById(id);
|
||||
if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
integration.projectId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.Integrations
|
||||
);
|
||||
|
||||
const deletedIntegration = await integrationDAL.deleteById(id);
|
||||
return { ...integration, ...deletedIntegration };
|
||||
};
|
||||
|
||||
const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => {
|
||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.Integrations
|
||||
);
|
||||
|
||||
const integrations = await integrationDAL.findByProjectId(projectId);
|
||||
return integrations;
|
||||
};
|
||||
|
||||
return {
|
||||
createIntegration,
|
||||
updateIntegration,
|
||||
deleteIntegration,
|
||||
listIntegrationByProject
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
|
||||
export type TCreateIntegrationDTO = {
|
||||
secretPath: string;
|
||||
integrationAuthId: string;
|
||||
app?: string;
|
||||
isActive: boolean;
|
||||
appId?: string;
|
||||
sourceEnvironment: string;
|
||||
targetEnvironment?: string;
|
||||
targetEnvironmentId?: string;
|
||||
targetService?: string;
|
||||
targetServiceId?: string;
|
||||
owner?: string;
|
||||
path?: string;
|
||||
region?: string;
|
||||
scope?: string;
|
||||
metadata?: {
|
||||
secretPrefix?: string;
|
||||
secretSuffix?: string;
|
||||
secretGCPLabel?: {
|
||||
labelName: string;
|
||||
labelValue: string;
|
||||
};
|
||||
};
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TUpdateIntegrationDTO = {
|
||||
id: string;
|
||||
app: string;
|
||||
appId: string;
|
||||
isActive?: boolean;
|
||||
secretPath: string;
|
||||
targetEnvironment: string;
|
||||
owner: string;
|
||||
environment: string;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TDeleteIntegrationDTO = {
|
||||
id: string;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
Reference in New Issue
Block a user