feat: rebrand Hemmelig to paste.es for cloudhost.es
- Set Spanish as default language with ephemeral/encrypted privacy focus - Translate all user-facing strings and legal pages to Spanish - Replace Norwegian flag with Spanish flag in footer - Remove Hemmelig/terces.cloud links, add cloudhost.es sponsorship - Rewrite PrivacyPage: zero data collection, ephemeral design emphasis - Rewrite TermsPage: Spanish law, RGPD, paste.es/CloudHost.es references - Update PWA manifest, HTML meta tags, package.json branding - Rename webhook headers to X-Paste-Event / X-Paste-Signature - Update API docs title and contact to paste.es / cloudhost.es Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
60
api/validations/instance.ts
Normal file
60
api/validations/instance.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const sanitizeString = (str: string) => str.trim().replace(/[\x00-\x1F\x7F]/g, '');
|
||||
|
||||
const sanitizedString = (maxLength: number) =>
|
||||
z.string().transform(sanitizeString).pipe(z.string().max(maxLength));
|
||||
|
||||
// Max logo size: 512KB in base64 (which is ~683KB as base64 string)
|
||||
const MAX_LOGO_BASE64_LENGTH = 700000;
|
||||
|
||||
export const instanceSettingsSchema = z.object({
|
||||
instanceName: sanitizedString(100).optional(),
|
||||
instanceDescription: sanitizedString(500).optional(),
|
||||
instanceLogo: z
|
||||
.string()
|
||||
.max(MAX_LOGO_BASE64_LENGTH, 'Logo must be smaller than 512KB')
|
||||
.refine(
|
||||
(val) => {
|
||||
if (!val || val === '') return true;
|
||||
// Check if it's a valid base64 data URL for images
|
||||
return /^data:image\/(png|jpeg|jpg|gif|svg\+xml|webp);base64,/.test(val);
|
||||
},
|
||||
{ message: 'Logo must be a valid image (PNG, JPEG, GIF, SVG, or WebP)' }
|
||||
)
|
||||
.optional(),
|
||||
allowRegistration: z.boolean().optional(),
|
||||
requireEmailVerification: z.boolean().optional(),
|
||||
maxSecretsPerUser: z.number().int().min(1).optional(),
|
||||
defaultSecretExpiration: z.number().int().min(1).optional(),
|
||||
maxSecretSize: z.number().int().min(1).optional(),
|
||||
|
||||
allowPasswordProtection: z.boolean().optional(),
|
||||
allowIpRestriction: z.boolean().optional(),
|
||||
allowFileUploads: z.boolean().optional(),
|
||||
maxPasswordAttempts: z.number().int().min(1).optional(),
|
||||
sessionTimeout: z.number().int().min(1).optional(),
|
||||
enableRateLimiting: z.boolean().optional(),
|
||||
rateLimitRequests: z.number().int().min(1).optional(),
|
||||
rateLimitWindow: z.number().int().min(1).optional(),
|
||||
|
||||
// Organization features
|
||||
requireInviteCode: z.boolean().optional(),
|
||||
allowedEmailDomains: sanitizedString(500).optional(),
|
||||
requireRegisteredUser: z.boolean().optional(),
|
||||
disableEmailPasswordSignup: z.boolean().optional(),
|
||||
|
||||
// Webhook notifications
|
||||
webhookEnabled: z.boolean().optional(),
|
||||
webhookUrl: z.string().url().optional().or(z.literal('')),
|
||||
webhookSecret: sanitizedString(200).optional(),
|
||||
webhookOnView: z.boolean().optional(),
|
||||
webhookOnBurn: z.boolean().optional(),
|
||||
|
||||
// Important message alert
|
||||
importantMessage: sanitizedString(1000).optional(),
|
||||
|
||||
// Prometheus metrics
|
||||
metricsEnabled: z.boolean().optional(),
|
||||
metricsSecret: sanitizedString(200).optional(),
|
||||
});
|
||||
Reference in New Issue
Block a user