From 812a19e12984733aa6b99fdc1f76785bd6ff9d76 Mon Sep 17 00:00:00 2001 From: Tueem Date: Fri, 23 Jan 2026 11:15:57 +0100 Subject: [PATCH 1/2] feat(auth): add token caching --- internal/database/tokendb.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/internal/database/tokendb.go b/internal/database/tokendb.go index cccdc16..40687e5 100644 --- a/internal/database/tokendb.go +++ b/internal/database/tokendb.go @@ -1,5 +1,9 @@ package database +import ( + "maps" +) + const TOKENTABLECREATE string = ` CREATE TABLE IF NOT EXISTS tokens ( name varchar(32) PRIMARY KEY NOT NULL, @@ -8,7 +12,9 @@ const TOKENTABLECREATE string = ` const INSERTTOKENSQL string = "INSERT INTO tokens VALUES (?, ?);" const DELETETOKENSQL string = "DELETE FROM tokens WHERE name = ?;" -const QUERYTOKENSQL string = "SELECT token FROM tokens;" +const QUERYTOKENSQL string = "SELECT * FROM tokens;" + +var tokenCache map[string]string = make(map[string]string) func InsertToken(name string, token string) error { _, err := database.Exec(INSERTTOKENSQL, name, token) @@ -20,6 +26,15 @@ func DeleteToken(name string) error { return err } +func ValidateTokenCache(token string) (bool, error) { + for v := range maps.Values(tokenCache) { + if token == v { + return true, nil + } + } + return ValidateToken(token) +} + func ValidateToken(token string) (bool, error) { result, err := database.Query(QUERYTOKENSQL) if err != nil { @@ -27,12 +42,14 @@ func ValidateToken(token string) (bool, error) { } defer result.Close() - var foundToken string + var name, foundToken string for result.Next() { - result.Scan(&token) + result.Scan(&name, &foundToken) + tokenCache[name] = foundToken if token == foundToken { return true, nil } } - return false, nil + err = result.Err() + return false, err } From e9a3e807ec7bb4839207929beee284b54911e2fd Mon Sep 17 00:00:00 2001 From: Tueem Date: Fri, 23 Jan 2026 11:17:58 +0100 Subject: [PATCH 2/2] feat(http): add server and auth middleware --- cmd/svg-templater/main.go | 16 ++++++++++++--- pkg/auth/authmiddleware.go | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 pkg/auth/authmiddleware.go diff --git a/cmd/svg-templater/main.go b/cmd/svg-templater/main.go index 878cd7c..d5dcb82 100644 --- a/cmd/svg-templater/main.go +++ b/cmd/svg-templater/main.go @@ -2,10 +2,13 @@ package main import ( "flag" + "fmt" "log" + "net/http" "tomatentum.net/svg-templater/internal/database" svgtemplater "tomatentum.net/svg-templater/internal/svg-templater" + "tomatentum.net/svg-templater/pkg/auth" ) var ( @@ -18,10 +21,11 @@ func main() { log.Fatal("Failed opening DB:\n", err) return } + defer database.Close() database.InitDB() prepareCommandLine() + prepareHTTP() handleCommandline() - defer database.Close() } func prepareCommandLine() { @@ -29,6 +33,12 @@ func prepareCommandLine() { flag.BoolVar(&deleteTokenFlag, "tokendel", false, "svg-templater --tokendel : Delete token with name") } +func prepareHTTP() { + http.HandleFunc("/", auth.AuthMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "You are authorized!") + }))) +} + func handleCommandline() { flag.Parse() if generateTokenFlag { @@ -36,7 +46,7 @@ func handleCommandline() { } else if deleteTokenFlag { svgtemplater.DeleteTokenCommand() } else { - log.Println("No commend provided!") - flag.PrintDefaults() + log.Println("Starting http server on :3000") + http.ListenAndServe(":3000", nil) } } diff --git a/pkg/auth/authmiddleware.go b/pkg/auth/authmiddleware.go new file mode 100644 index 0000000..10f95b1 --- /dev/null +++ b/pkg/auth/authmiddleware.go @@ -0,0 +1,40 @@ +package auth + +import ( + "log" + "net/http" + "strings" + + "tomatentum.net/svg-templater/internal/database" +) + +func AuthMiddleware(next http.Handler) http.HandlerFunc { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + valid, err := validateAuthHeader(r) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + log.Println("Database Query for token validation failed.\n", r) + return + } + + if valid { + next.ServeHTTP(w, r) + } else { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + }) +} + +// Accepts ("Authorization": "BEARER "), returns database error if query failed +func validateAuthHeader(r *http.Request) (bool, error) { + header := strings.Split(r.Header.Get("Authorization"), " ") + if len(header) < 2 { + return false, nil + } + token := header[1] + if len(strings.TrimSpace(token)) < 1 { + return false, nil + } + + return database.ValidateTokenCache(token) +}