used zod codemod

This commit is contained in:
Lokowitz
2025-11-16 14:18:17 +00:00
parent 000904eb31
commit 7db99a7dd5
191 changed files with 764 additions and 1232 deletions

View File

@@ -7,20 +7,20 @@ export const SiteSchema = z.object({
export const TargetHealthCheckSchema = z.object({ export const TargetHealthCheckSchema = z.object({
hostname: z.string(), hostname: z.string(),
port: z.number().int().min(1).max(65535), port: z.int().min(1).max(65535),
enabled: z.boolean().optional().default(true), enabled: z.boolean().optional().default(true),
path: z.string().optional(), path: z.string().optional(),
scheme: z.string().optional(), scheme: z.string().optional(),
mode: z.string().default("http"), mode: z.string().default("http"),
interval: z.number().int().default(30), interval: z.int().default(30),
"unhealthy-interval": z.number().int().default(30), "unhealthy-interval": z.int().default(30),
unhealthyInterval: z.number().int().optional(), // deprecated alias unhealthyInterval: z.int().optional(), // deprecated alias
timeout: z.number().int().default(5), timeout: z.int().default(5),
headers: z.array(z.object({ name: z.string(), value: z.string() })).nullable().optional().default(null), headers: z.array(z.object({ name: z.string(), value: z.string() })).nullable().optional().default(null),
"follow-redirects": z.boolean().default(true), "follow-redirects": z.boolean().default(true),
followRedirects: z.boolean().optional(), // deprecated alias followRedirects: z.boolean().optional(), // deprecated alias
method: z.string().default("GET"), method: z.string().default("GET"),
status: z.number().int().optional() status: z.int().optional()
}); });
// Schema for individual target within a resource // Schema for individual target within a resource
@@ -28,16 +28,16 @@ export const TargetSchema = z.object({
site: z.string().optional(), site: z.string().optional(),
method: z.enum(["http", "https", "h2c"]).optional(), method: z.enum(["http", "https", "h2c"]).optional(),
hostname: z.string(), hostname: z.string(),
port: z.number().int().min(1).max(65535), port: z.int().min(1).max(65535),
enabled: z.boolean().optional().default(true), enabled: z.boolean().optional().default(true),
"internal-port": z.number().int().min(1).max(65535).optional(), "internal-port": z.int().min(1).max(65535).optional(),
path: z.string().optional(), path: z.string().optional(),
"path-match": z.enum(["exact", "prefix", "regex"]).optional().nullable(), "path-match": z.enum(["exact", "prefix", "regex"]).optional().nullable(),
healthcheck: TargetHealthCheckSchema.optional(), healthcheck: TargetHealthCheckSchema.optional(),
rewritePath: z.string().optional(), // deprecated alias rewritePath: z.string().optional(), // deprecated alias
"rewrite-path": z.string().optional(), "rewrite-path": z.string().optional(),
"rewrite-match": z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(), "rewrite-match": z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(),
priority: z.number().int().min(1).max(1000).optional().default(100) priority: z.int().min(1).max(1000).optional().default(100)
}); });
export type TargetData = z.infer<typeof TargetSchema>; export type TargetData = z.infer<typeof TargetSchema>;
@@ -55,10 +55,10 @@ export const AuthSchema = z.object({
.optional() .optional()
.default([]) .default([])
.refine((roles) => !roles.includes("Admin"), { .refine((roles) => !roles.includes("Admin"), {
message: "Admin role cannot be included in sso-roles" error: "Admin role cannot be included in sso-roles"
}), }),
"sso-users": z.array(z.string().email()).optional().default([]), "sso-users": z.array(z.email()).optional().default([]),
"whitelist-users": z.array(z.string().email()).optional().default([]), "whitelist-users": z.array(z.email()).optional().default([]),
}); });
export const RuleSchema = z.object({ export const RuleSchema = z.object({
@@ -79,7 +79,7 @@ export const ResourceSchema = z
protocol: z.enum(["http", "tcp", "udp"]).optional(), protocol: z.enum(["http", "tcp", "udp"]).optional(),
ssl: z.boolean().optional(), ssl: z.boolean().optional(),
"full-domain": z.string().optional(), "full-domain": z.string().optional(),
"proxy-port": z.number().int().min(1).max(65535).optional(), "proxy-port": z.int().min(1).max(65535).optional(),
enabled: z.boolean().optional(), enabled: z.boolean().optional(),
targets: z.array(TargetSchema.nullable()).optional().default([]), targets: z.array(TargetSchema.nullable()).optional().default([]),
auth: AuthSchema.optional(), auth: AuthSchema.optional(),
@@ -100,9 +100,8 @@ export const ResourceSchema = z
); );
}, },
{ {
message: path: ["name", "protocol"],
"Resource must either be targets-only (only 'targets' field) or have both 'name' and 'protocol' fields at a minimum", error: "Resource must either be targets-only (only 'targets' field) or have both 'name' and 'protocol' fields at a minimum"
path: ["name", "protocol"]
} }
) )
.refine( .refine(
@@ -156,9 +155,8 @@ export const ResourceSchema = z
return true; return true;
}, },
{ {
message: path: ["full-domain"],
"When protocol is 'http', a 'full-domain' must be provided", error: "When protocol is 'http', a 'full-domain' must be provided"
path: ["full-domain"]
} }
) )
.refine( .refine(
@@ -174,9 +172,8 @@ export const ResourceSchema = z
return true; return true;
}, },
{ {
message: path: ["proxy-port", "exit-node"],
"When protocol is 'tcp' or 'udp', 'proxy-port' must be provided", error: "When protocol is 'tcp' or 'udp', 'proxy-port' must be provided"
path: ["proxy-port", "exit-node"]
} }
) )
.refine( .refine(
@@ -193,9 +190,8 @@ export const ResourceSchema = z
return true; return true;
}, },
{ {
message: path: ["auth"],
"When protocol is 'tcp' or 'udp', 'auth' must not be provided", error: "When protocol is 'tcp' or 'udp', 'auth' must not be provided"
path: ["auth"]
} }
); );
@@ -216,9 +212,9 @@ export const ClientResourceSchema = z.object({
// Schema for the entire configuration object // Schema for the entire configuration object
export const ConfigSchema = z export const ConfigSchema = z
.object({ .object({
"proxy-resources": z.record(z.string(), ResourceSchema).optional().default({}), "proxy-resources": z.record(z.string(), ResourceSchema).optional().prefault({}),
"client-resources": z.record(z.string(), ClientResourceSchema).optional().default({}), "client-resources": z.record(z.string(), ClientResourceSchema).optional().prefault({}),
sites: z.record(z.string(), SiteSchema).optional().default({}) sites: z.record(z.string(), SiteSchema).optional().prefault({})
}) })
.refine( .refine(
// Enforce the full-domain uniqueness across resources in the same stack // Enforce the full-domain uniqueness across resources in the same stack

View File

@@ -14,10 +14,8 @@ export const configSchema = z
.object({ .object({
app: z app: z
.object({ .object({
dashboard_url: z dashboard_url: z.url()
.string() .pipe(z.url())
.url()
.pipe(z.string().url())
.transform((url) => url.toLowerCase()) .transform((url) => url.toLowerCase())
.optional(), .optional(),
log_level: z log_level: z
@@ -31,14 +29,14 @@ export const configSchema = z
anonymous_usage: z.boolean().optional().default(true) anonymous_usage: z.boolean().optional().default(true)
}) })
.optional() .optional()
.default({}), .prefault({}),
notifications: z notifications: z
.object({ .object({
product_updates: z.boolean().optional().default(true), product_updates: z.boolean().optional().default(true),
new_releases: z.boolean().optional().default(true) new_releases: z.boolean().optional().default(true)
}) })
.optional() .optional()
.default({}) .prefault({})
}) })
.optional() .optional()
.default({ .default({
@@ -107,7 +105,7 @@ export const configSchema = z
token: z.string().optional().default("P-Access-Token") token: z.string().optional().default("P-Access-Token")
}) })
.optional() .optional()
.default({}), .prefault({}),
resource_session_request_param: z resource_session_request_param: z
.string() .string()
.optional() .optional()
@@ -132,7 +130,7 @@ export const configSchema = z
credentials: z.boolean().optional() credentials: z.boolean().optional()
}) })
.optional(), .optional(),
trust_proxy: z.number().int().gte(0).optional().default(1), trust_proxy: z.int().gte(0).optional().default(1),
secret: z.string().pipe(z.string().min(8)).optional(), secret: z.string().pipe(z.string().min(8)).optional(),
maxmind_db_path: z.string().optional() maxmind_db_path: z.string().optional()
}) })
@@ -189,7 +187,7 @@ export const configSchema = z
.default(5000) .default(5000)
}) })
.optional() .optional()
.default({}) .prefault({})
}) })
.optional(), .optional(),
traefik: z traefik: z
@@ -222,7 +220,7 @@ export const configSchema = z
.default("pp-transport-v") .default("pp-transport-v")
}) })
.optional() .optional()
.default({}), .prefault({}),
gerbil: z gerbil: z
.object({ .object({
exit_node_name: z.string().optional(), exit_node_name: z.string().optional(),
@@ -247,7 +245,7 @@ export const configSchema = z
.default(30) .default(30)
}) })
.optional() .optional()
.default({}), .prefault({}),
orgs: z orgs: z
.object({ .object({
block_size: z.number().positive().gt(0).optional().default(24), block_size: z.number().positive().gt(0).optional().default(24),
@@ -276,7 +274,7 @@ export const configSchema = z
.default(500) .default(500)
}) })
.optional() .optional()
.default({}), .prefault({}),
auth: z auth: z
.object({ .object({
window_minutes: z window_minutes: z
@@ -293,10 +291,10 @@ export const configSchema = z
.default(500) .default(500)
}) })
.optional() .optional()
.default({}) .prefault({})
}) })
.optional() .optional()
.default({}), .prefault({}),
email: z email: z
.object({ .object({
smtp_host: z.string().optional(), smtp_host: z.string().optional(),
@@ -308,7 +306,7 @@ export const configSchema = z
.transform(getEnvOrYaml("EMAIL_SMTP_PASS")), .transform(getEnvOrYaml("EMAIL_SMTP_PASS")),
smtp_secure: z.boolean().optional(), smtp_secure: z.boolean().optional(),
smtp_tls_reject_unauthorized: z.boolean().optional(), smtp_tls_reject_unauthorized: z.boolean().optional(),
no_reply: z.string().email().optional() no_reply: z.email().optional()
}) })
.optional(), .optional(),
flags: z flags: z
@@ -340,7 +338,7 @@ export const configSchema = z
.default("cname.pangolin.net") .default("cname.pangolin.net")
}) })
.optional() .optional()
.default({}) .prefault({})
}) })
.refine( .refine(
(data) => { (data) => {
@@ -355,7 +353,7 @@ export const configSchema = z
return true; return true;
}, },
{ {
message: "At least one domain must be defined" error: "At least one domain must be defined"
} }
) )
.refine( .refine(
@@ -370,7 +368,7 @@ export const configSchema = z
); );
}, },
{ {
message: "Server secret must be defined" error: "Server secret must be defined"
} }
) )
.refine( .refine(
@@ -382,7 +380,7 @@ export const configSchema = z
); );
}, },
{ {
message: "Dashboard URL must be defined" error: "Dashboard URL must be defined"
} }
); );

View File

@@ -50,14 +50,14 @@ export const privateConfigSchema = z.object({
host: z.string(), host: z.string(),
port: portSchema, port: portSchema,
password: z.string().optional(), password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0), db: z.int().nonnegative().optional().default(0),
replicas: z replicas: z
.array( .array(
z.object({ z.object({
host: z.string(), host: z.string(),
port: portSchema, port: portSchema,
password: z.string().optional(), password: z.string().optional(),
db: z.number().int().nonnegative().optional().default(0) db: z.int().nonnegative().optional().default(0)
}) })
) )
.optional() .optional()
@@ -79,14 +79,14 @@ export const privateConfigSchema = z.object({
.default("http://gerbil:3004") .default("http://gerbil:3004")
}) })
.optional() .optional()
.default({}), .prefault({}),
flags: z flags: z
.object({ .object({
enable_redis: z.boolean().optional().default(false), enable_redis: z.boolean().optional().default(false),
use_pangolin_dns: z.boolean().optional().default(false) use_pangolin_dns: z.boolean().optional().default(false)
}) })
.optional() .optional()
.default({}), .prefault({}),
branding: z branding: z
.object({ .object({
app_name: z.string().optional(), app_name: z.string().optional(),

View File

@@ -30,13 +30,13 @@ export const queryAccessAuditLogsQuery = z.object({
timeStart: z timeStart: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeStart must be a valid ISO date string" error: "timeStart must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)), .transform((val) => Math.floor(new Date(val).getTime() / 1000)),
timeEnd: z timeEnd: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeEnd must be a valid ISO date string" error: "timeEnd must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)) .transform((val) => Math.floor(new Date(val).getTime() / 1000))
.optional() .optional()
@@ -51,7 +51,7 @@ export const queryAccessAuditLogsQuery = z.object({
.string() .string()
.optional() .optional()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
.optional(), .optional(),
actor: z.string().optional(), actor: z.string().optional(),
type: z.string().optional(), type: z.string().optional(),
@@ -61,13 +61,13 @@ export const queryAccessAuditLogsQuery = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
export const queryAccessAuditLogsParams = z.object({ export const queryAccessAuditLogsParams = z.object({

View File

@@ -30,13 +30,13 @@ export const queryActionAuditLogsQuery = z.object({
timeStart: z timeStart: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeStart must be a valid ISO date string" error: "timeStart must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)), .transform((val) => Math.floor(new Date(val).getTime() / 1000)),
timeEnd: z timeEnd: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeEnd must be a valid ISO date string" error: "timeEnd must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)) .transform((val) => Math.floor(new Date(val).getTime() / 1000))
.optional() .optional()
@@ -50,13 +50,13 @@ export const queryActionAuditLogsQuery = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
export const queryActionAuditLogsParams = z.object({ export const queryActionAuditLogsParams = z.object({

View File

@@ -28,7 +28,7 @@ import { response } from "@server/lib/response";
import { encrypt } from "@server/lib/crypto"; import { encrypt } from "@server/lib/crypto";
import config from "@server/lib/config"; import config from "@server/lib/config";
const paramsSchema = z.object({}).strict(); const paramsSchema = z.strictObject({});
export type GetSessionTransferTokenRenponse = { export type GetSessionTransferTokenRenponse = {
token: string; token: string;

View File

@@ -62,10 +62,10 @@ import { isTargetValid } from "@server/lib/validators";
import { listExitNodes } from "#private/lib/exitNodes"; import { listExitNodes } from "#private/lib/exitNodes";
const bodySchema = z.object({ const bodySchema = z.object({
email: z.string().toLowerCase().email(), email: z.email().toLowerCase(),
ip: z.string().refine(isTargetValid), ip: z.string().refine(isTargetValid),
method: z.enum(["http", "https"]), method: z.enum(["http", "https"]),
port: z.number().int().min(1).max(65535), port: z.int().min(1).max(65535),
pincode: z pincode: z
.string() .string()
.regex(/^\d{6}$/) .regex(/^\d{6}$/)

View File

@@ -25,11 +25,9 @@ import stripe from "#private/lib/stripe";
import { getLineItems, getStandardFeaturePriceSet } from "@server/lib/billing"; import { getLineItems, getStandardFeaturePriceSet } from "@server/lib/billing";
import { getTierPriceSet, TierId } from "@server/lib/billing/tiers"; import { getTierPriceSet, TierId } from "@server/lib/billing/tiers";
const createCheckoutSessionSchema = z const createCheckoutSessionSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export async function createCheckoutSession( export async function createCheckoutSession(
req: Request, req: Request,

View File

@@ -23,11 +23,9 @@ import config from "@server/lib/config";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import stripe from "#private/lib/stripe"; import stripe from "#private/lib/stripe";
const createPortalSessionSchema = z const createPortalSessionSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export async function createPortalSession( export async function createPortalSession(
req: Request, req: Request,

View File

@@ -33,11 +33,9 @@ import {
SubscriptionItem SubscriptionItem
} from "@server/db"; } from "@server/db";
const getOrgSchema = z const getOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "get", method: "get",

View File

@@ -27,11 +27,9 @@ import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { FeatureId } from "@server/lib/billing";
import { GetOrgUsageResponse } from "@server/routers/billing/types"; import { GetOrgUsageResponse } from "@server/routers/billing/types";
const getOrgSchema = z const getOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "get", method: "get",

View File

@@ -21,11 +21,9 @@ import { fromZodError } from "zod-validation-error";
import { getOrgTierData } from "#private/lib/billing"; import { getOrgTierData } from "#private/lib/billing";
import { GetOrgTierResponse } from "@server/routers/billing/types"; import { GetOrgTierResponse } from "@server/routers/billing/types";
const getOrgSchema = z const getOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export async function getOrgTier( export async function getOrgTier(
req: Request, req: Request,

View File

@@ -23,13 +23,11 @@ import { fromError } from "zod-validation-error";
import { registry } from "@server/openApi"; import { registry } from "@server/openApi";
import { GetCertificateResponse } from "@server/routers/certificates/types"; import { GetCertificateResponse } from "@server/routers/certificates/types";
const getCertificateSchema = z const getCertificateSchema = z.strictObject({
.object({
domainId: z.string(), domainId: z.string(),
domain: z.string().min(1).max(255), domain: z.string().min(1).max(255),
orgId: z.string() orgId: z.string()
}) });
.strict();
async function query(domainId: string, domain: string) { async function query(domainId: string, domain: string) {
const [domainRecord] = await db const [domainRecord] = await db

View File

@@ -24,12 +24,10 @@ import stoi from "@server/lib/stoi";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const restartCertificateParamsSchema = z const restartCertificateParamsSchema = z.strictObject({
.object({ certId: z.string().transform(stoi).pipe(z.int().positive()),
certId: z.string().transform(stoi).pipe(z.number().int().positive()),
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "post", method: "post",
@@ -41,7 +39,7 @@ registry.registerPath({
certId: z certId: z
.string() .string()
.transform(stoi) .transform(stoi)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
orgId: z.string() orgId: z.string()
}) })
}, },

View File

@@ -23,13 +23,11 @@ import { db, domainNamespaces, resources } from "@server/db";
import { inArray } from "drizzle-orm"; import { inArray } from "drizzle-orm";
import { CheckDomainAvailabilityResponse } from "@server/routers/domain/types"; import { CheckDomainAvailabilityResponse } from "@server/routers/domain/types";
const paramsSchema = z.object({}).strict(); const paramsSchema = z.strictObject({});
const querySchema = z const querySchema = z.strictObject({
.object({
subdomain: z.string() subdomain: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "get", method: "get",

View File

@@ -23,24 +23,22 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z.object({}).strict(); const paramsSchema = z.strictObject({});
const querySchema = z const querySchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
async function query(limit: number, offset: number) { async function query(limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -78,105 +78,78 @@ import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToke
import semver from "semver"; import semver from "semver";
// Zod schemas for request validation // Zod schemas for request validation
const getResourceByDomainParamsSchema = z const getResourceByDomainParamsSchema = z.strictObject({
.object({
domain: z.string().min(1, "Domain is required") domain: z.string().min(1, "Domain is required")
}) });
.strict();
const getUserSessionParamsSchema = z const getUserSessionParamsSchema = z.strictObject({
.object({
userSessionId: z.string().min(1, "User session ID is required") userSessionId: z.string().min(1, "User session ID is required")
}) });
.strict();
const getUserOrgRoleParamsSchema = z const getUserOrgRoleParamsSchema = z.strictObject({
.object({
userId: z.string().min(1, "User ID is required"), userId: z.string().min(1, "User ID is required"),
orgId: z.string().min(1, "Organization ID is required") orgId: z.string().min(1, "Organization ID is required")
}) });
.strict();
const getRoleResourceAccessParamsSchema = z const getRoleResourceAccessParamsSchema = z.strictObject({
.object({
roleId: z roleId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe( .pipe(
z.number().int().positive("Role ID must be a positive integer") z.int().positive("Role ID must be a positive integer")
), ),
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe( .pipe(
z z.int()
.number()
.int()
.positive("Resource ID must be a positive integer") .positive("Resource ID must be a positive integer")
) )
}) });
.strict();
const getUserResourceAccessParamsSchema = z const getUserResourceAccessParamsSchema = z.strictObject({
.object({
userId: z.string().min(1, "User ID is required"), userId: z.string().min(1, "User ID is required"),
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe( .pipe(
z z.int()
.number()
.int()
.positive("Resource ID must be a positive integer") .positive("Resource ID must be a positive integer")
) )
}) });
.strict();
const getResourceRulesParamsSchema = z const getResourceRulesParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe( .pipe(
z z.int()
.number()
.int()
.positive("Resource ID must be a positive integer") .positive("Resource ID must be a positive integer")
) )
}) });
.strict();
const validateResourceSessionTokenParamsSchema = z const validateResourceSessionTokenParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe( .pipe(
z z.int()
.number()
.int()
.positive("Resource ID must be a positive integer") .positive("Resource ID must be a positive integer")
) )
}) });
.strict();
const validateResourceSessionTokenBodySchema = z const validateResourceSessionTokenBodySchema = z.strictObject({
.object({
token: z.string().min(1, "Token is required") token: z.string().min(1, "Token is required")
}) });
.strict();
const validateResourceAccessTokenBodySchema = z const validateResourceAccessTokenBodySchema = z.strictObject({
.object({
accessTokenId: z.string().optional(), accessTokenId: z.string().optional(),
resourceId: z.number().optional(), resourceId: z.number().optional(),
accessToken: z.string() accessToken: z.string()
}) });
.strict();
// Certificates by domains query validation // Certificates by domains query validation
const getCertificatesByDomainsQuerySchema = z const getCertificatesByDomainsQuerySchema = z.strictObject({
.object({
// Accept domains as string or array (domains or domains[]) // Accept domains as string or array (domains or domains[])
domains: z domains: z
.union([z.array(z.string().min(1)), z.string().min(1)]) .union([z.array(z.string().min(1)), z.string().min(1)])
@@ -185,8 +158,7 @@ const getCertificatesByDomainsQuerySchema = z
"domains[]": z "domains[]": z
.union([z.array(z.string().min(1)), z.string().min(1)]) .union([z.array(z.string().min(1)), z.string().min(1)])
.optional() .optional()
}) });
.strict();
// Type exports for request schemas // Type exports for request schemas
export type GetResourceByDomainParams = z.infer< export type GetResourceByDomainParams = z.infer<
@@ -591,11 +563,9 @@ hybridRouter.get(
} }
); );
const getOrgLoginPageParamsSchema = z const getOrgLoginPageParamsSchema = z.strictObject({
.object({
orgId: z.string().min(1) orgId: z.string().min(1)
}) });
.strict();
hybridRouter.get( hybridRouter.get(
"/org/:orgId/login-page", "/org/:orgId/login-page",
@@ -1217,7 +1187,7 @@ hybridRouter.post(
); );
const geoIpLookupParamsSchema = z.object({ const geoIpLookupParamsSchema = z.object({
ip: z.string().ip() ip: z.union([z.ipv4(), z.ipv6()])
}); });
hybridRouter.get( hybridRouter.get(
"/geoip/:ip", "/geoip/:ip",

View File

@@ -20,11 +20,9 @@ import license from "#private/license/license";
import { z } from "zod"; import { z } from "zod";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
const bodySchema = z const bodySchema = z.strictObject({
.object({
licenseKey: z.string().min(1).max(255) licenseKey: z.string().min(1).max(255)
}) });
.strict();
export async function activateLicense( export async function activateLicense(
req: Request, req: Request,

View File

@@ -23,11 +23,9 @@ import { eq } from "drizzle-orm";
import { licenseKey } from "@server/db"; import { licenseKey } from "@server/db";
import license from "#private/license/license"; import license from "#private/license/license";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
licenseKey: z.string().min(1).max(255) licenseKey: z.string().min(1).max(255)
}) });
.strict();
export async function deleteLicenseKey( export async function deleteLicenseKey(
req: Request, req: Request,

View File

@@ -35,18 +35,14 @@ import { TierId } from "@server/lib/billing/tiers";
import { build } from "@server/build"; import { build } from "@server/build";
import { CreateLoginPageResponse } from "@server/routers/loginPage/types"; import { CreateLoginPageResponse } from "@server/routers/loginPage/types";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
subdomain: z.string().nullable().optional(), subdomain: z.string().nullable().optional(),
domainId: z.string() domainId: z.string()
}) });
.strict();
export type CreateLoginPageBody = z.infer<typeof bodySchema>; export type CreateLoginPageBody = z.infer<typeof bodySchema>;

View File

@@ -22,11 +22,9 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { GetLoginPageResponse } from "@server/routers/loginPage/types"; import { GetLoginPageResponse } from "@server/routers/loginPage/types";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
async function query(orgId: string) { async function query(orgId: string) {
const [res] = await db const [res] = await db

View File

@@ -35,14 +35,12 @@ const paramsSchema = z
}) })
.strict(); .strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
subdomain: subdomainSchema.nullable().optional(), subdomain: subdomainSchema.nullable().optional(),
domainId: z.string().optional() domainId: z.string().optional()
}) })
.strict()
.refine((data) => Object.keys(data).length > 0, { .refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided for update" error: "At least one field must be provided for update"
}) })
.refine( .refine(
(data) => { (data) => {
@@ -51,7 +49,9 @@ const bodySchema = z
} }
return true; return true;
}, },
{ message: "Invalid subdomain" } {
error: "Invalid subdomain"
}
); );
export type UpdateLoginPageBody = z.infer<typeof bodySchema>; export type UpdateLoginPageBody = z.infer<typeof bodySchema>;

View File

@@ -22,12 +22,10 @@ import { sendEmail } from "@server/emails";
import SupportEmail from "@server/emails/templates/SupportEmail"; import SupportEmail from "@server/emails/templates/SupportEmail";
import config from "@server/lib/config"; import config from "@server/lib/config";
const bodySchema = z const bodySchema = z.strictObject({
.object({
body: z.string().min(1), body: z.string().min(1),
subject: z.string().min(1).max(255) subject: z.string().min(1).max(255)
}) });
.strict();
export async function sendSupportEmail( export async function sendSupportEmail(
req: Request, req: Request,

View File

@@ -29,15 +29,14 @@ import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers"; import { TierId } from "@server/lib/billing/tiers";
import { CreateOrgIdpResponse } from "@server/routers/orgIdp/types"; import { CreateOrgIdpResponse } from "@server/routers/orgIdp/types";
const paramsSchema = z.object({ orgId: z.string().nonempty() }).strict(); const paramsSchema = z.strictObject({ orgId: z.string().nonempty() });
const bodySchema = z const bodySchema = z.strictObject({
.object({
name: z.string().nonempty(), name: z.string().nonempty(),
clientId: z.string().nonempty(), clientId: z.string().nonempty(),
clientSecret: z.string().nonempty(), clientSecret: z.string().nonempty(),
authUrl: z.string().url(), authUrl: z.url(),
tokenUrl: z.string().url(), tokenUrl: z.url(),
identifierPath: z.string().nonempty(), identifierPath: z.string().nonempty(),
emailPath: z.string().optional(), emailPath: z.string().optional(),
namePath: z.string().optional(), namePath: z.string().optional(),
@@ -45,8 +44,7 @@ const bodySchema = z
autoProvision: z.boolean().optional(), autoProvision: z.boolean().optional(),
variant: z.enum(["oidc", "google", "azure"]).optional().default("oidc"), variant: z.enum(["oidc", "google", "azure"]).optional().default("oidc"),
roleMapping: z.string().optional() roleMapping: z.string().optional()
}) });
.strict();
// registry.registerPath({ // registry.registerPath({
// method: "put", // method: "put",

View File

@@ -24,28 +24,24 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { ListOrgIdpsResponse } from "@server/routers/orgIdp/types"; import { ListOrgIdpsResponse } from "@server/routers/orgIdp/types";
const querySchema = z const querySchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string().nonempty() orgId: z.string().nonempty()
}) });
.strict();
async function query(orgId: string, limit: number, offset: number) { async function query(orgId: string, limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -35,8 +35,7 @@ const paramsSchema = z
}) })
.strict(); .strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
name: z.string().optional(), name: z.string().optional(),
clientId: z.string().optional(), clientId: z.string().optional(),
clientSecret: z.string().optional(), clientSecret: z.string().optional(),
@@ -48,8 +47,7 @@ const bodySchema = z
scopes: z.string().optional(), scopes: z.string().optional(),
autoProvision: z.boolean().optional(), autoProvision: z.boolean().optional(),
roleMapping: z.string().optional() roleMapping: z.string().optional()
}) });
.strict();
export type UpdateOrgIdpResponse = { export type UpdateOrgIdpResponse = {
idpId: number; idpId: number;

View File

@@ -24,19 +24,15 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
const reGenerateSecretParamsSchema = z const reGenerateSecretParamsSchema = z.strictObject({
.object({ clientId: z.string().transform(Number).pipe(z.int().positive())
clientId: z.string().transform(Number).pipe(z.number().int().positive()) });
})
.strict();
const reGenerateSecretBodySchema = z const reGenerateSecretBodySchema = z.strictObject({
.object({
olmId: z.string().min(1).optional(), olmId: z.string().min(1).optional(),
secret: z.string().min(1).optional(), secret: z.string().min(1).optional(),
}) });
.strict();
export type ReGenerateSecretBody = z.infer<typeof reGenerateSecretBodySchema>; export type ReGenerateSecretBody = z.infer<typeof reGenerateSecretBodySchema>;

View File

@@ -29,12 +29,10 @@ export const paramsSchema = z.object({
orgId: z.string() orgId: z.string()
}); });
const bodySchema = z const bodySchema = z.strictObject({
.object({
remoteExitNodeId: z.string().length(15), remoteExitNodeId: z.string().length(15),
secret: z.string().length(48) secret: z.string().length(48)
}) });
.strict();
registry.registerPath({ registry.registerPath({

View File

@@ -25,22 +25,18 @@ import { hashPassword } from "@server/auth/password";
import { addPeer } from "@server/routers/gerbil/peers"; import { addPeer } from "@server/routers/gerbil/peers";
const updateSiteParamsSchema = z const updateSiteParamsSchema = z.strictObject({
.object({ siteId: z.string().transform(Number).pipe(z.int().positive())
siteId: z.string().transform(Number).pipe(z.number().int().positive()) });
})
.strict();
const updateSiteBodySchema = z const updateSiteBodySchema = z.strictObject({
.object({
type: z.enum(["newt", "wireguard"]), type: z.enum(["newt", "wireguard"]),
newtId: z.string().min(1).max(255).optional(), newtId: z.string().min(1).max(255).optional(),
newtSecret: z.string().min(1).max(255).optional(), newtSecret: z.string().min(1).max(255).optional(),
exitNodeId: z.number().int().positive().optional(), exitNodeId: z.int().positive().optional(),
pubKey: z.string().optional(), pubKey: z.string().optional(),
subnet: z.string().optional(), subnet: z.string().optional(),
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "post", method: "post",

View File

@@ -35,12 +35,10 @@ export const paramsSchema = z.object({
orgId: z.string() orgId: z.string()
}); });
const bodySchema = z const bodySchema = z.strictObject({
.object({
remoteExitNodeId: z.string().length(15), remoteExitNodeId: z.string().length(15),
secret: z.string().length(48) secret: z.string().length(48)
}) });
.strict();
export type CreateRemoteExitNodeBody = z.infer<typeof bodySchema>; export type CreateRemoteExitNodeBody = z.infer<typeof bodySchema>;

View File

@@ -24,12 +24,10 @@ import { fromError } from "zod-validation-error";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { FeatureId } from "@server/lib/billing";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string().min(1), orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1) remoteExitNodeId: z.string().min(1)
}) });
.strict();
export async function deleteRemoteExitNode( export async function deleteRemoteExitNode(
req: Request, req: Request,

View File

@@ -23,12 +23,10 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { GetRemoteExitNodeResponse } from "@server/routers/remoteExitNode/types"; import { GetRemoteExitNodeResponse } from "@server/routers/remoteExitNode/types";
const getRemoteExitNodeSchema = z const getRemoteExitNodeSchema = z.strictObject({
.object({
orgId: z.string().min(1), orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1) remoteExitNodeId: z.string().min(1)
}) });
.strict();
async function query(remoteExitNodeId: string) { async function query(remoteExitNodeId: string) {
const [remoteExitNode] = await db const [remoteExitNode] = await db

View File

@@ -23,11 +23,9 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { ListRemoteExitNodesResponse } from "@server/routers/remoteExitNode/types"; import { ListRemoteExitNodesResponse } from "@server/routers/remoteExitNode/types";
const listRemoteExitNodesParamsSchema = z const listRemoteExitNodesParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const listRemoteExitNodesSchema = z.object({ const listRemoteExitNodesSchema = z.object({
limit: z limit: z
@@ -35,13 +33,13 @@ const listRemoteExitNodesSchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
export function queryRemoteExitNodes(orgId: string) { export function queryRemoteExitNodes(orgId: string) {

View File

@@ -21,11 +21,9 @@ import { fromError } from "zod-validation-error";
import { z } from "zod"; import { z } from "zod";
import { PickRemoteExitNodeDefaultsResponse } from "@server/routers/remoteExitNode/types"; import { PickRemoteExitNodeDefaultsResponse } from "@server/routers/remoteExitNode/types";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export async function pickRemoteExitNodeDefaults( export async function pickRemoteExitNodeDefaults(
req: Request, req: Request,

View File

@@ -10,11 +10,9 @@ import { and, eq } from "drizzle-orm";
import { db } from "@server/db"; import { db } from "@server/db";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const deleteAccessTokenParamsSchema = z const deleteAccessTokenParamsSchema = z.strictObject({
.object({
accessTokenId: z.string() accessTokenId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "delete", method: "delete",

View File

@@ -24,22 +24,18 @@ import { encodeHexLowerCase } from "@oslojs/encoding";
import { sha256 } from "@oslojs/crypto/sha2"; import { sha256 } from "@oslojs/crypto/sha2";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
export const generateAccessTokenBodySchema = z export const generateAccessTokenBodySchema = z.strictObject({
.object({ validForSeconds: z.int().positive().optional(), // seconds
validForSeconds: z.number().int().positive().optional(), // seconds
title: z.string().optional(), title: z.string().optional(),
description: z.string().optional() description: z.string().optional()
}) });
.strict();
export const generateAccssTokenParamsSchema = z export const generateAccssTokenParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
export type GenerateAccessTokenResponse = Omit< export type GenerateAccessTokenResponse = Omit<
ResourceAccessToken, ResourceAccessToken,

View File

@@ -17,18 +17,16 @@ import stoi from "@server/lib/stoi";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const listAccessTokensParamsSchema = z const listAccessTokensParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.optional() .optional()
.transform(stoi) .transform(stoi)
.pipe(z.number().int().positive().optional()), .pipe(z.int().positive().optional()),
orgId: z.string().optional() orgId: z.string().optional()
}) })
.strict()
.refine((data) => !!data.resourceId !== !!data.orgId, { .refine((data) => !!data.resourceId !== !!data.orgId, {
message: "Either resourceId or orgId must be provided, but not both" error: "Either resourceId or orgId must be provided, but not both"
}); });
const listAccessTokensSchema = z.object({ const listAccessTokensSchema = z.object({
@@ -37,14 +35,14 @@ const listAccessTokensSchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
function queryAccessTokens( function queryAccessTokens(

View File

@@ -14,11 +14,9 @@ import {
import logger from "@server/logger"; import logger from "@server/logger";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
const bodySchema = z const bodySchema = z.strictObject({
.object({
name: z.string().min(1).max(255) name: z.string().min(1).max(255)
}) });
.strict();
export type CreateRootApiKeyBody = z.infer<typeof bodySchema>; export type CreateRootApiKeyBody = z.infer<typeof bodySchema>;

View File

@@ -20,13 +20,13 @@ const querySchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
function queryActions(apiKeyId: string) { function queryActions(apiKeyId: string) {

View File

@@ -16,13 +16,13 @@ const querySchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
const paramsSchema = z.object({ const paramsSchema = z.object({

View File

@@ -15,13 +15,13 @@ const querySchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
function queryApiKeys() { function queryApiKeys() {

View File

@@ -10,13 +10,10 @@ import { fromError } from "zod-validation-error";
import { eq, and, inArray } from "drizzle-orm"; import { eq, and, inArray } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const bodySchema = z const bodySchema = z.strictObject({
.object({ actionIds: z.tuple([z.string()], z.string())
actionIds: z
.array(z.string().nonempty())
.transform((v) => Array.from(new Set(v))) .transform((v) => Array.from(new Set(v)))
}) });
.strict();
const paramsSchema = z.object({ const paramsSchema = z.object({
apiKeyId: z.string().nonempty() apiKeyId: z.string().nonempty()

View File

@@ -9,13 +9,10 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { eq, and, inArray } from "drizzle-orm"; import { eq, and, inArray } from "drizzle-orm";
const bodySchema = z const bodySchema = z.strictObject({
.object({ orgIds: z.tuple([z.string()], z.string())
orgIds: z
.array(z.string().nonempty())
.transform((v) => Array.from(new Set(v))) .transform((v) => Array.from(new Set(v)))
}) });
.strict();
const paramsSchema = z.object({ const paramsSchema = z.object({
apiKeyId: z.string().nonempty() apiKeyId: z.string().nonempty()

View File

@@ -17,13 +17,13 @@ export const queryAccessAuditLogsQuery = z.object({
timeStart: z timeStart: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeStart must be a valid ISO date string" error: "timeStart must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)), .transform((val) => Math.floor(new Date(val).getTime() / 1000)),
timeEnd: z timeEnd: z
.string() .string()
.refine((val) => !isNaN(Date.parse(val)), { .refine((val) => !isNaN(Date.parse(val)), {
message: "timeEnd must be a valid ISO date string" error: "timeEnd must be a valid ISO date string"
}) })
.transform((val) => Math.floor(new Date(val).getTime() / 1000)) .transform((val) => Math.floor(new Date(val).getTime() / 1000))
.optional() .optional()
@@ -37,13 +37,13 @@ export const queryAccessAuditLogsQuery = z.object({
.string() .string()
.optional() .optional()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
.optional(), .optional(),
resourceId: z resourceId: z
.string() .string()
.optional() .optional()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
.optional(), .optional(),
actor: z.string().optional(), actor: z.string().optional(),
location: z.string().optional(), location: z.string().optional(),
@@ -54,13 +54,13 @@ export const queryAccessAuditLogsQuery = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
export const queryRequestAuditLogsParams = z.object({ export const queryRequestAuditLogsParams = z.object({

View File

@@ -22,13 +22,11 @@ import { sendEmail } from "@server/emails";
import ConfirmPasswordReset from "@server/emails/templates/NotifyResetPassword"; import ConfirmPasswordReset from "@server/emails/templates/NotifyResetPassword";
import config from "@server/lib/config"; import config from "@server/lib/config";
export const changePasswordBody = z export const changePasswordBody = z.strictObject({
.object({
oldPassword: z.string(), oldPassword: z.string(),
newPassword: passwordSchema, newPassword: passwordSchema,
code: z.string().optional() code: z.string().optional()
}) });
.strict();
export type ChangePasswordBody = z.infer<typeof changePasswordBody>; export type ChangePasswordBody = z.infer<typeof changePasswordBody>;

View File

@@ -7,10 +7,10 @@ import { response } from "@server/lib/response";
import { validateResourceSessionToken } from "@server/auth/sessions/resource"; import { validateResourceSessionToken } from "@server/auth/sessions/resource";
import logger from "@server/logger"; import logger from "@server/logger";
export const params = z.object({ export const params = z.strictObject({
token: z.string(), token: z.string(),
resourceId: z.string().transform(Number).pipe(z.number().int().positive()), resourceId: z.string().transform(Number).pipe(z.int().positive()),
}).strict(); });
export type CheckResourceSessionParams = z.infer<typeof params>; export type CheckResourceSessionParams = z.infer<typeof params>;

View File

@@ -16,12 +16,10 @@ import config from "@server/lib/config";
import { unauthorized } from "@server/auth/unauthorizedResponse"; import { unauthorized } from "@server/auth/unauthorizedResponse";
import { UserType } from "@server/types/UserTypes"; import { UserType } from "@server/types/UserTypes";
export const disable2faBody = z export const disable2faBody = z.strictObject({
.object({
password: z.string(), password: z.string(),
code: z.string().optional() code: z.string().optional()
}) });
.strict();
export type Disable2faBody = z.infer<typeof disable2faBody>; export type Disable2faBody = z.infer<typeof disable2faBody>;

View File

@@ -20,14 +20,12 @@ import { verifySession } from "@server/auth/sessions/verifySession";
import { UserType } from "@server/types/UserTypes"; import { UserType } from "@server/types/UserTypes";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit"; import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
export const loginBodySchema = z export const loginBodySchema = z.strictObject({
.object({ email: z.email().toLowerCase(),
email: z.string().toLowerCase().email(),
password: z.string(), password: z.string(),
code: z.string().optional(), code: z.string().optional(),
resourceGuid: z.string().optional() resourceGuid: z.string().optional()
}) });
.strict();
export type LoginBody = z.infer<typeof loginBodySchema>; export type LoginBody = z.infer<typeof loginBodySchema>;

View File

@@ -17,11 +17,9 @@ import ResetPasswordCode from "@server/emails/templates/ResetPasswordCode";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
import { UserType } from "@server/types/UserTypes"; import { UserType } from "@server/types/UserTypes";
export const requestPasswordResetBody = z export const requestPasswordResetBody = z.strictObject({
.object({ email: z.email().toLowerCase()
email: z.string().toLowerCase().email() });
})
.strict();
export type RequestPasswordResetBody = z.infer<typeof requestPasswordResetBody>; export type RequestPasswordResetBody = z.infer<typeof requestPasswordResetBody>;

View File

@@ -16,12 +16,10 @@ import { UserType } from "@server/types/UserTypes";
import { verifySession } from "@server/auth/sessions/verifySession"; import { verifySession } from "@server/auth/sessions/verifySession";
import config from "@server/lib/config"; import config from "@server/lib/config";
export const requestTotpSecretBody = z export const requestTotpSecretBody = z.strictObject({
.object({
password: z.string(), password: z.string(),
email: z.string().email().optional() email: z.email().optional()
}) });
.strict();
export type RequestTotpSecretBody = z.infer<typeof requestTotpSecretBody>; export type RequestTotpSecretBody = z.infer<typeof requestTotpSecretBody>;

View File

@@ -17,14 +17,12 @@ import ConfirmPasswordReset from "@server/emails/templates/NotifyResetPassword";
import { sendEmail } from "@server/emails"; import { sendEmail } from "@server/emails";
import { passwordSchema } from "@server/auth/passwordSchema"; import { passwordSchema } from "@server/auth/passwordSchema";
export const resetPasswordBody = z export const resetPasswordBody = z.strictObject({
.object({ email: z.email().toLowerCase(),
email: z.string().toLowerCase().email(),
token: z.string(), // reset secret code token: z.string(), // reset secret code
newPassword: passwordSchema, newPassword: passwordSchema,
code: z.string().optional() // 2fa code code: z.string().optional() // 2fa code
}) });
.strict();
export type ResetPasswordBody = z.infer<typeof resetPasswordBody>; export type ResetPasswordBody = z.infer<typeof resetPasswordBody>;

View File

@@ -99,28 +99,28 @@ async function clearChallenge(sessionId: string) {
await db.delete(webauthnChallenge).where(eq(webauthnChallenge.sessionId, sessionId)); await db.delete(webauthnChallenge).where(eq(webauthnChallenge.sessionId, sessionId));
} }
export const registerSecurityKeyBody = z.object({ export const registerSecurityKeyBody = z.strictObject({
name: z.string().min(1), name: z.string().min(1),
password: z.string().min(1), password: z.string().min(1),
code: z.string().optional() code: z.string().optional()
}).strict(); });
export const verifyRegistrationBody = z.object({ export const verifyRegistrationBody = z.strictObject({
credential: z.any() credential: z.any()
}).strict(); });
export const startAuthenticationBody = z.object({ export const startAuthenticationBody = z.strictObject({
email: z.string().email().optional() email: z.email().optional()
}).strict(); });
export const verifyAuthenticationBody = z.object({ export const verifyAuthenticationBody = z.strictObject({
credential: z.any() credential: z.any()
}).strict(); });
export const deleteSecurityKeyBody = z.object({ export const deleteSecurityKeyBody = z.strictObject({
password: z.string().min(1), password: z.string().min(1),
code: z.string().optional() code: z.string().optional()
}).strict(); });
export async function startRegistration( export async function startRegistration(
req: Request, req: Request,

View File

@@ -14,7 +14,7 @@ import { UserType } from "@server/types/UserTypes";
import moment from "moment"; import moment from "moment";
export const bodySchema = z.object({ export const bodySchema = z.object({
email: z.string().toLowerCase().email(), email: z.email().toLowerCase(),
password: passwordSchema, password: passwordSchema,
setupToken: z.string().min(1, "Setup token is required") setupToken: z.string().min(1, "Setup token is required")
}); });

View File

@@ -26,7 +26,7 @@ import { build } from "@server/build";
import resend, { AudienceIds, moveEmailToAudience } from "#dynamic/lib/resend"; import resend, { AudienceIds, moveEmailToAudience } from "#dynamic/lib/resend";
export const signupBodySchema = z.object({ export const signupBodySchema = z.object({
email: z.string().toLowerCase().email(), email: z.email().toLowerCase(),
password: passwordSchema, password: passwordSchema,
inviteToken: z.string().optional(), inviteToken: z.string().optional(),
inviteId: z.string().optional(), inviteId: z.string().optional(),

View File

@@ -8,11 +8,9 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
const validateSetupTokenSchema = z const validateSetupTokenSchema = z.strictObject({
.object({
token: z.string().min(1, "Token is required") token: z.string().min(1, "Token is required")
}) });
.strict();
export type ValidateSetupTokenResponse = { export type ValidateSetupTokenResponse = {
valid: boolean; valid: boolean;

View File

@@ -13,11 +13,9 @@ import logger from "@server/logger";
import { freeLimitSet, limitsService } from "@server/lib/billing"; import { freeLimitSet, limitsService } from "@server/lib/billing";
import { build } from "@server/build"; import { build } from "@server/build";
export const verifyEmailBody = z export const verifyEmailBody = z.strictObject({
.object({
code: z.string() code: z.string()
}) });
.strict();
export type VerifyEmailBody = z.infer<typeof verifyEmailBody>; export type VerifyEmailBody = z.infer<typeof verifyEmailBody>;

View File

@@ -18,13 +18,11 @@ import { generateBackupCodes } from "@server/lib/totp";
import { verifySession } from "@server/auth/sessions/verifySession"; import { verifySession } from "@server/auth/sessions/verifySession";
import { unauthorized } from "@server/auth/unauthorizedResponse"; import { unauthorized } from "@server/auth/unauthorizedResponse";
export const verifyTotpBody = z export const verifyTotpBody = z.strictObject({
.object({ email: z.email().optional(),
email: z.string().email().optional(),
password: z.string().optional(), password: z.string().optional(),
code: z.string() code: z.string()
}) });
.strict();
export type VerifyTotpBody = z.infer<typeof verifyTotpBody>; export type VerifyTotpBody = z.infer<typeof verifyTotpBody>;

View File

@@ -40,10 +40,10 @@ import { logRequestAudit } from "./logRequestAudit";
import cache from "@server/lib/cache"; import cache from "@server/lib/cache";
const verifyResourceSessionSchema = z.object({ const verifyResourceSessionSchema = z.object({
sessions: z.record(z.string()).optional(), sessions: z.record(z.string(), z.string()).optional(),
headers: z.record(z.string()).optional(), headers: z.record(z.string(), z.string()).optional(),
query: z.record(z.string()).optional(), query: z.record(z.string(), z.string()).optional(),
originalRequestURL: z.string().url(), originalRequestURL: z.url(),
scheme: z.string(), scheme: z.string(),
host: z.string(), host: z.string(),
path: z.string(), path: z.string(),

View File

@@ -8,17 +8,13 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { applyBlueprint } from "@server/lib/blueprints/applyBlueprint"; import { applyBlueprint } from "@server/lib/blueprints/applyBlueprint";
const applyBlueprintSchema = z const applyBlueprintSchema = z.strictObject({
.object({
blueprint: z.string() blueprint: z.string()
}) });
.strict();
const applyBlueprintParamsSchema = z const applyBlueprintParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "put", method: "put",

View File

@@ -12,15 +12,13 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { BlueprintData } from "./types"; import { BlueprintData } from "./types";
const getBlueprintSchema = z const getBlueprintSchema = z.strictObject({
.object({
blueprintId: z blueprintId: z
.string() .string()
.transform(stoi) .transform(stoi)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
orgId: z.string() orgId: z.string()
}) });
.strict();
async function query(blueprintId: number, orgId: string) { async function query(blueprintId: number, orgId: string) {
// Get the client // Get the client

View File

@@ -10,28 +10,24 @@ import { fromZodError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { BlueprintData } from "./types"; import { BlueprintData } from "./types";
const listBluePrintsParamsSchema = z const listBluePrintsParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const listBluePrintsSchema = z const listBluePrintsSchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
async function queryBlueprints(orgId: string, limit: number, offset: number) { async function queryBlueprints(orgId: string, limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -26,22 +26,18 @@ import { isIpInCidr } from "@server/lib/ip";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { listExitNodes } from "#dynamic/lib/exitNodes"; import { listExitNodes } from "#dynamic/lib/exitNodes";
const createClientParamsSchema = z const createClientParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const createClientSchema = z const createClientSchema = z.strictObject({
.object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
siteIds: z.array(z.number().int().positive()), siteIds: z.array(z.int().positive()),
olmId: z.string(), olmId: z.string(),
secret: z.string(), secret: z.string(),
subnet: z.string(), subnet: z.string(),
type: z.enum(["olm"]) type: z.enum(["olm"])
}) });
.strict();
export type CreateClientBody = z.infer<typeof createClientSchema>; export type CreateClientBody = z.infer<typeof createClientSchema>;

View File

@@ -10,11 +10,9 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const deleteClientSchema = z const deleteClientSchema = z.strictObject({
.object({ clientId: z.string().transform(Number).pipe(z.int().positive())
clientId: z.string().transform(Number).pipe(z.number().int().positive()) });
})
.strict();
registry.registerPath({ registry.registerPath({
method: "delete", method: "delete",

View File

@@ -11,11 +11,9 @@ import stoi from "@server/lib/stoi";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const getClientSchema = z const getClientSchema = z.strictObject({
.object({ clientId: z.string().transform(stoi).pipe(z.int().positive())
clientId: z.string().transform(stoi).pipe(z.number().int().positive()) });
})
.strict();
async function query(clientId: number) { async function query(clientId: number) {
// Get the client // Get the client

View File

@@ -78,11 +78,9 @@ async function getLatestOlmVersion(): Promise<string | null> {
} }
const listClientsParamsSchema = z const listClientsParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const listClientsSchema = z.object({ const listClientsSchema = z.object({
limit: z limit: z
@@ -90,13 +88,13 @@ const listClientsSchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
function queryClients(orgId: string, accessibleClientIds: number[]) { function queryClients(orgId: string, accessibleClientIds: number[]) {

View File

@@ -15,11 +15,9 @@ export type PickClientDefaultsResponse = {
subnet: string; subnet: string;
}; };
const pickClientDefaultsSchema = z const pickClientDefaultsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "get", method: "get",

View File

@@ -20,20 +20,16 @@ import {
import { sendToExitNode } from "#dynamic/lib/exitNodes"; import { sendToExitNode } from "#dynamic/lib/exitNodes";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
const updateClientParamsSchema = z const updateClientParamsSchema = z.strictObject({
.object({ clientId: z.string().transform(Number).pipe(z.int().positive())
clientId: z.string().transform(Number).pipe(z.number().int().positive()) });
})
.strict();
const updateClientSchema = z const updateClientSchema = z.strictObject({
.object({
name: z.string().min(1).max(255).optional(), name: z.string().min(1).max(255).optional(),
siteIds: z siteIds: z
.array(z.number().int().positive()) .array(z.int().positive())
.optional(), .optional(),
}) });
.strict();
export type UpdateClientBody = z.infer<typeof updateClientSchema>; export type UpdateClientBody = z.infer<typeof updateClientSchema>;

View File

@@ -15,20 +15,16 @@ import { isSecondLevelDomain, isValidDomain } from "@server/lib/validators";
import { build } from "@server/build"; import { build } from "@server/build";
import config from "@server/lib/config"; import config from "@server/lib/config";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
type: z.enum(["ns", "cname", "wildcard"]), type: z.enum(["ns", "cname", "wildcard"]),
baseDomain: subdomainSchema, baseDomain: subdomainSchema,
certResolver: z.string().optional().nullable(), certResolver: z.string().optional().nullable(),
preferWildcardCert: z.boolean().optional().nullable() // optional, only for wildcard preferWildcardCert: z.boolean().optional().nullable() // optional, only for wildcard
}) });
.strict();
export type CreateDomainResponse = { export type CreateDomainResponse = {

View File

@@ -10,12 +10,10 @@ import { and, eq } from "drizzle-orm";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { FeatureId } from "@server/lib/billing";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
domainId: z.string(), domainId: z.string(),
orgId: z.string() orgId: z.string()
}) });
.strict();
export type DeleteAccountDomainResponse = { export type DeleteAccountDomainResponse = {
success: boolean; success: boolean;

View File

@@ -10,12 +10,10 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { getServerIp } from "@server/lib/serverIpService"; // your in-memory IP module import { getServerIp } from "@server/lib/serverIpService"; // your in-memory IP module
const getDNSRecordsSchema = z const getDNSRecordsSchema = z.strictObject({
.object({
domainId: z.string(), domainId: z.string(),
orgId: z.string() orgId: z.string()
}) });
.strict();
async function query(domainId: string) { async function query(domainId: string) {
const records = await db const records = await db

View File

@@ -10,14 +10,12 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { domain } from "zod/v4/core/regexes"; import { domain } from "zod/v4/core/regexes";
const getDomainSchema = z const getDomainSchema = z.strictObject({
.object({
domainId: z domainId: z
.string() .string()
.optional(), .optional(),
orgId: z.string().optional() orgId: z.string().optional()
}) });
.strict();
async function query(domainId?: string, orgId?: string) { async function query(domainId?: string, orgId?: string) {
if (domainId) { if (domainId) {

View File

@@ -10,28 +10,24 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const listDomainsParamsSchema = z const listDomainsParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const listDomainsSchema = z const listDomainsSchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
async function queryDomains(orgId: string, limit: number, offset: number) { async function queryDomains(orgId: string, limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -8,12 +8,10 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
domainId: z.string(), domainId: z.string(),
orgId: z.string() orgId: z.string()
}) });
.strict();
export type RestartOrgDomainResponse = { export type RestartOrgDomainResponse = {
success: boolean; success: boolean;

View File

@@ -9,19 +9,15 @@ import { fromError } from "zod-validation-error";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
orgId: z.string(), orgId: z.string(),
domainId: z.string() domainId: z.string()
}) });
.strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
certResolver: z.string().optional().nullable(), certResolver: z.string().optional().nullable(),
preferWildcardCert: z.boolean().optional().nullable() preferWildcardCert: z.boolean().optional().nullable()
}) });
.strict();
export type UpdateDomainResponse = { export type UpdateDomainResponse = {
domainId: string; domainId: string;

View File

@@ -11,19 +11,15 @@ import config from "@server/lib/config";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import { idp, idpOrg } from "@server/db"; import { idp, idpOrg } from "@server/db";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
idpId: z.coerce.number(), idpId: z.coerce.number(),
orgId: z.string() orgId: z.string()
}) });
.strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
roleMapping: z.string().optional(), roleMapping: z.string().optional(),
orgMapping: z.string().optional() orgMapping: z.string().optional()
}) });
.strict();
export type CreateIdpOrgPolicyResponse = {}; export type CreateIdpOrgPolicyResponse = {};

View File

@@ -12,22 +12,20 @@ import { generateOidcRedirectUrl } from "@server/lib/idp/generateRedirectUrl";
import { encrypt } from "@server/lib/crypto"; import { encrypt } from "@server/lib/crypto";
import config from "@server/lib/config"; import config from "@server/lib/config";
const paramsSchema = z.object({}).strict(); const paramsSchema = z.strictObject({});
const bodySchema = z const bodySchema = z.strictObject({
.object({
name: z.string().nonempty(), name: z.string().nonempty(),
clientId: z.string().nonempty(), clientId: z.string().nonempty(),
clientSecret: z.string().nonempty(), clientSecret: z.string().nonempty(),
authUrl: z.string().url(), authUrl: z.url(),
tokenUrl: z.string().url(), tokenUrl: z.url(),
identifierPath: z.string().nonempty(), identifierPath: z.string().nonempty(),
emailPath: z.string().optional(), emailPath: z.string().optional(),
namePath: z.string().optional(), namePath: z.string().optional(),
scopes: z.string().nonempty(), scopes: z.string().nonempty(),
autoProvision: z.boolean().optional() autoProvision: z.boolean().optional()
}) });
.strict();
export type CreateIdpResponse = { export type CreateIdpResponse = {
idpId: number; idpId: number;

View File

@@ -10,12 +10,10 @@ import { idp, idpOrg } from "@server/db";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
idpId: z.coerce.number(), idpId: z.coerce.number(),
orgId: z.string() orgId: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "delete", method: "delete",

View File

@@ -23,11 +23,9 @@ const paramsSchema = z
}) })
.strict(); .strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
redirectUrl: z.string() redirectUrl: z.string()
}) });
.strict();
const querySchema = z.object({ const querySchema = z.object({
orgId: z.string().optional() // check what actuall calls it orgId: z.string().optional() // check what actuall calls it

View File

@@ -14,22 +14,20 @@ const paramsSchema = z.object({
idpId: z.coerce.number() idpId: z.coerce.number()
}); });
const querySchema = z const querySchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
async function query(idpId: number, limit: number, offset: number) { async function query(idpId: number, limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -10,22 +10,20 @@ import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const querySchema = z const querySchema = z.strictObject({
.object({
limit: z limit: z
.string() .string()
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()), .pipe(z.int().nonnegative()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}) });
.strict();
async function query(limit: number, offset: number) { async function query(limit: number, offset: number) {
const res = await db const res = await db

View File

@@ -10,19 +10,15 @@ import { OpenAPITags, registry } from "@server/openApi";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import { idp, idpOrg } from "@server/db"; import { idp, idpOrg } from "@server/db";
const paramsSchema = z const paramsSchema = z.strictObject({
.object({
idpId: z.coerce.number(), idpId: z.coerce.number(),
orgId: z.string() orgId: z.string()
}) });
.strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
roleMapping: z.string().optional(), roleMapping: z.string().optional(),
orgMapping: z.string().optional() orgMapping: z.string().optional()
}) });
.strict();
export type UpdateIdpOrgPolicyResponse = {}; export type UpdateIdpOrgPolicyResponse = {};

View File

@@ -18,8 +18,7 @@ const paramsSchema = z
}) })
.strict(); .strict();
const bodySchema = z const bodySchema = z.strictObject({
.object({
name: z.string().optional(), name: z.string().optional(),
clientId: z.string().optional(), clientId: z.string().optional(),
clientSecret: z.string().optional(), clientSecret: z.string().optional(),
@@ -32,8 +31,7 @@ const bodySchema = z
autoProvision: z.boolean().optional(), autoProvision: z.boolean().optional(),
defaultRoleMapping: z.string().optional(), defaultRoleMapping: z.string().optional(),
defaultOrgMapping: z.string().optional() defaultOrgMapping: z.string().optional()
}) });
.strict();
export type UpdateIdpResponse = { export type UpdateIdpResponse = {
idpId: number; idpId: number;

View File

@@ -23,12 +23,10 @@ export type CreateNewtResponse = {
secret: string; secret: string;
}; };
const createNewtSchema = z const createNewtSchema = z.strictObject({
.object({
newtId: z.string(), newtId: z.string(),
secret: z.string() secret: z.string()
}) });
.strict();
export async function createNewt( export async function createNewt(
req: Request, req: Request,

View File

@@ -18,7 +18,7 @@ import { sendToExitNode } from "#dynamic/lib/exitNodes";
const inputSchema = z.object({ const inputSchema = z.object({
publicKey: z.string(), publicKey: z.string(),
port: z.number().int().positive() port: z.int().positive()
}); });
type Input = z.infer<typeof inputSchema>; type Input = z.infer<typeof inputSchema>;

View File

@@ -23,12 +23,10 @@ export type CreateNewtResponse = {
secret: string; secret: string;
}; };
const createNewtSchema = z const createNewtSchema = z.strictObject({
.object({
newtId: z.string(), newtId: z.string(),
secret: z.string() secret: z.string()
}) });
.strict();
export async function createNewt( export async function createNewt(
req: Request, req: Request,

View File

@@ -9,11 +9,9 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
const getOrgSchema = z const getOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export async function checkId( export async function checkId(
req: Request, req: Request,

View File

@@ -27,13 +27,11 @@ import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { FeatureId } from "@server/lib/billing";
import { build } from "@server/build"; import { build } from "@server/build";
const createOrgSchema = z const createOrgSchema = z.strictObject({
.object({
orgId: z.string(), orgId: z.string(),
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
subnet: z.string() subnet: z.string()
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "put", method: "put",

View File

@@ -13,11 +13,9 @@ import { sendToClient } from "#dynamic/routers/ws";
import { deletePeer } from "../gerbil/peers"; import { deletePeer } from "../gerbil/peers";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const deleteOrgSchema = z const deleteOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export type DeleteOrgResponse = {}; export type DeleteOrgResponse = {};

View File

@@ -10,11 +10,9 @@ import logger from "@server/logger";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const getOrgSchema = z const getOrgSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export type GetOrgResponse = { export type GetOrgResponse = {
org: Org; org: Org;

View File

@@ -18,11 +18,9 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
const getOrgParamsSchema = z const getOrgParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
export type GetOrgOverviewResponse = { export type GetOrgOverviewResponse = {
orgName: string; orgName: string;

View File

@@ -16,13 +16,13 @@ const listOrgsSchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
registry.registerPath({ registry.registerPath({

View File

@@ -20,13 +20,13 @@ const listOrgsSchema = z.object({
.optional() .optional()
.default("1000") .default("1000")
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()), .pipe(z.int().positive()),
offset: z offset: z
.string() .string()
.optional() .optional()
.default("0") .default("0")
.transform(Number) .transform(Number)
.pipe(z.number().int().nonnegative()) .pipe(z.int().nonnegative())
}); });
// registry.registerPath({ // registry.registerPath({

View File

@@ -15,14 +15,11 @@ import { getOrgTierData } from "#dynamic/lib/billing";
import { TierId } from "@server/lib/billing/tiers"; import { TierId } from "@server/lib/billing/tiers";
import { cache } from "@server/lib/cache"; import { cache } from "@server/lib/cache";
const updateOrgParamsSchema = z const updateOrgParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const updateOrgBodySchema = z const updateOrgBodySchema = z.strictObject({
.object({
name: z.string().min(1).max(255).optional(), name: z.string().min(1).max(255).optional(),
requireTwoFactor: z.boolean().optional(), requireTwoFactor: z.boolean().optional(),
maxSessionLengthHours: z.number().nullable().optional(), maxSessionLengthHours: z.number().nullable().optional(),
@@ -40,9 +37,8 @@ const updateOrgBodySchema = z
.min(build === "saas" ? 0 : -1) .min(build === "saas" ? 0 : -1)
.optional() .optional()
}) })
.strict()
.refine((data) => Object.keys(data).length > 0, { .refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided for update" error: "At least one field must be provided for update"
}); });
registry.registerPath({ registry.registerPath({

View File

@@ -10,29 +10,22 @@ import { fromError } from "zod-validation-error";
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const addEmailToResourceWhitelistBodySchema = z const addEmailToResourceWhitelistBodySchema = z.strictObject({
.object({ email: z.email()
email: z
.string()
.email()
.or( .or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, { z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
message: error: "Invalid email address. Wildcard (*) must be the entire local part."
"Invalid email address. Wildcard (*) must be the entire local part."
}) })
) )
.transform((v) => v.toLowerCase()) .transform((v) => v.toLowerCase())
}) });
.strict();
const addEmailToResourceWhitelistParamsSchema = z const addEmailToResourceWhitelistParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "post", method: "post",

View File

@@ -15,22 +15,18 @@ import config from "@server/lib/config";
import stoi from "@server/lib/stoi"; import stoi from "@server/lib/stoi";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit"; import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
const authWithAccessTokenBodySchema = z const authWithAccessTokenBodySchema = z.strictObject({
.object({
accessToken: z.string(), accessToken: z.string(),
accessTokenId: z.string().optional() accessTokenId: z.string().optional()
}) });
.strict();
const authWithAccessTokenParamsSchema = z const authWithAccessTokenParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.optional() .optional()
.transform(stoi) .transform(stoi)
.pipe(z.number().int().positive().optional()) .pipe(z.int().positive().optional())
}) });
.strict();
export type AuthWithAccessTokenResponse = { export type AuthWithAccessTokenResponse = {
session?: string; session?: string;

View File

@@ -15,20 +15,16 @@ import { verifyPassword } from "@server/auth/password";
import config from "@server/lib/config"; import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit"; import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
export const authWithPasswordBodySchema = z export const authWithPasswordBodySchema = z.strictObject({
.object({
password: z.string() password: z.string()
}) });
.strict();
export const authWithPasswordParamsSchema = z export const authWithPasswordParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
export type AuthWithPasswordResponse = { export type AuthWithPasswordResponse = {
session?: string; session?: string;

View File

@@ -14,20 +14,16 @@ import { verifyPassword } from "@server/auth/password";
import config from "@server/lib/config"; import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit"; import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
export const authWithPincodeBodySchema = z export const authWithPincodeBodySchema = z.strictObject({
.object({
pincode: z.string() pincode: z.string()
}) });
.strict();
export const authWithPincodeParamsSchema = z export const authWithPincodeParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
export type AuthWithPincodeResponse = { export type AuthWithPincodeResponse = {
session?: string; session?: string;

View File

@@ -14,21 +14,17 @@ import logger from "@server/logger";
import config from "@server/lib/config"; import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit"; import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
const authWithWhitelistBodySchema = z const authWithWhitelistBodySchema = z.strictObject({
.object({ email: z.email().toLowerCase(),
email: z.string().toLowerCase().email(),
otp: z.string().optional() otp: z.string().optional()
}) });
.strict();
const authWithWhitelistParamsSchema = z const authWithWhitelistParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
export type AuthWithWhitelistResponse = { export type AuthWithWhitelistResponse = {
otpSent?: boolean; otpSent?: boolean;

View File

@@ -25,14 +25,11 @@ import { createCertificate } from "#dynamic/routers/certificates/createCertifica
import { getUniqueResourceName } from "@server/db/names"; import { getUniqueResourceName } from "@server/db/names";
import { validateAndConstructDomain } from "@server/lib/domainUtils"; import { validateAndConstructDomain } from "@server/lib/domainUtils";
const createResourceParamsSchema = z const createResourceParamsSchema = z.strictObject({
.object({
orgId: z.string() orgId: z.string()
}) });
.strict();
const createHttpResourceSchema = z const createHttpResourceSchema = z.strictObject({
.object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
subdomain: z.string().nullable().optional(), subdomain: z.string().nullable().optional(),
http: z.boolean(), http: z.boolean(),
@@ -40,7 +37,6 @@ const createHttpResourceSchema = z
domainId: z.string(), domainId: z.string(),
stickySession: z.boolean().optional(), stickySession: z.boolean().optional(),
}) })
.strict()
.refine( .refine(
(data) => { (data) => {
if (data.subdomain) { if (data.subdomain) {
@@ -48,18 +44,18 @@ const createHttpResourceSchema = z
} }
return true; return true;
}, },
{ message: "Invalid subdomain" } {
error: "Invalid subdomain"
}
); );
const createRawResourceSchema = z const createRawResourceSchema = z.strictObject({
.object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
http: z.boolean(), http: z.boolean(),
protocol: z.enum(["tcp", "udp"]), protocol: z.enum(["tcp", "udp"]),
proxyPort: z.number().int().min(1).max(65535) proxyPort: z.int().min(1).max(65535)
// enableProxy: z.boolean().default(true) // always true now // enableProxy: z.boolean().default(true) // always true now
}) })
.strict()
.refine( .refine(
(data) => { (data) => {
if (!config.getRawConfig().flags?.allow_raw_resources) { if (!config.getRawConfig().flags?.allow_raw_resources) {
@@ -70,7 +66,7 @@ const createRawResourceSchema = z
return true; return true;
}, },
{ {
message: "Raw resources are not allowed" error: "Raw resources are not allowed"
} }
); );

View File

@@ -15,24 +15,20 @@ import {
} from "@server/lib/validators"; } from "@server/lib/validators";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
const createResourceRuleSchema = z const createResourceRuleSchema = z.strictObject({
.object({
action: z.enum(["ACCEPT", "DROP", "PASS"]), action: z.enum(["ACCEPT", "DROP", "PASS"]),
match: z.enum(["CIDR", "IP", "PATH", "COUNTRY"]), match: z.enum(["CIDR", "IP", "PATH", "COUNTRY"]),
value: z.string().min(1), value: z.string().min(1),
priority: z.number().int(), priority: z.int(),
enabled: z.boolean().optional() enabled: z.boolean().optional()
}) });
.strict();
const createResourceRuleParamsSchema = z const createResourceRuleParamsSchema = z.strictObject({
.object({
resourceId: z resourceId: z
.string() .string()
.transform(Number) .transform(Number)
.pipe(z.number().int().positive()) .pipe(z.int().positive())
}) });
.strict();
registry.registerPath({ registry.registerPath({
method: "put", method: "put",

Some files were not shown because too many files have changed in this diff Show More