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>
169 lines
4.3 KiB
Python
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())
|