feat(server): added some more validation and feedback for deletion etc

This commit is contained in:
Akhil Mohan
2024-03-21 20:23:44 +05:30
parent e201e80a06
commit 70fe80414d
11 changed files with 255 additions and 68 deletions
+14 -1
View File
@@ -1,6 +1,11 @@
import { z } from "zod";
import { IntegrationAuthsSchema, SecretApprovalPoliciesSchema, UsersSchema } from "@app/db/schemas";
import {
DynamicSecretsSchema,
IntegrationAuthsSchema,
SecretApprovalPoliciesSchema,
UsersSchema
} from "@app/db/schemas";
// sometimes the return data must be santizied to avoid leaking important values
// always prefer pick over omit in zod
@@ -56,3 +61,11 @@ export const secretRawSchema = z.object({
secretValue: z.string(),
secretComment: z.string().optional()
});
export const SanitizedDynamicSecretSchema = DynamicSecretsSchema.omit({
inputIV: true,
inputTag: true,
inputCiphertext: true,
keyEncoding: true,
algorithm: true
});
@@ -2,6 +2,8 @@ import ms from "ms";
import { z } from "zod";
import { DynamicSecretLeasesSchema } from "@app/db/schemas";
import { daysToMillisecond } from "@app/lib/dates";
import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -16,8 +18,15 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
ttl: z
.string()
.optional()
.refine((val) => typeof val === "undefined" || ms(val) > 0, "TTL must be a positive number"),
path: z.string().default("/"),
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
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()
}),
response: {
@@ -49,7 +58,7 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
}),
body: z.object({
projectId: z.string(),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
@@ -80,8 +89,19 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
leaseId: z.string()
}),
body: z.object({
ttl: z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
projectId: z.string(),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
@@ -113,7 +133,7 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
}),
querystring: z.object({
projectId: z.string(),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
@@ -1,11 +1,14 @@
import ms from "ms";
import { z } from "zod";
import { DynamicSecretsSchema } from "@app/db/schemas";
import { daysToMillisecond } from "@app/lib/dates";
import { removeTrailingSlash } from "@app/lib/fn";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { DynamicSecretProviderSchema } from "@app/services/dynamic-secret/providers/models";
import { SanitizedDynamicSecretSchema } from "../sanitizedSchemas";
export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
@@ -14,18 +17,32 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
body: z.object({
projectId: z.string(),
provider: DynamicSecretProviderSchema,
defaultTTL: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number"),
defaultTTL: z.string().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" });
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
maxTTL: z
.string()
.optional()
.refine((val) => typeof val === "undefined" || ms(val) > 0, "Max TTL must be a positive number"),
path: z.string().default("/"),
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
if (valMs > daysToMillisecond(1))
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(),
slug: z.string().toLowerCase()
}),
response: {
200: z.object({
dynamicSecret: DynamicSecretsSchema
dynamicSecret: SanitizedDynamicSecretSchema
})
}
},
@@ -51,22 +68,39 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}),
body: z.object({
projectId: z.string(),
inputs: z.any().optional(),
defaultTTL: z
.string()
.optional()
.refine((val) => typeof val === "undefined" || ms(val) > 0, "TTL must be a positive number"),
maxTTL: z
.string()
.optional()
.refine((val) => typeof val === "undefined" || ms(val) > 0, "Max TTL must be a positive number"),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string(),
newSlug: z.string()
data: z.object({
inputs: z.any().optional(),
defaultTTL: z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
maxTTL: z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
if (valMs > daysToMillisecond(1))
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
})
.nullable(),
newSlug: z.string().optional()
})
}),
response: {
200: z.object({
dynamicSecret: DynamicSecretsSchema
dynamicSecret: SanitizedDynamicSecretSchema
})
}
},
@@ -78,7 +112,10 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
...req.body
path: req.body.path,
projectId: req.body.projectId,
environment: req.body.environment,
...req.body.data
});
return { dynamicSecret: dynamicSecretCfg };
}
@@ -93,12 +130,12 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}),
body: z.object({
projectId: z.string(),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
200: z.object({
dynamicSecret: DynamicSecretsSchema
dynamicSecret: SanitizedDynamicSecretSchema
})
}
},
@@ -116,18 +153,52 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
}
});
server.route({
url: "/:slug",
method: "GET",
schema: {
params: z.object({
slug: z.string()
}),
querystring: z.object({
projectId: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
200: z.object({
dynamicSecret: SanitizedDynamicSecretSchema.extend({
inputs: z.unknown()
})
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const dynamicSecretCfg = await server.services.dynamicSecret.getDetails({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
slug: req.params.slug,
...req.query
});
return { dynamicSecret: dynamicSecretCfg };
}
});
server.route({
url: "/",
method: "GET",
schema: {
querystring: z.object({
projectId: z.string(),
path: z.string(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
environment: z.string()
}),
response: {
200: z.object({
dynamicSecrets: DynamicSecretsSchema.array()
dynamicSecrets: SanitizedDynamicSecretSchema.array()
})
}
},