mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-24 19:24:16 +00:00
use hyphens as the encode for dids
This commit is contained in:
@@ -299,6 +299,13 @@ func (nr *NamespaceResolver) Repository(ctx context.Context, name reference.Name
|
||||
identityStr := parts[0]
|
||||
imageName := parts[1]
|
||||
|
||||
// Support hyphen-encoded DIDs in image paths (e.g., did-plc-abc123/repo:tag)
|
||||
// OCI reference grammar doesn't allow colons in path components, so DIDs must
|
||||
// be encoded with hyphens instead: did:plc:abc123 → did-plc-abc123
|
||||
if decoded, ok := token.DecodeDIDFromHyphens(identityStr); ok {
|
||||
identityStr = decoded
|
||||
}
|
||||
|
||||
// Resolve identity to DID, handle, and PDS endpoint
|
||||
did, handle, pdsEndpoint, err := atproto.ResolveIdentity(ctx, identityStr)
|
||||
if err != nil {
|
||||
|
||||
+20
-14
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -277,18 +276,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// parseBasicAuthDID fixes DID usernames that are mangled by HTTP Basic Auth.
|
||||
// Basic Auth splits on the first colon, so "did:plc:abc123" as a username
|
||||
// produces username="did" and the rest gets prepended to the password.
|
||||
//
|
||||
// This handles two cases:
|
||||
// 1. URL-encoded DIDs (did%3Aplc%3Aabc123) — decoded back to did:plc:abc123
|
||||
// 2. Raw DIDs — reconstructed from the mangled username + password
|
||||
// 1. Hyphen-encoded DIDs (did-plc-abc123) — converted to did:plc:abc123.
|
||||
// This is the recommended format for tools like helm that reject colons in usernames.
|
||||
// 2. Raw DIDs split by BasicAuth — "did:plc:abc123" gets split on the first colon
|
||||
// into username="did", password="plc:abc123:<real-password>". Reconstructed here.
|
||||
func parseBasicAuthDID(username, password string) (string, string) {
|
||||
// Case 1: URL-encoded DID (e.g., did%3Aplc%3Aabc123)
|
||||
if decoded, err := url.QueryUnescape(username); err == nil && decoded != username {
|
||||
if strings.HasPrefix(decoded, "did:") {
|
||||
return decoded, password
|
||||
}
|
||||
// Case 1: Hyphen-encoded DID (e.g., did-plc-abc123 or did-web-example.com)
|
||||
if did, ok := DecodeDIDFromHyphens(username); ok {
|
||||
return did, password
|
||||
}
|
||||
|
||||
// Case 2: Raw DID was split by BasicAuth on the first colon
|
||||
@@ -298,15 +295,11 @@ func parseBasicAuthDID(username, password string) (string, string) {
|
||||
}
|
||||
|
||||
if strings.HasPrefix(password, "plc:") {
|
||||
// did:plc:<base32-id> — the ID is a single segment (no colons)
|
||||
// password = "plc:<id>:<real-password>"
|
||||
rest := strings.TrimPrefix(password, "plc:")
|
||||
if idx := strings.Index(rest, ":"); idx > 0 {
|
||||
return "did:plc:" + rest[:idx], rest[idx+1:]
|
||||
}
|
||||
} else if strings.HasPrefix(password, "web:") {
|
||||
// did:web:<hostname> — hostname uses dots not colons
|
||||
// password = "web:<hostname>:<real-password>"
|
||||
rest := strings.TrimPrefix(password, "web:")
|
||||
if idx := strings.Index(rest, ":"); idx > 0 {
|
||||
return "did:web:" + rest[:idx], rest[idx+1:]
|
||||
@@ -315,3 +308,16 @@ func parseBasicAuthDID(username, password string) (string, string) {
|
||||
|
||||
return username, password
|
||||
}
|
||||
|
||||
// DecodeDIDFromHyphens converts a hyphen-encoded DID back to colon-separated form.
|
||||
// "did-plc-abc123" → "did:plc:abc123", "did-web-example.com" → "did:web:example.com"
|
||||
// Returns the decoded DID and true if the input matched, or ("", false) otherwise.
|
||||
func DecodeDIDFromHyphens(s string) (string, bool) {
|
||||
if strings.HasPrefix(s, "did-plc-") {
|
||||
return "did:plc:" + strings.TrimPrefix(s, "did-plc-"), true
|
||||
}
|
||||
if strings.HasPrefix(s, "did-web-") {
|
||||
return "did:web:" + strings.TrimPrefix(s, "did-web-"), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
@@ -659,15 +659,15 @@ func TestParseBasicAuthDID(t *testing.T) {
|
||||
wantPassword: "mypassword",
|
||||
},
|
||||
{
|
||||
name: "URL-encoded did:plc",
|
||||
username: "did%3Aplc%3Aabc123",
|
||||
name: "hyphen-encoded did:plc",
|
||||
username: "did-plc-abc123",
|
||||
password: "mypassword",
|
||||
wantUsername: "did:plc:abc123",
|
||||
wantPassword: "mypassword",
|
||||
},
|
||||
{
|
||||
name: "URL-encoded did:web",
|
||||
username: "did%3Aweb%3Aexample.com",
|
||||
name: "hyphen-encoded did:web",
|
||||
username: "did-web-example.com",
|
||||
password: "mypassword",
|
||||
wantUsername: "did:web:example.com",
|
||||
wantPassword: "mypassword",
|
||||
|
||||
Reference in New Issue
Block a user