# sharelink — Halo 资源下载管理插件

管理文章中的资源下载链接：下载统计、按资源的邮箱验证、防止附件直链下载、文章引用扫描。

📖 **[详细配置指南与使用说明（含截图）](docs/使用指南.md)**

💬 **使用交流**：遇到问题或有功能建议，欢迎到博客文章 [《Halo 博客「资源下载管理」插件 · 配置指南与使用说明》](https://blog.songshiyu.cn/archives/halo-bo-ke-zi-yuan-xia-zai-guan-li-cha-jian-pei-zhi-zhi-nan-yu-shi-yong-shuo-ming) 下方留言评论，会及时回复。

## 安装

要求 Halo 2.22+。

1. 从 [Releases](https://github.com/shirainbown/plugin-sharelink/releases) 下载最新的 `sharelink-*.jar`
2. Halo Console → 左侧「插件」→ 右上角「安装」→ 上传 jar 并启用

## 功能

- **下载资源管理**（Console「内容 → 下载管理」）：选择附件创建下载资源，生成 `/download/{slug}` 下载链接，复制后粘贴到文章即可。
- **下载统计**：每个资源的下载次数、去重下载人数、详细下载记录（时间/邮箱/IP/UA），支持 CSV 导出。
- **邮箱验证**：按资源开关。访客输入邮箱 → 收验证码（走 Halo 通知中心，复用站点 SMTP）→ 验证后下载。已验证邮箱持久化，后续免验证；开启「信任评论插件已验证的邮箱」后，与评论组件（plugin-comment-widget fork）的已验证邮箱互认。
- **防直链**：注册为资源的本地附件，其 `/upload/**` 直链对外返回 404；文件由插件从磁盘流式输出，URL 不暴露。
- **文章引用扫描**：扫描已发布文章内容，展示每个资源被哪些文章引用（可跳转编辑/访问），5 分钟缓存 + 手动刷新。

## 工作原理（简）

- 访客流程：`/download/{slug}`（自包含 HTML 页）→（可选邮箱验证）→ POST `downloads/-/token` 换一次性 token（默认 60s 有效）→ `/download/{slug}/file?token=` 核销并流式下载、记录计数。
- 防直链：`AdditionalWebFilter` 拦截 GET/HEAD `/upload/**`，命中受保护附件 permalink 集合返回 404。
- 免验证资源：同一 IP 在去重窗口（默认 10 分钟）内重复下载只计 1 次。

## 构建

```bash
cd ui && pnpm install && pnpm build   # 前端产物输出到 src/main/resources/console
cd .. && ./gradlew build -x test      # 产出 build/libs/sharelink-<version>.jar
```

- 无本地 JDK 时：`settings.gradle` 已配 foojay-resolver 自动下载 JDK 21 到 `~/.gradle`。
- 前端独立构建（不集成进 gradle），改前端后记得先 `pnpm -C ui build` 再打 jar。

## 部署 / 升级注意事项

1. Console「插件 → 安装 → 远程下载/本地上传」安装 jar。
2. **升级已安装的插件时**，UI 会弹「插件已存在，是否升级？」确认框，必须点「确定」才会真正替换。
3. **前端静态资源按 `?version=` 缓存**：发布新版本务必递增 `gradle.properties` 的 `version`，否则浏览器会沿用旧 console 包。
4. 升级后如行为未变，停用再启用插件强制重启。

## 使用注意

- 不要把文章内需要直接显示的图片注册为下载资源（其 `/upload/` 直链会被 404，图片将无法显示）。
- 外部对象存储（S3 等）附件无法拦截直链（防直链仅对本地存储策略生效）；此类附件走回环 HTTP 转发下载。
- 邮箱验证依赖「设置 → 通知设置」中已配置的邮件通知器。

## 设置项

| 组 | 项 | 默认 |
|---|---|---|
| 基本设置 | 下载令牌有效期（秒） | 60 |
| 基本设置 | 免验证资源下载去重窗口（分钟） | 10 |
| 邮箱验证 | 验证码有效期（分钟） | 10 |
| 邮箱验证 | 重发间隔（秒） | 60 |
| 邮箱验证 | 同一邮箱每日发送上限 | 5 |
| 邮箱验证 | 验证码最大错误尝试次数 | 5 |
| 邮箱验证 | 同一 IP 每小时发送上限 | 20 |
| 邮箱验证 | 信任评论插件已验证的邮箱 | 开 |
