Add message retention and hide emails by default
- db: cleanup_old_messages(days) purges messages older than N days in batches; recipients/reads/deliveries/reactions follow via ON DELETE CASCADE. Returns attachment file_ids no longer referenced by any surviving message (forwarded copies keep their files) and removes their image_uploads rows - server: MESSAGE_RETENTION_DAYS env var (default 0 = keep forever); hourly cleanup deletes expired messages and securely removes orphaned attachment blobs from the upload dir - schema: email_visible now defaults to 0 — previously any logged-in user who knew a UUID could read another user's email via get_profile - migrations: SQL script to apply the new default and reset the flag on existing databases (run manually, see file header) - docker-compose: document MESSAGE_RETENTION_DAYS Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
16
server.py
16
server.py
@@ -203,6 +203,10 @@ CONNECTION_RL_MAX = 20 # max requests per window per connection
|
||||
MAX_CONNECTIONS_PER_IP = 10
|
||||
MAX_CONNECTIONS_GLOBAL = 200
|
||||
METADATA_RETENTION_DAYS = int(os.getenv("METADATA_RETENTION_DAYS", "90"))
|
||||
# Message retention: 0 (default) keeps messages forever; N > 0 purges
|
||||
# messages (and their per-recipient ciphertexts, deliveries, reads,
|
||||
# reactions and orphaned attachment blobs) older than N days.
|
||||
MESSAGE_RETENTION_DAYS = int(os.getenv("MESSAGE_RETENTION_DAYS", "0"))
|
||||
# TCP keepalive settings (seconds)
|
||||
TCP_KEEPALIVE_IDLE = 25 # Start keepalive probes after 25s of idle
|
||||
TCP_KEEPALIVE_INTERVAL = 10 # Send probes every 10s
|
||||
@@ -3177,6 +3181,18 @@ async def main():
|
||||
reads_del, reactions_del)
|
||||
except Exception as e:
|
||||
logger.warning("Metadata cleanup error: %s", e)
|
||||
if MESSAGE_RETENTION_DAYS > 0:
|
||||
try:
|
||||
msgs_del, orphan_files = await adb.cleanup_old_messages(MESSAGE_RETENTION_DAYS)
|
||||
for fid in orphan_files:
|
||||
p = _safe_upload_path(fid, ".enc")
|
||||
if p:
|
||||
await asyncio.to_thread(_secure_delete, p)
|
||||
if msgs_del or orphan_files:
|
||||
logger.info("Message retention: %d messages, %d attachment files purged",
|
||||
msgs_del, len(orphan_files))
|
||||
except Exception as e:
|
||||
logger.warning("Message retention cleanup error: %s", e)
|
||||
|
||||
asyncio.create_task(_periodic_cleanup())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user