diff --git a/README.md b/README.md index 2ac1abe..e11efbf 100644 --- a/README.md +++ b/README.md @@ -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://./`, a *matching* clone URL is computed by templating `[[wildcard]].clone-url` with `` and ``, where `` is computed by templating each element of `[[wildcard]].index-repos` with ``, and `[[wildcard]]` is the section where the match occurred. - **Project repository:** If the request URL is `scheme://.//`, a *matching* clone URL is computed by templating `[[wildcard]].clone-url` with `` and ``, 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: diff --git a/src/auth.go b/src/auth.go index eb9ad2f..b3b5f3a 100644 --- a/src/auth.go +++ b/src/auth.go @@ -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 { diff --git a/src/pages.go b/src/pages.go index 12ac700..c1147f3 100644 --- a/src/pages.go +++ b/src/pages.go @@ -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 }