Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
pkg-proxy/internal/server/hosted_auth.go
simon chrzanowski ea696a7abc
Add a hosted config block and a bearer token check for writes
hosted.enabled turns on pushing packages to the proxy and is off by default, like mirror_api. A pushed version is served in place of the upstream version with the same number, so anyone who can write could swap a package for every client. Enabling it therefore requires hosted.token, which supports ${VAR_NAME} expansion and can be set with PROXY_HOSTED_TOKEN. hosted.max_upload_size caps one archive and defaults to 100MB.

requireBearerToken compares SHA-256 digests of the presented and configured tokens in constant time and answers 401 with a WWW-Authenticate challenge otherwise.

Refs #133
2026-10-14 13:23:19 +02:00

37 lines
1.1 KiB
Go

package server
import (
"crypto/sha256"
"crypto/subtle"
"net/http"
"strings"
)
const bearerScheme = "bearer "
// requireBearerToken rejects requests that do not carry
// "Authorization: Bearer <token>". Both tokens are hashed before comparing so
// the check takes the same time whatever the length of the presented token.
func requireBearerToken(token string) func(http.Handler) http.Handler {
want := sha256.Sum256([]byte(token))
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
presented, ok := bearerToken(r)
got := sha256.Sum256([]byte(presented))
if !ok || subtle.ConstantTimeCompare(got[:], want[:]) != 1 {
w.Header().Set("WWW-Authenticate", `Bearer realm="proxy"`)
writeError(w, http.StatusUnauthorized, ErrCodeUnauthorized, "a valid bearer token is required")
return
}
next.ServeHTTP(w, r)
})
}
}
func bearerToken(r *http.Request) (string, bool) {
header := r.Header.Get("Authorization")
if len(header) <= len(bearerScheme) || !strings.EqualFold(header[:len(bearerScheme)], bearerScheme) {
return "", false
}
return header[len(bearerScheme):], true
}