2026-05-30 · 稳定性 / 安全加固(子进程超时、SSRF、并发锁、上传持久化、轮询容错)
+ API + Canvas + Bugfix + Security +问题:只读审查发现一批可复现隐患:run() 子进程(yt-dlp/ffmpeg/ffprobe)无超时会让 job 永挂 downloading 并泄漏进程;create_job 的源链接未校验,可被 file:///内网地址做 SSRF 与本地文件读取;视频队列多线程并发改同一 job 状态无锁互相覆盖;画布上传视频用 blob: URL,重载后视频丢失;首页/详情页轮询一次网络抖动就永久停。
改动(后端 api/main.py / api/db.py):run() 增加 timeout(下载 DOWNLOAD_TIMEOUT_SECONDS 默认 600s,其余 300s),超时 kill 并标 failed;新增 validate_source_url()——只允许 http(s)、拒绝私有/环回/链路本地 IP、域名走 SOURCE_URL_ALLOWED_HOSTS 白名单(默认主流短视频平台);新增 per-job RLock,save_state/update/update_generated_video 及 retry 的 check-and-set 全部在锁内;db.py 改用 psycopg_pool 连接池、写失败由 logging.error 暴露;只读 GET 媒体路由改用不创建目录的 job_path();多处 Image.open() 改 with 防 fd 泄漏。
改动(前端画布 web/canvas-app/src/):VideoNode.vue 上传改走后端 /jobs/upload 拿稳定 URL(新增 uploadCanvasVideo),cleanNodeForStorage 同时剥离 blob:;useCachedMediaUrl.js 用真实 blob.size 统计缓存(修复 chunked 视频 size=0 让 LRU 失效)、catch 路径补 token 竞态校验;useApi.js 读参考图补 credentials、移除与 Canvas 层重复的节点级视频轮询;request.js timeout 改 60s + withCredentials;删除 api/video.js 中忽略 taskId 的死代码。
改动(Next 首页 web/app/):首页/详情页视频轮询改为容错(连续失败 10 次才停);agent 页预览 ObjectURL 创建移入 useEffect 确保配对 revoke;登录页 pointermove 用 rAF 节流并跳过 coarse 指针。飞书自动跳转行为按确认保留不动。
影响 / 验证:新增后端依赖 psycopg-pool(已写入 api/requirements.txt,未装时自动回退按调用建连);新增可选 env:DOWNLOAD_TIMEOUT_SECONDS、SOURCE_URL_ALLOWED_HOSTS、DB_POOL_MAX_SIZE。本地 py_compile 与 pnpm build(canvas + next)通过。描述需求时:源链接受白名单约束(新平台需加 SOURCE_URL_ALLOWED_HOSTS);画布上传视频现在持久化为后端 /api/jobs/... 地址。