mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-05-24 17:01:31 +00:00
45 lines
1.3 KiB
Go
45 lines
1.3 KiB
Go
package testpds
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// signServiceAuthJWT mints a JWT in the shape Hold expects, signed with the
|
|
// identity's K-256 signing key. The header advertises ES256K (the algorithm
|
|
// ATProto PDSes use). The Hold's ValidateServiceToken in pkg/hold/pds/auth.go
|
|
// parses the JWT manually rather than via golang-jwt, so we don't need to
|
|
// match golang-jwt's exact byte ordering — just produce well-formed
|
|
// base64url(JSON).header.base64url(JSON).payload.base64url(sig).
|
|
func (i *Identity) signServiceAuthJWT(aud, lxm string, exp time.Time) (string, error) {
|
|
header := map[string]string{"alg": "ES256K", "typ": "JWT"}
|
|
headerJSON, err := json.Marshal(header)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal header: %w", err)
|
|
}
|
|
|
|
payload := map[string]any{
|
|
"iss": i.DID.String(),
|
|
"aud": aud,
|
|
"exp": exp.Unix(),
|
|
"lxm": lxm,
|
|
"iat": time.Now().Unix(),
|
|
}
|
|
payloadJSON, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal payload: %w", err)
|
|
}
|
|
|
|
signingInput := base64.RawURLEncoding.EncodeToString(headerJSON) + "." +
|
|
base64.RawURLEncoding.EncodeToString(payloadJSON)
|
|
|
|
sig, err := i.SigningKey.HashAndSign([]byte(signingInput))
|
|
if err != nil {
|
|
return "", fmt.Errorf("sign: %w", err)
|
|
}
|
|
|
|
return signingInput + "." + base64.RawURLEncoding.EncodeToString(sig), nil
|
|
}
|