package handlers import ( "errors" "net/http" "time" "github.com/go-chi/chi/v5" "sneak.berlin/go/pixa/internal/encurl" "sneak.berlin/go/pixa/internal/imagerequest" ) // HandleImageEnc handles requests to /v1/e/{token}/* for encrypted // image URLs. The trailing path (e.g., /img.jpg) is ignored but helps // browsers identify the content type. func (s *Handlers) HandleImageEnc() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if s.refuseBlockedReferer(w, r) { return } req, expires, ok := s.parseImageEncRequest(w, r) if !ok { return } s.serveImage(w, r, req, expires) } } // parseImageEncRequest decrypts the token of an encrypted image URL into an // image request and checks it, and returns it with the token's expiry. On a // token that is missing, does not decrypt, has expired or asks for something // not valid, it writes an error response and returns false. func (s *Handlers) parseImageEncRequest( w http.ResponseWriter, r *http.Request, ) (*imagerequest.Request, time.Time, bool) { // Extract token from URL token := chi.URLParam(r, "token") if token == "" { s.respondError(w, "missing token", http.StatusBadRequest) return nil, time.Time{}, false } // Decrypt and validate the payload req, expires, err := s.encGen.Parse(token) if err != nil { if errors.Is(err, encurl.ErrExpired) { s.log.Debug("encrypted URL expired", "error", err) s.respondError(w, "URL has expired", http.StatusGone) return nil, time.Time{}, false } s.log.Debug("invalid encrypted URL", "error", err) s.respondError(w, "invalid encrypted URL", http.StatusBadRequest) return nil, time.Time{}, false } // Apply the same dimension and fit-mode bounds as the plain image // route: a sealed payload is trusted for its origin, not for staying // within limits. This refuses an over-limit size before the source is // fetched. An unknown fit mode is a 400 here rather than a 500 from the // processor. err = imagerequest.ValidateImageRequest(req) if err != nil { s.log.Debug("encrypted URL failed validation", "error", err) s.respondError(w, "invalid encrypted URL: "+err.Error(), http.StatusBadRequest) return nil, time.Time{}, false } return req, expires, true }