From 269836fc991a746ebd7b16bede8f8c1e042461e1 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Sat, 23 Dec 2023 20:54:55 +0000 Subject: [PATCH] ips: add advanced settings for ip logging --- auth.go | 41 ++++++++++++++++++++++++++++++----------- config.go | 3 +++ config/config-base.json | 23 +++++++++++++++++++++++ main.go | 2 ++ user-auth.go | 4 ++-- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/auth.go b/auth.go index 20bb18c..64635c1 100644 --- a/auth.go +++ b/auth.go @@ -18,6 +18,28 @@ const ( REFRESH_TOKEN_VALIDITY_SEC = 3600 * 24 ) +func (app *appContext) logIpInfo(gc *gin.Context, user bool, out string) { + app.info.Printf(out) + if (user && LOGIPU) || (!user && LOGIP) { + app.info.Printf(" (ip=%s)", strings.TrimSpace(gc.Request.Header.Get("X-Real-IP"))) + } + app.info.Print("\n") +} +func (app *appContext) logIpDebug(gc *gin.Context, user bool, out string) { + app.debug.Printf(out) + if (user && LOGIPU) || (!user && LOGIP) { + app.debug.Printf(" (ip=%s)", strings.TrimSpace(gc.Request.Header.Get("X-Real-IP"))) + } + app.debug.Print("\n") +} +func (app *appContext) logIpErr(gc *gin.Context, user bool, out string) { + app.err.Printf(out) + if (user && LOGIPU) || (!user && LOGIP) { + app.err.Printf(" (ip=%s)", strings.TrimSpace(gc.Request.Header.Get("X-Real-IP"))) + } + app.err.Print("\n") +} + func (app *appContext) webAuth() gin.HandlerFunc { return app.authenticate } @@ -133,8 +155,7 @@ type getTokenDTO struct { Token string `json:"token" example:"kjsdklsfdkljfsjsdfklsdfkldsfjdfskjsdfjklsdf"` // API token for use with everything else. } -func (app *appContext) decodeValidateLoginHeader(gc *gin.Context) (username, password string, ok bool) { - ip := strings.TrimSpace(gc.Request.Header.Get("X-Real-IP")) +func (app *appContext) decodeValidateLoginHeader(gc *gin.Context, userpage bool) (username, password string, ok bool) { header := strings.SplitN(gc.Request.Header.Get("Authorization"), " ", 2) auth, _ := base64.StdEncoding.DecodeString(header[1]) creds := strings.SplitN(string(auth), ":", 2) @@ -142,7 +163,7 @@ func (app *appContext) decodeValidateLoginHeader(gc *gin.Context) (username, pas password = creds[1] ok = false if username == "" || password == "" { - app.debug.Print("Auth denied: blank username/password ip=", ip, "\n") + app.logIpDebug(gc, userpage, "Auth denied: blank username/password") respond(401, "Unauthorized", gc) return } @@ -150,18 +171,17 @@ func (app *appContext) decodeValidateLoginHeader(gc *gin.Context) (username, pas return } -func (app *appContext) validateJellyfinCredentials(username, password string, gc *gin.Context) (user mediabrowser.User, ok bool) { - ip := strings.TrimSpace(gc.Request.Header.Get("X-Real-IP")) +func (app *appContext) validateJellyfinCredentials(username, password string, gc *gin.Context, userpage bool) (user mediabrowser.User, ok bool) { ok = false user, status, err := app.authJf.Authenticate(username, password) if status != 200 || err != nil { if status == 401 || status == 400 { - app.info.Print("Auth denied: Invalid username/password (Jellyfin) ip=", ip, "\n") + app.logIpInfo(gc, userpage, "Auth denied: Invalid username/password (Jellyfin)") respond(401, "Unauthorized", gc) return } if status == 403 { - app.info.Print("Auth denied: Jellyfin account disabled ip=", ip, "\n") + app.logIpInfo(gc, userpage, "Auth denied: Jellyfin account disabled") respond(403, "yourAccountWasDisabled", gc) return } @@ -182,9 +202,8 @@ func (app *appContext) validateJellyfinCredentials(username, password string, gc // @tags Auth // @Security getTokenAuth func (app *appContext) getTokenLogin(gc *gin.Context) { - ip := strings.TrimSpace(gc.Request.Header.Get("X-Real-IP")) app.info.Println("Token requested (login attempt)") - username, password, ok := app.decodeValidateLoginHeader(gc) + username, password, ok := app.decodeValidateLoginHeader(gc, false) if !ok { return } @@ -199,12 +218,12 @@ func (app *appContext) getTokenLogin(gc *gin.Context) { } } if !app.jellyfinLogin && !match { - app.info.Print("Auth denied: Invalid username/password ip=", ip, "\n") + app.logIpInfo(gc, false, "Auth denied: Invalid username/password") respond(401, "Unauthorized", gc) return } if !match { - user, ok := app.validateJellyfinCredentials(username, password, gc) + user, ok := app.validateJellyfinCredentials(username, password, gc, false) if !ok { return } diff --git a/config.go b/config.go index 91ea6bd..4b1d835 100644 --- a/config.go +++ b/config.go @@ -120,6 +120,9 @@ func (app *appContext) loadConfig() error { app.config.Section("jellyfin").Key("device").SetValue("jfa-go") app.config.Section("jellyfin").Key("device_id").SetValue(fmt.Sprintf("jfa-go-%s-%s", version, commit)) + LOGIP = app.config.Section("advanced").Key("log_ips").MustBool(false) + LOGIPU = app.config.Section("advanced").Key("log_ips_userpage").MustBool(false) + // These two settings are pretty much the same url1 := app.config.Section("invite_emails").Key("url_base").String() url2 := app.config.Section("password_resets").Key("url_base").String() diff --git a/config/config-base.json b/config/config-base.json index 5bcb500..1f19920 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -297,6 +297,29 @@ "advanced": true }, "settings": { + "log_ips": { + "name": "Log IPs accessing Admin Page", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Log IP addresses in console and in activities. See notice below on legality." + }, + "log_ips_userpage": { + "name": "Log IPs accessing User Page", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Log IP addresses in console and in activities. See notice below on legality." + }, + "ip_note": { + "name": "Logging IPs:", + "type": "note", + "value": "", + "required": "false", + "description": "Logging IP addresses through jfa-go may violate GDPR or other privacy regulations, as IPs are linked to account information. Enable at your own risk." + }, "tls": { "name": "TLS/HTTP2", "required": false, diff --git a/main.go b/main.go index 52c96c8..949d91a 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,8 @@ var ( SWAGGER *bool QUIT = false RUNNING = false + LOGIP = false // Log admin IPs + LOGIPU = false // Log user IPs // Used to know how many times to re-broadcast restart signal. RESTARTLISTENERCOUNT = 0 warning = color.New(color.FgYellow).SprintfFunc() diff --git a/user-auth.go b/user-auth.go index 53c9ae0..518d6c6 100644 --- a/user-auth.go +++ b/user-auth.go @@ -46,12 +46,12 @@ func (app *appContext) getUserTokenLogin(gc *gin.Context) { return } app.info.Println("UserToken requested (login attempt)") - username, password, ok := app.decodeValidateLoginHeader(gc) + username, password, ok := app.decodeValidateLoginHeader(gc, true) if !ok { return } - user, ok := app.validateJellyfinCredentials(username, password, gc) + user, ok := app.validateJellyfinCredentials(username, password, gc, true) if !ok { return }