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:
parent
3ea2ab4258
commit
3bc5c16c5d
26
app.py
26
app.py
@ -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
|
||||
|
||||
@ -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:
|
||||
@ -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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user