Update logging

This commit is contained in:
2026-01-05 13:57:08 +01:00
parent 776b56afc1
commit 81af6d2470

31
main.go
View File

@@ -40,6 +40,9 @@ type openResponse struct {
} }
func main() { func main() {
infoLog := log.New(os.Stdout, "", log.LstdFlags)
errLog := log.New(os.Stderr, "ERROR: ", log.LstdFlags)
listen := flag.String("listen", "127.0.0.1:8765", "listen address (host:port), should be loopback") listen := flag.String("listen", "127.0.0.1:8765", "listen address (host:port), should be loopback")
token := flag.String("token", "", "shared secret token; if empty, requests are allowed without authentication") token := flag.String("token", "", "shared secret token; if empty, requests are allowed without authentication")
var allowed allowList var allowed allowList
@@ -47,16 +50,16 @@ func main() {
flag.Parse() flag.Parse()
if !isLoopbackListenAddr(*listen) { if !isLoopbackListenAddr(*listen) {
log.Fatalf("refusing to listen on non-loopback address: %s", *listen) errLog.Fatalf("refusing to listen on non-loopback address: %s", *listen)
} }
if strings.TrimSpace(*token) == "" { if strings.TrimSpace(*token) == "" {
generated, err := generateToken() generated, err := generateToken()
if err != nil { if err != nil {
log.Fatalf("failed to generate token: %v", err) errLog.Fatalf("failed to generate token: %v", err)
} }
*token = generated *token = generated
log.Printf("generated token (set this in the plugin config): %s", *token) infoLog.Printf("generated token (set this in the plugin config): %s", *token)
} }
mux := http.NewServeMux() mux := http.NewServeMux()
@@ -72,7 +75,6 @@ func main() {
start := time.Now() start := time.Now()
var rawPath string var rawPath string
if r.Method == http.MethodOptions { if r.Method == http.MethodOptions {
log.Printf("/open preflight remote=%s origin=%q", r.RemoteAddr, r.Header.Get("Origin"))
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
return return
} }
@@ -85,24 +87,23 @@ func main() {
dec := json.NewDecoder(http.MaxBytesReader(w, r.Body, 32*1024)) dec := json.NewDecoder(http.MaxBytesReader(w, r.Body, 32*1024))
dec.DisallowUnknownFields() dec.DisallowUnknownFields()
if err := dec.Decode(&req); err != nil { if err := dec.Decode(&req); err != nil {
log.Printf("/open bad-json remote=%s method=%s err=%v dur=%s", r.RemoteAddr, r.Method, err, time.Since(start)) errLog.Printf("/open bad-json method=%s err=%v dur=%s", r.Method, err, time.Since(start))
writeJSON(w, http.StatusBadRequest, openResponse{OK: false, Message: "invalid json"}) writeJSON(w, http.StatusBadRequest, openResponse{OK: false, Message: "invalid json"})
return return
} }
default: default:
log.Printf("/open method-not-allowed remote=%s method=%s dur=%s", r.RemoteAddr, r.Method, time.Since(start)) errLog.Printf("/open method-not-allowed method=%s dur=%s", r.Method, time.Since(start))
writeJSON(w, http.StatusMethodNotAllowed, openResponse{OK: false, Message: "GET or POST required"}) writeJSON(w, http.StatusMethodNotAllowed, openResponse{OK: false, Message: "GET or POST required"})
return return
} }
rawPath = req.Path rawPath = req.Path
log.Printf("/open request remote=%s method=%s ua=%q path=%q", r.RemoteAddr, r.Method, r.UserAgent(), rawPath)
if !checkToken(r, *token) { if !checkToken(r, *token) {
// Allow token to be supplied via query string for GET fallback. // Allow token to be supplied via query string for GET fallback.
qt := strings.TrimSpace(r.URL.Query().Get("token")) qt := strings.TrimSpace(r.URL.Query().Get("token"))
if qt == "" || !subtleStringEqual(qt, strings.TrimSpace(*token)) { if qt == "" || !subtleStringEqual(qt, strings.TrimSpace(*token)) {
log.Printf("/open unauthorized remote=%s method=%s path=%q headerToken=%t queryToken=%t dur=%s", r.RemoteAddr, r.Method, rawPath, strings.TrimSpace(r.Header.Get("X-Filetools-Token")) != "", qt != "", time.Since(start)) errLog.Printf("/open unauthorized method=%s path=%q headerToken=%t queryToken=%t dur=%s", r.Method, rawPath, strings.TrimSpace(r.Header.Get("X-Filetools-Token")) != "", qt != "", time.Since(start))
writeJSON(w, http.StatusUnauthorized, openResponse{OK: false, Message: "unauthorized"}) writeJSON(w, http.StatusUnauthorized, openResponse{OK: false, Message: "unauthorized"})
return return
} }
@@ -110,23 +111,23 @@ func main() {
target, err := normalizePath(req.Path) target, err := normalizePath(req.Path)
if err != nil { if err != nil {
log.Printf("/open bad-path remote=%s method=%s path=%q err=%v dur=%s", r.RemoteAddr, r.Method, rawPath, err, time.Since(start)) errLog.Printf("/open bad-path method=%s path=%q err=%v dur=%s", r.Method, rawPath, err, time.Since(start))
writeJSON(w, http.StatusBadRequest, openResponse{OK: false, Message: err.Error()}) writeJSON(w, http.StatusBadRequest, openResponse{OK: false, Message: err.Error()})
return return
} }
if len(allowed) > 0 && !isAllowed(target, allowed) { if len(allowed) > 0 && !isAllowed(target, allowed) {
log.Printf("/open forbidden remote=%s method=%s path=%q normalized=%q dur=%s", r.RemoteAddr, r.Method, rawPath, target, time.Since(start)) errLog.Printf("/open forbidden method=%s path=%q normalized=%q dur=%s", r.Method, rawPath, target, time.Since(start))
writeJSON(w, http.StatusForbidden, openResponse{OK: false, Message: "path not allowed"}) writeJSON(w, http.StatusForbidden, openResponse{OK: false, Message: "path not allowed"})
return return
} }
if err := openFolder(target); err != nil { if err := openFolder(target); err != nil {
log.Printf("/open open-failed remote=%s method=%s path=%q normalized=%q err=%v dur=%s", r.RemoteAddr, r.Method, rawPath, target, err, time.Since(start)) errLog.Printf("/open open-failed method=%s path=%q normalized=%q err=%v dur=%s", r.Method, rawPath, target, err, time.Since(start))
writeJSON(w, http.StatusInternalServerError, openResponse{OK: false, Message: err.Error()}) writeJSON(w, http.StatusInternalServerError, openResponse{OK: false, Message: err.Error()})
return return
} }
log.Printf("/open opened remote=%s method=%s path=%q normalized=%q dur=%s", r.RemoteAddr, r.Method, rawPath, target, time.Since(start)) infoLog.Printf("/open opened method=%s path=%q normalized=%q dur=%s", r.Method, rawPath, target, time.Since(start))
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
// For GET callers (image-ping), a 204 avoids console noise from non-image responses. // For GET callers (image-ping), a 204 avoids console noise from non-image responses.
@@ -146,9 +147,9 @@ func main() {
IdleTimeout: 30 * time.Second, IdleTimeout: 30 * time.Second,
} }
log.Printf("listening on http://%s", *listen) infoLog.Printf("listening on http://%s", *listen)
log.Printf("os=%s arch=%s", runtime.GOOS, runtime.GOARCH) infoLog.Printf("os=%s arch=%s", runtime.GOOS, runtime.GOARCH)
log.Fatal(srv.ListenAndServe()) errLog.Fatal(srv.ListenAndServe())
} }
func isLoopbackListenAddr(addr string) bool { func isLoopbackListenAddr(addr string) bool {