用 Go 编写的自托管轻量在线剪切板
  • Go 69.7%
  • TypeScript 22.5%
  • Shell 3.9%
  • Makefile 2.1%
  • CSS 0.9%
  • Other 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
liyp 86acb52746
All checks were successful
Check / Frontend build (push) Successful in 10m53s
Check / Validate commit messages (push) Has been skipped
Check / Go quality and tests (push) Successful in 10m38s
Release / build (push) Successful in 10m34s
Release / create-release (push) Successful in 12s
fix: 升级 go.mod 至 1.26.9 修复 CI govulncheck 报告的标准库漏洞
2026-10-11 23:04:30 +08:00
.gitea/workflows fix: 升级 go.mod 至 1.26.9 修复 CI govulncheck 报告的标准库漏洞 2026-10-11 23:04:30 +08:00
.lint-baseline ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
db ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
frontend fix: 修复 markdown 表格断行渲染,并加固读取接口与限流 2026-08-01 18:28:24 +08:00
handler ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
id feat: 初始化 pastego 项目 2026-06-05 21:03:28 +08:00
mime feat: 添加 React 前端,移除服务端高亮,改进 CSRF 配置 2026-06-06 22:08:36 +08:00
model test: 补齐各模块测试,覆盖率 57.7% → 80.1% 2026-10-11 22:19:36 +08:00
packaging/arch fix: 修复 markdown 表格断行渲染,并加固读取接口与限流 2026-08-01 18:28:24 +08:00
scripts ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
static fix: 修复 markdown 表格断行渲染,并加固读取接口与限流 2026-08-01 18:28:24 +08:00
.gitignore fix: 修复 markdown 表格断行渲染,并加固读取接口与限流 2026-08-01 18:28:24 +08:00
config.go test: 补齐各模块测试,覆盖率 57.7% → 80.1% 2026-10-11 22:19:36 +08:00
config_test.go test: 补齐各模块测试,覆盖率 57.7% → 80.1% 2026-10-11 22:19:36 +08:00
go.mod fix: 升级 go.mod 至 1.26.9 修复 CI govulncheck 报告的标准库漏洞 2026-10-11 23:04:30 +08:00
go.sum ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
main.go refactor: 用 Go 1.22 ServeMux 路由模式重构请求分发,拆分 main.go 组装逻辑 2026-10-11 21:56:25 +08:00
Makefile ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
README.md ci: 参照 DEEIX-Chat 增加后端质量门禁与 push/PR 检查流水线 2026-10-11 22:33:45 +08:00
requirements.md feat: 添加 React 前端,移除服务端高亮,改进 CSRF 配置 2026-06-06 22:08:36 +08:00
server.go test: 补齐各模块测试,覆盖率 57.7% → 80.1% 2026-10-11 22:19:36 +08:00
server_test.go test: 补齐各模块测试,覆盖率 57.7% → 80.1% 2026-10-11 22:19:36 +08:00

PasteGo - 轻量级在线剪切板

一个用 Go 编写的轻量级在线剪切板服务,支持文本、代码、图片等任意文件的上传与分享,提供 React Web 界面。

特性

  • 多类型支持 - 文本、代码、图片、任意文件
  • 自动语法高亮 - highlight.js 驱动,根据内容自动检测语言
  • 私有模式 - 通过不可猜测的长链接访问敏感内容
  • 定时过期 - 支持 1小时/1天/7天/30天/永久
  • 零依赖部署 - 单二进制 + SQLite 文件
  • 安全防护 - 速率限制、CSRF 防护、XSS 防护、安全响应头
  • React 前端 - 基于 hastebin 风格的现代化 UI,支持二维码
  • 代码高亮修复 - 针对 Prism markdown 表格 token 的 display: table 拆分问题,通过 CSS 强制行内排列使表格一行显示

快速开始

安装

# 从源码编译
git clone https://git.liyp.cc/xmengnet/pastego.git
cd pastego
go build -ldflags="-s -w" -o pastego .

# 构建前端
cd frontend && npm install && npm run build

# 或直接下载预编译二进制
# https://git.liyp.cc/xmengnet/pastego/releases

启动服务

# 默认端口 4832
./pastego

# 自定义端口
./pastego -addr :8080

# 自定义数据库路径
./pastego -dsn /data/pastego.db

# 环境变量配置
export CLIP_ADDR=:8080
export CLIP_DSN=/data/pastego.db
./pastego

服务启动后访问 http://localhost:4832 即可使用 Web 界面。

使用指南

Web 界面

  1. 访问 http://localhost:4832 进入编辑器
  2. 在编辑器中输入内容(支持 Tab 缩进)
  3. 底部任务栏可设置:
    • 语法类型(留空自动检测)
    • 过期时间(无过期 ~ 1个月)
    • 私有模式(不生成短链接)
  4. 点击 paste! 获取分享链接
  5. 查看页(/?id=xxx)自动高亮代码,显示二维码

API 文档

创建剪切板

POST /
Content-Type: multipart/form-data

Form 字段:
  c        (必填)  内容
  syntax   (可选)  语法类型:sql/json/yaml/py/go/sh 等
  sunset   (可选)  过期秒数:3600/86400/604800
  p        (可选)  私有模式:p=1
  filename (可选)  文件名(自动推断 mimetype)

示例:

# 管道上传
echo "Hello World" | curl -F "c=@-" http://localhost:4832/

# 指定语法 + 过期时间
echo '{"key":"value"}' | curl -F "c=@-" -F "syntax=json" -F "sunset=86400" http://localhost:4832/

# 上传图片
curl -F "c=@screenshot.png" http://localhost:4832/

# 私有剪切板
cat secret.txt | curl -F "c=@-" -F "p=1" http://localhost:4832/

响应(200):

{
  "url": "http://localhost:4832/abc123",
  "short": "abc123",
  "long": "AJJ1vikJUiGkSLlni-aYVR8UrHd5",
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "mimetype": "text/plain",
  "size": 128,
  "status": "created"
}

查看剪切板

GET /:id

Accept 头决定返回格式:
  text/plain       → 原始内容
  application/json → JSON 元数据
  */*              → 根据存储的 mimetype 返回

示例:

# 获取原始内容
curl http://localhost:4832/abc123

# 获取 JSON 元数据
curl -H "Accept: application/json" http://localhost:4832/abc123

更新剪切板

PUT /:id                           ← id 必须是 UUID
Content-Type: multipart/form-data

Form 字段:
  c        (必填) 新内容
  syntax   (可选) 新语法类型
  sunset   (可选) 新过期时间
  filename (可选) 新文件名

响应:

{
  "url": "http://localhost:4832/abc123",
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "updated"
}

删除剪切板

DELETE /:id                        ← id 必须是 UUID

响应:

{
  "url": "http://localhost:4832/abc123",
  "status": "deleted"
}

统计信息

GET /s

响应:

{
  "pastes": 1234
}

数据模型

SQLite 表结构

CREATE TABLE pastes (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    uuid       TEXT    NOT NULL UNIQUE,
    short      TEXT    DEFAULT '',
    long_id    TEXT    NOT NULL UNIQUE,
    content    BLOB    NOT NULL,
    mimetype   TEXT    DEFAULT 'text/plain',
    syntax     TEXT    DEFAULT '',
    filename   TEXT    DEFAULT '',
    size       INTEGER DEFAULT 0,
    private    INTEGER DEFAULT 0,
    sunset     INTEGER,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    deleted    INTEGER DEFAULT 0
);

ID 体系

ID 类型 格式 用途 说明
short 6-8 位 base62 公开分享链接 私有模式时为空
long_id 24 位 base62 私有访问链接 不可猜测
uuid UUID v4 更新/删除认证 仅修改操作使用

配置

环境变量

变量 说明 默认值
CLIP_ADDR 监听地址 :4832
CLIP_DSN SQLite 数据库路径 pastego.db
CLIP_MAX_SIZE 单文件/文本最大字节数 10485760 (10MB)
CLIP_ORIGINS CSRF 可信域名(逗号分隔),不设置则禁用 CSRF 防护 空
CLIP_TRUSTED_PROXY 是否信任反向代理透传的 IP 头(设为 1/true 启用) false
CLIP_BASE_URL 生成分享链接用的对外地址,如 https://clip.example.com;不设置则按 http://localhost:端口 拼接 空
CLIP_RATE_LIMIT 每秒允许的请求数 10
CLIP_RATE_LIMIT_BURST 限流突发容量 20

命令行参数

./pastego [选项]

选项:
  -addr string      监听地址(默认 ":4832")
  -dsn string       SQLite 数据库路径(默认 "pastego.db")
  -max-size int     单文件最大字节数(默认 10485760)
  -origins string   CSRF 可信域名,逗号分隔
  -trusted-proxy    信任反向代理透传的 IP 头(默认 false)
  -log-format string 日志格式:text 或 json
  -base-url string  生成分享链接用的对外地址
  -rate-limit float 每秒允许的请求数(默认 10)
  -rate-limit-burst int 限流突发容量(默认 20)

项目结构

pastego/
├── main.go              # HTTP 服务器入口
├── server.go            # 路由注册、中间件链组装、后台清理循环
├── config.go            # 配置管理
├── go.mod / go.sum      # Go 依赖
├── db/
│   ├── db.go            # SQLite 初始化(连接池配置)
│   └── paste.go         # CRUD 操作
├── handler/
│   ├── paste.go         # HTTP 处理器
│   ├── stat.go          # 统计接口
│   ├── log.go           # 访问日志中间件
│   ├── security.go      # 安全响应头中间件
│   ├── ratelimit.go     # 速率限制中间件
│   ├── csrf.go          # CSRF 防护中间件
│   ├── static.go        # 嵌入式静态文件服务
│   └── about.go         # 关于页面
├── model/
│   └── paste.go         # 数据模型
├── id/
│   └── id.go            # ID 生成器
├── mime/
│   └── mime.go          # Mimetype 映射
├── frontend/            # React 前端(Vite + TypeScript + Tailwind)
│   ├── src/
│   │   ├── App.tsx      # 创建页
│   │   ├── View.tsx     # 查看页(语法高亮 + 二维码)
│   │   ├── api/         # API 客户端
│   │   ├── components/  # UI 组件
│   │   └── lib/         # 工具库
│   ├── package.json
│   └── vite.config.ts
└── static/              # 构建产物(前端 + about.md)
    ├── index.html       # SPA 入口
    ├── assets/          # JS/CSS 资源
    └── about.md         # 关于页面内容

开发

依赖

包 用途
github.com/mattn/go-sqlite3 SQLite 驱动
github.com/google/uuid UUID v4 生成
github.com/yuin/goldmark Markdown 渲染(about 页面)

构建

# 构建后端
go build -o pastego .

# 构建前端
cd frontend && npm install && npm run build

# 交叉编译后端
GOOS=linux GOARCH=amd64 go build -o pastego-linux .
GOOS=darwin GOARCH=arm64 go build -o pastego-mac .
GOOS=windows GOARCH=amd64 go build -o pastego.exe .

运行

./pastego
# 访问 http://localhost:4832

CI/CD 与质量门禁

CI 基于 Gitea Actions(.gitea/workflows/):

  • check.yml - push / PR 时自动执行:
    • Go 质量门禁(scripts/check-go-quality.sh):gofmt、禁止生产代码使用 interface{}、go vet、staticcheck(带 .lint-baseline/ 基线棘轮,只拦截新增告警)、deadcode 零容忍
    • go test -race 带覆盖率
    • govulncheck 依赖漏洞扫描
    • go build 构建验证
    • 前端 npm ci && npm run build
    • PR 提交信息校验(type: subject 规范,见 scripts/check-commit-messages.sh)
  • release.yml - 打 v* tag 时构建多平台二进制、Arch Linux 包并创建 Release

本地开发可运行与 CI 相同的门禁:

make lint      # gofmt / interface{} / go vet / staticcheck / deadcode
make check-vuln  # govulncheck 漏洞扫描
make quality   # lint + 竞态测试 + 漏洞扫描

staticcheck / deadcode / govulncheck 通过 go.mod 的 tool 指令声明, go tool <name> 自动下载对应版本,无需手动安装。

过期清理机制

  • 启动时开启后台 goroutine,每 60 秒执行一次
  • sunset <= now() 且 deleted = 0 → 标记为 deleted = 1
  • 物理删除:sunset 距今超过 7 天的已过期记录直接 DELETE

安全说明

安全防护措施

1. 速率限制

  • 基于 IP 的令牌桶算法限流
  • 默认每秒 10 个请求,突发最多 20 个
  • 默认不信任 X-Forwarded-For / X-Real-Ip 头(防止公网直连时被伪造绕过); 只有部署在反向代理后面时,才应设置 CLIP_TRUSTED_PROXY=1 或 -trusted-proxy 启用

2. CSRF 防护

  • 验证 Origin 和 Referer 头
  • 只对修改操作(POST/PUT/DELETE)生效
  • 不设置 CLIP_ORIGINS 时禁用,设置后只允许指定域名

3. XSS 防护

  • 危险 MIME 类型(HTML/SVG/JS)以纯文本显示源码

4. 安全响应头

  • Content-Security-Policy: 限制资源加载来源
  • X-Content-Type-Options: nosniff: 防止 MIME 嗅探
  • X-Frame-Options: DENY: 防止点击劫持

上传大小限制

  • 无论是文件上传还是普通文本字段,内容大小都不超过 CLIP_MAX_SIZE; 超出的文件上传返回 413(不会静默截断),超出的文本字段同样返回 413
  • 整个请求体也受 maxSize + 1MB 的硬上限约束,防止超大型 multipart 请求导致内存/磁盘耗尽

内容所有权与删除

  • 出于安全考虑,uuid(更新/删除该 paste 的唯一写凭证)只在创建响应中返回一次, 后续任何读取接口(包括 JSON 接口)不再返回 uuid/short/long
  • 这意味着:只有创建者在创建时保存的凭证才能删除/修改自己的 paste; 收到分享链接的其他查看者将看不到删除按钮,也无法通过读取接口拿到写凭证

生产环境部署建议

# 1. 配置可信域名(启用 CSRF 防护)
export CLIP_ORIGINS="pastego.yourdomain.com"

# 2. 若部署在 Nginx/Caddy 等反向代理后面,启用可信代理头(保证限流按真实客户端 IP)
export CLIP_TRUSTED_PROXY=1

# 3. 使用反向代理(Nginx/Caddy)并启用 HTTPS
# 4. 配置防火墙,只开放必要端口
# 5. 定期备份 SQLite 数据库文件

致谢

本项目的前端(React + TypeScript + Tailwind)参考/改编自 ian-hon/hastebin-frontend。

同时感谢以下开源项目:

License

MIT License