From a98b8a86d714dee4ebcb840a5c8661f28ca2c52d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 15 Jan 2025 16:59:13 -0700 Subject: [PATCH] Update for latest worker thinking --- api/_responses/redirect.go | 15 +++++++++++---- api/_routers/98-use-rcontext.go | 3 ++- api/custom/byid.go | 29 ++++++++++++++++++++++++++--- api/routes.go | 2 +- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/api/_responses/redirect.go b/api/_responses/redirect.go index 13a7303d..a5451d23 100644 --- a/api/_responses/redirect.go +++ b/api/_responses/redirect.go @@ -2,7 +2,7 @@ package _responses import ( "crypto/hmac" - "crypto/sha256" + "crypto/sha512" "encoding/hex" "net/url" "strconv" @@ -27,7 +27,14 @@ func Redirect(ctx rcontext.RequestContext, toUrl string, auth _apimeta.AuthConte } // Append the expiration time to the URL - toUrl = appendQueryParam(toUrl, "matrix_exp", strconv.FormatInt(expirationTime.UnixMilli(), 10)) + toUrl = appendQueryParam(toUrl, "exp", strconv.FormatInt(expirationTime.UnixMilli(), 10)) + + // Append a value we expect to survive the round trip that only we know about + // We do this after the expiration value to cover that field as well. + mac := hmac.New(sha512.New, []byte("THIS IS ANOTHER SECRET VALUE")) // TODO: @@ Actual secret key + mac.Write([]byte(toUrl)) + requestHmac := mac.Sum(nil) + toUrl = appendQueryParam(toUrl, "request", hex.EncodeToString(requestHmac)+"."+hex.EncodeToString([]byte(toUrl))) // Prepare our HMAC message contents as a JSON object hmacMessage := toUrl + "||" @@ -36,12 +43,12 @@ func Redirect(ctx rcontext.RequestContext, toUrl string, auth _apimeta.AuthConte } // Actually do the HMAC - mac := hmac.New(sha256.New, []byte("THIS_IS_A_SECRET_KEY")) // TODO: @@ Actual secret key + mac = hmac.New(sha512.New, []byte("THIS_IS_A_SECRET_KEY")) // TODO: @@ Actual secret key mac.Write([]byte(hmacMessage)) verifyHmac := mac.Sum(nil) // Append the HMAC to the URL - toUrl = appendQueryParam(toUrl, "matrix_verify", hex.EncodeToString(verifyHmac)) + toUrl = appendQueryParam(toUrl, "verify", hex.EncodeToString(verifyHmac)) } return &RedirectResponse{ToUrl: toUrl} } diff --git a/api/_routers/98-use-rcontext.go b/api/_routers/98-use-rcontext.go index 07523153..5bf49a22 100644 --- a/api/_routers/98-use-rcontext.go +++ b/api/_routers/98-use-rcontext.go @@ -129,7 +129,8 @@ beforeParseDownload: } if shouldCache { - headers.Set("Cache-Control", "private, max-age=259200") // 3 days + // TODO: @@ Only set `public` for CDNs, otherwise use `private` + headers.Set("Cache-Control", "public, max-age=259200") // 3 days } if downloadRes.SizeBytes > 0 { diff --git a/api/custom/byid.go b/api/custom/byid.go index 8b64f25f..770395e8 100644 --- a/api/custom/byid.go +++ b/api/custom/byid.go @@ -1,7 +1,11 @@ package custom import ( + "crypto/hmac" + "crypto/sha512" + "encoding/hex" "net/http" + "strings" "github.com/t2bot/matrix-media-repo/api/_apimeta" "github.com/t2bot/matrix-media-repo/api/_responses" @@ -13,12 +17,31 @@ import ( ) func GetMediaById(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { - if !user.IsShared { - return _responses.AuthFailed() - } + //if !user.IsShared { + // return _responses.AuthFailed() + //} // TODO: This is beyond dangerous and needs proper filtering + requestVal := r.URL.Query().Get("request") + requestValParts := strings.Split(requestVal, ".") + if len(requestValParts) != 2 { + return _responses.AuthFailed() + } + verifyMac := requestValParts[0] + toUrlB, err := hex.DecodeString(requestValParts[1]) + if err != nil { + rctx.Log.Error("Failed to decode request value: %s", err) + return _responses.AuthFailed() + } + toUrl := string(toUrlB) + mac := hmac.New(sha512.New, []byte("THIS IS ANOTHER SECRET VALUE")) // TODO: @@ Actual secret key + mac.Write([]byte(toUrl)) + expectedMac := hex.EncodeToString(mac.Sum(nil)) + if strings.ToLower(verifyMac) != strings.ToLower(expectedMac) { + return _responses.AuthFailed() + } + db := database.GetInstance().Media.Prepare(rctx) ds, err := datastores.Pick(rctx, datastores.LocalMediaKind) if err != nil { diff --git a/api/routes.go b/api/routes.go index affcd8ef..f1dad9cd 100644 --- a/api/routes.go +++ b/api/routes.go @@ -62,7 +62,7 @@ func buildRoutes() http.Handler { purgeOneRoute := makeRoute(_routers.RequireAccessToken(custom.PurgeIndividualRecord, false), "purge_individual_media", counter) register([]string{"DELETE"}, PrefixMedia, "download/:server/:mediaId", mxUnstable, router, purgeOneRoute) register([]string{"GET"}, PrefixMedia, "usage", msc4034, router, makeRoute(_routers.RequireAccessToken(unstable.PublicUsage, false), "usage", counter)) - register([]string{"GET"}, PrefixMMR, "byid/:objectId", mxNoVersion, router, makeRoute(_routers.RequireRepoAdmin(custom.GetMediaById), "byid", counter)) + register([]string{"GET"}, PrefixMMR, "byid/:objectId", mxNoVersion, router, makeRoute(_routers.OptionalAccessToken(custom.GetMediaById), "byid", counter)) // Custom and top-level features router.Handler("GET", fmt.Sprintf("%s/version", PrefixMedia), makeRoute(_routers.OptionalAccessToken(custom.GetVersion), "get_version", counter))