feat(server): updated dynamic secret names from feedback, added describe and fixed login not working

This commit is contained in:
Akhil Mohan
2024-03-26 13:18:31 +05:30
parent b592f4cb6d
commit a7d2ec80c6
11 changed files with 259 additions and 139 deletions

View File

@@ -8,7 +8,7 @@ export async function up(knex: Knex): Promise<void> {
if (!doesTableExist) {
await knex.schema.createTable(TableName.DynamicSecret, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.string("slug").notNullable();
t.string("name").notNullable();
t.integer("version").notNullable();
t.string("type").notNullable();
t.string("defaultTTL").notNullable();
@@ -23,7 +23,7 @@ export async function up(knex: Knex): Promise<void> {
t.string("status");
t.string("statusDetails");
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
t.unique(["slug", "folderId"]);
t.unique(["name", "folderId"]);
t.timestamps(true, true, true);
});
}

View File

@@ -9,7 +9,7 @@ import { TImmutableDBKeys } from "./models";
export const DynamicSecretsSchema = z.object({
id: z.string().uuid(),
slug: z.string(),
name: z.string(),
version: z.number(),
type: z.string(),
defaultTTL: z.string(),

View File

@@ -285,3 +285,81 @@ export const AUDIT_LOGS = {
actor: "The actor to filter the audit logs by."
}
} as const;
export const DYNAMIC_SECRETS = {
LIST: {
projectSlug: "The slug of the project to create dynamic secret in.",
environmentSlug: "The slug of the environment to list folders from.",
path: "The path to list folders from."
},
LIST_LEAES_BY_NAME: {
projectSlug: "The slug of the project to create dynamic secret in.",
environmentSlug: "The slug of the environment to list folders from.",
path: "The path to list folders from.",
name: "The name of the dynamic secret."
},
GET_BY_NAME: {
projectSlug: "The slug of the project to create dynamic secret in.",
environmentSlug: "The slug of the environment to list folders from.",
path: "The path to list folders from.",
name: "The name of the dynamic secret."
},
CREATE: {
projectSlug: "The slug of the project to create dynamic secret in.",
environmentSlug: "The slug of the environment to create the dynamic secret in.",
path: "The path to create the dynamic secret in.",
name: "The name of the dynamic secret.",
provider: "The type of dynamic secret.",
defaultTTL: "The default TTL that will be applied for all the leases.",
maxTTL: "The maximum limit a TTL can be leases or renewed."
},
UPDATE: {
projectSlug: "The slug of the project to update dynamic secret in.",
environmentSlug: "The slug of the environment to update the dynamic secret in.",
path: "The path to update the dynamic secret in.",
name: "The name of the dynamic secret.",
inputs: "The new partial values for the configurated provider of the dynamic secret",
defaultTTL: "The default TTL that will be applied for all the leases.",
maxTTL: "The maximum limit a TTL can be leases or renewed.",
newName: "The new name for the dynamic secret."
},
DELETE: {
projectSlug: "The slug of the project to delete dynamic secret in.",
environmentSlug: "The slug of the environment to delete the dynamic secret in.",
path: "The path to delete the dynamic secret in.",
name: "The name of the dynamic secret.",
isForced:
"A boolean flag to delete the the dynamic secret from infisical without trying to remove it from external provider. Used when the dynamic secret got modified externally."
}
} as const;
export const DYNAMIC_SECRET_LEASES = {
GET_BY_LEASEID: {
projectSlug: "The slug of the project to create dynamic secret in.",
environmentSlug: "The slug of the environment to list folders from.",
path: "The path to list folders from.",
leaseId: "The ID of the dynamic secret lease."
},
CREATE: {
projectSlug: "The slug of the project of the dynamic secret in.",
environmentSlug: "The slug of the environment of the dynamic secret in.",
path: "The path of the dynamic secret in.",
dynamicSecretName: "The name of the dynamic secret.",
ttl: "The lease lifetime ttl. If not provided the default TTL of dynamic secret will be used."
},
RENEW: {
projectSlug: "The slug of the project of the dynamic secret in.",
environmentSlug: "The slug of the environment of the dynamic secret in.",
path: "The path of the dynamic secret in.",
leaseId: "The ID of the dynamic secret lease.",
ttl: "The renew TTL that gets added with current expiry (ensure it's below max TTL) for a total less than creation time + max TTL."
},
DELETE: {
projectSlug: "The slug of the project of the dynamic secret in.",
environmentSlug: "The slug of the environment of the dynamic secret in.",
path: "The path of the dynamic secret in.",
leaseId: "The ID of the dynamic secret lease.",
isForced:
"A boolean flag to delete the the dynamic secret from infisical without trying to remove it from external provider. Used when the dynamic secret got modified externally."
}
} as const;

View File

@@ -2,6 +2,7 @@ import ms from "ms";
import { z } from "zod";
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
import { DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs";
import { daysToMillisecond } from "@app/lib/dates";
import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -15,11 +16,12 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
method: "POST",
schema: {
body: z.object({
slug: z.string().min(1),
projectSlug: z.string().min(1),
dynamicSecretName: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.dynamicSecretName).toLowerCase(),
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.projectSlug),
ttl: z
.string()
.optional()
.describe(DYNAMIC_SECRET_LEASES.CREATE.ttl)
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
@@ -28,8 +30,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRET_LEASES.CREATE.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.path)
}),
response: {
200: z.object({
@@ -46,6 +48,7 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
name: req.body.dynamicSecretName,
...req.body
});
return { lease, data, dynamicSecret };
@@ -57,13 +60,19 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
method: "DELETE",
schema: {
params: z.object({
leaseId: z.string()
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.leaseId)
}),
body: z.object({
projectSlug: z.string().min(1),
path: z.string().min(1).trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1),
isForced: z.boolean().default(false)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.projectSlug),
path: z
.string()
.min(1)
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(DYNAMIC_SECRET_LEASES.DELETE.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.environmentSlug),
isForced: z.boolean().default(false).describe(DYNAMIC_SECRET_LEASES.DELETE.isForced)
}),
response: {
200: z.object({
@@ -90,11 +99,12 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
method: "POST",
schema: {
params: z.object({
leaseId: z.string()
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.leaseId)
}),
body: z.object({
ttl: z
.string()
.describe(DYNAMIC_SECRET_LEASES.RENEW.ttl)
.optional()
.superRefine((val, ctx) => {
if (!val) return;
@@ -104,9 +114,15 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
projectSlug: z.string().min(1),
path: z.string().min(1).trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.projectSlug),
path: z
.string()
.min(1)
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(DYNAMIC_SECRET_LEASES.RENEW.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.ttl)
}),
response: {
200: z.object({
@@ -133,12 +149,17 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
method: "GET",
schema: {
params: z.object({
leaseId: z.string()
leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.leaseId)
}),
querystring: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.projectSlug),
path: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.environmentSlug)
}),
response: {
200: z.object({

View File

@@ -1,7 +1,9 @@
import slugify from "@sindresorhus/slugify";
import ms from "ms";
import { z } from "zod";
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
import { DYNAMIC_SECRETS } from "@app/lib/api-docs";
import { daysToMillisecond } from "@app/lib/dates";
import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -16,9 +18,12 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
method: "POST",
schema: {
body: z.object({
projectSlug: z.string().min(1),
provider: DynamicSecretProviderSchema,
defaultTTL: z.string().superRefine((val, ctx) => {
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.CREATE.projectSlug),
provider: DynamicSecretProviderSchema.describe(DYNAMIC_SECRETS.CREATE.provider),
defaultTTL: z
.string()
.describe(DYNAMIC_SECRETS.CREATE.defaultTTL)
.superRefine((val, ctx) => {
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
@@ -27,6 +32,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}),
maxTTL: z
.string()
.describe(DYNAMIC_SECRETS.CREATE.maxTTL)
.optional()
.superRefine((val, ctx) => {
if (!val) return;
@@ -37,9 +43,17 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
})
.nullable(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1),
slug: z.string().min(1).toLowerCase()
path: z.string().describe(DYNAMIC_SECRETS.CREATE.path).trim().default("/").transform(removeTrailingSlash),
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
name: z
.string()
.describe(DYNAMIC_SECRETS.CREATE.name)
.min(1)
.toLowerCase()
.max(64)
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid"
})
}),
response: {
200: z.object({
@@ -61,20 +75,21 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:slug",
url: "/:name",
method: "PATCH",
schema: {
params: z.object({
slug: z.string()
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.UPDATE.name)
}),
body: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1),
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.UPDATE.projectSlug),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.UPDATE.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.UPDATE.environmentSlug),
data: z.object({
inputs: z.any().optional(),
inputs: z.any().optional().describe(DYNAMIC_SECRETS.UPDATE.inputs),
defaultTTL: z
.string()
.describe(DYNAMIC_SECRETS.UPDATE.defaultTTL)
.optional()
.superRefine((val, ctx) => {
if (!val) return;
@@ -86,6 +101,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}),
maxTTL: z
.string()
.describe(DYNAMIC_SECRETS.UPDATE.maxTTL)
.optional()
.superRefine((val, ctx) => {
if (!val) return;
@@ -96,7 +112,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
})
.nullable(),
newSlug: z.string().optional()
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional()
})
}),
response: {
@@ -107,15 +123,15 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const dynamicSecretCfg = await server.services.dynamicSecret.updateBySlug({
const dynamicSecretCfg = await server.services.dynamicSecret.updateByName({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
name: req.params.name,
path: req.body.path,
projectSlug: req.body.projectSlug,
environment: req.body.environment,
environmentSlug: req.body.environmentSlug,
...req.body.data
});
return { dynamicSecret: dynamicSecretCfg };
@@ -123,17 +139,17 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:slug",
url: "/:name",
method: "DELETE",
schema: {
params: z.object({
slug: z.string()
name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.DELETE.name)
}),
body: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1),
isForced: z.boolean().default(false)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.DELETE.projectSlug),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.DELETE.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.DELETE.environmentSlug),
isForced: z.boolean().default(false).describe(DYNAMIC_SECRETS.DELETE.isForced)
}),
response: {
200: z.object({
@@ -143,12 +159,12 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const dynamicSecretCfg = await server.services.dynamicSecret.deleteBySlug({
const dynamicSecretCfg = await server.services.dynamicSecret.deleteByName({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
name: req.params.name,
...req.body
});
return { dynamicSecret: dynamicSecretCfg };
@@ -156,16 +172,16 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:slug",
url: "/:name",
method: "GET",
schema: {
params: z.object({
slug: z.string()
name: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.name)
}),
querystring: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.projectSlug),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.GET_BY_NAME.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.environmentSlug)
}),
response: {
200: z.object({
@@ -182,7 +198,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
name: req.params.name,
...req.query
});
return { dynamicSecret: dynamicSecretCfg };
@@ -194,9 +210,9 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
method: "GET",
schema: {
querystring: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST.projectSlug),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.LIST.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST.environmentSlug)
}),
response: {
200: z.object({
@@ -218,16 +234,21 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:slug/leases",
url: "/:name/leases",
method: "GET",
schema: {
params: z.object({
slug: z.string()
name: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.name)
}),
querystring: z.object({
projectSlug: z.string().min(1),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string().min(1)
projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.projectSlug),
path: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.path),
environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.environmentSlug)
}),
response: {
200: z.object({
@@ -242,7 +263,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
name: req.params.name,
...req.query
});
return { leases };

View File

@@ -32,7 +32,7 @@ export const dynamicSecretLeaseDALFactory = (db: TDbClient) => {
.select(selectAllTableCols(TableName.DynamicSecretLease))
.select(
db.ref("id").withSchema(TableName.DynamicSecret).as("dynId"),
db.ref("slug").withSchema(TableName.DynamicSecret).as("dynSlug"),
db.ref("name").withSchema(TableName.DynamicSecret).as("dynName"),
db.ref("version").withSchema(TableName.DynamicSecret).as("dynVersion"),
db.ref("type").withSchema(TableName.DynamicSecret).as("dynType"),
db.ref("defaultTTL").withSchema(TableName.DynamicSecret).as("dynDefaultTTL"),
@@ -54,7 +54,7 @@ export const dynamicSecretLeaseDALFactory = (db: TDbClient) => {
...DynamicSecretLeasesSchema.parse(doc),
dynamicSecret: {
id: doc.dynId,
slug: doc.dynSlug,
name: doc.dynName,
version: doc.dynVersion,
type: doc.dynType,
defaultTTL: doc.dynDefaultTTL,

View File

@@ -45,9 +45,9 @@ export const dynamicSecretLeaseServiceFactory = ({
projectDAL
}: TDynamicSecretLeaseServiceFactoryDep) => {
const create = async ({
environment,
environmentSlug,
path,
slug,
name,
projectSlug,
actor,
actorId,
@@ -69,13 +69,13 @@ export const dynamicSecretLeaseServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const totalLeasesTaken = await dynamicSecretLeaseDAL.countLeasesForDynamicSecret(dynamicSecretCfg.id);
@@ -119,7 +119,7 @@ export const dynamicSecretLeaseServiceFactory = ({
actor,
projectSlug,
path,
environment,
environmentSlug,
leaseId
}: TRenewDynamicSecretLeaseDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
@@ -135,10 +135,10 @@ export const dynamicSecretLeaseServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
@@ -180,7 +180,7 @@ export const dynamicSecretLeaseServiceFactory = ({
const revokeLease = async ({
leaseId,
environment,
environmentSlug,
path,
projectSlug,
actor,
@@ -202,10 +202,10 @@ export const dynamicSecretLeaseServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
@@ -245,12 +245,12 @@ export const dynamicSecretLeaseServiceFactory = ({
const listLeases = async ({
path,
slug,
name,
actor,
actorId,
projectSlug,
actorOrgId,
environment,
environmentSlug,
actorAuthMethod
}: TListDynamicSecretLeasesDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
@@ -266,13 +266,13 @@ export const dynamicSecretLeaseServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const dynamicSecretLeases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
@@ -283,7 +283,7 @@ export const dynamicSecretLeaseServiceFactory = ({
projectSlug,
actorOrgId,
path,
environment,
environmentSlug,
actor,
actorId,
leaseId,
@@ -302,10 +302,10 @@ export const dynamicSecretLeaseServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);

View File

@@ -5,9 +5,9 @@ export enum DynamicSecretLeaseStatus {
}
export type TCreateDynamicSecretLeaseDTO = {
slug: string;
name: string;
path: string;
environment: string;
environmentSlug: string;
ttl?: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
@@ -15,21 +15,21 @@ export type TCreateDynamicSecretLeaseDTO = {
export type TDetailsDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretLeasesDTO = {
slug: string;
name: string;
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
isForced?: boolean;
} & Omit<TProjectPermission, "projectId">;
@@ -37,7 +37,7 @@ export type TDeleteDynamicSecretLeaseDTO = {
export type TRenewDynamicSecretLeaseDTO = {
leaseId: string;
path: string;
environment: string;
environmentSlug: string;
ttl?: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;

View File

@@ -48,11 +48,11 @@ export const dynamicSecretServiceFactory = ({
const create = async ({
path,
actor,
slug,
name,
actorId,
maxTTL,
provider,
environment,
environmentSlug,
projectSlug,
actorOrgId,
defaultTTL,
@@ -71,13 +71,13 @@ export const dynamicSecretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const existingDynamicSecret = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const existingDynamicSecret = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (existingDynamicSecret)
throw new BadRequestError({ message: "Provided dynamic secret already exist under the folder" });
@@ -99,22 +99,22 @@ export const dynamicSecretServiceFactory = ({
maxTTL,
defaultTTL,
folderId: folder.id,
slug
name
});
return dynamicSecretCfg;
};
const updateBySlug = async ({
slug,
const updateByName = async ({
name,
maxTTL,
defaultTTL,
inputs,
environment,
environmentSlug,
projectSlug,
path,
actor,
actorId,
newSlug,
newName,
actorOrgId,
actorAuthMethod
}: TUpdateDynamicSecretDTO) => {
@@ -132,17 +132,17 @@ export const dynamicSecretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
if (newSlug) {
const existingDynamicSecret = await dynamicSecretDAL.findOne({ slug: newSlug, folderId: folder.id });
if (newName) {
const existingDynamicSecret = await dynamicSecretDAL.findOne({ name: newName, folderId: folder.id });
if (existingDynamicSecret)
throw new BadRequestError({ message: "Provided dynamic secret already exist under the folder" });
}
@@ -171,7 +171,7 @@ export const dynamicSecretServiceFactory = ({
keyEncoding: encryptedInput.encoding,
maxTTL,
defaultTTL,
slug: newSlug ?? slug,
name: newName ?? name,
status: null,
statusDetails: null
});
@@ -179,15 +179,15 @@ export const dynamicSecretServiceFactory = ({
return updatedDynamicCfg;
};
const deleteBySlug = async ({
const deleteByName = async ({
actorAuthMethod,
actorOrgId,
actorId,
actor,
projectSlug,
slug,
name,
path,
environment,
environmentSlug,
isForced
}: TDeleteDynamicSecretDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
@@ -204,13 +204,13 @@ export const dynamicSecretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const leases = await dynamicSecretLeaseDAL.find({ dynamicSecretId: dynamicSecretCfg.id });
@@ -239,10 +239,10 @@ export const dynamicSecretServiceFactory = ({
};
const getDetails = async ({
slug,
name,
projectSlug,
path,
environment,
environmentSlug,
actorAuthMethod,
actorOrgId,
actorId,
@@ -261,13 +261,13 @@ export const dynamicSecretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ slug, folderId: folder.id });
const dynamicSecretCfg = await dynamicSecretDAL.findOne({ name, folderId: folder.id });
if (!dynamicSecretCfg) throw new BadRequestError({ message: "Dynamic secret not found" });
const decryptedStoredInput = JSON.parse(
infisicalSymmetricDecrypt({
@@ -289,7 +289,7 @@ export const dynamicSecretServiceFactory = ({
actor,
projectSlug,
path,
environment
environmentSlug
}: TListDynamicSecretsDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
@@ -304,10 +304,10 @@ export const dynamicSecretServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
subject(ProjectPermissionSub.Secrets, { environment: environmentSlug, secretPath: path })
);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
const folder = await folderDAL.findBySecretPath(projectId, environmentSlug, path);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const dynamicSecretCfg = await dynamicSecretDAL.find({ folderId: folder.id });
@@ -316,8 +316,8 @@ export const dynamicSecretServiceFactory = ({
return {
create,
updateBySlug,
deleteBySlug,
updateByName,
deleteByName,
getDetails,
list
};

View File

@@ -16,39 +16,39 @@ export type TCreateDynamicSecretDTO = {
defaultTTL: string;
maxTTL?: string | null;
path: string;
environment: string;
slug: string;
environmentSlug: string;
name: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateDynamicSecretDTO = {
slug: string;
newSlug?: string;
name: string;
newName?: string;
defaultTTL?: string;
maxTTL?: string | null;
path: string;
environment: string;
environmentSlug: string;
inputs?: TProvider["inputs"];
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteDynamicSecretDTO = {
slug: string;
name: string;
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
isForced?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TDetailsDynamicSecretDTO = {
slug: string;
name: string;
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListDynamicSecretsDTO = {
path: string;
environment: string;
environmentSlug: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;

View File

@@ -13,8 +13,8 @@ import { DynamicSecretSqlDBSchema, TDynamicProviderFns } from "./models";
const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000;
const generatePassword = (size?: number) => {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*'$#";
return customAlphabet(charset, 32)(size);
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*$#";
return customAlphabet(charset, 48)(size);
};
export const SqlDatabaseProvider = (): TDynamicProviderFns => {
@@ -61,13 +61,13 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
const providerInputs = await validateProviderInputs(inputs);
const db = await getClient(providerInputs);
const username = alphaNumericNanoId(21);
const username = alphaNumericNanoId(32);
const password = generatePassword();
const expiration = new Date(expireAt).toISOString();
const creationStatement = handlebars.compile(providerInputs.creationStatement, { noEscape: true })({
username,
password: "infisical",
password,
expiration
});