fix(security): demo sends nothing, hidden SMTP password, body limits (FLAW-33..38)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s

- Demo: senders for mail, Discord and webhooks refuse, no alarm ticker;
  test alarm, SMTP test, server settings, backups, account and session
  changes of the shared demo accounts answer 403; the session list only
  shows the own device. The UI shows the notices and disables the controls.
- SMTP password is never sent back (smtpPassSet), empty keeps it.
- ?token= on webhook ingest accepts only API keys.
- Request bodies capped at 2 MB (sync 8 MB, imports 101 MB).
- Deleting an account removes its server backups.
- Backup downloads, exports and import uploads get 30 minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 19:43:23 +01:00
1 parent 3709282a4f
commit 9d9698186c
21 files changed
+631 -304

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
package api
import (
"net/http"
"strings"
"testing"
)
func TestRequestBodyLimited(t *testing.T) {
srv, _, token := setupTestServer(t)
router := srv.Router()
huge := `{"content":"` + strings.Repeat("x", defaultMaxBody) + `"}`
if rec := sessionCall(router, "POST", "/api/v1/inbox", token, huge, ""); rec.Code != http.StatusBadRequest && rec.Code != http.StatusRequestEntityTooLarge {
t.Fatalf("body over the limit: want 400/413, got %d", rec.Code)
}
if rec := sessionCall(router, "POST", "/api/v1/inbox", token, `{"content":"klein"}`, ""); rec.Code >= 300 {
t.Fatalf("normal body: got %d %s", rec.Code, rec.Body.String())
}
if bodyLimitFor("/api/v1/docs/doc_1/sync") != syncMaxBody || bodyLimitFor("/api/v1/import/obsidian") <= defaultMaxBody {
t.Fatal("sync and import keep their larger limits")
}
}
func TestWebhookTokenInURLOnlyAPIKey(t *testing.T) {
srv, _, token := setupTestServer(t)
rec := sessionCall(srv.Router(), "POST", "/api/v1/webhooks/ingest?token="+token, "", `{"text":"x"}`, "")
if rec.Code != http.StatusUnauthorized {
t.Fatalf("session token in URL: want 401, got %d", rec.Code)
}
}