Allow limiting maximum lifetime of preview sites.

This commit is contained in:
Catherine
2026-05-28 11:43:08 +00:00
parent a7063e00ef
commit 6f84e0f0d4
6 changed files with 52 additions and 29 deletions
+1
View File
@@ -16,6 +16,7 @@ clone-url = "https://codeberg.org/<user>/<project>.git"
index-repo = "pages"
index-repo-branch = "main"
authorization = "forgejo"
max-preview-lifetime = "7d"
[fallback] # non-default section
proxy-to = "https://codeberg.page"
+4
View File
@@ -11,6 +11,7 @@ import (
"path"
"slices"
"strings"
"time"
"golang.org/x/net/idna"
)
@@ -116,6 +117,8 @@ type Authorization struct {
branch string
// The authorized forge user.
forgeUser *ForgeUser
// If zero, any expiration is allowed. If not, site must expire no later than this time.
expiresNoLater time.Time
}
func (auth *Authorization) ForgeRepoURL() string {
@@ -671,6 +674,7 @@ func authorizeForgeWildcard(r *http.Request) (*Authorization, error) {
errs = append(errs, err)
} else {
auth.branch = branch
auth.expiresNoLater = time.Now().AddDate(0, 0, int(pattern.MaxPreviewLifetime))
return auth, nil
}
}
+7 -6
View File
@@ -79,12 +79,13 @@ type ServerConfig struct {
}
type WildcardConfig struct {
Domain string `toml:"domain"`
PreviewDomain string `toml:"preview-domain"`
CloneURL string `toml:"clone-url"` // URL template, not an exact URL
IndexRepo string `toml:"index-repo" default:"pages"`
IndexRepoBranch string `toml:"index-repo-branch" default:"pages"`
Authorization string `toml:"authorization"`
Domain string `toml:"domain"`
PreviewDomain string `toml:"preview-domain"`
CloneURL string `toml:"clone-url"` // URL template, not an exact URL
IndexRepo string `toml:"index-repo" default:"pages"`
IndexRepoBranch string `toml:"index-repo-branch" default:"pages"`
Authorization string `toml:"authorization"`
MaxPreviewLifetime uint `toml:"max-preview-lifetime"` // in days
}
type FallbackConfig struct {
+23 -11
View File
@@ -492,7 +492,9 @@ func checkDryRun(w http.ResponseWriter, r *http.Request) bool {
return false
}
func getUpdateOptions(w http.ResponseWriter, r *http.Request) (opts UpdateOptions, ok bool) {
func getUpdateOptions(
w http.ResponseWriter, r *http.Request, auth *Authorization,
) (opts UpdateOptions, ok bool) {
var err error
if config.Feature("expiration") {
@@ -507,6 +509,11 @@ func getUpdateOptions(w http.ResponseWriter, r *http.Request) (opts UpdateOption
return
}
}
if !auth.expiresNoLater.IsZero() {
if opts.expiresAt.IsZero() || opts.expiresAt.After(auth.expiresNoLater) {
opts.expiresAt = auth.expiresNoLater
}
}
}
ok = true
@@ -530,11 +537,6 @@ func putPage(w http.ResponseWriter, r *http.Request) error {
return err
}
opts, ok := getUpdateOptions(w, r)
if !ok {
return nil
}
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(config.Limits.UpdateTimeout))
defer cancel()
@@ -565,6 +567,11 @@ func putPage(w http.ResponseWriter, r *http.Request) error {
return err
}
opts, ok := getUpdateOptions(w, r, auth)
if !ok {
return nil
}
if checkDryRun(w, r) {
return nil
}
@@ -582,6 +589,11 @@ func putPage(w http.ResponseWriter, r *http.Request) error {
repoURL := auth.ForgeRepoURL()
opts, ok := getUpdateOptions(w, r, auth)
if !ok {
return nil
}
if checkDryRun(w, r) {
return nil
}
@@ -609,11 +621,6 @@ func patchPage(w http.ResponseWriter, r *http.Request) error {
return err
}
opts, ok := getUpdateOptions(w, r)
if !ok {
return nil
}
auth, err := AuthorizeUpdateFromArchive(r)
if err != nil {
return err
@@ -622,6 +629,11 @@ func patchPage(w http.ResponseWriter, r *http.Request) error {
principal := GetPrincipal(r.Context())
copyForgeAuthToPrincipal(principal, auth)
opts, ok := getUpdateOptions(w, r, auth)
if !ok {
return nil
}
if checkDryRun(w, r) {
return nil
}
+3
View File
@@ -100,6 +100,9 @@ func Update(
case UpdateNoChange:
status = "unchanged"
}
if newManifest.ExpiresAt != nil {
logc.Printf(ctx, "expire %s: at %s", webRoot, newManifest.ExpiresAt.AsTime())
}
if storedManifest.Commit != nil {
logc.Printf(ctx, "update %s ok: %s %s", webRoot, *storedManifest.Commit, status)
} else {
+14 -12
View File
@@ -9,12 +9,13 @@ import (
)
type WildcardPattern struct {
Domain []string
PreviewDomain []string
CloneURL *fasttemplate.Template
IndexRepo *fasttemplate.Template
IndexBranch string
Authorization bool
Domain []string
PreviewDomain []string
CloneURL *fasttemplate.Template
IndexRepo *fasttemplate.Template
IndexBranch string
Authorization bool
MaxPreviewLifetime uint
}
func (pattern *WildcardPattern) GetHost() string {
@@ -123,12 +124,13 @@ func TranslateWildcards(wildcardConfigs []WildcardConfig) ([]*WildcardPattern, e
}
wildcardPatterns = append(wildcardPatterns, &WildcardPattern{
Domain: strings.Split(wildcardConfig.Domain, "."),
PreviewDomain: strings.Split(wildcardConfig.PreviewDomain, "."),
CloneURL: cloneURLTemplate,
IndexRepo: indexRepoTemplate,
IndexBranch: indexRepoBranch,
Authorization: authorization,
Domain: strings.Split(wildcardConfig.Domain, "."),
PreviewDomain: strings.Split(wildcardConfig.PreviewDomain, "."),
CloneURL: cloneURLTemplate,
IndexRepo: indexRepoTemplate,
IndexBranch: indexRepoBranch,
Authorization: authorization,
MaxPreviewLifetime: wildcardConfig.MaxPreviewLifetime,
})
}
return wildcardPatterns, nil