fix(api): validate push and domain verification targets (#2346)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-02 17:23:34 +02:00
1 parent 693aec2b4d
commit 1d84689b45
5 files changed
+75 -3

No files matched your search

@@ -11,6 +11,7 @@ import {
Int32Type,
withOpenApiType,
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
import {HostnameType} from '@fluxer/schema/src/primitives/UrlValidators';
import {z} from 'zod';
const ConnectionTypeSchema = withOpenApiType(
@@ -62,7 +63,7 @@ export type VerifyAndCreateConnectionRequest = z.infer<typeof VerifyAndCreateCon
export const CreateConnectionRequest = z.object({
type: ConnectionTypeSchema.describe('The type of connection to create'),
identifier: z.string().min(1).max(253).describe('The connection identifier (handle or domain)'),
identifier: HostnameType.describe('The connection identifier (handle or domain)'),
visibility_flags: Int32Type.optional().describe('Bitfield controlling who can see this connection'),
});
@@ -514,6 +514,13 @@ export const RegisterMobileDeviceRequest = z
})
.superRefine((value, ctx) => {
if (value.platform !== 'android_unified_push') return;
if (!URLType.safeParse(value.token).success) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['token'],
message: 'UnifiedPush registrations require a valid endpoint URL',
});
}
if (!value.encryption_key) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
@@ -7,6 +7,7 @@ import {z} from 'zod';
const PROTOCOLS = ['http', 'https'];
const FILENAME_SAFE_REGEX = /^[\p{L}\p{N}\p{M}_.-]+$/u;
const HOSTNAME_LABEL_REGEX = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
const URL_VALIDATOR_OPTIONS = {
require_protocol: true,
require_host: true,
@@ -50,6 +51,27 @@ function createUrlSchema() {
);
}
export function isFqdnHostname(hostname: string): boolean {
if (!hostname || hostname.length > 253 || !hostname.includes('.')) {
return false;
}
const labels = hostname.split('.');
for (const label of labels) {
if (!label || label.length > 63 || !HOSTNAME_LABEL_REGEX.test(label)) {
return false;
}
}
return !/^\d+$/.test(labels[labels.length - 1]);
}
export const HostnameType = z
.string()
.transform((value) => {
const trimmed = value.trim().toLowerCase();
return trimmed.endsWith('.') ? trimmed.slice(0, -1) : trimmed;
})
.refine(isFqdnHostname, ValidationErrorCodes.INVALID_FORMAT);
export const URLType = createUrlSchema();
export const AttachmentURLType = z
.string()