From 61f74054f9ce450765622d5061a7b08680a658f5 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Fri, 7 Aug 2026 07:01:13 -0600 Subject: [PATCH] =?UTF-8?q?fix(Minor=20M3):=20blog=20/=20github=20?= =?UTF-8?q?=E5=8A=A0=E5=9B=9E=20URL=20=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 旧 account/serializers.py:125,127 是 serializers.URLField,迁移时降级成了 z.string().max(256)。这两个字段会被前端渲染成可点击链接,放任自由字符串等于 允许写入 javascript: 一类伪协议。 只放行 http(s)://,空串表示清空。实测 javascript:alert(1) 与 not a url 均 400, https://example.com/x 与空串 200。 Co-Authored-By: Claude Opus 5 --- packages/contract/src/account.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/contract/src/account.ts b/packages/contract/src/account.ts index d5a531c..c6c65ce 100644 --- a/packages/contract/src/account.ts +++ b/packages/contract/src/account.ts @@ -9,12 +9,25 @@ export const registerRequestSchema = z.object({ password: z.string().min(6).max(20), }) +/** + * 对齐旧后端 `account/serializers.py:125,127` 的 `serializers.URLField`: + * 这两个字段会被前端渲染成可点击链接,放任自由字符串等于允许写入 + * `javascript:` 一类的伪协议。只放行 http/https,空串与 null 表示「清空」。 + */ +const linkField = z + .string() + .max(256) + .refine( + (value) => value === "" || /^https?:\/\/\S+$/i.test(value), + "必须是以 http:// 或 https:// 开头的网址", + ) + export const updateProfileRequestSchema = z.object({ realName: z.string().max(32).nullable().optional(), avatar: z.string().max(256).optional(), - blog: z.string().max(256).nullable().optional(), + blog: linkField.nullable().optional(), mood: z.string().max(256).nullable().optional(), - github: z.string().max(256).nullable().optional(), + github: linkField.nullable().optional(), school: z.string().max(64).nullable().optional(), major: z.string().max(64).nullable().optional(), language: z.string().max(32).nullable().optional(),