Skip to content

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LanShare · 局域网互传

桌面窗口一开,手机扫码就能传 —— 不用装客户端,不用记 IP,文件不经过互联网。

Rust License

LanShare 桌面窗口

它是什么

lanshare 是一个用 Rust 写的局域网文件互传工具。

在电脑上打开它,会出现一个原生桌面窗口,里面直接显示二维码、访问地址和收到的文件。 手机连同一个 Wi-Fi 扫一下二维码,浏览器里就能上传下载。

  • 电脑端:桌面窗口,不用开终端
  • 手机端:浏览器,不用装 App

为什么手机端还是浏览器?因为 iOS / Android 上装不了我们写的桌面程序。 浏览器是唯一一个所有设备都有的客户端 —— 这是绕不开的。 桌面窗口替代的是终端,不是浏览器。

特性

传文件

  • 扫码直达,二维码里已包含密码,扫一次就进
  • 拖拽上传,也能直接 Ctrl+V 粘贴截图
  • 每个文件独立进度条、实时速度、剩余时间,可单独取消
  • 上传与下载都支持断点续传
    • 下载:HTTP Range,大文件、音视频拖动都行
    • 上传:大文件(≥ 8 MB)自动切成 4 MB 分片,断线后从断点继续而不是从零重来; 刷新页面后重新选择同一个文件也能接着传
  • 多端实时同步:谁传了、谁删了,所有设备立刻看到
  • 中文文件名全程无损

安全

  • 默认开启密码保护,随机 6 位,窗口里显示得一清二楚
  • 只有两条路能进:扫码,或者手动输地址后输密码
  • 密码用恒定时间比较,防时序侧信道
  • 登录限速:连续失败 8 次后锁定,逐次翻倍,上限 30 分钟
  • 会话 Cookie 存的是随机会话令牌,不是密码本身
  • 文件名净化,../../etc/passwd 这类路径穿越被挡掉

一次性文件

  • --ephemeral(界面可勾选):文件只存在临时目录,关掉就销毁
  • 正常关闭窗口、Ctrl+Ckill、注销,都会触发销毁
  • 唯一拦不住的是 kill -9;这种情况残留的目录会在下次启动时被清掉

其他

  • 只读模式:只准下载,禁止上传与删除
  • 不限制文件大小(默认)——上传 5 GB 实测内存恒定在 9 MB 左右,全程流式, 想限制时用 --max-size 指定
  • 深色界面,内置中文字体(不会出现方框)
  • 完全离线:前端资源编译进二进制,不引用任何 CDN

安装

sudo dpkg -i lanshare_0.1.0_amd64.deb

或从源码构建:

cargo build --release
sudo install -m 0755 target/release/lanshare /usr/local/bin/

使用

lanshare

窗口里会显示:

  • 左侧:二维码、访问地址、访问密码
  • 右侧:设置收到的文件列表(可打开 / 删除 / 一键清空)

手机扫码 → 浏览器打开 → 拖文件上传。电脑这边文件立刻出现在列表里。

参数

参数 说明 默认
-d, --dir <PATH> 文件存储目录 ~/Downloads/LanShare
-p, --port <PORT> 监听端口 8080
--password [<PWD>] 设置访问密码;不带值则随机生成 随机 6 位
--no-auth 关闭密码校验
--ephemeral 一次性模式,退出即销毁文件 关闭
--no-gui 只开服务不开窗口(服务器 / 脚本用) 开窗口
--max-size <MB> 单文件上限,0 为不限 0(不限)
--readonly 只读模式 关闭
--host <IP> 绑定地址 0.0.0.0

常见用法

# 用自己的密码
lanshare --password 我的密码

# 传完就销毁,不留痕迹
lanshare --ephemeral

# 关掉密码(只在完全可信的网络里这么做)
lanshare --no-auth

# 服务器 / 脚本场景:不开窗口,只跑服务
lanshare --no-gui -p 9000

# 只读分享一个目录
lanshare -d ~/Pictures --readonly

# 想限制单文件大小(默认不限)
lanshare --max-size 2048

没有图形环境时(SSH、systemd)会自动退回终端模式,不需要手动加 --no-gui

开机自启(可选)

deb 包内置用户级 systemd 服务:

systemctl --user enable --now lanshare

界面

桌面窗口 手机浏览器界面
电脑端:桌面窗口(二维码 + 密码 + 文件列表) 手机端:浏览器界面(扫码后打开)

安全说明

这个工具面向可信的局域网(家里、办公室)。请了解以下边界:

  • 传输是 HTTP 明文。密码只是访问门槛,没有 TLS,同网段的人理论上能嗅探内容。 传敏感文件请先自行打包加密。
  • 默认密码是 6 位数字(约 100 万种组合)。它足够挡住随手点进来的同事, 但挡不住有心人长期爆破 —— 限速能大幅拖慢,但不能根治。 要更强的安全性,请用 --password 设一个长密码。
  • 路由器开了 AP 隔离(公共 / 访客 Wi-Fi 常见)时设备之间无法互访, 这是网络策略,不是程序问题。
  • 服务以你的用户身份运行,只能读写存储目录,不会执行上传的文件

手机 / 其他设备打不开怎么办

按顺序排查,绝大多数是第一条。

1. 防火墙拦截

Linux 上 ufw 默认入站策略是 DROP。服务端一切正常、日志毫无异常, 但连接在到达进程之前就被内核丢掉了,表现就是手机一直转圈直到超时。

sudo ufw allow 8080/tcp     # 换成你实际用的端口

启动时 lanshare 会检测到这种情况并直接把命令打出来。

2. 不在同一网段

对比两边 IP 的前三段。手机在「设置 → WLAN → 当前网络」里能看到自己的 IP。

3. 路由器开了 AP 隔离

公共 / 访客 Wi-Fi 常见,会禁止无线设备互访。换个网络或开手机热点试试。

4. 手机切回了移动数据

部分手机在 Wi-Fi 无外网时自动切回。临时关掉移动数据。

工作原理

手机浏览器  ──HTTP/SSE──┐
                        ├──▶  lanshare 桌面窗口  ──▶  存储目录
另一台电脑  ──HTTP/SSE──┘        (内嵌 HTTP 服务)
  • 存储目录即事实来源:启动时扫描建索引,每个文件分配随机 ID。 URL 里只有 ID,不泄露文件名,也天然兼容中文与重名。
  • 上传先写 .lanshare-tmp/*.part,完成后原子 rename, 失败或超限自动清理,不会留下半个文件。
  • SSE 负责实时同步:连上先收一份完整快照,之后每次变更再收通知。
  • 一次性模式的临时目录名带 PID,用 Drop + self-pipe 信号处理器双重保证销毁; 启动时还会清理已退出进程留下的目录(严格只认自己的命名格式,不会误删别人的)。

测试

cargo test                                    # 205 项测试
cargo clippy --all-targets -- -D warnings     # 静态检查,零告警
cargo fmt --all -- --check                    # 格式检查

覆盖范围:

  • 安全:路径穿越(/\ 两种写法)、控制字符、Windows 保留名、 超长中文名的 UTF-8 边界截断、密码比对、登录限速(阈值 / 递增 / 上限 / 来源隔离 / 成功清零 / 不影响正常轮询)
  • 存储:重名去重、空文件、中断上传清理、重启重新扫描
  • 下载Range 各种形态(0-99 / 500- / -100 / 越界)、 中文名的 RFC 5987 编码、inlineattachment
  • 接口:上传 → 列表 → 下载 → 删除全链路、超限清理、只读模式各项拦截
  • 二维码:点阵边长与定位图案、静默区、逐格渲染比对、纯黑白、超长载荷
  • 一次性目录:命名解析、拒绝外来同前缀目录、管道创建
  • 地址刷新:地址未变时不广播、变化时地址与二维码一起重建、 启动时只有回环的过期地址能被后台循环自动纠正
  • 分片续传:偏移校验与纠正(409 返回真实偏移)、断点接续后内容不乱、 声明大小与配置上限的拦截、放弃后不留残留、会话过期回收、会话数上限、 路径穿越文件名同样被净化、只读与密码模式下的拦截

另外用真实窗口与真实浏览器做过端到端验证:

  • 桌面窗口在 Xvfb 下截图,逐格比对二维码 29/29 行与期望点阵完全一致
  • 手机端路径用 Chrome DevTools 协议驱动:上传 250 KB 后字节完全一致、 SSE 推送到达、四条下载入口全部可用、移动端滑动删除可用
  • 两种模式下 SIGTERM 均已确认销毁临时文件
  • 续传:真实 Chrome 上传 40 MB 时用 CDP 限速并在中途断网, 恢复后偏移序列显示从断点继续(未回到 0),md5 与源文件一致

打包

./scripts/build-deb.sh              # 构建并打包
./scripts/build-deb.sh --skip-build # 复用已有二进制

产物:dist/lanshare_<版本>_<架构>.deb

脚本直接手写 DEBIAN/ 目录并用 dpkg-deb --build --root-owner-group 打包, 不依赖 debhelper 与 dh-cargo,也不需要 root。打包后自动校验必需路径、 二进制可执行性、md5sums 一致性,以及(若安装了)lintian

项目结构

src/
  main.rs         入口:图形环境检测、一次性目录守卫
  lib.rs          库入口(便于集成测试直接驱动路由)
  cli.rs          参数定义
  config.rs       配置解析、一次性目录生命周期
  cleanup.rs      self-pipe 信号处理器,保证 SIGTERM 也销毁文件
  gui.rs          桌面窗口(egui)
  controller.rs   服务启停(供窗口调用)
  banner.rs       终端横幅与终端二维码
  net.rs          局域网地址探测、二维码点阵
  firewall.rs     防火墙检测与放行提示
  store.rs        文件存储、文件名净化、原子落盘
  upload.rs       分片续传上传的会话管理
  state.rs        共享状态、文本片段、事件广播
  server.rs       端口绑定与优雅关闭
  error.rs        统一 JSON 错误响应
  util.rs         随机串、Range 解析、下载文件名编码
  routes/
    mod.rs        路由组装
    api.rs        业务接口
    auth.rs       密码鉴权与登录限速
    pages.rs      内嵌静态资源
web/              手机端界面(零构建,编译期嵌入二进制)
tests/integration.rs
packaging/        deb 元数据、desktop、systemd 单元、图标
scripts/build-deb.sh

已知限制

  • 只支持 IPv4 局域网,不做公网穿透、IPv6 与内置 HTTPS
  • 默认不限制文件大小;磁盘写满前不会主动拦截,超大文件请留意剩余空间
  • 没有 mDNS,不能用 lanshare.local 访问,需要看二维码或地址
  • 文本片段保存在内存里,重启即清空
  • kill -9 无法拦截(残留目录会在下次启动时清理)

许可证

MIT

About

局域网文件互传工具:打开桌面窗口,手机扫码即可互传文件 · Rust + egui,打包为 deb

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages