From 71dac3cbb2095bb7b7c0033fe6b017213466dac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bot=20of=20Thomas=20G=C3=BCttler?= Date: Fri, 5 Jun 2026 16:22:59 +0200 Subject: [PATCH] fix: remove hashed_ip from bugreport service, store email in mail.eml (#442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - **Remove hashed_ip entirely**: dropped `HashedIP` field, `hashIP` function, and all IP extraction logic from the server. No IP address is collected or stored in any form. - **Move contact email out of report.json**: if the user opts to include their email for follow-up, it is now written to `mail.eml` in the report directory instead of being embedded in `report.json`. This keeps PII separate from the structured report data. - Remove now-unused imports (`crypto/sha256`, `encoding/hex`, `strings`). - Flutter client (`bug_report_screen.dart`) was already not sending a `hashed_ip` field — no client changes needed. ## Test plan - [x] `go build ./...` in `server/bugreport/` passes with no errors - [x] `go vet ./...` passes with no warnings - Reports without a contact email produce only `report.json` (no `mail.eml`) - Reports with a contact email produce `report.json` (no `email` key) and `mail.eml` containing the address Closes #441 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Thomas SharedInbox Reviewed-on: https://codeberg.org/guettli/sharedinbox/pulls/442 --- server/bugreport/main.go | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/server/bugreport/main.go b/server/bugreport/main.go index 8850e91..90a6846 100644 --- a/server/bugreport/main.go +++ b/server/bugreport/main.go @@ -2,8 +2,6 @@ package main import ( "crypto/rand" - "crypto/sha256" - "encoding/hex" "encoding/json" "fmt" "io" @@ -13,7 +11,6 @@ import ( "os" "path/filepath" "strconv" - "strings" "sync" "time" ) @@ -21,12 +18,10 @@ import ( // BugReport represents the data stored in report.json type BugReport struct { Description string `json:"description"` - Email string `json:"email"` AboutInfo string `json:"about_info"` EmailData string `json:"email_data,omitempty"` SyncLog string `json:"sync_log,omitempty"` Timestamp time.Time `json:"timestamp"` - HashedIP string `json:"hashed_ip"` } var ( @@ -75,12 +70,6 @@ func generateUUID() (string, error) { return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]), nil } -func hashIP(ip string) string { - h := sha256.New() - h.Write([]byte(ip)) - return hex.EncodeToString(h.Sum(nil)) -} - func bugReportHandler(storageDir string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Enable CORS so the web app (if applicable) can upload @@ -143,20 +132,6 @@ func bugReportHandler(storageDir string) http.HandlerFunc { emailData := r.FormValue("email_data") syncLog := r.FormValue("sync_log") - // Get IP address - ip, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - ip = r.RemoteAddr - } - // Check X-Forwarded-For if behind a proxy - if xff := r.Header.Get("X-Forwarded-For"); xff != "" { - parts := strings.Split(xff, ",") - if len(parts) > 0 { - ip = strings.TrimSpace(parts[0]) - } - } - hashedIP := hashIP(ip) - uuidVal, err := generateUUID() if err != nil { log.Printf("Failed to generate UUID: %v", err) @@ -179,12 +154,10 @@ func bugReportHandler(storageDir string) http.HandlerFunc { // Write report.json report := BugReport{ Description: description, - Email: email, AboutInfo: aboutInfo, EmailData: emailData, SyncLog: syncLog, Timestamp: now, - HashedIP: hashedIP, } reportJSONPath := filepath.Join(reportDir, "report.json") @@ -205,6 +178,17 @@ func bugReportHandler(storageDir string) http.HandlerFunc { return } + // Write contact email to mail.eml (kept separate from report.json to isolate PII) + if email != "" { + mailEmlPath := filepath.Join(reportDir, "mail.eml") + err = os.WriteFile(mailEmlPath, []byte(email), 0600) + if err != nil { + log.Printf("Failed to write mail.eml: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + } + // Save attachments form := r.MultipartForm files := form.File["attachments[]"]