56 lines
2.2 KiB
TypeScript
56 lines
2.2 KiB
TypeScript
import { z } from 'zod'
|
|
import DOMPurify from 'isomorphic-dompurify'
|
|
|
|
const sanitizeString = (str: string) => DOMPurify.sanitize(str).trim()
|
|
const urlSchema = z.string().url("Invalid URL").refine((val) => val.startsWith("http://") || val.startsWith("https://"), {
|
|
message: "URL must start with http:// or https://",
|
|
})
|
|
|
|
export const coinSchema = z.object({
|
|
name: z.string()
|
|
.min(1, "Name is required")
|
|
.max(50, "Name too long")
|
|
.regex(/^[\x20-\x7E]+$/, "Name can only contain standard characters")
|
|
.transform(sanitizeString),
|
|
ticker: z.string()
|
|
.min(3, "Ticker must be at least 3 characters")
|
|
.max(10, "Ticker cannot exceed 10 characters")
|
|
.regex(/^[a-zA-Z0-9]+$/, "Ticker can only contain letters and numbers")
|
|
.toUpperCase()
|
|
.transform(sanitizeString),
|
|
description: z.string()
|
|
.max(500, "Description too long")
|
|
.regex(/^[\x20-\x7E\n\r]*$/, "Description can only contain standard characters")
|
|
.optional()
|
|
.transform(val => sanitizeString(val || '')),
|
|
image: urlSchema.optional().or(z.literal('')),
|
|
website: urlSchema.optional().or(z.literal('')),
|
|
twitter: urlSchema.optional().or(z.literal('')),
|
|
telegram: urlSchema.optional().or(z.literal('')),
|
|
initialBuy: z.number().min(0).max(100, "Initial buy cannot exceed 100 SOL").optional().default(0),
|
|
useUserImage: z.boolean().optional(),
|
|
verified: z.boolean().optional().default(false),
|
|
boosted: z.boolean().optional().default(false),
|
|
})
|
|
|
|
export const commentSchema = z.object({
|
|
coinId: z.string().min(1, "Coin ID required"),
|
|
text: z.string()
|
|
.min(1)
|
|
.max(280, "Comment too long")
|
|
.regex(/^[\x20-\x7E\n\r]+$/, "Comment can only contain standard characters")
|
|
.transform(sanitizeString),
|
|
})
|
|
|
|
export type CreateCoinInput = z.infer<typeof coinSchema>
|
|
export type CreateCommentInput = z.infer<typeof commentSchema>
|
|
|
|
export const RESERVED_USERNAMES = [
|
|
'api', 'coin', 'create', 'dashboard', 'login', 'onboarding', 'privacy', 'terms', 'u',
|
|
'admin', 'administrator', 'mod', 'moderator', 'support', 'help', 'system', 'sys',
|
|
'bot', 'pummmp', 'null', 'undefined', 'void', 'root', 'webmaster', '404', '500'
|
|
]
|
|
|
|
export const isReservedUsername = (username: string) => {
|
|
return RESERVED_USERNAMES.includes(username.toLowerCase());
|
|
}
|