# 文件传输与局域网直连

> HTML: https://remote.ivjn.us/docs/zh-CN/files-and-lan/

Agent、Exchange、CLI、网页控制台和手机控制端支持文件传输。支持的设备会声明 `files` 能力。

## 文件传输

```sh
remote-cli file i5m ls /tmp
remote-cli file i5m upload ./example.zip /tmp/example.zip
remote-cli file i5m download /tmp/example.zip ./downloaded.zip
remote-cli file i5m fetch https://example.com/example.zip ./example.zip
remote-cli file i5m fetch https://files.example.org/library/clip.mp4.Aran ./clip.mp4
remote-cli file i5m fetch --warm https://files.example.org/library/clip.mp4.Aran
```

默认不覆盖已有文件；上传或下载时添加 `--overwrite` 才允许覆盖。CLI 使用 Ctrl+C 取消，网页和手机控制端提供取消按钮。网页在设备详情的“文件”页操作，手机控制端从设备详情进入“文件传输”。

传输分块为 64 KiB，每块确认后继续。单文件上限 1 GiB；网页下载上限 128 MiB，较大文件请使用 CLI 或手机控制端。目录最多返回 1000 项，不支持递归目录上传。上传在目标目录写入临时文件，完整接收后原子替换；取消、断线或超时会清理未完成的临时文件。CLI 下载也使用临时文件，手机端下载到缓存后调用系统分享/保存。

文件访问使用 Agent 进程的系统权限，不限制在某个共享目录。只读账号不能列目录、上传或下载；Exchange 沿用设备所属工作区、会话隔离和操作审计，不记录文件内容。Android 上 `.` 指向 Agent 应用文件目录，访问其他目录受 Android 权限限制，不能绕过系统沙箱。

## 通过 Agent 下载网络文件

网页文件页的“网络文件链接”接受 HTTP/HTTPS URL。Agent 从自己的网络访问链接，将响应分块传回 Console，浏览器保存到本机；文件不会先保存到 Agent 磁盘。该入口需要更新原生 Agent（包括 Android、OpenWrt 和桌面），浏览器扩展目前不提供文件传输。

CLI 使用 `file DEVICE fetch URL LOCAL`，支持 `--overwrite`，默认保留已有文件。网页仍限制 128 MiB，CLI 限制 1 GiB；支持没有 Content-Length 的流式响应。非成功 HTTP 状态、连接或读取超时、超出大小限制都会中止；CLI 仅在完整接收后发布目标文件。取消和断线关闭网络请求，网页不会保存不完整文件。

`.Aran` 链接：`file DEVICE fetch URL.Aran LOCAL` 保存解密后的文件，大小等于清单记录的大小，1 GiB 上限按明文计算。`--warm`（不写 LOCAL）只向源站对每个数据块发 HEAD 请求预热，4 个并发，打印进度并在结束时给出完成/失败块数；任一块失败则命令失败。`--raw` 照旧保存清单 JSON。P2P 默认开启：不带 `--p2p-*` 选项时由 Agent 自行通过 `https://p2p.ivjn.us` 加入组 `ivjncn`（桌面 0.1.51 起、Android 0.1.52 起；只读查询，不注册、不对外提供），`--no-p2p` 关闭，显式指定的选项覆盖默认值，快速失败规则同媒体播放。桌面与 Android Agent 支持；OpenWrt Agent 会返回 `This Agent build cannot decrypt .Aran files`；早于 0.1.51 的 Agent 会让 CLI 提示 `Upgrade this Agent to fetch .Aran files`，需要升级 Agent。

URL 不接受内嵌账号密码；最多跟随 5 次重定向，拒绝 HTTPS 降级。下载使用验证证书的 rustls 配置，不继承管理服务器的 `--insecure` 选项；需要私有 CA 或自定义认证请求时使用下方 HTTP 入口。

## 类 curl 的 HTTP 请求

在设备“通过 Agent 发送 HTTP 请求”页粘贴 curl 命令，Console 将其转换为密封的 `net_req`，由所选 Agent 请求目标，再显示状态码、耗时、响应头和响应正文。支持 `-X/--request`、`-H/--header`、`-d/--data`、`--data-raw`、`--data-binary`（内联内容）、`--json`、`-I/--head`、`-L/--location`、`-m/--max-time` 和 `--url`。支持引号和反斜杠续行；不执行 shell，也不读取 `@file`。输入不会保存到本地存储，切换设备会清空请求和响应。

```sh
curl -X POST 'https://example.com/api' -H 'Content-Type: application/json' --data-raw '{"message":"hello"}'
```

原生系列共用已有 HTTP 引擎，不需要安装系统 curl；CLI 的对应入口为 `remote-cli net DEVICE http URL -X POST -H 'Content-Type: application/json' -d '{"message":"hello"}'`。新浏览器扩展也通告 `net` 并支持 HTTP 请求，需要在扩展配置中授予网站访问权限；不提供 ICMP ping。浏览器禁止的 Cookie、Host、Origin 等请求头会明确报错，且不附带浏览器 Cookie。Chromium 隐藏的重定向会提示改用最终 URL，不静默跟随到未授权站点。

请求体上限 256 KiB、超时最多 120 秒。原生响应正文最多 1 MiB，浏览器扩展最多 128 KiB；超出时标记截断。此入口用于文本/API 响应；二进制和较大文件使用网络文件下载。HTTP 4xx/5xx 保留状态与正文供排查。只读权限不能发送请求，取消会关闭对应会话。

## 局域网控制端口

局域网控制默认关闭，默认 TCP 端口为 **7277**。仅在可信局域网中启用。启用前设备必须已经固定工作区根（`remote-agent seal root`，或先连上 Exchange 完成 TOFU）。没有局域网访问令牌。不要把端口转发到公网。

在现有 Agent JSON 配置中添加：

```json
{
  "lan_enabled": true,
  "lan_port": 7277
}
```

保留配置中原有的 `server`、`device_id` 和 `token` 字段。也可使用 `--lan-enabled`、`--lan-port`，或 `REMOTE_LAN_ENABLED`、`REMOTE_LAN_PORT`。未固定工作区根时，启用 LAN 会拒绝启动。

桌面配置页和 LuCI 设置页均有开关。修改后重新启动 Agent；桌面配置页要求先停止连接再修改。关闭开关并重启后，不再监听此端口。程序不会自动创建防火墙放行规则。

CLI 直连单独写配置，不要用 `login`（它要求非空令牌）。`server` 填设备的 `http://IP:7277`，`token` 留空，请求不带 `Authorization`：

```toml
server = "http://192.168.1.20:7277"
token = ""
```

用 `REMOTE_CLI_CONFIG` 指向该文件可以保留另一份云端登录。密封身份和授权缓存放在这份配置所在目录：`seal-grants.json` 中的离线 grant，以及 `seal-chains.json` 中根签发在前的证书链。所有设备操作只打开密封会话，包括设备卡片带 `local` 或局域网地址上 `/api/auth/me` 返回 401 的直连设备。Agent 不签发、不续签这些授权。云端离线时只能使用缓存中仍有效的根链授权。`sessions` 和 `session-kill` 不可用：局域网没有会话目录，设备会话仍由 Exchange 管理。

直连只暴露本机设备。外层只接受私有、链路本地或回环地址，并校验 Origin。`GET /api/devices` 在通过这些检查后只返回设备 ID 和启动密封握手所需的 `seal_key` / `seal_mode`。`GET /api/auth/me` 在密封握手之前不返回操作员身份。`GET /ws/operator` 只接受密封会话，不提供明文兼容路径。

客户端在 `open_sealed` 的 hello 里内联提交操作员公钥证明，以及上述离线缓存的 grant（`hello.grant`）和可选证书链（`hello.chain`，根签发的在前）。设备用与 Exchange 路径相同的规则核对本机根、设备范围和 view/manage，会话内容保持密封。网页控制台仍通过 Exchange 连接设备。默认监听 IPv4 所有接口；云端离线时仍可使用。LAN 绑定失败会记录错误，云端重连继续运行。

## 回归验证

```sh
python scripts/file-transfer-smoke.py --agent target/debug/remote-agent --cli target/debug/remote-cli
python scripts/agent-ui-smoke.py --agent target/debug/remote-agent --platform linux
```

需要 Python 3.11+ 与 `websockets`。Windows 使用 `.exe` 路径和 `--platform windows`。测试使用临时配置与文件，不修改现有登录或设备。
