142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import { timeZoneSchema } from "@calcom/lib/dayjs/timeZone.schema";
|
|
import { validateUrlForSSRFSync } from "@calcom/lib/ssrfProtection";
|
|
import { teamMetadataStrictSchema } from "@calcom/prisma/zod-utils";
|
|
|
|
/**
|
|
* Optional nullable URL schema with SSRF protections
|
|
* Rejects internal/private networks and cloud metadata endpoints
|
|
*/
|
|
const ssrfSafeOptionalUrl: z.ZodEffects<
|
|
z.ZodOptional<z.ZodNullable<z.ZodString>>,
|
|
string | null | undefined,
|
|
string | null | undefined
|
|
> = z
|
|
.string()
|
|
.nullable()
|
|
.optional()
|
|
.refine(
|
|
(url) => {
|
|
if (url == null || url === "") return true;
|
|
return validateUrlForSSRFSync(url).isValid;
|
|
},
|
|
{ message: "URL is not allowed for security reasons" }
|
|
);
|
|
|
|
// Note: orgId has .transform() that converts string to number, so input accepts string | number but output is always number
|
|
|
|
export type TUpdateInputSchemaInput = {
|
|
name?: string;
|
|
orgId?: string | number;
|
|
bio?: string;
|
|
logoUrl?: string | null;
|
|
calVideoLogo?: string | null;
|
|
banner?: string | null;
|
|
slug?: string;
|
|
hideBranding?: boolean;
|
|
hideBookATeamMember?: boolean;
|
|
brandColor?: string;
|
|
darkBrandColor?: string;
|
|
theme?: string | null;
|
|
timeZone?: string;
|
|
weekStart?: string;
|
|
timeFormat?: number;
|
|
metadata?: z.infer<ReturnType<typeof teamMetadataStrictSchema.unwrap>>;
|
|
lockEventTypeCreation?: boolean;
|
|
lockEventTypeCreationOptions?: "DELETE" | "HIDE";
|
|
adminGetsNoSlotsNotification?: boolean;
|
|
allowSEOIndexing?: boolean;
|
|
orgProfileRedirectsToVerifiedDomain?: boolean;
|
|
disablePhoneOnlySMSNotifications?: boolean;
|
|
disableAutofillOnBookingPage?: boolean;
|
|
orgAutoJoinOnSignup?: boolean;
|
|
disableAttendeeConfirmationEmail?: boolean;
|
|
disableAttendeeCancellationEmail?: boolean;
|
|
disableAttendeeRescheduledEmail?: boolean;
|
|
disableAttendeeRequestEmail?: boolean;
|
|
disableAttendeeReassignedEmail?: boolean;
|
|
disableAttendeeAwaitingPaymentEmail?: boolean;
|
|
disableAttendeeRescheduleRequestEmail?: boolean;
|
|
disableAttendeeLocationChangeEmail?: boolean;
|
|
disableAttendeeNewEventEmail?: boolean;
|
|
};
|
|
|
|
export type TUpdateInputSchema = {
|
|
name?: string;
|
|
orgId?: number;
|
|
bio?: string;
|
|
logoUrl?: string | null;
|
|
calVideoLogo?: string | null;
|
|
banner?: string | null;
|
|
slug?: string;
|
|
hideBranding?: boolean;
|
|
hideBookATeamMember?: boolean;
|
|
brandColor?: string;
|
|
darkBrandColor?: string;
|
|
theme?: string | null;
|
|
timeZone?: string;
|
|
weekStart?: string;
|
|
timeFormat?: number;
|
|
metadata?: z.infer<ReturnType<typeof teamMetadataStrictSchema.unwrap>>;
|
|
lockEventTypeCreation?: boolean;
|
|
lockEventTypeCreationOptions?: "DELETE" | "HIDE";
|
|
adminGetsNoSlotsNotification?: boolean;
|
|
allowSEOIndexing?: boolean;
|
|
orgProfileRedirectsToVerifiedDomain?: boolean;
|
|
disablePhoneOnlySMSNotifications?: boolean;
|
|
disableAutofillOnBookingPage?: boolean;
|
|
orgAutoJoinOnSignup?: boolean;
|
|
disableAttendeeConfirmationEmail?: boolean;
|
|
disableAttendeeCancellationEmail?: boolean;
|
|
disableAttendeeRescheduledEmail?: boolean;
|
|
disableAttendeeRequestEmail?: boolean;
|
|
disableAttendeeReassignedEmail?: boolean;
|
|
disableAttendeeAwaitingPaymentEmail?: boolean;
|
|
disableAttendeeRescheduleRequestEmail?: boolean;
|
|
disableAttendeeLocationChangeEmail?: boolean;
|
|
disableAttendeeNewEventEmail?: boolean;
|
|
};
|
|
|
|
export const ZUpdateInputSchema: z.ZodType<TUpdateInputSchema, z.ZodTypeDef, TUpdateInputSchemaInput> =
|
|
z.object({
|
|
name: z.string().optional(),
|
|
orgId: z
|
|
.string()
|
|
.regex(/^\d+$/)
|
|
.transform((id) => parseInt(id))
|
|
.or(z.number())
|
|
.optional(),
|
|
bio: z.string().optional(),
|
|
logoUrl: ssrfSafeOptionalUrl,
|
|
calVideoLogo: ssrfSafeOptionalUrl.transform((v) => v || null),
|
|
banner: ssrfSafeOptionalUrl,
|
|
slug: z.string().optional(),
|
|
hideBranding: z.boolean().optional(),
|
|
hideBookATeamMember: z.boolean().optional(),
|
|
brandColor: z.string().optional(),
|
|
darkBrandColor: z.string().optional(),
|
|
theme: z.string().optional().nullable(),
|
|
timeZone: timeZoneSchema.optional(),
|
|
weekStart: z.string().optional(),
|
|
timeFormat: z.number().optional(),
|
|
metadata: teamMetadataStrictSchema.unwrap().optional(),
|
|
lockEventTypeCreation: z.boolean().optional(),
|
|
lockEventTypeCreationOptions: z.enum(["DELETE", "HIDE"]).optional(),
|
|
adminGetsNoSlotsNotification: z.boolean().optional(),
|
|
allowSEOIndexing: z.boolean().optional(),
|
|
orgProfileRedirectsToVerifiedDomain: z.boolean().optional(),
|
|
disablePhoneOnlySMSNotifications: z.boolean().optional(),
|
|
disableAutofillOnBookingPage: z.boolean().optional(),
|
|
orgAutoJoinOnSignup: z.boolean().optional(),
|
|
disableAttendeeConfirmationEmail: z.boolean().optional(),
|
|
disableAttendeeCancellationEmail: z.boolean().optional(),
|
|
disableAttendeeRescheduledEmail: z.boolean().optional(),
|
|
disableAttendeeRequestEmail: z.boolean().optional(),
|
|
disableAttendeeReassignedEmail: z.boolean().optional(),
|
|
disableAttendeeAwaitingPaymentEmail: z.boolean().optional(),
|
|
disableAttendeeRescheduleRequestEmail: z.boolean().optional(),
|
|
disableAttendeeLocationChangeEmail: z.boolean().optional(),
|
|
disableAttendeeNewEventEmail: z.boolean().optional(),
|
|
});
|