From 8d08de6d9c677f808997c928a3e1aef5e82af99f Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Thu, 31 Jul 2025 08:44:49 -0400 Subject: [PATCH] fix: allow social preview images (#934) * feat(ogtags): when encountering opengraph URLs, add them to an allow cache Signed-off-by: Xe Iaso * feat(lib): automatically allow any urls in the ogtags allow cache Signed-off-by: Xe Iaso * docs: update CHANGELOG Signed-off-by: Xe Iaso * chore: spelling Signed-off-by: Xe Iaso * docs(changelog): remove this bit to make it its own PR Signed-off-by: Xe Iaso * test(palemoon): add 180 second timeout Signed-off-by: Xe Iaso * test(palemoon): actually invoke timeout Signed-off-by: Xe Iaso --------- Signed-off-by: Xe Iaso --- .github/actions/spelling/expect.txt | 2 +- docs/docs/CHANGELOG.md | 1 + internal/ogtags/cache.go | 14 ++++++++++++++ internal/ogtags/cache_test.go | 9 ++++++++- lib/anubis.go | 6 ++++++ test/palemoon/amd64/test.sh | 6 ++++++ 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 78e9ded..d89fff5 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -204,7 +204,7 @@ nobots NONINFRINGEMENT nosleep OCOB -ogtags +ogtag omgili omgilibot openai diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index e9e8da4..19a59f3 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Custom-AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client)'s default User-Agent has an increased weight by default ([#852](https://github.com/TecharoHQ/anubis/issues/852)). - The [`segments`](./admin/configuration/expressions.mdx#segments) function was added for splitting a path into its slash-separated segments. - When issuing a challenge, Anubis stores information about that challenge into the store. That stored information is later used to validate challenge responses. This works around nondeterminism in bot rules. ([#917](https://github.com/TecharoHQ/anubis/issues/917)) +- When parsing [Open Graph tags](./admin/configuration/open-graph.mdx), add any URLs found in the responses to a temporary "allow cache" so that social preview images work. ## v1.21.3: Minfilia Warde - Echo 3 diff --git a/internal/ogtags/cache.go b/internal/ogtags/cache.go index 40b7444..838d016 100644 --- a/internal/ogtags/cache.go +++ b/internal/ogtags/cache.go @@ -5,7 +5,9 @@ import ( "errors" "log/slog" "net/url" + "strings" "syscall" + "time" ) // GetOGTags is the main function that retrieves Open Graph tags for a URL @@ -45,6 +47,18 @@ func (c *OGTagCache) GetOGTags(ctx context.Context, url *url.URL, originalHost s // Store in cache c.cache.Set(ctx, cacheKey, ogTags, c.ogTimeToLive) + for k, v := range ogTags { + switch { + case strings.HasSuffix(k, "image"), strings.HasSuffix(k, "audio"), strings.HasSuffix(k, "secure_url"), strings.HasSuffix(k, "video"): + v, _ = strings.CutPrefix(v, "http://") + v, _ = strings.CutPrefix(v, "https://") + slog.Debug("setting ogtags allow for", "url", k) + if err := c.cache.Underlying.Set(ctx, "ogtags:allow:"+v, []byte(k), time.Hour); err != nil { + slog.Debug("can't set ogtag allow cache", "err", err) + } + } + } + return ogTags, nil } diff --git a/internal/ogtags/cache_test.go b/internal/ogtags/cache_test.go index 7efd497..08bf4e3 100644 --- a/internal/ogtags/cache_test.go +++ b/internal/ogtags/cache_test.go @@ -1,6 +1,7 @@ package ogtags import ( + "errors" "net/http" "net/http/httptest" "net/url" @@ -9,6 +10,7 @@ import ( "time" "github.com/TecharoHQ/anubis/lib/policy/config" + "github.com/TecharoHQ/anubis/lib/store" "github.com/TecharoHQ/anubis/lib/store/memory" ) @@ -166,8 +168,13 @@ func TestGetOGTags(t *testing.T) { if !ok || initialValue != cachedValue { t.Errorf("Cache does not line up: expected %s: %s, got: %s", key, initialValue, cachedValue) } - } + + t.Run("ensure image is cached as allow", func(t *testing.T) { + if _, err := cache.cache.Underlying.Get(t.Context(), "ogtags:allow:example.com/image.jpg"); errors.Is(err, store.ErrNotFound) { + t.Fatal("ogtags allow caching for example.com/image.jpg did not work") + } + }) } // TestGetOGTagsWithHostConsideration tests the behavior of the cache with and without host consideration and for multiple hosts in a theoretical setup. diff --git a/lib/anubis.go b/lib/anubis.go index 790985f..b9eba5f 100644 --- a/lib/anubis.go +++ b/lib/anubis.go @@ -153,6 +153,12 @@ func (s *Server) maybeReverseProxyOrPage(w http.ResponseWriter, r *http.Request) func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request, httpStatusOnly bool) { lg := internal.GetRequestLogger(s.logger, r) + if val, _ := s.store.Get(r.Context(), fmt.Sprintf("ogtags:allow:%s%s", r.Host, r.URL.String())); val != nil { + lg.Debug("serving opengraph tag asset") + s.ServeHTTPNext(w, r) + return + } + // Adjust cookie path if base prefix is not empty cookiePath := "/" if anubis.BasePrefix != "" { diff --git a/test/palemoon/amd64/test.sh b/test/palemoon/amd64/test.sh index dc093cc..3a0ccbe 100755 --- a/test/palemoon/amd64/test.sh +++ b/test/palemoon/amd64/test.sh @@ -13,6 +13,11 @@ function capture_vnc_snapshots() { done } +function timeout() { + sleep 180 + exit 1 +} + source ../../lib/lib.sh if [ "$GITHUB_ACTIONS" = "true" ]; then @@ -24,6 +29,7 @@ set -euo pipefail build_anubis_ko mint_cert relayd +timeout & go run ../../cmd/cipra/ --compose-name $(basename $(pwd)) docker compose down -t 1 || :