- 家长手机号登录 + 孩子设备一次性激活(长期会话) - 周模板自动生成每日任务快照,支持拍照凭证直传对象存储 - 连击计算(空白日自动达成)、家长补卡带标记 - 家长端三标签:今日概览 / 任务模板 / 设备管理 - Docker 独立输出,经 Traefik 接入 jump.hn12301.net Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
1.5 KiB
TypeScript
39 lines
1.5 KiB
TypeScript
// 对象存储签名工具:浏览器直传用查询串签名(浏览器无法设置 Date 请求头)
|
|
import crypto from "node:crypto";
|
|
|
|
const REGION = process.env.OSS_REGION ?? "oss-cn-hangzhou";
|
|
const BUCKET = process.env.OSS_BUCKET ?? "";
|
|
const ID = process.env.OSS_ACCESS_KEY_ID ?? "";
|
|
const SECRET = process.env.OSS_ACCESS_KEY_SECRET ?? "";
|
|
|
|
const HOST = `${BUCKET}.${REGION}.aliyuncs.com`;
|
|
|
|
// 生成带签名的临时访问地址
|
|
function signUrl(method: string, key: string, seconds: number, contentType = "") {
|
|
const expires = Math.floor(Date.now() / 1000) + seconds;
|
|
const resource = `/${BUCKET}/${key}`;
|
|
const str = `${method}\n\n${contentType}\n${expires}\n${resource}`;
|
|
const signature = crypto.createHmac("sha1", SECRET).update(str).digest("base64");
|
|
const qs = new URLSearchParams({
|
|
OSSAccessKeyId: ID,
|
|
Expires: String(expires),
|
|
Signature: signature,
|
|
});
|
|
return `https://${HOST}/${encodeURIComponent(key)}?${qs}`;
|
|
}
|
|
|
|
// 直传地址:浏览器收到后直接 fetch PUT,有效期 10 分钟
|
|
export function uploadUrl(key: string, contentType: string) {
|
|
return signUrl("PUT", key, 600, contentType);
|
|
}
|
|
|
|
// 展示地址:签名 GET,有效期 5 分钟,用完由页面刷新重新签发
|
|
export function viewUrl(key: string) {
|
|
return signUrl("GET", key, 300);
|
|
}
|
|
|
|
// 照片键名:photos/孩子ID/日期/随机16进制.jpg
|
|
export function photoKey(childId: number, date: string) {
|
|
return `photos/${childId}/${date}/${crypto.randomBytes(8).toString("hex")}.jpg`;
|
|
}
|