From 1b3219f164f7157cbcf90a9bc084c4b694e28dbe Mon Sep 17 00:00:00 2001 From: Mitchell Macpherson Date: Thu, 25 Jan 2024 15:29:30 +1100 Subject: [PATCH] fix: JWT Signing key will use hashed Discord App Client ID to prevent breaking on server reboot --- hash.go | 24 ++++++++++++++++++++++++ module_app.go | 9 +++++++-- module_callback.go | 2 ++ module_entrypoint.go | 2 ++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 hash.go diff --git a/hash.go b/hash.go new file mode 100644 index 0000000..5939772 --- /dev/null +++ b/hash.go @@ -0,0 +1,24 @@ +package caddydiscord + +import ( + "crypto/sha256" + "crypto/sha512" + "encoding/hex" +) + +func hashString512(input string) string { + hasher := sha512.New() + hasher.Write([]byte(input)) + return hex.EncodeToString(hasher.Sum(nil)) +} + +func hashString256(input string, length int) string { + hasher := sha256.New() + hasher.Write([]byte(input)) + fullHash := hex.EncodeToString(hasher.Sum(nil)) + + if length > len(fullHash) { + length = len(fullHash) + } + return fullHash[:length] +} diff --git a/module_app.go b/module_app.go index de75de7..2f5461a 100644 --- a/module_app.go +++ b/module_app.go @@ -1,7 +1,6 @@ package caddydiscord import ( - "encoding/hex" "fmt" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" @@ -31,6 +30,7 @@ type DiscordPortalApp struct { Realms RealmRegistry `json:"realms"` oauthConfig *oauth2.Config Key string `json:"key,omitempty"` + Signature string `json:"signature,omitempty"` } // CaddyModule returns the Caddy module information. @@ -42,7 +42,12 @@ func (DiscordPortalApp) CaddyModule() caddy.ModuleInfo { } func (d *DiscordPortalApp) Provision(_ caddy.Context) error { - d.Key = hex.EncodeToString(randomness(64)) + // Discord App ID is used as entropy for JWT signing keys. + d.Key = hashString512(d.ClientID) + + // TODO: Signature will be used for cookie integrity checks, to ensure checks are inline with most recent Caddyfile. + // TODOTODO: Use parsed caddyfile signature for checks, instead of just Discord App Client ID. + d.Signature = hashString256(d.ClientID, 16) return nil } diff --git a/module_callback.go b/module_callback.go index 1f0b2e9..74f9042 100644 --- a/module_callback.go +++ b/module_callback.go @@ -39,6 +39,7 @@ type DiscordAuthPlugin struct { Key string tokenSigner TokenSignerSignature flowTokenParser FlowTokenParserSignature + signature string } func (DiscordAuthPlugin) CaddyModule() caddy.ModuleInfo { @@ -62,6 +63,7 @@ func (s *DiscordAuthPlugin) Provision(ctx caddy.Context) error { s.tokenSigner = NewTokenSigner(key) s.flowTokenParser = NewFlowTokenParser(key) + s.signature = app.Signature return nil } diff --git a/module_entrypoint.go b/module_entrypoint.go index 8cac5c6..fec5d95 100644 --- a/module_entrypoint.go +++ b/module_entrypoint.go @@ -62,6 +62,8 @@ func (e ProtectorPlugin) Authenticate(w http.ResponseWriter, r *http.Request) (c q.Del("DISCO_REALM") r.URL.RawQuery = q.Encode() + // TODO: Expires should be reduced if authorisation failed. + cookie := &http.Cookie{ Name: fmt.Sprintf("%s_%s", cookieName, realm), Value: signedToken,