Files
secpaste/cli.py
nanoclaw ff41256f2f Initial commit: SecPaste encrypted pastebin client
SecPaste is a Python library and CLI tool for sharing encrypted content via
public pastebin services with zero-knowledge architecture.

Features:
- Pluggable crypto backends (AES-256-GCM, ChaCha20-Poly1305, Kyber-768)
- Pluggable pastebin providers (dpaste.com, extensible)
- URL fragment key storage (key never sent to server)
- Both CLI and library usage
- Post-quantum cryptography support (experimental)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-07 22:52:32 +00:00

169 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""Command-line interface for SecPaste."""
import sys
import argparse
from pathlib import Path
from .client import SecPasteClient
def paste_command(args):
"""Handle paste command."""
# Read content
if args.file:
content = Path(args.file).read_text()
elif args.content:
content = args.content
else:
# Read from stdin
content = sys.stdin.read()
# Initialize client
client = SecPasteClient(cipher=args.cipher, provider=args.provider)
# Build provider options
kwargs = {}
if args.expiry:
kwargs['expiry'] = args.expiry
if args.syntax:
kwargs['syntax'] = args.syntax
try:
# Paste
url = client.paste(content, **kwargs)
print(url)
return 0
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
def fetch_command(args):
"""Handle fetch command."""
# Initialize client
client = SecPasteClient(provider=args.provider)
try:
# Fetch and decrypt
content = client.fetch(args.url)
# Output
if args.output:
Path(args.output).write_text(content)
print(f"Saved to: {args.output}", file=sys.stderr)
else:
print(content)
return 0
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
def list_command(args):
"""Handle list command."""
print("Available ciphers:")
for cipher in SecPasteClient.list_ciphers():
print(f" - {cipher}")
print("\nAvailable providers:")
for provider in SecPasteClient.list_providers():
print(f" - {provider}")
return 0
def main():
"""Main CLI entry point."""
parser = argparse.ArgumentParser(
description='SecPaste: Encrypted pastebin client with pluggable crypto',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Paste from stdin with AES-256-GCM (default)
echo "secret data" | secpaste paste
# Paste file with ChaCha20
secpaste paste -f secret.txt -c chacha20-poly1305
# Paste with custom expiry
secpaste paste -f data.json --expiry week --syntax json
# Fetch and decrypt
secpaste fetch https://dpaste.com/ABC123#aes-256-gcm:key...
# List available options
secpaste list
"""
)
subparsers = parser.add_subparsers(dest='command', help='Command to execute')
# Paste command
paste_parser = subparsers.add_parser('paste', help='Encrypt and paste content')
paste_parser.add_argument(
'-f', '--file',
help='File to paste (default: read from stdin)'
)
paste_parser.add_argument(
'-t', '--content',
help='Text content to paste'
)
paste_parser.add_argument(
'-c', '--cipher',
default='aes-256-gcm',
help='Cipher backend to use (default: aes-256-gcm)'
)
paste_parser.add_argument(
'-p', '--provider',
default='dpaste',
help='Pastebin provider (default: dpaste)'
)
paste_parser.add_argument(
'--expiry',
choices=['onetime', 'hour', 'day', 'week', 'month', 'never'],
default='week',
help='Paste expiration (default: week)'
)
paste_parser.add_argument(
'--syntax',
help='Syntax highlighting language (e.g., python, json, text)'
)
paste_parser.set_defaults(func=paste_command)
# Fetch command
fetch_parser = subparsers.add_parser('fetch', help='Fetch and decrypt paste')
fetch_parser.add_argument(
'url',
help='Full URL with encryption key in fragment (#key)'
)
fetch_parser.add_argument(
'-o', '--output',
help='Output file (default: print to stdout)'
)
fetch_parser.add_argument(
'-p', '--provider',
default='dpaste',
help='Pastebin provider (default: dpaste)'
)
fetch_parser.set_defaults(func=fetch_command)
# List command
list_parser = subparsers.add_parser('list', help='List available ciphers and providers')
list_parser.set_defaults(func=list_command)
# Parse arguments
args = parser.parse_args()
if not args.command:
parser.print_help()
return 1
# Execute command
return args.func(args)
if __name__ == '__main__':
sys.exit(main())