Accept forge authorization for deleting a site.

This commit is contained in:
miyuko
2026-03-03 00:22:34 +00:00
parent c85c7327bf
commit 3e377986bc
3 changed files with 40 additions and 7 deletions

View File

@@ -117,7 +117,7 @@ The authorization flow for content updates (`PUT`, `PATCH`, `DELETE`, `POST` req
4. **Wildcard Match (content):** If the method is `POST`, and a `[[wildcard]]` configuration section exists where the suffix of a hostname (compared label-wise) is equal to `[[wildcard]].domain`, and (for `PUT` requests) the body contains a repository URL, and the requested clone URL is a *matching* clone URL, the request is authorized.
- **Index repository:** If the request URL is `scheme://<user>.<host>/`, a *matching* clone URL is computed by templating `[[wildcard]].clone-url` with `<user>` and `<project>`, where `<project>` is computed by templating each element of `[[wildcard]].index-repos` with `<user>`, and `[[wildcard]]` is the section where the match occurred.
- **Project repository:** If the request URL is `scheme://<user>.<host>/<project>/`, a *matching* clone URL is computed by templating `[[wildcard]].clone-url` with `<user>` and `<project>`, and `[[wildcard]]` is the section where the match occurred.
5. **Forge Authorization:** If the method is `PUT` or `PATCH`, and the body contains an archive, and a `[[wildcard]]` configuration section exists where the suffix of a hostname (compared label-wise) is equal to `[[wildcard]].domain`, and `[[wildcard]].authorization` is non-empty, and the request includes a `Forge-Authorization:` header, and the header (when forwarded as `Authorization:`) grants push permissions to a repository at the *matching* clone URL (as defined above) as determined by an API call to the forge, the request is authorized. (This enables publishing a site for a private repository.)
5. **Forge Authorization:** If the method is `PUT` or `PATCH` or `DELETE`, and (unless the method is `DELETE`) the body contains an archive, and a `[[wildcard]]` configuration section exists where the suffix of a hostname (compared label-wise) is equal to `[[wildcard]].domain`, and `[[wildcard]].authorization` is non-empty, and the request includes a `Forge-Authorization:` header, and the header (when forwarded as `Authorization:`) grants push permissions to a repository at the *matching* clone URL (as defined above) as determined by an API call to the forge, the request is authorized. (This enables publishing a site for a private repository.)
5. **Default Deny:** Otherwise, the request is not authorized.
The authorization flow for metadata retrieval (`GET` requests with site paths starting with `.git-pages/`) in the following order, with the first of multiple applicable rule taking precedence:

View File

@@ -390,9 +390,6 @@ func AuthorizeMetadataRetrieval(r *http.Request) (*Authorization, error) {
return nil, joinErrors(causes...)
}
// Returns `repoURLs, err` where if `err == nil` then the request is authorized to clone from
// any repository URL included in `repoURLs` (by case-insensitive comparison), or any URL at all
// if `repoURLs == nil`.
func AuthorizeUpdateFromRepository(r *http.Request) (*Authorization, error) {
causes := []error{AuthError{http.StatusUnauthorized, "unauthorized"}}
@@ -643,8 +640,9 @@ func authorizeForgeWithToken(r *http.Request) (*Authorization, error) {
continue
}
// This will actually be ignored by the caller of AuthorizeUpdateFromArchive,
// but we return this information as it makes sense to do contextually here.
// This will actually be ignored by the callers of AuthorizeUpdateFromArchive and
// AuthorizeDeletion, but we return this information as it makes sense to do
// contextually here.
return &Authorization{[]string{repoURL}, branch}, nil
}
}
@@ -696,6 +694,41 @@ func AuthorizeUpdateFromArchive(r *http.Request) (*Authorization, error) {
return nil, joinErrors(causes...)
}
func AuthorizeDeletion(r *http.Request) (*Authorization, error) {
causes := []error{AuthError{http.StatusUnauthorized, "unauthorized"}}
if err := CheckForbiddenDomain(r); err != nil {
return nil, err
}
auth := authorizeInsecure(r)
if auth != nil {
return auth, nil
}
auth, err := authorizeDNSChallenge(r)
if err != nil && IsUnauthorized(err) {
causes = append(causes, err)
} else if err != nil { // bad request
return nil, err
} else {
logc.Printf(r.Context(), "auth: DNS challenge: allow *\n")
return auth, nil
}
auth, err = authorizeForgeWithToken(r)
if err != nil && IsUnauthorized(err) {
causes = append(causes, err)
} else if err != nil { // bad request
return nil, err
} else {
logc.Printf(r.Context(), "auth: forge token: allow\n")
return auth, nil
}
return nil, joinErrors(causes...)
}
func CheckForbiddenDomain(r *http.Request) error {
host, err := GetHost(r)
if err != nil {

View File

@@ -661,7 +661,7 @@ func deletePage(w http.ResponseWriter, r *http.Request) error {
return err
}
_, err = AuthorizeUpdateFromRepository(r)
_, err = AuthorizeDeletion(r)
if err != nil {
return err
}