diff --git a/README.md b/README.md index 62697c5..e3cf330 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ umami [] { client_ip_header cookie_consent [] cookie_resolution [] + device_detection trusted_ip_header report_all_resources debug @@ -34,6 +35,7 @@ umami [] { - **client_ip_header** is the name of an HTTP header which will be sent to Umami **alongside** `X-Forwarded-For`, which contains the visitor's IP address. - **cookie_consent** is the name of a cookie, if that cookie's value is `false` then this plugin will not run. If a name is not set, the default name is `umami_consent`. - **cookie_resolution** is the name of a cookie whose value should be the user's screen resolution, for example `1920x1080`. It is your responsibility to set this cookie with client-side JavaScript (not provided). If this cookie is not set, device type will just be reported as unknown. If a name is not set, the default name is `umami_resolution`. +- **device_detection** can be enabled to set the sent screen resolution based on `Sec-CH-UA-Mobile`/`Sec-CH-UA-Platform`, for some rudimentary device detection without cookies. If this and `cookie_resolution` are both enabled, a screen resolution set by the cookie will take precedence. - **trusted_ip_header** is the name of an incoming HTTP request header which contains the visitor's true IP, which will then be sent to Umami via the `X-Forwarded-For`. This may be useful if your Caddy server is behind a reverse proxy. - **report_all_resources** can be included to report **all** requests to Umami, overriding allowed_extensions. By default, only requests with certain extensions are reported. This may be especially useful when using this module with a matcher. @@ -53,8 +55,7 @@ example.com { website_uuid "4fa2c16a-6c0f-488f-986f-bc26d90c76d1" allowed_extensions "" .html .htm .php client_ip_header X-Real-IP - cookie_consent - cookie_resolution screenres + device_detection } // ... diff --git a/umami.go b/umami.go index fb215c0..529b3da 100644 --- a/umami.go +++ b/umami.go @@ -32,6 +32,7 @@ type Umami struct { TrustedIPHeader string CookieConsent string CookieResolution string + DeviceDetection bool } // CaddyModule returns the Caddy module information. @@ -110,15 +111,27 @@ func (p Umami) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp. fmt.Printf("Error getting resolution cookie: %v\n", err) } } + if cookie != nil { + payload["screen"] = cookie.Value + } + } - // handle if cookie does not exist - if cookie == nil { - cookie = &http.Cookie{ - Name: p.CookieResolution, - Value: "", - } + if payload["screen"] == nil && p.DeviceDetection { + mobile := r.Header.Get("Sec-CH-UA-Mobile") + platform := r.Header.Get("Sec-CH-UA-Platform") + + if p.DebugLogging { + fmt.Printf("Mobile: %s\n", mobile) + fmt.Printf("Platform: %s\n", platform) + } + + if mobile == "?1" { + payload["screen"] = "400x800" // mobile + } else if platform == `"Android"` { + payload["screen"] = "900x600" // tablet + } else if platform == `"Chrome OS"` || platform == `"macOS"` { + payload["screen"] = "1200x800" // laptop } - payload["screen"] = cookie.Value } visitorInfo := map[string]interface{}{ @@ -189,7 +202,7 @@ func (p *Umami) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } p.WebsiteUUID = d.Val() case "report_all_resources": - p.ReportAllResources = d.Val() == "true" + p.ReportAllResources = true case "allowed_extensions": if !d.NextArg() { return d.ArgErr() @@ -222,6 +235,8 @@ func (p *Umami) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } else { p.CookieResolution = d.Val() } + case "device_detection": + p.DeviceDetection = true default: return d.Errf("unknown option '%s'", d.Val()) @@ -252,7 +267,9 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) if umami.DebugLogging { fmt.Printf("Event Endpoint: %s\n", umami.EventEndpoint) fmt.Printf("Website UUID: %s\n", umami.WebsiteUUID) + fmt.Printf("Reporting All Resources: %v\n", umami.ReportAllResources) fmt.Printf("Allowed Extensions: %v\n", umami.AllowedExtensions) + fmt.Printf("Device Detection: %v\n", umami.DeviceDetection) } return umami, nil }