From b7bee75e1f1c7cc023ea1833334179f3e0425aa1 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sun, 13 Oct 2024 19:50:11 -0700 Subject: [PATCH] Function to re-sign photo URLs on profile pages * With the new JWT signatures on photo URLs, it was no longer possible for creative users to embed their gallery photos on their profile page. * Add a function to ReSignPhotoLinks that finds/replaces (on the server side) all references to paths under "/static/photos/" and gives them a fresh ?jwt= query string signature. * Note: only applies to the profile page essays, ReSignPhotoLinks is a template func that must be opted-in on a per page basis. Other miscellaneous fixes * Add "Edit" buttons in the corners of profile cards, when the current user looks at their profile page. They link to URIs like "/settings#profile/about_me" which will now: 1. Select the "Profile settings" tab like #profile 2. Scroll and focus the profile essay field that the user clicked to edit. --- pkg/config/config.go | 4 ++ pkg/photo/photosign.go | 25 +++++++++++++ pkg/templates/template_funcs.go | 8 ++++ web/templates/account/profile.html | 57 +++++++++++++++++++++++------ web/templates/account/settings.html | 17 +++++---- 5 files changed, 91 insertions(+), 20 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index edb7fb3..270408e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -25,6 +25,10 @@ const ( PhotoDiskPath = "./web/static/photos" ) +// PhotoURLRegexp describes an image path under "/static/photos" that can be parsed from Markdown or HTML input. +// It is used by e.g. the ReSignURLs function - if you move image URLs to a CDN this may need updating. +var PhotoURLRegexp = regexp.MustCompile(`(?:['"])(/static/photos/[^'"\s?]+(?:\?[^'"\s]*)?)(?:['"]|[^'"\s]*)`) + // Security const ( BcryptCost = 14 diff --git a/pkg/photo/photosign.go b/pkg/photo/photosign.go index 9d62d8c..c1ea8a1 100644 --- a/pkg/photo/photosign.go +++ b/pkg/photo/photosign.go @@ -1,6 +1,7 @@ package photo import ( + "strings" "time" "code.nonshy.com/nonshy/website/pkg/config" @@ -28,6 +29,30 @@ func VisibleAvatarURL(user, currentUser *models.User) string { return "/static/img/shy.png" } +// ReSignPhotoLinks will search a blob of text for photo gallery links ("/static/photos/*") and re-sign +// their JWT security tokens. +func ReSignPhotoLinks(currentUser *models.User, text string) string { + var matches = config.PhotoURLRegexp.FindAllStringSubmatch(text, -1) + for _, m := range matches { + var ( + origString = m[0] + url = m[1] + filename string + ) + log.Error("ReSignPhotoLinks: got [%s] url [%s]", origString, url) + + // Trim the /static/photos/ prefix off to get the URL down to its base filename. + filename = strings.Split(url, "?")[0] + filename = strings.TrimPrefix(filename, config.PhotoWebPath) + filename = strings.TrimPrefix(filename, "/") + + // Sign the URL and replace the original. + signed := SignedPhotoURL(currentUser, filename) + text = strings.ReplaceAll(text, origString, signed) + } + return text +} + // SignedPhotoURL returns a URL path to a photo's filename, signed for the current user only. func SignedPhotoURL(user *models.User, filename string) string { return createSignedPhotoURL(user.ID, user.Username, filename, false) diff --git a/pkg/templates/template_funcs.go b/pkg/templates/template_funcs.go index fa2eb0b..80dd9d4 100644 --- a/pkg/templates/template_funcs.go +++ b/pkg/templates/template_funcs.go @@ -71,6 +71,14 @@ func TemplateFuncs(r *http.Request) template.FuncMap { // Get a description for an admin scope (e.g. for transparency page). "AdminScopeDescription": config.AdminScopeDescription, + + // "ReSignPhotoLinks": photo.ReSignPhotoLinks, + "ReSignPhotoLinks": func(s template.HTML) template.HTML { + if currentUser, err := session.CurrentUser(r); err == nil { + return template.HTML(photo.ReSignPhotoLinks(currentUser, string(s))) + } + return s + }, } } diff --git a/web/templates/account/profile.html b/web/templates/account/profile.html index b306f6f..d52e293 100644 --- a/web/templates/account/profile.html +++ b/web/templates/account/profile.html @@ -314,42 +314,75 @@
- {{or (ToMarkdown (.User.GetProfileField "about_me")) "n/a"}} + {{or (ReSignPhotoLinks (ToMarkdown (.User.GetProfileField "about_me"))) "n/a"}}
- {{or (ToMarkdown (.User.GetProfileField "interests")) "n/a"}} + {{or (ReSignPhotoLinks (ToMarkdown (.User.GetProfileField "interests"))) "n/a"}}
- {{or (ToMarkdown (.User.GetProfileField "music_movies")) "n/a"}} + {{or (ReSignPhotoLinks (ToMarkdown (.User.GetProfileField "music_movies"))) "n/a"}}
diff --git a/web/templates/account/settings.html b/web/templates/account/settings.html index b833302..b722943 100644 --- a/web/templates/account/settings.html +++ b/web/templates/account/settings.html @@ -307,7 +307,7 @@
-
+
-
+