From e24af7a5240b48982885546d82ee0da66534dc8d Mon Sep 17 00:00:00 2001
From: man90 <man90@tuta.io>
Date: Thu, 20 Nov 2025 17:17:38 +0100
Subject: [PATCH 1/3] Move admin token check functionality to a separate
 function

---
 handlers/getCache.go        | 14 +++++---------
 handlers/getCacheSummary.go | 15 ++++++---------
 utils/CheckAdminToken.go    | 19 +++++++++++++++++++
 3 files changed, 30 insertions(+), 18 deletions(-)
 create mode 100644 utils/CheckAdminToken.go

diff --git a/handlers/getCache.go b/handlers/getCache.go
index 230f25c..77606eb 100644
--- a/handlers/getCache.go
+++ b/handlers/getCache.go
@@ -1,21 +1,17 @@
 package handlers
 
 import (
-	"bdo-rest-api/cache"
 	"encoding/json"
 	"net/http"
 
-	"github.com/spf13/viper"
+	"bdo-rest-api/cache"
+	"bdo-rest-api/utils"
 )
 
 func getCache(w http.ResponseWriter, r *http.Request) {
-	if token := viper.GetString("admintoken"); len(token) > 0 {
-		providedToken := r.Header.Get("Authorization")
-
-		if providedToken != "Bearer "+token {
-			w.WriteHeader(http.StatusUnauthorized)
-			return
-		}
+	if !utils.CheckAdminToken(r) {
+		w.WriteHeader(http.StatusUnauthorized)
+		return
 	}
 
 	cacheType := r.PathValue("cacheType")
diff --git a/handlers/getCacheSummary.go b/handlers/getCacheSummary.go
index 7b8f84c..d1bc859 100644
--- a/handlers/getCacheSummary.go
+++ b/handlers/getCacheSummary.go
@@ -1,13 +1,14 @@
 package handlers
 
 import (
-	"bdo-rest-api/cache"
 	"encoding/json"
 	"net/http"
 	"strings"
 
+	"bdo-rest-api/cache"
+	"bdo-rest-api/utils"
+
 	sf "github.com/sa-/slicefunk"
-	"github.com/spf13/viper"
 )
 
 func getParseCacheKey(cacheType string) func(string) map[string]interface{} {
@@ -44,13 +45,9 @@ func getParseCacheKey(cacheType string) func(string) map[string]interface{} {
 }
 
 func getCacheSummary(w http.ResponseWriter, r *http.Request) {
-	if token := viper.GetString("admintoken"); len(token) > 0 {
-		providedToken := r.Header.Get("Authorization")
-
-		if providedToken != "Bearer "+token {
-			w.WriteHeader(http.StatusUnauthorized)
-			return
-		}
+	if !utils.CheckAdminToken(r) {
+		w.WriteHeader(http.StatusUnauthorized)
+		return
 	}
 
 	json.NewEncoder(w).Encode(map[string]interface{}{
diff --git a/utils/CheckAdminToken.go b/utils/CheckAdminToken.go
new file mode 100644
index 0000000..d5f4922
--- /dev/null
+++ b/utils/CheckAdminToken.go
@@ -0,0 +1,19 @@
+package utils
+
+import (
+	"net/http"
+
+	"github.com/spf13/viper"
+)
+
+func CheckAdminToken(r *http.Request) bool {
+	if token := viper.GetString("admintoken"); len(token) > 0 {
+		providedToken := r.Header.Get("Authorization")
+
+		if providedToken != "Bearer "+token {
+			return false
+		}
+	}
+
+	return true
+}

From 9c2737bf17cc38e1abcda243ecf7ea9b41e3cd71 Mon Sep 17 00:00:00 2001
From: man90 <man90@tuta.io>
Date: Thu, 20 Nov 2025 18:29:23 +0100
Subject: [PATCH 2/3] Implement bypassCache query parameter

---
 handlers/getAdventurer.go                   | 22 ++++++++++++---------
 handlers/getAdventurerSearch.go             | 22 ++++++++++++---------
 handlers/getGuild.go                        | 22 ++++++++++++---------
 handlers/getGuildSearch.go                  | 22 ++++++++++++---------
 validators/ValidateBypassCacheQueryParam.go |  5 +++++
 5 files changed, 57 insertions(+), 36 deletions(-)
 create mode 100644 validators/ValidateBypassCacheQueryParam.go

diff --git a/handlers/getAdventurer.go b/handlers/getAdventurer.go
index 9802503..b8a4dcb 100644
--- a/handlers/getAdventurer.go
+++ b/handlers/getAdventurer.go
@@ -6,6 +6,7 @@ import (
 
 	"bdo-rest-api/cache"
 	"bdo-rest-api/scraper"
+	"bdo-rest-api/utils"
 	"bdo-rest-api/validators"
 )
 
@@ -22,17 +23,20 @@ func getAdventurer(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if data, status, date, expires, ok := cache.Profiles.GetRecord([]string{region, profileTarget}); ok {
-		w.Header().Set("Expires", expires)
-		w.Header().Set("Last-Modified", date)
+	bypassCache := validators.ValidateBypassCacheQueryParam(r.URL.Query()["bypassCache"])
+	if !bypassCache || !utils.CheckAdminToken(r) {
+		if data, status, date, expires, ok := cache.Profiles.GetRecord([]string{region, profileTarget}); ok {
+			w.Header().Set("Expires", expires)
+			w.Header().Set("Last-Modified", date)
 
-		if status == http.StatusOK {
-			json.NewEncoder(w).Encode(data)
-		} else {
-			w.WriteHeader(status)
-		}
+			if status == http.StatusOK {
+				json.NewEncoder(w).Encode(data)
+			} else {
+				w.WriteHeader(status)
+			}
 
-		return
+			return
+		}
 	}
 
 	if ok := giveMaintenanceResponse(w, region); ok {
diff --git a/handlers/getAdventurerSearch.go b/handlers/getAdventurerSearch.go
index 29256be..fe28d93 100644
--- a/handlers/getAdventurerSearch.go
+++ b/handlers/getAdventurerSearch.go
@@ -6,6 +6,7 @@ import (
 
 	"bdo-rest-api/cache"
 	"bdo-rest-api/scraper"
+	"bdo-rest-api/utils"
 	"bdo-rest-api/validators"
 )
 
@@ -25,17 +26,20 @@ func getAdventurerSearch(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if data, status, date, expires, ok := cache.ProfileSearch.GetRecord([]string{region, query, searchType}); ok {
-		w.Header().Set("Expires", expires)
-		w.Header().Set("Last-Modified", date)
+	bypassCache := validators.ValidateBypassCacheQueryParam(r.URL.Query()["bypassCache"])
+	if !bypassCache || !utils.CheckAdminToken(r) {
+		if data, status, date, expires, ok := cache.ProfileSearch.GetRecord([]string{region, query, searchType}); !bypassCache && ok {
+			w.Header().Set("Expires", expires)
+			w.Header().Set("Last-Modified", date)
 
-		if status == http.StatusOK {
-			json.NewEncoder(w).Encode(data)
-		} else {
-			w.WriteHeader(status)
-		}
+			if status == http.StatusOK {
+				json.NewEncoder(w).Encode(data)
+			} else {
+				w.WriteHeader(status)
+			}
 
-		return
+			return
+		}
 	}
 
 	if ok := giveMaintenanceResponse(w, region); ok {
diff --git a/handlers/getGuild.go b/handlers/getGuild.go
index 3fcc71b..a84c984 100644
--- a/handlers/getGuild.go
+++ b/handlers/getGuild.go
@@ -6,6 +6,7 @@ import (
 
 	"bdo-rest-api/cache"
 	"bdo-rest-api/scraper"
+	"bdo-rest-api/utils"
 	"bdo-rest-api/validators"
 )
 
@@ -22,17 +23,20 @@ func getGuild(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if data, status, date, expires, ok := cache.GuildProfiles.GetRecord([]string{region, name}); ok {
-		w.Header().Set("Expires", expires)
-		w.Header().Set("Last-Modified", date)
+	bypassCache := validators.ValidateBypassCacheQueryParam(r.URL.Query()["bypassCache"])
+	if !bypassCache || !utils.CheckAdminToken(r) {
+		if data, status, date, expires, ok := cache.GuildProfiles.GetRecord([]string{region, name}); !bypassCache && ok {
+			w.Header().Set("Expires", expires)
+			w.Header().Set("Last-Modified", date)
 
-		if status == http.StatusOK {
-			json.NewEncoder(w).Encode(data)
-		} else {
-			w.WriteHeader(status)
-		}
+			if status == http.StatusOK {
+				json.NewEncoder(w).Encode(data)
+			} else {
+				w.WriteHeader(status)
+			}
 
-		return
+			return
+		}
 	}
 
 	if ok := giveMaintenanceResponse(w, region); ok {
diff --git a/handlers/getGuildSearch.go b/handlers/getGuildSearch.go
index 566e494..197e51f 100644
--- a/handlers/getGuildSearch.go
+++ b/handlers/getGuildSearch.go
@@ -6,6 +6,7 @@ import (
 
 	"bdo-rest-api/cache"
 	"bdo-rest-api/scraper"
+	"bdo-rest-api/utils"
 	"bdo-rest-api/validators"
 )
 
@@ -22,17 +23,20 @@ func getGuildSearch(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if data, status, date, expires, ok := cache.GuildSearch.GetRecord([]string{region, name}); ok {
-		w.Header().Set("Expires", expires)
-		w.Header().Set("Last-Modified", date)
+	bypassCache := validators.ValidateBypassCacheQueryParam(r.URL.Query()["bypassCache"])
+	if !bypassCache || !utils.CheckAdminToken(r) {
+		if data, status, date, expires, ok := cache.GuildSearch.GetRecord([]string{region, name}); !bypassCache && ok {
+			w.Header().Set("Expires", expires)
+			w.Header().Set("Last-Modified", date)
 
-		if status == http.StatusOK {
-			json.NewEncoder(w).Encode(data)
-		} else {
-			w.WriteHeader(status)
-		}
+			if status == http.StatusOK {
+				json.NewEncoder(w).Encode(data)
+			} else {
+				w.WriteHeader(status)
+			}
 
-		return
+			return
+		}
 	}
 
 	if ok := giveMaintenanceResponse(w, region); ok {
diff --git a/validators/ValidateBypassCacheQueryParam.go b/validators/ValidateBypassCacheQueryParam.go
new file mode 100644
index 0000000..57fdd30
--- /dev/null
+++ b/validators/ValidateBypassCacheQueryParam.go
@@ -0,0 +1,5 @@
+package validators
+
+func ValidateBypassCacheQueryParam(query []string) (bypassCache bool) {
+	return len(query) > 0 && query[0] == "1"
+}

From 108534372230db299525ded7102b3cb6c2bc0e4c Mon Sep 17 00:00:00 2001
From: man90 <man90@tuta.io>
Date: Fri, 21 Nov 2025 22:41:35 +0100
Subject: [PATCH 3/3] Bump version number

---
 handlers/getStatus.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/handlers/getStatus.go b/handlers/getStatus.go
index 0e916d2..4dcb5f9 100644
--- a/handlers/getStatus.go
+++ b/handlers/getStatus.go
@@ -12,7 +12,7 @@ import (
 )
 
 var initTime = time.Now()
-var version = "1.16.0"
+var version = "1.17.0"
 
 func getStatus(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(map[string]interface{}{
