From 781492baedc9fe989ad06b22edd3c314438bdae9 Mon Sep 17 00:00:00 2001 From: Don Bowman Date: Sun, 10 Jan 2021 20:41:52 -0500 Subject: [PATCH] feat: allow ENDPOINT_URI/COOKIE_DOMAIN to be unset, default to Host: header In some environments a website will have more than one domain name, serving the same content. This makes it impossible to set ENDPOINT_URI/COOKIE_DOMAIN as server environment variables. If ENDPOINT_URI is unset, use Host: header in its place. Update cache path to be qualified by it. Allow COOKIE_DOMAIN to be unset. --- .gitignore | 6 ++++++ README.md | 6 +++--- server/ga.go | 35 +++++++++++++++++++++++------------ server/gtm.go | 19 ++++++++++++------- server/main.go | 2 -- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 66fd13c..824a0c3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,9 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +server/.vscode/ +server/__debug_bin +server/go.sum +server/server + diff --git a/README.md b/README.md index 4a39c3a..982a118 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ docker run \ |Variable|Description|Example| |-----------------|-----|-----| |```ENABLE_DEBUG_OUTPUT```|Set this to true to let the proxy print debug details for setting up or debugging.|false| -|```ENDPOINT_URI```|URI where the proxy will be reachable at.|www.google.com| +|```ENDPOINT_URI```|URI where the proxy will be reachable at. If not present, will use `Host` header.|www.google.com| |```JS_SUBDIRECTORY```|It is intended to serve the javascript files within a subdirectory of the URI. Here you can define a name for it.|js| |```HTML_SUBDIRECTORY```|It is intended to serve the html files (like the GTM iframe) within a subdirectory of the URI. Here you can define a name for it.|html| |```GA_CACHE_TIME```|Time in seconds the proxy caches the Google Analytics client javascript.|3600| @@ -91,7 +91,7 @@ docker run \ |```ENABLE_SERVER_SIDE_GA_COOKIES```|If the proxy should transfer the client id to a serverside cookie, set this to true.|true| |```GA_SERVER_SIDE_COOKIE```|Set the cookie name for the serverside cookie.|_gggp| |```GA_CLIENT_SIDE_COOKIE```|Set the cookie name for the clientside cookie, where google analytics will take the client id from.|_ga| -|```COOKIE_DOMAIN```|The [domain](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Attributes) where the cookies are setup to.|google.com| +|```COOKIE_DOMAIN```|The [domain](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Attributes) where the cookies are setup to. If not present, use the `Host` header.|google.com| |```COOKIE_SECURE```|If your website is accessable through https://, you should set this variable to true. [More info](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Secure)|true| @@ -278,4 +278,4 @@ If you found this repo useful, please consider a donation. Thank You! [Bitcoin: 131AUMEDiAFHakkLHnvhYgvunKR6d38kZx](https://www.blockchain.com/btc/address/131AUMEDiAFHakkLHnvhYgvunKR6d38kZx) -[Ethereum: 0x9eB04Daf33DEF7dec2f5D454D1c63c020aBe8D8f](https://www.blockchain.com/eth/address/0x9eB04Daf33DEF7dec2f5D454D1c63c020aBe8D8f) \ No newline at end of file +[Ethereum: 0x9eB04Daf33DEF7dec2f5D454D1c63c020aBe8D8f](https://www.blockchain.com/eth/address/0x9eB04Daf33DEF7dec2f5D454D1c63c020aBe8D8f) diff --git a/server/ga.go b/server/ga.go index f92a10c..688e757 100644 --- a/server/ga.go +++ b/server/ga.go @@ -40,15 +40,26 @@ func googleAnalyticsJsHandle(w http.ResponseWriter, r *http.Request, path string var statusCodeToReturn int = 200 var headersToReturn http.Header var usedCache bool + var endpointURI = settingsGGGP.EndpointURI + var cookieDomain = settingsGGGP.CookieDomain + var cachePath = path - GaCache, CacheExists := srcGaCache[path] + if settingsGGGP.EndpointURI == "" { + endpointURI = r.Host + cachePath = endpointURI + "/" + path + } + if settingsGGGP.CookieDomain == "" { + cookieDomain = r.Host + } + + GaCache, CacheExists := srcGaCache[cachePath] if CacheExists == false { gaMapSync.Lock() - srcGaCache[path] = gaSourceCodeCache{lastUpdate: 0} + srcGaCache[cachePath] = gaSourceCodeCache{lastUpdate: 0} gaMapSync.Unlock() - GaCache, _ = srcGaCache[path] + GaCache, _ = srcGaCache[cachePath] } if settingsGGGP.EnableDebugOutput { @@ -138,13 +149,13 @@ func googleAnalyticsJsHandle(w http.ResponseWriter, r *http.Request, path string } re := regexp.MustCompile(`googletagmanager.com`) - body = re.ReplaceAll([]byte(body), []byte(settingsGGGP.EndpointURI)) + body = re.ReplaceAll([]byte(body), []byte(endpointURI)) re = regexp.MustCompile(`\/gtm.js`) body = re.ReplaceAll([]byte(body), []byte(`/`+settingsGGGP.JsSubdirectory+`/`+settingsGGGP.GtmFilename)) re = regexp.MustCompile(`www.google-analytics.com`) - body = re.ReplaceAll([]byte(body), []byte(settingsGGGP.EndpointURI)) + body = re.ReplaceAll([]byte(body), []byte(endpointURI)) re = regexp.MustCompile(`analytics.js`) body = re.ReplaceAll([]byte(body), []byte(`/`+settingsGGGP.JsSubdirectory+`/`+settingsGGGP.GaFilename)) @@ -208,7 +219,7 @@ func googleAnalyticsJsHandle(w http.ResponseWriter, r *http.Request, path string // Reassigning the copy of the struct back to map gaMapSync.Lock() - srcGaCache[path] = GaCache + srcGaCache[cachePath] = GaCache gaMapSync.Unlock() } @@ -241,16 +252,16 @@ func googleAnalyticsJsHandle(w http.ResponseWriter, r *http.Request, path string if settingsGGGP.CookieSecure { if settingsGGGP.EnableDebugOutput { - fmt.Println(`Set-Cookie: ` + settingsGGGP.ServerSideGaCookieName + `=` + newCookieContent + `; Domain=` + settingsGGGP.CookieDomain + `; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) + fmt.Println(`Set-Cookie: ` + settingsGGGP.ServerSideGaCookieName + `=` + newCookieContent + `; Domain=` + cookieDomain + `; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) } - w.Header().Add(`Set-Cookie`, settingsGGGP.ServerSideGaCookieName+`=`+newCookieContent+`; Domain=`+settingsGGGP.CookieDomain+`; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) - w.Header().Add(`Set-Cookie`, settingsGGGP.ClientSideGaCookieName+`=`+newCookieDecodedContent+`; Domain=`+settingsGGGP.CookieDomain+`; Secure; SameSite=Lax; Path=/; Max-Age=63072000`) + w.Header().Add(`Set-Cookie`, settingsGGGP.ServerSideGaCookieName+`=`+newCookieContent+`; Domain=`+cookieDomain+`; Secure; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) + w.Header().Add(`Set-Cookie`, settingsGGGP.ClientSideGaCookieName+`=`+newCookieDecodedContent+`; Domain=`+cookieDomain+`; Secure; SameSite=Lax; Path=/; Max-Age=63072000`) } else { if settingsGGGP.EnableDebugOutput { - fmt.Println(`Set-Cookie: ` + settingsGGGP.ServerSideGaCookieName + `=` + newCookieContent + `; Domain=` + settingsGGGP.CookieDomain + `; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) + fmt.Println(`Set-Cookie: ` + settingsGGGP.ServerSideGaCookieName + `=` + newCookieContent + `; Domain=` + cookieDomain + `; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) } - w.Header().Add(`Set-Cookie`, settingsGGGP.ServerSideGaCookieName+`=`+newCookieContent+`; Domain=`+settingsGGGP.CookieDomain+`; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) - w.Header().Add(`Set-Cookie`, settingsGGGP.ClientSideGaCookieName+`=`+newCookieDecodedContent+`; Domain=`+settingsGGGP.CookieDomain+`; SameSite=Lax; Path=/; Max-Age=63072000`) + w.Header().Add(`Set-Cookie`, settingsGGGP.ServerSideGaCookieName+`=`+newCookieContent+`; Domain=`+cookieDomain+`; HttpOnly; SameSite=Lax; Path=/; Max-Age=63072000`) + w.Header().Add(`Set-Cookie`, settingsGGGP.ClientSideGaCookieName+`=`+newCookieDecodedContent+`; Domain=`+cookieDomain+`; SameSite=Lax; Path=/; Max-Age=63072000`) } } diff --git a/server/gtm.go b/server/gtm.go index 93bc920..98711e9 100644 --- a/server/gtm.go +++ b/server/gtm.go @@ -34,6 +34,11 @@ func googleTagManagerHandle(w http.ResponseWriter, r *http.Request, path string) var statusCodeToReturn int = 200 var headersToReturn http.Header var usedCache bool + var endpointURI = settingsGGGP.EndpointURI + + if settingsGGGP.EndpointURI == "" { + endpointURI = r.Host + } if innerID, ok := r.URL.Query()[`id`]; ok { if len(innerID[0]) >= 4 { @@ -63,14 +68,14 @@ func googleTagManagerHandle(w http.ResponseWriter, r *http.Request, path string) } } - GtmCache, CacheExists := srcGtmCache[GtmContainerID+GtmURLAddition] + GtmCache, CacheExists := srcGtmCache[endpointURI+"/"+GtmContainerID+GtmURLAddition] if CacheExists == false { gtmMapSync.Lock() - srcGtmCache[GtmContainerID+GtmURLAddition] = gtmSourceCodeCache{lastUpdate: 0} + srcGtmCache[endpointURI+"/"+GtmContainerID+GtmURLAddition] = gtmSourceCodeCache{lastUpdate: 0} gtmMapSync.Unlock() - GtmCache, _ = srcGtmCache[GtmContainerID+GtmURLAddition] + GtmCache, _ = srcGtmCache[endpointURI+"/"+GtmContainerID+GtmURLAddition] } if !isInSlice(settingsGGGP.AllowedGtmIds, r.URL.Query()[`id`][0]) && !isInSlice(settingsGGGP.AllowedGtmIds, r.URL.Query()[`id`][0][4:]) && settingsGGGP.RestrictGtmIds { @@ -171,16 +176,16 @@ func googleTagManagerHandle(w http.ResponseWriter, r *http.Request, path string) // body = re.ReplaceAll([]byte(body), []byte(settingsGGGP.EndpointURI+`/`+settingsGGGP.JsSubdirectory+`/`+settingsGGGP.GtmAFilename)) re := regexp.MustCompile(`(www\.)?googletagmanager.com`) - body = re.ReplaceAll([]byte(body), []byte(settingsGGGP.EndpointURI)) + body = re.ReplaceAll([]byte(body), []byte(endpointURI)) - re = regexp.MustCompile(settingsGGGP.EndpointURI + `\/a`) + re = regexp.MustCompile(endpointURI + `\/a`) body = re.ReplaceAll([]byte(body), []byte(`www.googletagmanager.com\/a`)) re = regexp.MustCompile(`\/gtm.js`) body = re.ReplaceAll([]byte(body), []byte(`/`+settingsGGGP.JsSubdirectory+`/`+settingsGGGP.GtmFilename)) re = regexp.MustCompile(`www.google-analytics.com`) - body = re.ReplaceAll([]byte(body), []byte(settingsGGGP.EndpointURI)) + body = re.ReplaceAll([]byte(body), []byte(endpointURI)) re = regexp.MustCompile(`(\/)?analytics.js`) body = re.ReplaceAll([]byte(body), []byte(`/`+settingsGGGP.JsSubdirectory+`/`+settingsGGGP.GaFilename)) @@ -233,7 +238,7 @@ func googleTagManagerHandle(w http.ResponseWriter, r *http.Request, path string) // Reassigning the copy of the struct back to map gtmMapSync.Lock() - srcGtmCache[GtmContainerID+GtmURLAddition] = GtmCache + srcGtmCache[endpointURI+"/"+GtmContainerID+GtmURLAddition] = GtmCache gtmMapSync.Unlock() } diff --git a/server/main.go b/server/main.go index 954016b..a0e3acc 100644 --- a/server/main.go +++ b/server/main.go @@ -101,7 +101,6 @@ func setResponseHeaders(w http.ResponseWriter, headers http.Header) { func main() { // Check if required environment variables are set for _, envVar := range [...]string{ - "ENDPOINT_URI", "JS_SUBDIRECTORY", "GA_PLUGINS_DIRECTORYNAME", "GTM_FILENAME", @@ -112,7 +111,6 @@ func main() { "GA_COLLECT_ENDPOINT", "GA_COLLECT_REDIRECT_ENDPOINT", "GA_COLLECT_J_ENDPOINT", - "COOKIE_DOMAIN", } { if os.Getenv(envVar) == `` { fmt.Println(`ERROR: Seems the required environment variable '` + envVar + `' is missing. Exiting.`)