Files
尘曲 73a6614118 Add web interface and Docker deployment
Expose the paste tool through a lightweight web UI/API and provide the container setup required for the publicpaste service.
2026-05-13 01:00:40 +08:00

149 lines
5.3 KiB
Markdown

# publicpaste
`publicpaste` is a tiny Python package and CLI that posts text to multiple public paste providers concurrently and returns the first successful direct URL.
- Python 3 standard library first
- zero runtime dependencies
- CLI and Python API
- concurrent provider fan-out with first-success return
- optional verification of the returned URL
> Only paste text that is safe to publish. Returned links are public, and third-party services have their own retention and acceptable-use policies.
## Install
From this repository:
```sh
python -m pip install .
```
## CLI
```sh
publicpaste "hello from publicpaste"
echo "hello from stdin" | publicpaste
publicpaste --file a.txt
```
By default stdout contains only the URL, making the command easy to pipe:
```sh
url=$(publicpaste --file notes.txt)
```
JSON output includes the provider name:
```sh
publicpaste --json "hello"
# {"url":"https://...","provider":"paste.rs"}
```
Useful options:
- `--timeout SECONDS`: per-provider timeout, default `8.0`
- `--overall-timeout SECONDS`: total wait budget, default `12.0`
- `--json`: print `url` and `provider` as JSON
- `--verbose`: print provider diagnostics on failure
- `--verify`: GET the returned URL and confirm a 2xx response containing a text fragment
- `--list-providers`: list provider names
- `--provider NAME`: use only a provider; repeat to select several
- `--disable-provider NAME`: disable a provider; repeatable
Failures print a concise error to stderr and exit with status `1`.
## Web service
`publicpaste` also includes a zero-dependency web UI and JSON API:
```sh
python -m publicpaste.web
# or, after installation:
publicpaste-web
```
Open `http://127.0.0.1:12072`, enter text, and click “完成”. The page calls `POST /api/paste`, shows the returned URL/provider, and copies the URL to the clipboard.
Useful environment variables:
- `PUBLICPASTE_HOST`: bind host, default `0.0.0.0`
- `PUBLICPASTE_PORT`: bind port, default `12072`
- `PUBLICPASTE_DATA_DIR`: data/log directory, default `/data`
- `PUBLICPASTE_TIMEOUT`: per-provider timeout, default `8.0`
- `PUBLICPASTE_OVERALL_TIMEOUT`: total wait budget, default `12.0`
- `PUBLICPASTE_VERIFY`: verify returned URL when true, default false
Health check:
```sh
curl http://127.0.0.1:12072/health
```
## Docker
Build and run with Compose:
```sh
docker compose up -d --build
```
The included `compose.yml` uses image/container name `publicpaste`, maps `12072:12072`, and stores logs/data in `/vol1/1000/docker/publicpaste/data` mounted at `/data`.
## Python API
```python
from publicpaste import paste_text
result = paste_text("hello", timeout=8.0, overall_timeout=12.0)
print(result.url)
print(result.provider)
```
Signature:
```python
paste_text(
text,
timeout=8.0,
overall_timeout=12.0,
providers=None,
disabled_providers=None,
verify=False,
)
```
`providers` may be a sequence of provider names or provider instances. `disabled_providers` removes providers by name. The function returns a `PasteResult` dataclass with at least `url` and `provider`. If every provider fails, it raises `PasteError` with aggregated per-provider errors.
## Providers
Default enabled providers:
- `paste.rs``POST https://paste.rs/`, raw UTF-8 body; `GET /<id>` returns plain text.
- `dpaste.org``POST https://dpaste.org/api/`, form fields `content`, `lexer=plain`, `format=url`, `expires_on=2592000`.
- `0x0.st` — multipart field `file`, filename `paste.txt`, `text/plain`; this is a public file host, so use only non-sensitive text.
- `snippet.host` — form fields `content`, `visibility=2`, `expires=1month`, `language=plain text`; parses `Location` or HTML URL.
- `paste.centos.org``POST https://paste.centos.org/`, form fields `code`, `lang=text`, `expire=1440`; parses the final redirected view URL. Its documented `/api/create` endpoint currently requires an API key, so the browser-compatible form endpoint is used.
- `termbin.com` — TCP port `9999`; low priority but enabled by default.
Each provider has a response parsing method so parsing can be unit tested without network access.
## Validation and verification
Provider responses are accepted only when the URL uses `http` or `https` and matches the expected provider host and path shape. By default `publicpaste` does not fetch the returned URL after creation, keeping the fastest provider path quick.
When `verify=True` or `--verify` is used, `publicpaste` performs a GET against the returned direct URL and checks that the response is 2xx and contains a fragment of the original text. HTML escaping is tolerated.
## Why not PrivateBin, privydrop, clipboard-style services, or similar?
This project intentionally targets simple public paste endpoints with stable, scriptable APIs. It does not include PrivateBin, privydrop, clipboard-style services, or similar tools when they require browser JavaScript, P2P flows, access codes, encrypted URL fragments, unstable/undocumented APIs, or interaction patterns that do not reliably return a direct public URL from a simple request.
The initially reviewed services that are not enabled by default for those reasons include `clipboard.im`, `clipboard.run`, `clipboardify.com`, `clipboardonline.com`, `privydrop.app`, `privatebin.net`, `paste.drhack.net`, `pasteme.cn`, `paste.sdjz.wiki`, and `myonlineclipboard.com`.
## Tests
Tests are unit-only and do not access the public internet:
```sh
python -m pytest
```