fix(Minor M3): blog / github 加回 URL 校验

旧 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 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 07:01:13 -06:00
parent 20ecc05f63
commit 61f74054f9

View File

@@ -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(),