Add 'Never' expiry option for encrypted URLs
- Make ExpiresAt optional in CBOR (omitempty) for smaller tokens - Treat ExpiresAt=0 as 'never expires' in parser - URL-encode token with url.PathEscape() for safety - Add 'Never' as default TTL option in generator form
This commit is contained in:
@@ -40,7 +40,7 @@ type Payload struct {
|
|||||||
Format imgcache.ImageFormat `cbor:"f,omitempty"` // default: orig
|
Format imgcache.ImageFormat `cbor:"f,omitempty"` // default: orig
|
||||||
Quality int `cbor:"ql,omitempty"` // default: 85
|
Quality int `cbor:"ql,omitempty"` // default: 85
|
||||||
FitMode imgcache.FitMode `cbor:"fm,omitempty"` // default: cover
|
FitMode imgcache.FitMode `cbor:"fm,omitempty"` // default: cover
|
||||||
ExpiresAt int64 `cbor:"e"` // required, Unix timestamp
|
ExpiresAt int64 `cbor:"e,omitempty"` // 0 = never expires
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generator creates and parses encrypted URL tokens.
|
// Generator creates and parses encrypted URL tokens.
|
||||||
@@ -90,8 +90,8 @@ func (g *Generator) Parse(token string) (*Payload, error) {
|
|||||||
return nil, ErrInvalidFormat
|
return nil, ErrInvalidFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check expiration
|
// Check expiration (0 = never expires)
|
||||||
if time.Now().Unix() > p.ExpiresAt {
|
if p.ExpiresAt != 0 && time.Now().Unix() > p.ExpiresAt {
|
||||||
return nil, ErrExpired
|
return nil, ErrExpired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,12 +126,17 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
|
|||||||
quality = 85
|
quality = 85
|
||||||
}
|
}
|
||||||
|
|
||||||
if ttl <= 0 {
|
|
||||||
ttl = 2592000 // 30 days default
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create payload
|
// Create payload
|
||||||
expiresAt := time.Now().Add(time.Duration(ttl) * time.Second)
|
// ttl=0 means never expires
|
||||||
|
var expiresAt time.Time
|
||||||
|
var expiresAtUnix int64
|
||||||
|
|
||||||
|
if ttl > 0 {
|
||||||
|
expiresAt = time.Now().Add(time.Duration(ttl) * time.Second)
|
||||||
|
expiresAtUnix = expiresAt.Unix()
|
||||||
|
}
|
||||||
|
// else expiresAtUnix stays 0 (never expires)
|
||||||
|
|
||||||
payload := &encurl.Payload{
|
payload := &encurl.Payload{
|
||||||
SourceHost: parsed.Host,
|
SourceHost: parsed.Host,
|
||||||
SourcePath: parsed.Path,
|
SourcePath: parsed.Path,
|
||||||
@@ -141,7 +146,7 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
|
|||||||
Format: imgcache.ImageFormat(format),
|
Format: imgcache.ImageFormat(format),
|
||||||
Quality: quality,
|
Quality: quality,
|
||||||
FitMode: imgcache.FitMode(fit),
|
FitMode: imgcache.FitMode(fit),
|
||||||
ExpiresAt: expiresAt.Unix(),
|
ExpiresAt: expiresAtUnix,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate encrypted token
|
// Generate encrypted token
|
||||||
@@ -153,18 +158,24 @@ func (s *Handlers) HandleGenerateURL() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build full URL
|
// Build full URL (URL-encode the token for safety)
|
||||||
scheme := "https"
|
scheme := "https"
|
||||||
if s.config.Debug {
|
if s.config.Debug {
|
||||||
scheme = "http"
|
scheme = "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
host := r.Host
|
host := r.Host
|
||||||
generatedURL := scheme + "://" + host + "/v1/e/" + token
|
generatedURL := scheme + "://" + host + "/v1/e/" + url.PathEscape(token)
|
||||||
|
|
||||||
|
// Format expiry for display
|
||||||
|
expiresAtStr := "Never"
|
||||||
|
if ttl > 0 {
|
||||||
|
expiresAtStr = expiresAt.Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
|
||||||
s.renderGenerator(w, &generatorData{
|
s.renderGenerator(w, &generatorData{
|
||||||
GeneratedURL: generatedURL,
|
GeneratedURL: generatedURL,
|
||||||
ExpiresAt: expiresAt.Format(time.RFC3339),
|
ExpiresAt: expiresAtStr,
|
||||||
FormURL: sourceURL,
|
FormURL: sourceURL,
|
||||||
FormWidth: widthStr,
|
FormWidth: widthStr,
|
||||||
FormHeight: heightStr,
|
FormHeight: heightStr,
|
||||||
|
|||||||
Reference in New Issue
Block a user