Skip to content
Catherina0Public

About

Resources

Stars

6 stars

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

Repository files navigation

clipboard

一个自托管的临时共享空间服务。任意设备输入同一串空间密钥即可加入同一个临时空间,用来共享多段文本和文件;也可以额外设置空间密码提升端到端加密强度。所有使用均为端到端加密;服务端不记录任何信息,包括时间、动作和 IP。我们拒绝因为审查导致您的隐私信息泄漏。

功能

  • 空间密钥访问:同一空间密钥对应同一空间,大小写不敏感。
  • 全量端到端加密:所有文本、文件内容和文件名元数据都在浏览器内加密后上传。
  • 创建保护:创建新空间需要 Cloudflare Turnstile 人机验证。
  • 加入保护:加入空间只允许进入已经存在且未过期的空间;不存在的空间密钥会返回错误,不会自动创建。
  • 多段文本:每次保存会新增一个文本卡片,支持一键复制和删除。
  • 文件共享:支持上传、单文件下载、删除。
  • 一键导出:浏览器本地解密并打包为 zip,文本会保存为 clipboard-texts.txt。
  • 立即销毁:手动删除当前空间的所有文本和文件。
  • 手动续期:普通空间续期 10 分钟;扩容空间续期 24 小时。
  • 匿名空间:所有空间都不写 app 审计日志,不记录任何信息,包括时间、动作和 IP。
  • 隐私承诺:我们拒绝因为审查导致您的隐私信息泄漏。

空间规则

空间密钥和扩容密钥都只允许数字和英文字母,服务端会统一转成大写后处理。空间密码是可选的端到端加密密钥,不发送给服务端,只保存在当前浏览器内存里;如果不填写空间密码,浏览器会使用空间码本身派生 E2EE 密钥。换设备加入同一空间时,必须使用同一个空间码和同一个空间密码设置。

状态 容量 默认过期/续期
普通空间 10MB 10 分钟
使用有效扩容密钥 1GB 24 小时
使用高级扩容密钥 4GB 48 小时

扩容密钥只在创建空间时生效,用来提升容量和续期时长。每个扩容密钥最多同时维持 3 个未过期空间。空间过期后,同一个空间密钥不会在加入时自动创建,需要重新通过“创建空间”流程并完成人机验证。

Cloudflare Turnstile

生产环境应配置 Turnstile,创建新空间时会校验 token:

TURNSTILE_REQUIRED=true
TURNSTILE_SITE_KEY="0x..."
TURNSTILE_SECRET_KEY="0x..."

同时配置 TURNSTILE_SITE_KEY 和 TURNSTILE_SECRET_KEY 时默认启用 Turnstile;只缺其中一个时不会在前端显示缺失 key 的验证框。本地开发可设置 TURNSTILE_REQUIRED=false。

本地运行

cd clipboard
npm install
npm start

打开:

http://127.0.0.1:8080

扩容密钥

扩容密钥不写明文,只配置 SHA-256 哈希。服务端会先把用户输入转成大写,再计算 SHA-256。

生成哈希:

npm run hash-key -- ABC123

配置示例:

EXPANSION_KEY_HASHES="e0bebd22819993425814866b62701e2919ea26f1370499c1037b53b9d49c2c8a:Admin"

多个密钥:

EXPANSION_KEY_HASHES="hash1:Admin,hash2:Ops"

本地开发可以把配置写进 .env:

cp .env.example .env

然后编辑 .env。.env 已加入 .gitignore,不要提交;开源仓库只提交 .env.example。

常用命令

npm start
npm run dev
npm test
npm run hash-key -- ABC123

安全边界

  • 所有新写入的文本和文件必须带 E2EE 格式前缀;服务端会拒绝明文文本和未加密文件上传。
  • 加密构造:WebCrypto PBKDF2 使用 HMAC-SHA-256、250000 次迭代和 salt clipboard:e2ee:v1:<spaceKey>,从“空间密码;若未填写则为空间码”派生不可导出的 AES-GCM 256-bit key;每段文本、文件内容和文件名元数据分别使用 96-bit 随机 IV 加密,GCM 认证标签为 128-bit。
  • 空间密码不会发送给服务端,也不会写入 sessionStorage;没有空间密码时,知道空间码的人也拥有解密能力。
  • 后量子边界:这个流程没有 RSA/ECDH 这类公钥交换,因此不暴露“录下今天的公钥握手、未来用量子计算解开会话密钥”的风险;实际抗离线猜测能力仍主要取决于空间码或空间密码的熵,以及 PBKDF2 参数带来的猜测成本。
  • 服务端下载接口只返回密文字节;文本导出和全部导出都在浏览器本地解密后生成。
  • 前端渲染保存文本时使用纯文本写入,不把用户文本作为 HTML 插入。
  • 支持上传任意文件格式,包括 .exe、.js、.html 等;服务端不按扩展名阻止文件,而是把上传内容当作不可解释的密文字节保存。
  • 文件落盘统一使用服务端生成的 UUID .bin 文件名,下载统一以 attachment 和 application/octet-stream 返回,避免服务器或浏览器把上传内容当作可执行/可渲染内容处理。
  • 开启 Helmet 安全响应头和严格 CSP。
  • 空间密钥和扩容密钥都不以明文落盘;扩容密钥只在空间元数据里保存哈希,用于容量状态。
  • 前端密钥输入框使用密码框显示。

Web App 型 E2EE 仍依赖前端代码分发可信:如果服务端在用户打开页面前已被控制,攻击者可能下发恶意 JavaScript 窃取加密密钥。生产环境建议继续放在 Nginx 后,只绑定本机端口,并保持部署链路和主机权限隔离。

部署

推荐生产环境把 Node 服务绑定到 127.0.0.1,再用 Nginx、Caddy 或其它反向代理提供 HTTPS。

Node + systemd

git clone https://github.com/Catherina0/clipboard.git
cd clipboard
npm ci --omit=dev
cp .env.example .env
nano .env

示例 systemd 服务:

[Unit]
Description=Clipboard temporary sharing service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=clipboard
Group=clipboard
WorkingDirectory=/opt/clipboard
Environment=NODE_ENV=production
Environment=HOST=127.0.0.1
Environment=PORT=8080
Environment=CLIPBOARD_DATA_DIR=/opt/clipboard/data
ExecStart=/usr/bin/node /opt/clipboard/src/server.js
Restart=always
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/opt/clipboard/data

[Install]
WantedBy=multi-user.target

启动后验证:

curl http://127.0.0.1:8080/health

Nginx 反代

server {
    listen 443 ssl http2;
    server_name clipboard.example.com;

    client_max_body_size 4096m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

Docker

也可以用 Docker 运行:

docker build -t clipboard:latest .
docker run -d \
  --name clipboard \
  -p 127.0.0.1:8080:8080 \
  -v clipboard-data:/app/data \
  --env-file .env \
  --restart unless-stopped \
  clipboard:latest

日志

应用日志取决于部署方式:

journalctl -u clipboard -f
docker logs -f clipboard

About

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages