From 2665ac1deeb44aa0b707163749e136bf682eb7c8 Mon Sep 17 00:00:00 2001 From: renjue Date: Wed, 24 Jun 2026 14:34:22 +0800 Subject: [PATCH] Fix image signed URLs ignoring updated public base URL. Resolve public_base_url at SignURL time so admin settings apply without restart. Co-authored-by: Cursor --- cmd/luminary/main.go | 4 ++-- internal/prediction/service.go | 9 ++++----- internal/storage/imagestore/store.go | 23 ++++++++++++++-------- internal/storage/imagestore/store_test.go | 24 +++++++++++++++++++++++ 4 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 internal/storage/imagestore/store_test.go diff --git a/cmd/luminary/main.go b/cmd/luminary/main.go index 4ff4c1f..6c18120 100644 --- a/cmd/luminary/main.go +++ b/cmd/luminary/main.go @@ -72,10 +72,10 @@ func main() { } return "http://" + a } - imgStore := imagestore.New(db.DB(), imageDir, publicURL(), rt.EncryptionKey(), rt.SignedURLTTL()) + imgStore := imagestore.New(db.DB(), imageDir, publicURL, rt.EncryptionKey(), rt.SignedURLTTL()) _ = imgStore.EnsureDir() - predSvc := prediction.NewService(db.DB(), memCache, imgStore, publicURL(), rt.PredictionWaitSeconds()) + predSvc := prediction.NewService(db.DB(), memCache, imgStore, rt.PredictionWaitSeconds()) gw := gateway.New(memCache, rt) mon := monitor.New(gw, memCache, db, rt) diff --git a/internal/prediction/service.go b/internal/prediction/service.go index becb807..b92e44e 100644 --- a/internal/prediction/service.go +++ b/internal/prediction/service.go @@ -24,20 +24,19 @@ type Service struct { db *gorm.DB cache *cache.Store images *imagestore.Store - hub *Hub - publicURL string - waitSec int64 + hub *Hub + waitSec int64 mu sync.Mutex running map[string]context.CancelFunc } -func NewService(db *gorm.DB, c *cache.Store, images *imagestore.Store, publicURL string, waitSec int64) *Service { +func NewService(db *gorm.DB, c *cache.Store, images *imagestore.Store, waitSec int64) *Service { if waitSec <= 0 { waitSec = 60 } return &Service{ db: db, cache: c, images: images, hub: NewHub(), - publicURL: strings.TrimRight(publicURL, "/"), waitSec: waitSec, + waitSec: waitSec, running: make(map[string]context.CancelFunc), } } diff --git a/internal/storage/imagestore/store.go b/internal/storage/imagestore/store.go index d3bd66e..83598c3 100644 --- a/internal/storage/imagestore/store.go +++ b/internal/storage/imagestore/store.go @@ -17,15 +17,22 @@ import ( ) type Store struct { - db *gorm.DB - baseDir string - signKey string - publicURL string - ttl time.Duration + db *gorm.DB + baseDir string + signKey string + publicURL func() string + ttl time.Duration } -func New(db *gorm.DB, baseDir, publicURL, signKey string, ttl time.Duration) *Store { - return &Store{db: db, baseDir: baseDir, publicURL: strings.TrimRight(publicURL, "/"), signKey: signKey, ttl: ttl} +func New(db *gorm.DB, baseDir string, publicURL func() string, signKey string, ttl time.Duration) *Store { + return &Store{db: db, baseDir: baseDir, publicURL: publicURL, signKey: signKey, ttl: ttl} +} + +func (s *Store) baseURL() string { + if s.publicURL == nil { + return "" + } + return strings.TrimRight(s.publicURL(), "/") } func (s *Store) EnsureDir() error { @@ -76,7 +83,7 @@ func (s *Store) ListByPrediction(predictionID string) ([]model.StoredImage, erro func (s *Store) SignURL(imageID string) string { exp := time.Now().Add(s.ttl).Unix() sig := s.sign(imageID, exp) - return fmt.Sprintf("%s/files/%s?exp=%d&sig=%s", s.publicURL, imageID, exp, sig) + return fmt.Sprintf("%s/files/%s?exp=%d&sig=%s", s.baseURL(), imageID, exp, sig) } func (s *Store) Verify(imageID string, exp int64, sig string) bool { diff --git a/internal/storage/imagestore/store_test.go b/internal/storage/imagestore/store_test.go new file mode 100644 index 0000000..6748900 --- /dev/null +++ b/internal/storage/imagestore/store_test.go @@ -0,0 +1,24 @@ +package imagestore + +import ( + "testing" + "time" +) + +func TestSignURLUsesDynamicPublicBase(t *testing.T) { + current := "http://localhost:8293" + store := New(nil, t.TempDir(), func() string { return current }, "test-key", time.Hour) + + if got := store.SignURL("img-1"); !hasPrefix(got, "http://localhost:8293/files/img-1") { + t.Fatalf("unexpected url: %s", got) + } + + current = "https://gateway.example.com" + if got := store.SignURL("img-2"); !hasPrefix(got, "https://gateway.example.com/files/img-2") { + t.Fatalf("expected updated base url, got: %s", got) + } +} + +func hasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[:len(prefix)] == prefix +}