
Secure secret sharing via one-time or short-lived links.
Share passwords, credentials, keys, or other sensitive data without using insecure channels like email or chat. Secrets are encrypted client-side before transmission -- the server never sees plaintext.
Whisper uses a layered security approach:
See Security Details for the full ***graphic design.
bash# Generate a config file with a random secret key export SECRET_KEY=$(head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 48) sed "s/CHANGE_ME_TO_A_RANDOM_STRING_OF_32_OR_MORE_CHARACTERS/$SECRET_KEY/" src/config.default.yaml > config.yaml # Build from source (optional, can also pull viyh/whisper:0.2.0): # docker build -t viyh/whisper . # Run docker run -d --name whisper -p 8000:8000 \ -v $(pwd)/config.yaml:/usr/src/app/config.yaml \ viyh/whisper:0.2.0
Browse to http://localhost:8000
Copy src/config.default.yaml to config.yaml and customize. Mount it into the container at /usr/src/app/config.yaml.
| Setting | Description |
|---|---|
secret_key | Server-level secret for password hashing. Must be a unique random string of 32+ characters. Change this from the default. |
storage_class | Storage backend class path (see Storage Backends). |
| Setting | Default | Description |
|---|---|---|
storage_config | {} | Backend-specific settings (bucket name, path, etc.) |
storage_clean_interval | 900 | Seconds between expired secret cleanup runs. |
max_data_size_kb | 100 | Maximum upload size in KB. |
app_listen_ip | 0.0.0.0 | Internal listen address. |
app_port | 5000 | Internal Flask port (nginx proxies externally). |
app_url_base | / | URL base path (e.g., /whisper/ for subpath hosting). |
argon2_time_cost | 5 | Argon2id time cost parameter. Higher = slower + more secure. |
argon2_memory_cost | 131072 | Argon2id memory cost in KB (*** = 128 MB). |
argon2_parallelism | 1 | Argon2id parallelism parameter. |
| Variable | Default | Description |
|---|---|---|
WEB_PORT | 8000 | External nginx listen port. |
LOG_LEVEL | INFO | Set to DEBUG for verbose logging. |
CONFIG_FILE | config.yaml | Config file path inside the container. |
Stores secrets as JSON files. Mount a volume for persistence.
yamlstorage_class: whisper.storage.local.local storage_config: path: /tmp/whisper
bashdocker run -d --name whisper -p 8000:8000 \ -v $(pwd)/config.yaml:/usr/src/app/config.yaml \ -v whisper-data:/tmp/whisper \ whisper
Simplest and most secure -- secrets are lost on restart.
yamlstorage_class: whisper.storage.memory.memory storage_config: {}
Uses S3 object tags (create_date, expire_date) so the cleanup process only reads tags, not full objects.
yamlstorage_class: whisper.storage.aws.s3 storage_config: bucket_name: my-whisper-bucket bucket_path: secrets
Credentials: IAM role (recommended), credential file mount (-v ~/.aws:/.aws:ro), or environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION).
Minimum IAM permissions:
json{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation", "s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:GetObjectTagging", "s3:PutObjectTagging", "s3:DeleteObjectTagging" ], "Resource": [ "arn:aws:s3:::my-whisper-bucket", "arn:aws:s3:::my-whisper-bucket/*" ] }] }
Uses object metadata (create_date, expire_date) for efficient cleanup.
yamlstorage_class: whisper.storage.gcp.gcs storage_config: gcp_project: my-project bucket_name: my-whisper-bucket bucket_path: secrets
Credentials: Application default credentials (recommended), or mount gcloud config (-v ~/.config/gcloud:/.config/gcloud:ro).
Required GCS permissions:
storage.objects.get, storage.objects.update, storage.objects.list, storage.objects.create, storage.objects.delete, storage.multipartUploads.create, storage.multipartUploads.abort, storage.multipartUploads.listParts, storage.multipartUploads.list, storage.buckets.get
Or use built-in roles: roles/storage.legacyObjectOwner + roles/storage.legacyBucketWriter.
json{ "id": "8d692508856cabba82d73e15ef6f0364de70546c", "create_date": 1657421435, "expire_date": -1, "data": "U2FsdGVkX1/qMytBOYisCGZ3KjpkowinHQhu12lGY8E=", "hash": "$argon2id$v=19$m=131072,t=5,p=1$...", "version": 2 }
| Field | Description |
|---|---|
id | 160-bit random hex identifier (40 chars). |
create_date | UNIX timestamp of creation. |
expire_date | UNIX timestamp of expiration, or -1 for one-time use. |
data | Client-encrypted ciphertext (AES-256-GCM for v2, AES-CBC for v1). |
hash | Server-side password hash (Argon2id for v2, bcrypt for v1). |
version | *** version: 1 = legacy, 2 = current. |
Creating a secret:
secret_key as additional input.Retrieving a secret:
The server never has access to the plaintext password or data.
If you have a pre-0.2.0 secret link that was created with the v1 format (PBKDF2 + bcrypt + ***JS AES-CBC), check out the release/0.1.0_to_0.2.0 branch, which retains v1 decryption support.
The default in-memory rate limiter (storage_uri="memory://") tracks state per-gunicorn-worker. In multi-worker or multi-container deployments, each worker enforces limits independently. For shared rate-limit state across workers, configure a Redis backend via flask-limiter.
Storage backends must subclass store and implement:
| Method | Description |
|---|---|
start() | Initialize the backend. |
get_secret(secret_id) | Return secret object or False. |
set_secret(s) | Save a secret object. |
delete_secret(secret_id) | Delete a secret. |
claim_secret(secret_id) | Atomically delete and return True if it existed (for one-time secrets). |
delete_expired() | Iterate stored secrets and delete any where is_expired() returns True. |
See src/whisper/storage/memory.py for a minimal example.
bashdocker build -t whisper:dev . docker run -it --rm --name whisper -p 8000:8000 \ -e LOG_LEVEL=DEBUG \ -v $(pwd)/src/config.yaml:/usr/src/app/config.yaml \ whisper:dev
bash# Standard build docker build -t whisper:0.2.0 . # Cross-platform build docker buildx build --platform=linux/amd64,linux/arm64 \ -t whisper:0.2.0 .
Backend: Python 3.12, Flask 3.1, Gunicorn 23, Nginx (Debian Slim)
**Client-side *****: Web *** API (AES-256-GCM, PBKDF2), argon2-browser (WASM)
Frontend: Bootstrap 5.3, clipboard.js, vanilla JS (no jQuery)
Storage: Local disk, in-memory, AWS S3, GCP Cloud Storage
Pull requests are welcome. See CONTRIBUTING.md for setup and guidelines. For security issues, see SECURITY.md.
Joe Richards (GitHub: https://github.com/viyh)
MIT License
探索更多轩辕镜像的使用方法,找到最适合您系统的配置方式
通过 Docker 登录认证访问私有仓库
无需登录使用专属域名
Kubernetes 集群配置 Containerd
K3s 轻量级 Kubernetes 镜像加速
VS Code Dev Containers 配置
Podman 容器引擎配置
HPC 科学计算容器配置
ghcr、Quay、nvcr 等镜像仓库
Harbor Proxy Repository 对接专属域名
Portainer Registries 加速拉取
Nexus3 Docker Proxy 内网缓存
需要其他帮助?请查看我们的 常见问题Docker 镜像访问常见问题解答 或 提交工单
manifest unknown
no matching manifest(架构)
invalid tar header(解压)
TLS 证书失败
DNS 超时
410 Gone 排查
402 与流量用尽
401 认证失败
429 限流
D-Bus 凭证提示
413 与超大单层
来自真实用户的反馈,见证轩辕镜像的优质服务