// Copyright (C) 2021 The Syncthing Authors. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. package main import ( "bytes" "compress/gzip" "crypto/sha256" "fmt" "net" "net/http" "os" "path/filepath" "time" ) // userIDFor returns a string we can use as the user ID for the purpose of // counting affected users. It's the truncated hash of a salt, the user // remote IP, and the current month. func userIDFor(req *http.Request) string { addr := req.RemoteAddr if fwd := req.Header.Get("x-forwarded-for"); fwd != "" { addr = fwd } if host, _, err := net.SplitHostPort(addr); err == nil { addr = host } now := time.Now().Format("200601") salt := "stcrashreporter" hash := sha256.Sum256([]byte(salt + addr + now)) return fmt.Sprintf("%x", hash[:8]) } // 01234567890abcdef... => 01/23 func dirFor(base string) string { return filepath.Join(base[0:2], base[2:4]) } func fullPathCompressed(root, reportID string) string { return filepath.Join(root, dirFor(reportID), reportID) + ".gz" } func compressAndWrite(bs []byte, fullPath string) error { // Compress the report for storage buf := new(bytes.Buffer) gw := gzip.NewWriter(buf) _, _ = gw.Write(bs) // can't fail gw.Close() // Create an output file with the compressed report return os.WriteFile(fullPath, buf.Bytes(), 0o644) }