拆分能力、分配范围和业务关系,固定管理员能力并收紧组织级写入口。 补齐内容、课表、设备会话和实时通道授权,兼容旧库分配及历史快照。 重写权限分配预览,按实际可操作范围展示维护入口,合并学生入口并独立学年升级页。 增加授权攻击矩阵及静态门禁,更新隔离回归与开发契约。 验证:授权矩阵 23 段通过,Node 24 下 Web 63/63,类型检查、lint 与文档严格构建通过。
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
/**
|
|
* 安装包文件名/版本号只允许这些字符。
|
|
*
|
|
* 它们会被拼进磁盘路径(`data/client-releases/<版本>/<文件名>`),
|
|
* 所以必须挡住 `..`、`/`、`\` —— 否则一个 `version=../../` 就能写到仓库外面去。
|
|
*/
|
|
const SAFE_SEGMENT = /^[0-9A-Za-z._-]+$/;
|
|
|
|
export const clientReleaseVersionSchema = z
|
|
.string()
|
|
.trim()
|
|
.min(1, '请输入版本号')
|
|
.max(40, '版本号最多 40 个字符')
|
|
.refine((value) => SAFE_SEGMENT.test(value) && value !== '.' && value !== '..' && !value.includes('..'), {
|
|
message: '版本号只能包含字母、数字、点、下划线与短横线',
|
|
});
|
|
|
|
/** `POST /api/update/client/fetch`:让服务端替教室机器从 GitHub 拉一份安装包 */
|
|
export const fetchClientReleaseSchema = z.object({
|
|
version: clientReleaseVersionSchema,
|
|
});
|
|
|
|
/** `POST /api/update/client/releases`:登记一份已经放进磁盘的安装包(手工兜底与自动化用) */
|
|
export const registerClientReleaseSchema = z.object({
|
|
version: clientReleaseVersionSchema,
|
|
fileName: z
|
|
.string()
|
|
.trim()
|
|
.min(1)
|
|
.max(120)
|
|
.refine((value) => SAFE_SEGMENT.test(value) && value !== '.' && value !== '..' && !value.includes('..'), {
|
|
message: '文件名只能包含字母、数字、点、下划线与短横线',
|
|
})
|
|
.optional(),
|
|
notes: z.string().trim().max(500).optional(),
|
|
});
|
|
|
|
export const clientReleaseVersionParamSchema = z.object({ version: clientReleaseVersionSchema });
|
|
|
|
export type FetchClientReleaseInput = z.infer<typeof fetchClientReleaseSchema>;
|
|
export type RegisterClientReleaseInput = z.infer<typeof registerClientReleaseSchema>;
|