From 1e55e61786eaedd59c067f4306fb8427dc92ef52 Mon Sep 17 00:00:00 2001 From: clsr Date: Tue, 15 Nov 2016 15:17:45 +0100 Subject: Add logging support --- api.go | 3 +- log.go | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 20 ++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 log.go diff --git a/api.go b/api.go index 49b8a61..464d110 100644 --- a/api.go +++ b/api.go @@ -67,7 +67,7 @@ func handleUpload(w http.ResponseWriter, r *http.Request) { output := r.FormValue("output") resp := response{Files: []result{}} - if r.Method == http.MethodGet && output == "html" { + if r.Method == http.MethodGet && (output == "html" || output == "") { respond(w, output, resp) return } @@ -113,6 +113,7 @@ func handleUpload(w http.ResponseWriter, r *http.Request) { Hash: hex.EncodeToString(bhash), Size: size, } + LogUpload(r, res) resp.Files = append(resp.Files, res) part.Close() diff --git a/log.go b/log.go new file mode 100644 index 0000000..f2305ce --- /dev/null +++ b/log.go @@ -0,0 +1,138 @@ +package main + +import ( + "crypto/sha1" + "encoding/base64" + "encoding/json" + "fmt" + "net" + "net/http" + "os" + "path" + "sync" + "time" +) + +type Logger struct { + LogDir string + LogIP bool + LogUserAgent bool + LogReferer bool + HashIP bool + HashUserAgent bool + HashReferer bool + HashSalt string + logFile *os.File + encoder *json.Encoder + lastDate string + lock sync.Mutex +} + +type LogEntry map[string]interface{} + +func InitLogger(logdir string) *Logger { + return &Logger{ + LogDir: logdir, + } +} + +func (l *Logger) Log(entry LogEntry) { + l.lock.Lock() + defer l.lock.Unlock() + _, err := l.getLogFile() + if err != nil { + fmt.Fprintf(os.Stderr, "error opening log file: %s\n", err) + return + } + err = l.encoder.Encode(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "error writing to log: %s\n", err) + } +} + +func (l *Logger) LogUpload(req *http.Request, res result) { + host, _, _ := net.SplitHostPort(req.RemoteAddr) + l.logUpload( + host, // ip + req.UserAgent(), // userAgent + req.Referer(), // referer + res.Name, // origName + path.Base(res.Url), // idext + res.Hash, // hash + res.Size, // size + ) +} + +func (l *Logger) logUpload(ip, userAgent, referer, origName, idext, hash string, size int64) { + if !l.LogIP { + ip = "" + } else if l.HashIP { + ip = l.hash(ip) + } + if !l.LogUserAgent { + userAgent = "" + } else if l.HashUserAgent { + userAgent = l.hash(userAgent) + } + if !l.LogReferer { + referer = "" + } else if l.HashReferer { + referer = l.hash(referer) + } + l.Log(LogEntry{ + "type": "upload", + "timestamp": time.Now().UTC().Format(time.RFC3339), + "ip": ip, + "user_agent": userAgent, + "referer": referer, + "orig_name": origName, + "id": idext, + "hash": hash, + "size": size, + }) +} + +func (l *Logger) hash(s string) string { + h := sha1.New() + h.Write([]byte(l.HashSalt)) + h.Write([]byte(s)) + h.Write([]byte(l.HashSalt)) + return base64.RawURLEncoding.EncodeToString(h.Sum(nil)) +} + +func (l *Logger) getLogFile() (*os.File, error) { + if l.lastDate == "" { + if err := os.MkdirAll(l.LogDir, 0755); err != nil { + return nil, err + } + } + currentDate := time.Now().UTC().Format("2006-01-02") + if l.lastDate == currentDate { + return l.logFile, nil + } + f, err := os.OpenFile(path.Join(l.LogDir, currentDate+".log.json"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + return f, err + } + if l.logFile != nil { + l.logFile.Close() + } + l.lastDate = currentDate + l.logFile = f + l.encoder = json.NewEncoder(f) + return f, nil +} + +var DefaultLogger = InitLogger("log") + +func Log(entry LogEntry) { + if DefaultLogger != nil { + DefaultLogger.Log(entry) + } +} + +func LogUpload(req *http.Request, res result) { + if DefaultLogger != nil { + DefaultLogger.LogUpload(req, res) + } +} diff --git a/main.go b/main.go index 40dae35..d66416f 100644 --- a/main.go +++ b/main.go @@ -76,6 +76,14 @@ func main() { grill := flag.Bool("grill", false, "enable grills") idLength := flag.Int("id-length", DefaultIdLength, "length of uploaded file IDs") idCharset := flag.String("id-charset", "", "charset for uploaded file IDs (default lowercase letters a-z)") + enableLog := flag.Bool("log", false, "enable logging") + logIP := flag.Bool("log-ip", false, "log IP addresses") + logIPHash := flag.Bool("log-ip-hash", false, "log hashed IP addresses") + logUA := flag.Bool("log-ua", false, "log User-Agent headers") + logUAHash := flag.Bool("log-ua-hash", false, "log hashed User-Agent headers") + logReferer := flag.Bool("log-referer", false, "log Referer headers") + logRefererHash := flag.Bool("log-referer-hash", false, "log hashed Referer headers") + logHashSalt := flag.String("log-hash-salt", "", "salt to use for hashed log entries") flag.Parse() @@ -96,6 +104,18 @@ func main() { storage.IdCharset = *idCharset } + if !*enableLog { + DefaultLogger = nil + } else { + DefaultLogger.LogIP = *logIP || *logIPHash + DefaultLogger.LogUserAgent = *logUA || *logUAHash + DefaultLogger.LogReferer = *logReferer || *logRefererHash + DefaultLogger.HashIP = *logIPHash + DefaultLogger.HashUserAgent = *logUAHash + DefaultLogger.HashReferer = *logRefererHash + DefaultLogger.HashSalt = *logHashSalt + } + http.HandleFunc("/upload.php", handleUpload) http.Handle("/u/", http.StripPrefix("/u/", http.HandlerFunc(handleFile))) if *grill { -- cgit