feat: changed the whole api from projectid to slug

This commit is contained in:
Akhil Mohan
2024-03-22 14:18:12 +05:30
parent 70fe80414d
commit e3e62430ba
28 changed files with 357 additions and 165 deletions
@@ -1,10 +1,71 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
import { DynamicSecretLeasesSchema, TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify, selectAllTableCols } from "@app/lib/knex";
export type TDynamicSecretLeaseDALFactory = ReturnType<typeof dynamicSecretLeaseDALFactory>;
export const dynamicSecretLeaseDALFactory = (db: TDbClient) => {
const orm = ormify(db, TableName.DynamicSecretLease);
return orm;
const findById = async (id: string, tx?: Knex) => {
try {
const doc = await (tx || db)(TableName.DynamicSecretLease)
.where({ id })
.first()
.join(
TableName.DynamicSecret,
`${TableName.DynamicSecretLease}.dynamicSecretId`,
`${TableName.DynamicSecret}.id`
)
.select(selectAllTableCols(TableName.DynamicSecretLease))
.select(
db.ref("id").withSchema(TableName.DynamicSecret).as("dynId"),
db.ref("slug").withSchema(TableName.DynamicSecret).as("dynSlug"),
db.ref("version").withSchema(TableName.DynamicSecret).as("dynVersion"),
db.ref("type").withSchema(TableName.DynamicSecret).as("dynType"),
db.ref("defaultTTL").withSchema(TableName.DynamicSecret).as("dynDefaultTTL"),
db.ref("maxTTL").withSchema(TableName.DynamicSecret).as("dynMaxTTL"),
db.ref("inputIV").withSchema(TableName.DynamicSecret).as("dynInputIV"),
db.ref("inputTag").withSchema(TableName.DynamicSecret).as("dynInputTag"),
db.ref("inputCiphertext").withSchema(TableName.DynamicSecret).as("dynInputCiphertext"),
db.ref("algorithm").withSchema(TableName.DynamicSecret).as("dynAlgorithm"),
db.ref("keyEncoding").withSchema(TableName.DynamicSecret).as("dynKeyEncoding"),
db.ref("folderId").withSchema(TableName.DynamicSecret).as("dynFolderId"),
db.ref("status").withSchema(TableName.DynamicSecret).as("dynStatus"),
db.ref("statusDetails").withSchema(TableName.DynamicSecret).as("dynStatusDetails"),
db.ref("createdAt").withSchema(TableName.DynamicSecret).as("dynCreatedAt"),
db.ref("updatedAt").withSchema(TableName.DynamicSecret).as("dynUpdatedAt")
);
if (!doc) return;
return {
...DynamicSecretLeasesSchema.parse(doc),
dynamicSecret: {
id: doc.dynId,
slug: doc.dynSlug,
version: doc.dynVersion,
type: doc.dynType,
defaultTTL: doc.dynDefaultTTL,
maxTTL: doc.dynMaxTTL,
inputIV: doc.dynInputIV,
inputTag: doc.dynInputTag,
inputCiphertext: doc.dynInputCiphertext,
algorithm: doc.dynAlgorithm,
keyEncoding: doc.dynKeyEncoding,
folderId: doc.dynFolderId,
status: doc.dynStatus,
statusDetails: doc.dynStatusDetails,
createdAt: doc.dynCreatedAt,
updatedAt: doc.dynUpdatedAt
}
};
} catch (error) {
throw new DatabaseError({ error, name: "DynamicSecretLeaseFindById" });
}
};
return { ...orm, findById };
};
@@ -9,12 +9,14 @@ import { BadRequestError } from "@app/lib/errors";
import { TDynamicSecretDALFactory } from "../dynamic-secret/dynamic-secret-dal";
import { DynamicSecretProviders, TDynamicProviderFns } from "../dynamic-secret/providers/models";
import { TProjectDALFactory } from "../project/project-dal";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TDynamicSecretLeaseDALFactory } from "./dynamic-secret-lease-dal";
import { TDynamicSecretLeaseQueueServiceFactory } from "./dynamic-secret-lease-queue";
import {
TCreateDynamicSecretLeaseDTO,
TDeleteDynamicSecretLeaseDTO,
TDetailsDynamicSecretLeaseDTO,
TListDynamicSecretLeasesDTO,
TRenewDynamicSecretLeaseDTO
} from "./dynamic-secret-lease-types";
@@ -26,6 +28,7 @@ type TDynamicSecretLeaseServiceFactoryDep = {
dynamicSecretQueueService: TDynamicSecretLeaseQueueServiceFactory;
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
};
export type TDynamicSecretLeaseServiceFactory = ReturnType<typeof dynamicSecretLeaseServiceFactory>;
@@ -36,19 +39,24 @@ export const dynamicSecretLeaseServiceFactory = ({
dynamicSecretDAL,
folderDAL,
permissionService,
dynamicSecretQueueService
dynamicSecretQueueService,
projectDAL
}: TDynamicSecretLeaseServiceFactoryDep) => {
const create = async ({
environment,
path,
slug,
projectId,
projectSlug,
actor,
actorId,
actorOrgId,
actorAuthMethod,
ttl
}: TCreateDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -57,7 +65,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
@@ -102,11 +110,15 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId,
actorId,
actor,
projectId,
projectSlug,
path,
environment,
leaseId
}: TRenewDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -125,12 +137,7 @@ export const dynamicSecretLeaseServiceFactory = ({
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({
id: dynamicSecretLease.dynamicSecretId,
folderId: folder.id
});
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
const decryptedStoredInput = JSON.parse(
infisicalSymmetricDecrypt({
@@ -168,12 +175,16 @@ export const dynamicSecretLeaseServiceFactory = ({
leaseId,
environment,
path,
projectId,
projectSlug,
actor,
actorId,
actorOrgId,
actorAuthMethod
}: TDeleteDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -182,7 +193,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
@@ -192,12 +203,7 @@ export const dynamicSecretLeaseServiceFactory = ({
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({
id: dynamicSecretLease.dynamicSecretId,
folderId: folder.id
});
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
const decryptedStoredInput = JSON.parse(
infisicalSymmetricDecrypt({
@@ -220,11 +226,15 @@ export const dynamicSecretLeaseServiceFactory = ({
slug,
actor,
actorId,
projectId,
projectSlug,
actorOrgId,
environment,
actorAuthMethod
}: TListDynamicSecretLeasesDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -233,7 +243,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
@@ -247,10 +257,46 @@ export const dynamicSecretLeaseServiceFactory = ({
return dynamicSecretLeases;
};
const getLeaseDetails = async ({
projectSlug,
actorOrgId,
path,
environment,
actor,
actorId,
leaseId,
actorAuthMethod
}: TDetailsDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
if (!dynamicSecretLease) throw new BadRequestError({ message: "Dynamic secret lease not found" });
return dynamicSecretLease;
};
return {
create,
listLeases,
revokeLease,
renewLease
renewLease,
getLeaseDetails
};
};
@@ -9,23 +9,34 @@ export type TCreateDynamicSecretLeaseDTO = {
path: string;
environment: string;
ttl?: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDetailsDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretLeasesDTO = {
slug: string;
path: string;
environment: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TRenewDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
ttl?: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
@@ -8,6 +8,7 @@ import { BadRequestError } from "@app/lib/errors";
import { TDynamicSecretLeaseDALFactory } from "../dynamic-secret-lease/dynamic-secret-lease-dal";
import { TDynamicSecretLeaseQueueServiceFactory } from "../dynamic-secret-lease/dynamic-secret-lease-queue";
import { TProjectDALFactory } from "../project/project-dal";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TDynamicSecretDALFactory } from "./dynamic-secret-dal";
import {
@@ -26,6 +27,7 @@ type TDynamicSecretServiceFactoryDep = {
dynamicSecretProviders: Record<DynamicSecretProviders, TDynamicProviderFns>;
dynamicSecretQueueService: Pick<TDynamicSecretLeaseQueueServiceFactory, "pruneDynamicSecret">;
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
@@ -37,7 +39,8 @@ export const dynamicSecretServiceFactory = ({
folderDAL,
dynamicSecretProviders,
permissionService,
dynamicSecretQueueService
dynamicSecretQueueService,
projectDAL
}: TDynamicSecretServiceFactoryDep) => {
const create = async ({
path,
@@ -47,11 +50,15 @@ export const dynamicSecretServiceFactory = ({
maxTTL,
provider,
environment,
projectId,
projectSlug,
actorOrgId,
defaultTTL,
actorAuthMethod
}: TCreateDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -96,7 +103,7 @@ export const dynamicSecretServiceFactory = ({
defaultTTL,
inputs,
environment,
projectId,
projectSlug,
path,
actor,
actorId,
@@ -104,6 +111,11 @@ export const dynamicSecretServiceFactory = ({
actorOrgId,
actorAuthMethod
}: TUpdateDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -161,11 +173,16 @@ export const dynamicSecretServiceFactory = ({
actorOrgId,
actorId,
actor,
projectId,
projectSlug,
slug,
path,
environment
}: TDeleteDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -201,7 +218,7 @@ export const dynamicSecretServiceFactory = ({
const getDetails = async ({
slug,
projectId,
projectSlug,
path,
environment,
actorAuthMethod,
@@ -209,6 +226,10 @@ export const dynamicSecretServiceFactory = ({
actorId,
actor
}: TDetailsDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -244,10 +265,14 @@ export const dynamicSecretServiceFactory = ({
actorOrgId,
actorId,
actor,
projectId,
projectSlug,
path,
environment
}: TListDynamicSecretsDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
@@ -18,7 +18,8 @@ export type TCreateDynamicSecretDTO = {
path: string;
environment: string;
slug: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateDynamicSecretDTO = {
slug: string;
@@ -28,21 +29,25 @@ export type TUpdateDynamicSecretDTO = {
path: string;
environment: string;
inputs?: TProvider["inputs"];
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretDTO = {
slug: string;
path: string;
environment: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDetailsDynamicSecretDTO = {
slug: string;
path: string;
environment: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretsDTO = {
path: string;
environment: string;
} & TProjectPermission;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
@@ -13,7 +13,7 @@ import { DynamicSecretSqlDBSchema, TDynamicProviderFns } from "./models";
const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000;
const generatePassword = (size?: number) => {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%^&*()_+-=[]{}|;,./<>";
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*'$#";
return customAlphabet(charset, 20)(size);
};
@@ -62,7 +62,7 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
await db.raw(creationStatement.toString());
await db.destroy();
return { entityId: username, data: { username, password } };
return { entityId: username, data: { DB_USERNAME: username, DB_PASSWORD: password } };
};
const revoke = async (inputs: unknown, entityId: string) => {