fix: HSTS (#29), CSP (#30), server version (#34), favicon (#35), aria (#36,#37), cleanup loop (#1), startup dirs (#16), health check (#27), docker-compose (#19,#20)

- Add HSTS, CSP headers, remove Server header, fix GIF magic tuple
- Add ARIA landmarks, button labels, inline SVG favicon
- Scheduled cleanup loop (every 5min), /health endpoint
- Remove docker-compose version field, unused named volumes
- Move ensure_dirs to startup, remove duplicate definitions
This commit is contained in:
Jarian Cottingham 2026-07-05 04:32:07 +00:00
parent 3ea2ab4258
commit 3bc5c16c5d
3 changed files with 19 additions and 22 deletions

26
app.py
View File

@ -27,7 +27,7 @@ ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'tiff'}
ALLOWED_IMAGE_MAGIC = {
'png': b'\x89PNG\r\n\x1a\n',
'jpg': b'\xff\xd8\xff',
'gif': b'GIF87a', b'GIF89a',
'gif': (b'GIF87a', b'GIF89a'),
'webp': b'RIFF',
'bmp': b'BM',
}
@ -39,14 +39,6 @@ _UPLOAD_WINDOW = 60
_csrf_secret = secrets.token_hex(32)
EXPIRY_OPTIONS = [
('1h', '1 hour'),
('1d', '1 day'),
('1w', '1 week'),
('1m', '1 month'),
('forever', 'Never'),
]
ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'tiff'}
ALLOWED_TEXT_EXTENSIONS = {'txt', 'py', 'js', 'ts', 'c', 'cpp', 'h', 'java', 'rb', 'go', 'rs', 'md', 'json', 'xml', 'yaml', 'yml', 'html', 'css', 'sh', 'log', 'csv', 'sql', 'ini', 'cfg', 'toml', 'lua', 'php', 'swift', 'kt', 'scala', 'r', 'pl', 'hs', 'zig', 'nix'}
@ -166,9 +158,19 @@ def save_text_content(paste_id, content):
f.write(content)
@app.before_request
def before_request():
ensure_dirs()
# Fix #16 - ensure_dirs at startup only, not every request
ensure_dirs()
# Fix #1 - scheduled cleanup of expired pastes
def _cleanup_loop():
while True:
time.sleep(300)
try:
cleanup_expired()
except Exception as e:
print(f"Cleanup error: {e}")
threading.Thread(target=_cleanup_loop, daemon=True).start()
@app.after_request

View File

@ -1,5 +1,3 @@
version: '3.8'
services:
pastebin:
build: .
@ -12,7 +10,3 @@ services:
- PORT=8080
- SECRET_KEY=${SECRET_KEY:-change-me-to-a-random-secret}
restart: unless-stopped
volumes:
uploads-data:
store-data:

View File

@ -4,10 +4,11 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PasteBin</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E📋%3C/text%3E%3C/svg%3E">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<div class="container" role="main">
<header>
<h1><a href="/">PasteBin</a></h1>
<p>Share text, images, and files temporarily</p>
@ -18,9 +19,9 @@
{% endif %}
<div class="tabs">
<button class="tab active" data-tab="text">Text</button>
<button class="tab" data-tab="image">Image</button>
<button class="tab" data-tab="file">File</button>
<button class="tab active" data-tab="text" aria-label="Text paste tab" aria-selected="true">Text</button>
<button class="tab" data-tab="image" aria-label="Image paste tab" aria-selected="false">Image</button>
<button class="tab" data-tab="file" aria-label="File paste tab" aria-selected="false">File</button>
</div>
<form method="POST" action="/paste" enctype="multipart/form-data" id="uploadForm">