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>
This commit is contained in:
168
cli.py
Normal file
168
cli.py
Normal file
@@ -0,0 +1,168 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user