Files
sharelink/AGENTS.md
T
shirainbown aa4befa0ff feat: sharelink 资源下载管理插件 v1.1.0
- 下载资源管理与 /download/{slug} 下载链接
- 下载统计(次数/去重人数/明细/CSV 导出)
- 按资源邮箱验证(Halo 通知中心发信,互认评论插件已验证邮箱)
- 本地附件防直链(/upload/** 404)
- 文章引用扫描
- Console 前端:Vue3 + ui-plugin-bundler-kit
2026-08-03 00:25:15 +08:00

4.0 KiB
Raw Blame History

AGENTS.md — sharelinkHalo 资源下载管理插件)

项目概述

Halo 2.x>=2.22,目标实例 Halo Pro 2.25.4)插件。管理文章中的资源下载链接:按资源的下载统计、邮箱验证、防附件直链、文章引用扫描。邮箱验证体系复制改造自 ~/Documents/Code/Ai/blog-commentplugin-comment-widget fork 的 emailcode/guard 包)。

结构

  • src/main/java/run/halo/sharelink/
    • model/ 自定义 Extension@GVK group sharelink.halo.run):DownloadResourcespec.slug 唯一索引)、DownloadRecordspec.resourceSlug 索引)、VerifiedDownloadername=SHA-256(归一化邮箱)
    • emailcode/ 验证码:Guava 内存缓存、限流、NotificationCenter 发信(REASON_TYPE sharelink-download-verification,模板在 resources/extensions/notification.yaml
    • verify/ 公开端点 api.sharelink.halo.run/v1alpha1email-verify/-/send|/-/check+ VerifiedEmailService(本插件 VerifiedDownloader 评论插件 VerifiedCommenter,后者运行时 Unstructured fetch,缺席自动降级)
    • download/ RouterFunction BeanGET /download/{slug}(自包含 HTML 页)、GET /download/{slug}/file(一次性 token 核销 → 记录 → 流式下载);FileStreamer 本地附件直接读盘(halo.work-dir/attachments + storage.halo.run/local-relative-path 注解),外部存储回环 HTTP(带 X-Sharelink-Internal 头)
    • protect/UploadProtectFilter AdditionalWebFilterGET/HEAD /upload/** 命中受保护附件 → 404
    • reference/PostReferenceService 扫描已发布文章 releaseSnapshot 内容匹配 /download/{slug}5min 缓存
    • console/ConsoleEndpoint console.api.sharelink.halo.run/v1alpha1:资源 CRUD(body 为扁平 spec)、记录分页/删除/CSV、references 查询/刷新
  • src/main/resources/extensions/ settings.yaml、notification.yaml、role-templates.yaml(匿名放行公开 APIconsole view/manage 角色,ui-permissions: plugin:sharelink:view/manage
  • ui/ console 前端:Vue 3 + @halo-dev/ui-shared + ui-plugin-bundler-kitrsbuild),产物输出到 src/main/resources/console/构建前会覆盖该目录,勿手改)。API 层 ui/src/api/index.tsnormalizeResource() 把后端扁平 ResourceVo 转成 Halo 风格结构

构建 / 部署

pnpm -C ui install && pnpm -C ui build
export JAVA_HOME=~/.gradle/jdks/jdk-21.0.12+8/Contents/Home  # 本机无系统 JDK
./gradlew build -x test    # build/libs/sharelink-<version>.jar

关键经验(踩过的坑):

  1. 改代码后发布必须递增 gradle.properties 的 version——console 静态资源按 ?version= 缓存,不递增浏览器会用旧包。
  2. Console UI 升级插件会弹「插件已存在,是否升级?」确认框,不点确定不会真正替换 jar。
  3. 插件数据存 ExtensionStoreMySQL),卸载/重装插件不丢数据;但 Halo 的插件静态资源目录在重装时才重新解压。
  4. 计数在「token 核销 + 附件可流式输出」之后才写入,下载失败不计数;免验证资源按 slug+IP 内存窗口去重。
  5. UI 安装有两条路:①「远程下载」需要 Halo 服务器能反向访问本机 jar 服务(本机换网/IP 变化后会失败);②「本地上传」用 webbridge 时 CDP setFileInputFiles 被浏览器禁用,可用兜底方案:分块 base64 经 evaluate 推到页面 window.__jarB64 → JS 构造 File + DataTransfer → 对 .uppy-Dashboard-inner 派发合成 dragenter/dragover/drop 事件触发 Uppy 上传 → 再点升级确认框「确定」。
  6. 下载页自包含 HTML 里若给元素自定义了 display(如 flex),必须补 [hidden] { display: none !important; },否则 hidden 属性失效导致元素误显示。

测试

端到端验证依赖目标实例(http://192.168.3.2:8090)。公开 API 可用 curl 匿名测试: POST /apis/api.sharelink.halo.run/v1alpha1/downloads/-/token {"slug":"..."}GET /download/{slug}/file?token=...