|
@@ -0,0 +1,618 @@
|
|
|
|
|
+# 容器取证问答:agent-node-kangshifu
|
|
|
|
|
+
|
|
|
|
|
+- 时间:2026-11-14T08:19:31.534Z
|
|
|
|
|
+- 房间:`!HkH3Pa-Nv8t30_9wWLblLpAuWMUpuzoa6D19ItKnPh8`(临时房间,可保留查阅)
|
|
|
|
|
+- 消息统计:正文 17 段 / 工具过程 1 段 / 文件 0 个
|
|
|
|
|
+- 结束原因:收到 ✅ reaction
|
|
|
|
|
+
|
|
|
|
|
+## 我发出的问题
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+# 梳理:文件传输的完整链路(找出为什么会有多个上限、多条路径)
|
|
|
|
|
+
|
|
|
|
|
+用户裁决:
|
|
|
|
|
+1. 文件**不能**通过 Matrix 传输,必须是 S3 链接
|
|
|
|
|
+2. **取消上传大小上限**,改为 800MB
|
|
|
|
|
+3. lj-test 和 kangshifu **都要改**
|
|
|
|
|
+4. **先梳理,再设计**,不要直接改
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 一、请如实回答这几个问题(只读)
|
|
|
|
|
+
|
|
|
|
|
+## Q1:App → 容器,文件到底怎么过去的
|
|
|
|
|
+
|
|
|
|
|
+**这是用户最关心的一点**:文件本体到底有没有经过 Matrix?
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# 看入站媒体插件如何处理 App 发来的 m.file
|
|
|
|
|
+ls -la /opt/data/plugins/plugin-matrix-inbound-s3/ 2>/dev/null
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|http" /opt/data/plugins/plugin-matrix-inbound-s3/__init__.py 2>/dev/null | head -30
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**要回答**:
|
|
|
|
|
+- App 发来 `m.file`,`url` 字段是 `https://s3...` 还是 `mxc://`?
|
|
|
|
|
+- 容器是**直接下载那个 https URL**,还是先转成 mxc 再下载?
|
|
|
|
|
+- **文件本体有没有经过 Matrix 服务器?**
|
|
|
|
|
+
|
|
|
|
|
+## Q2:容器 → App,文件怎么过去的
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+grep -n "def \|send_content_event\|msg_content\|url" /opt/data/plugins/plugin-matrix-outbound-s3/__init__.py 2>/dev/null | head -30
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**要回答**:发出去的 `m.file` 里,`url` 是 https 还是 mxc?文件本体经过 Matrix 吗?
|
|
|
|
|
+
|
|
|
|
|
+## Q3:现在有几处大小限制(全部列出来)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+echo "=== App 侧(我不知道,你只看容器侧)==="
|
|
|
|
|
+grep -rn "max_media_bytes\|MAX_FILE_BYTES\|max_inbound\|max_size\|too large\|oversize\|104857600\|20971520" \
|
|
|
|
|
+ /opt/data/plugins/ /opt/data/scripts/ /opt/data/config.yaml /opt/data/.env 2>/dev/null | grep -v ".pyc" | head -30
|
|
|
|
|
+
|
|
|
|
|
+echo "=== Hermes 内核默认值 ==="
|
|
|
|
|
+grep -rn "DEFAULT_INBOUND_MEDIA_MAX_BYTES\|_max_media_bytes\|MATRIX_MAX_MEDIA_BYTES" \
|
|
|
|
|
+ /opt/hermes/ 2>/dev/null | head -20
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**要回答**:把所有限制列成表 —— 哪个文件、哪一行、值是多少、在哪一步生效。
|
|
|
|
|
+
|
|
|
|
|
+## Q4:超限时的行为
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+grep -rn "Rejecting oversized\|too large\|oversize" /opt/hermes/ /opt/data/plugins/ 2>/dev/null | head -20
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**要回答**:超限时是**静默丢弃**还是**回复用户**?
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 二、我这边已知的事实(供你对照)
|
|
|
|
|
+
|
|
|
|
|
+| 项 | App 侧现状 |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| App → 容器 | `sendFileByUrl()`:先传云盘,事件里 `url = https://s3...`,**文件本体不进 Matrix** |
|
|
|
|
|
+| 容器 → App | 容器发 `m.file`,`url = https://s3.../deliverables/...` |
|
|
|
|
|
+| App 侧大小限制 | `CLOUD_LIMIT_BYTES = Infinity`(**不限制**) |
|
|
|
|
|
+
|
|
|
|
|
+**所以 App 侧本来就是「只传链接」。** 需要确认容器侧是不是也这样。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 三、回答格式
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+## Q1 App → 容器
|
|
|
|
|
+url 字段 = https / mxc
|
|
|
|
|
+文件本体经过 Matrix 吗 = 是/否
|
|
|
|
|
+代码位置 = ?
|
|
|
|
|
+
|
|
|
|
|
+## Q2 容器 → App
|
|
|
|
|
+url 字段 = https / mxc
|
|
|
|
|
+文件本体经过 Matrix 吗 = 是/否
|
|
|
|
|
+代码位置 = ?
|
|
|
|
|
+
|
|
|
|
|
+## Q3 所有大小限制
|
|
|
|
|
+| 文件:行号 | 值 | 在哪一步生效 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| ... | ... | ... |
|
|
|
|
|
+
|
|
|
|
|
+## Q4 超限行为
|
|
|
|
|
+静默 / 回复用户 = ?
|
|
|
|
|
+代码位置 = ?
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+🔴 只要事实和代码原文。**不要提建议,先梳理清楚。**
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 容器回答(原文,按时间顺序,未删改)
|
|
|
|
|
+
|
|
|
|
|
+### 1【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+收到。这一轮只做只读检查:先查这四处代码路径,再按 Q1–Q4 给您代码原文。
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 5【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+which hermes 2>/dev/null; ls -d /opt/...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "MATRIX_MAX_MEDIA_BYTES\|mat...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+which hermes 2>/dev/null; ls -d /opt/...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "MATRIX_MAX_MEDIA_BYTES\|mat...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sym=/usr/local/lib/python3.13/dist-pa...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "hermes" /opt/data/config.ya...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+which hermes 2>/dev/null; ls -d /opt/...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "MATRIX_MAX_MEDIA_BYTES\|mat...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sym=/usr/local/lib/python3.13/dist-pa...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "hermes" /opt/data/config.ya...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '870,900p' /opt/hermes/plugins...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "matrix_platform\|sys.path.i...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 8【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+which hermes 2>/dev/null; ls -d /opt/...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "MATRIX_MAX_MEDIA_BYTES\|mat...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sym=/usr/local/lib/python3.13/dist-pa...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "hermes" /opt/data/config.ya...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '870,900p' /opt/hermes/plugins...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "matrix_platform\|sys.path.i...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+find / -name "matrix_platform*" -not ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '1440,1530p' /opt/hermes/plugi...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 9【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+...
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 10【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+grep -n "def \|mxc\|download\|fetch\|...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -n "def \|send_content_event\|ms...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L196-315
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "_max_media_bytes\|max_media...
|
|
|
|
|
+```
|
|
|
|
|
+📖 Reading __init__.py L309-428
|
|
|
|
|
+💻 terminal
|
|
|
|
|
+```
|
|
|
|
|
+which hermes 2>/dev/null; ls -d /opt/...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "MATRIX_MAX_MEDIA_BYTES\|mat...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sym=/usr/local/lib/python3.13/dist-pa...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "hermes" /opt/data/config.ya...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '870,900p' /opt/hermes/plugins...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+grep -rn "matrix_platform\|sys.path.i...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+find / -name "matrix_platform*" -not ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '1440,1530p' /opt/hermes/plugi...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '490,520p' /opt/hermes/gateway...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== cache funcs enforcing cap =...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 11【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 12【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== config.yaml keys (no secret...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== which python runs gateway /...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 13【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== config.yaml keys (no secret...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== which python runs gateway /...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== outbound 180-210 ==="; sed ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== running process ==="; ps au...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 14【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== config.yaml keys (no secret...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== which python runs gateway /...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== outbound 180-210 ==="; sed ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== running process ==="; ps au...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== E2EE mode in .env (value on...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+ps aux | grep "gateway run" | grep -v...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 15【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== config.yaml keys (no secret...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== which python runs gateway /...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== outbound 180-210 ==="; sed ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== running process ==="; ps au...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== E2EE mode in .env (value on...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+ps aux | grep "gateway run" | grep -v...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== document cache func ==="; g...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+tr '\0' '\n' < /proc/161280/environ 2...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 16【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+* ```
|
|
|
|
|
+echo "=== adapter 2130-2160 inbound s...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+sed -n '575,595p;650,695p' /opt/herme...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== config.yaml keys (no secret...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== which python runs gateway /...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== outbound 180-210 ==="; sed ...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== running process ==="; ps au...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== E2EE mode in .env (value on...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+ps aux | grep "gateway run" | grep -v...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== document cache func ==="; g...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+tr '\0' '\n' < /proc/161280/environ 2...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+echo "=== 1) .env 里所有 media/size/limi...
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 17【prose】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+全部只读核查已完成。以下是**代码原文事实**。
|
|
|
|
|
+
|
|
|
|
|
+## Q1 App → 容器
|
|
|
|
|
+
|
|
|
|
|
+**url 字段 = `https`**(``)
|
|
|
|
|
+**文件本体经过 Matrix 吗 = 否**
|
|
|
|
|
+**代码位置** =
|
|
|
|
|
+
|
|
|
|
|
+上游原版 `/opt/hermes/plugins/platforms/matrix/adapter.py:2138-2141` 会写死拒收:
|
|
|
|
|
+```python
|
|
|
|
|
+url = source_content.get("url", "")
|
|
|
|
|
+if url and not str(url).startswith("mxc://"):
|
|
|
|
|
+ logger.warning("[Matrix] Rejecting inbound media %s with non-MXC URL", event_id)
|
|
|
|
|
+ return
|
|
|
|
|
+```
|
|
|
|
|
+本插件 `__init__.py:45` 白名单只放行精确的 host:
|
|
|
|
|
+```python
|
|
|
|
|
+FMODE_MEDIA_HOSTS = frozenset({"s3.fmode.cn"})
|
|
|
|
|
+```
|
|
|
|
|
+`__init__.py:168-183` 处,入口会无条件包一层,并直接把 `https_url` 交给自己的 `_handle_https_media`,**不会**转成 mxc:
|
|
|
|
|
+```python
|
|
|
|
|
+if _u and not str(_u).startswith("mxc://"):
|
|
|
|
|
+ https_url = str(_u)
|
|
|
|
|
+if https_url:
|
|
|
|
|
+ return await _handle_https_media(self, ..., https_url)
|
|
|
|
|
+```
|
|
|
|
|
+`__init__.py:272-274` 直接对那个 https URL 发 GET,并显式禁止重定向:
|
|
|
|
|
+```python
|
|
|
|
|
+async with http.get(url, timeout=aiohttp.ClientTimeout(total=120), allow_redirects=False, **req_kw) as resp:
|
|
|
|
|
+```
|
|
|
|
|
+**结论:文件本体从 App 直达 S3 再到容器,从不进入 Matrix 服务器。** 已核实的依据还有:`MATRIX_E2EE_MODE=off`,进程 161280 的 environ 中无 `MATRIX_MAX_MEDIA_BYTES`。
|
|
|
|
|
+
|
|
|
|
|
+## Q2 容器 → App
|
|
|
|
|
+
|
|
|
|
|
+**url 字段 = `https`**(`https://s3.fmode.cn/deliverables/...`)
|
|
|
|
|
+**文件本体经过 Matrix 吗 = 否**
|
|
|
|
|
+**代码位置** =
|
|
|
|
|
+
|
|
|
|
|
+插件文件头 `:1-7` 即写明:「事件 content.url 直接写 https 直链,**不调 upload_media**」。
|
|
|
|
|
+`:281-290` 拼事件体,`url` 用的就是 S3 直链:
|
|
|
|
|
+```python
|
|
|
|
|
+msg_content = {
|
|
|
|
|
+ "msgtype": msgtype, "body": caption or filename,
|
|
|
|
|
+ "url": url,
|
|
|
|
|
+ "info": {"mimetype": content_type, "size": len(data)},
|
|
|
|
|
+```
|
|
|
|
|
+`:302` 直接发事件,不经过 upload:`return await self._send_content_event(room_id, msg_content)`
|
|
|
|
|
+`:249-251` 还有强校验:只要不是 `` 开头就拒发:
|
|
|
|
|
+```python
|
|
|
|
|
+if not url.startswith(""):
|
|
|
|
|
+ return self._fmode_outbound_fail("bad deliverables url: %s" % url)
|
|
|
|
|
+```
|
|
|
|
|
+**唯一例外(会让文件进 Matrix)**:`:196-203` E2EE 房间会回退到上游走 mxc。当前 `E2EE_MODE=off`,这条分支未启用。
|
|
|
|
|
+
|
|
|
|
|
+## Q3 所有大小限制(全部)
|
|
|
|
|
+
|
|
|
|
|
+| 文件:行号 | 值 | 在哪一步生效 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `plugin-matrix-inbound-s3/__init__.py:262` | `max_bytes = 50 * 1024 * 1024`(50 MiB) | **入站下载**。在 `_fetch_and_cache_attachment` 里硬编码,与 env 无关 |
|
|
|
|
|
+| `plugin-matrix-inbound-s3/__init__.py:282-283` | 同上 50 MiB | 入站 Content-Length 预检,超出就 `raise ValueError("media exceeds size limit")` |
|
|
|
|
|
+| `plugin-matrix-inbound-s3/__init__.py:288-289` | 同上 50 MiB | 入站流式累加,超出就 raise |
|
|
|
|
|
+| `plugin-matrix-inbound-s3/__init__.py:325-329` | `self._max_media_bytes`(见下,实际 100 MiB) | 入站事件 `info.size` 预检,超出直接 return(更早于上一条) |
|
|
|
|
|
+| `/opt/hermes/plugins/platforms/matrix/adapter.py:884` | `_env_number("MATRIX_MAX_MEDIA_BYTES", 100 * 1024 * 1024)` → **100 MiB**(env 未设,取默认) | 适配器级总闸,入站+出站都读它 |
|
|
|
|
|
+| `adapter.py:2144-2147` | 100 MiB | 上游入站事件 size 预检(被插件的 325 行先行拦截) |
|
|
|
|
|
+| `adapter.py:1514-1515` | 100 MiB | `_download_external_media_with_cap` Content-Length 预检(仅 image) |
|
|
|
|
|
+| `adapter.py:1520-1521` | 100 MiB | 同上,流式累加 |
|
|
|
|
|
+| `adapter.py:1745` | 100 MiB | `_upload_and_send` 开头上限判断 |
|
|
|
|
|
+| `adapter.py:1817` | 100 MiB | `_send_local_file` 读盘前 `p.stat.st_size` 判断 |
|
|
|
|
|
+| `adapter.py:1793` | 100 MiB | `_media_too_large` 组装错误文案 |
|
|
|
|
|
+| `plugin-matrix-outbound-s3/__init__.py:186-188` | `self._max_media_bytes`(100 MiB) | **出站上传前**判断,复用上游取值 |
|
|
|
|
|
+| `/opt/hermes/gateway/platforms/base.py:504` | `DEFAULT_INBOUND_MEDIA_MAX_BYTES = 128 * 1024 * 1024`(128 MiB) | 兜底终局。实测 `get_inbound_media_max_bytes` = **134217728** |
|
|
|
|
|
+| `base.py:586 / 657 / 685 / 526-539` | 128 MiB | `cache_image/audio/video_from_bytes` + `_cache_media_from_url` 真正落盘前 |
|
|
|
|
|
+| `base.py:1428-1441` `cache_document_from_bytes` | **无任何大小校验** | 文档类落盘不过闸 |
|
|
|
|
|
+
|
|
|
|
|
+**上限汇总:链路上一共有 50 MiB(入站,插件硬编码)、100 MiB(适配器级,env 可调)和 128 MiB(gateway 兜底)三重限制,实际瓶颈是 50 MiB。**
|
|
|
|
|
+另外确认:`uploader.mjs` 与 `fmode-app-deliver.py` **均无大小上限**(无命中); 与 `config.yaml` 中**没有任何** media/size 键,故 100 MiB 全靠默认值。
|
|
|
|
|
+
|
|
|
|
|
+## Q4 超限行为
|
|
|
|
|
+
|
|
|
|
|
+**入站 = 静默丢弃(不回复用户)**,只在服务端记一条 warning。
|
|
|
|
|
+- 位置 1,事件预检:`plugin-matrix-inbound-s3/__init__.py:326-329`
|
|
|
|
|
+```python
|
|
|
|
|
+if event_size_int and max_bytes and event_size_int > max_bytes:
|
|
|
|
|
+ logger.warning("[Matrix] Rejecting oversized inbound media %s (%d > %d bytes)", event_id, event_size_int, max_bytes)
|
|
|
|
|
+ return
|
|
|
|
|
+```
|
|
|
|
|
+- 位置 2,下载抛错后被兜住:`:338-340`
|
|
|
|
|
+```python
|
|
|
|
|
+except Exception as e:
|
|
|
|
|
+ logger.warning("[Matrix] Failed to cache https media %s: %s", event_id, e)
|
|
|
|
|
+ return
|
|
|
|
|
+```
|
|
|
|
|
+同一层路径 `:342-344` 缓存无路径时也只 warning + return。
|
|
|
|
|
+
|
|
|
|
|
+**上游同款**(`adapter.py:2144-2147`):`logger.warning(...)` 后 `return`,同样静默。
|
|
|
|
|
+
|
|
|
|
|
+**出站 = 返回失败,但用户看不到**:`adapter.py:1789-1793`
|
|
|
|
|
+```python
|
|
|
|
|
+def _media_too_large(self, size: int) -> SendResult:
|
|
|
|
|
+ return SendResult(success=False, error=f"Media file exceeds Matrix limit ({size} > {self._max_media_bytes} bytes)")
|
|
|
|
|
+```
|
|
|
|
|
+出站侧由 `plugin-matrix-outbound-s3/__init__.py:186-188` 沿用同一判断,返回的 `SendResult(success=False)` 不会变成聊天里的一条提示。
|
|
|
|
|
+
|
|
|
|
|
+## 补充事实:为什么会有多条路径
|
|
|
|
|
+
|
|
|
|
|
+- **两套入站入口并存**:上游原版只认 `mxc://`,本插件是运行时 monkey-patch 出来的旁路(`plugin.yaml` 自述不修改 `/opt/hermes` 只读上游)。所以插件 `_handle_https_media` 是「复刻上游流程」,代码里同样保留了一份 100 MiB 判断(325 行)和一份自己的 50 MiB(262 行)。
|
|
|
|
|
+- **三重阈值不同源**:50 MiB 是插件作者自定;100 MiB 是 Hermes 适配器默认(可由 `MATRIX_MAX_MEDIA_BYTES` 覆盖,当前未设);128 MiB 是 gateway 平台层的内存保护默认(可由 `config.yaml: gateway.max_inbound_media_bytes` 覆盖,当前未设)。
|
|
|
|
|
+- **文档类不过 gateway 闸**:`cache_document_from_bytes` 无校验,所以 `.pdf/.xlsx/.md` 等只受 50 MiB 和 100 MiB 约束;图片音视频还会被 128 MiB 兜一层。
|
|
|
|
|
+- **出站文档中提到的另一处 8 MiB**:`plugin-fmode/plugin/fmode_core/security.py:48 MAX_FILE_BYTES = 8MB` 是**安全扫描**跳过阈值,与传输无关,但同一份配置里易混淆。
|
|
|
|
|
+
|
|
|
|
|
+以上均为只读检查:未改动任何文件、未重启服务、未写入存储。
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 18【ack】
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+✅ 容器已标记完成
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 工具过程(仅供核对,非回答内容)
|
|
|
|
|
+
|
|
|
|
|
+- `💻 terminal ``` ls -la /opt/data/plugins/ 2>/dev/null... ````
|