Commit Graph

7 Commits

Author SHA1 Message Date
Matrix Music Bot Dev 5ea92de6b9 feat(commands): 房间/DM 感知的命令解析器(M2.1)
子命令(v1):
  !help / !h / !?        显示帮助
  !req / !request / !点歌 / !来一首 <关键词...>
  !req-url / !url <URL> 直接粘 URL
  !queue / !q / !队列
  !np / !nowplaying
  !skip / !next / !跳过

权限模型:
  - DM:无需 mention,直接发命令
  - 房间:根据 [commands] mention_required_in_rooms 配置
    - true:必须包含 @bot_user_id 或 @bot_localpart
    - false:任何消息都会解析

mention 文本从消息中剥离后再解析(修复 bug:之前 format 出了 @@)

中文/英文命令别名都支持(如「点歌」「跳过」)。

render_reply 已实现 help;其他命令返回 M3+ 占位提示。

测试:cargo test commands → 11 passed
  - DM 解析 / 房间解析 / mention 必需 / mention 关闭 / 多别名 / 缺参 / 错命令
2026-07-02 20:53:01 +08:00
Matrix Music Bot Dev 39afe31d19 feat(bootstrap): matrix-sdk login + 加密 session 持久化 + restore(M1.3b/c)
新增模块:
  src/client.rs   ── matrix-sdk ClientBuilder 工厂(含 crypto store + EncryptionSettings)
  src/bootstrap.rs ── login/restore 两个公开入口函数

依赖环境:
  - 系统需要 libsqlite3 → 已通过 pacman 安装 mingw-w64-x86_64-sqlite3
  - 运行时需要 MATRIX_BOT_SECRET_PASSPHRASE 环境变量(≥8 字符)

login 流程:
  1. 检查 secret.bin 不存在(避免覆盖现有 device)
  2. 构造 Client(homeserver + sqlite_store + EncryptionSettings)
  3. matrix_auth().login_username().initial_device_display_name().send()
  4. /login response → MatrixSession(impl From<&Response> for MatrixSession)
  5. MatrixSession 序列化为 JSON
  6. secret_store::save() 加密写入 data/secret.bin
  7. 输出 user_id + device_id 提示操作员在 Element 中验证

restore 流程(给后续 M2 的 run 子命令用):
  1. 检查 secret.bin 存在
  2. secret_store::load() 解密
  3. MatrixSession JSON → MatrixSession 结构
  4. 构造 Client(沿用 crypto.db)
  5. client.restore_session(session)
  6. 返回 (Client, user_id, device_id)

cmd_login 改造:
  - 从环境变量读取 passphrase(避免 CLI history 泄漏)
  - 长度 < 8 字符拒绝
  - 内部用 tokio multi-thread runtime 跑 async login

secret_store 微调:
  - SessionSecrets 改为存储 matrix_session: serde_json::Value + schema_version
  - 因 serde_json::Value 不实现 Zeroize,移除 #[derive(Zeroize)]
  - 依赖 matrix-sdk 内部 SessionMeta/SessionTokens 自带的 zeroize 保证内存安全

CLI 实测(fake homeserver):
  - 缺 passphrase → 友好错误
  - 有 passphrase → 走到 matrix-sdk /login 调用,因 DNS 失败是预期行为

测试:
  cargo test → 4 passed(secret_store roundtrip + 噪声 ciphertext + config 解析)
2026-07-02 20:03:38 +08:00
Matrix Music Bot Dev ecc40beed8 feat(secret_store): Argon2id + AES-256-GCM 加密的会话密钥存储(M1.3a)
依赖新增:
  - aes-gcm 0.11
  - argon2 0.5.3
  - getrandom 0.3 (std feature)
  - base64 0.22.1
  - serde_json 1.0
  - zeroize 1.9
  - rand_core (尝试后移除:rand 0.10 / 0.9 的 OsRng API 都复杂,改为更底层的 getrandom)

文件格式(JSON 包装):
  {
    "version": 1,
    "kdf": "argon2id",
    "salt_b64": "...",     // 16 bytes
    "nonce_b64": "...",    // 12 bytes
    "ciphertext_b64": "..."  // AES-256-GCM(plaintext, AAD="matrix-music-bot secret v1")
  }

安全参数:
  - KDF: Argon2id (m=19456 KiB, t=2, p=1) — OWASP 推荐
  - 加密: AES-256-GCM(认证加密,任何篡改都会被检测)
  - AAD: 标识文件版本与 KDF,防止 ciphertext 重放到不同上下文
  - 每次加密随机 salt + nonce,确保同样明文产生不同 ciphertext
  - 写入采用 .bin.tmp → rename 原子操作,避免半写状态

API:
  save(path, &secrets, passphrase) -> AppResult<()>
  load(path, passphrase) -> AppResult<SessionSecrets>
  exists(path) -> bool

SessionSecrets 包含 access_token / device_id / user_id 三个字段,
实现 Zeroize on drop。

测试:
  cargo test → 4 passed
    - secret_store::roundtrip_via_disk: 加密 + 解密往返,错误口令被 AES-GCM 拒绝
    - secret_store::ciphertext_differs_each_time: 同样明文两次加密 ciphertext 不同

后续 M1.3b:在 src/bootstrap.rs 中调用 matrix-sdk 的 Client::builder() + login_username,
拿到 access_token 后调 secret_store::save() 写入 ./data/secret.bin。
2026-07-02 19:50:56 +08:00
Matrix Music Bot Dev 19e724444b feat: 实现 config + clap CLI + 错误处理(M1.2)
新增依赖(与 matrix-sdk 0.18.0 兼容):
  - tokio 1.52 (full)
  - clap 4.6 (derive + env)
  - serde 1.0 (derive) + toml 1.1
  - thiserror 2.0 + anyhow 1.0
  - tracing 0.1 + tracing-subscriber 0.3 (env-filter)
  - async-trait 0.1

推迟到对应 milestone(M3 / M5)添加以避免 libsqlite3-sys 与
matrix-sdk-sqlite 冲突:rusqlite、reqwest。详见 Cargo.toml 注释。

新增模块:
  src/config.rs  ── AppConfig 结构(Homeserver/Bot/Data/Commands/Crypto/Music)+ TOML 加载/序列化 + 自动发现路径
  src/error.rs   ── AppError 枚举(thiserror)+ AppResult 别名
  src/main.rs    ── clap CLI 骨架:login / run / config / version 子命令

CLI 子命令状态:
  - version      打印版本 + matrix-sdk 版本
  - config init  在 ./config/bot.toml 生成示例配置
  - config path  打印当前配置文件路径
  - config print  打印当前配置
  - login       ⚠️ M1.3 占位(返回错误)
  - run         ⚠️ M2 占位(读取配置后返回错误)

配置默认值(plan 已确认的选型):
  - [crypto] auto_enable_cross_signing = true
  - [commands] prefix = !, mention_required_in_rooms = true
  - [music] ytdlp_path = 'yt-dlp'(PATH 中查找),search_limit = 5

gitignore 增补:排除 /config/bot.toml(操作员真实配置含凭证)

测试:
  - cargo build 通过(仅 dead_code warning,未使用的 AppError 变体将在后续 milestone 引用)
  - cargo test 2 passed(最小配置解析 + 示例配置往返)
  - CLI 实测:version / config init / config print / login / run 均按预期

后续 M1.3:在 src/bootstrap.rs 实现 matrix-sdk Client::builder() + login_username
+ secret_store 加密保存 access_token/device_id。
2026-07-02 01:35:54 +08:00
Matrix Music Bot Dev 17eb51e215 chore: 初始化 Cargo 项目骨架与构建验证
工具链:rustup + stable-x86_64-pc-windows-gnu + MinGW gcc 链接器

包含内容:
- Cargo.toml(edition 2024,name=matrix-music-bot)
- Cargo.lock(dev profile 验证通过)
- src/main.rs(hello world 占位,已 cargo build 通过)
- .cargo/config.toml(项目级 cargo 配置,指定 MinGW gcc 为链接器)
- .gitignore 增补:排除项目根的 plan 副本(正式版在 ~/.claude/plans/)

构建验证:cargo build 在 MinGW gcc 链接器下成功完成(1.56s)

后续 M1.2 将添加:clap(CLI 解析)+ serde/toml(配置文件)+ thiserror/anyhow
+ tracing(日志)+ tokio(async)+ matrix-sdk(含 E2EE crypto 与 UI timeline)
2026-07-02 01:25:33 +08:00
Matrix Music Bot Dev 5c4b8d8b82 docs: 添加 CLAUDE.md 项目协作规范
包含两条核心规则:

1. 技术决策流程:必须列出 2+ 方案 + 解释优缺点 + 用户拍板;
   不得自行默认选择。详见 CLAUDE.md 第 1 节。

2. Git 实时提交规范:禁止积累大批改动后一次性提交;
   每个逻辑单元完成后立即提交(单文件/单函数/milestone 边界);
   中文 commit message + Conventional Commits 风格;
   提交前必须 cargo build/check 通过。
   详见 CLAUDE.md 第 2 节。
2026-07-02 01:09:01 +08:00
Matrix Music Bot Dev 3426acbb77 chore: 初始化仓库结构(.gitignore + data/ 占位)
- 排除 /target、/data、secret.bin、.env 等敏感与构建产物
- 保留 data/.gitkeep 占位以便运行时生成 bot.db / crypto.db
2026-07-02 01:08:45 +08:00