fix(server): harden deployment, media, state, jobs
- Lock down /media/: deny state.json, DBs, sessions; allowlist extensions incl. archives/docs (M-1) - parse_bool() fixes; HEAD 404; shutdown drains queue; range edge cases (M-3, M-4, M-7, M-8) - int() coercion -> 400; no filesystem paths in errors; path-only access log (M-19, L-1) - Security headers, QR TTL 60s, trusted-host allowlist, legacy add/remove via update() (L-4, L-5, L-6, L-8) - Clean continuous channels on import and migration; restart-during-drain; tombstone managers (F-1, F-3, F-4) - Durability: fsync + unique tmp + stale sweep + 0600/0700 perms (M-10, M-18) - Jobs run on dedicated loop thread; set_scrape_media passthrough; media chunked; state throttled; exact media file reuse; honest scrape failure status (M-11, M-12, M-13, M-14) - Health aggregates per-account; legacy GETs delegate post-migration (M-15, M-9) - k8s: runAsNonRoot 1000 + resource limits, no readOnlyRootFilesystem (M-16) - UI: dropped-invalid and credentials-reentry toasts; swagger XSS-safe (F-2, L-9, L-2) - CI: non-blocking pip-audit job in both workflows (L-3) - 50 tests passing; REVIEW.md updated (C-1/M-20 won't fix: local-only by design)
This commit is contained in:
+8
-1
@@ -204,10 +204,16 @@ function renderAccountPanel(accountId) {
|
||||
if (!runAllTracked && channels.length === 0 && enabled) {
|
||||
if (!confirmAction('Continuous scraping enabled with no selected channels. Save anyway?')) return;
|
||||
}
|
||||
await api(`/api/accounts/${accountId}/continuous`, {
|
||||
const resp = await api(`/api/accounts/${accountId}/continuous`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ enabled, interval_minutes: intervalMinutes, run_all_tracked: runAllTracked, channels }),
|
||||
});
|
||||
if (resp.dropped_invalid && resp.dropped_invalid.length) {
|
||||
const n = resp.dropped_invalid.length;
|
||||
const shown = resp.dropped_invalid.slice(0, 3).join(', ');
|
||||
const extra = n > 3 ? '…' : '';
|
||||
showToast(`${n} invalid channel(s) skipped: ${shown}${extra}`, 'warn');
|
||||
}
|
||||
await refreshAccount(accountId);
|
||||
});
|
||||
|
||||
@@ -956,6 +962,7 @@ async function main() {
|
||||
await loadAccounts();
|
||||
switchAccount(accountId);
|
||||
showToast(`Imported ${accountId}.`, 'success');
|
||||
showToast('Credentials (api_id/api_hash) are not exported for security — re-enter them in Settings if needed.', 'warn');
|
||||
} catch (err) {
|
||||
showToast(`Failed to import account: ${err.message}`, 'error');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user