A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
81
fork

Configure Feed

Select the types of activity you want to include in your feed.

use hyphens as the encode for dids

+31 -18
+7
pkg/appview/middleware/registry.go
··· 299 299 identityStr := parts[0] 300 300 imageName := parts[1] 301 301 302 + // Support hyphen-encoded DIDs in image paths (e.g., did-plc-abc123/repo:tag) 303 + // OCI reference grammar doesn't allow colons in path components, so DIDs must 304 + // be encoded with hyphens instead: did:plc:abc123 → did-plc-abc123 305 + if decoded, ok := token.DecodeDIDFromHyphens(identityStr); ok { 306 + identityStr = decoded 307 + } 308 + 302 309 // Resolve identity to DID, handle, and PDS endpoint 303 310 did, handle, pdsEndpoint, err := atproto.ResolveIdentity(ctx, identityStr) 304 311 if err != nil {
+20 -14
pkg/auth/token/handler.go
··· 6 6 "fmt" 7 7 "log/slog" 8 8 "net/http" 9 - "net/url" 10 9 "strings" 11 10 "time" 12 11 ··· 277 276 } 278 277 279 278 // parseBasicAuthDID fixes DID usernames that are mangled by HTTP Basic Auth. 280 - // Basic Auth splits on the first colon, so "did:plc:abc123" as a username 281 - // produces username="did" and the rest gets prepended to the password. 282 279 // 283 280 // This handles two cases: 284 - // 1. URL-encoded DIDs (did%3Aplc%3Aabc123) — decoded back to did:plc:abc123 285 - // 2. Raw DIDs — reconstructed from the mangled username + password 281 + // 1. Hyphen-encoded DIDs (did-plc-abc123) — converted to did:plc:abc123. 282 + // This is the recommended format for tools like helm that reject colons in usernames. 283 + // 2. Raw DIDs split by BasicAuth — "did:plc:abc123" gets split on the first colon 284 + // into username="did", password="plc:abc123:<real-password>". Reconstructed here. 286 285 func parseBasicAuthDID(username, password string) (string, string) { 287 - // Case 1: URL-encoded DID (e.g., did%3Aplc%3Aabc123) 288 - if decoded, err := url.QueryUnescape(username); err == nil && decoded != username { 289 - if strings.HasPrefix(decoded, "did:") { 290 - return decoded, password 291 - } 286 + // Case 1: Hyphen-encoded DID (e.g., did-plc-abc123 or did-web-example.com) 287 + if did, ok := DecodeDIDFromHyphens(username); ok { 288 + return did, password 292 289 } 293 290 294 291 // Case 2: Raw DID was split by BasicAuth on the first colon ··· 298 295 } 299 296 300 297 if strings.HasPrefix(password, "plc:") { 301 - // did:plc:<base32-id> — the ID is a single segment (no colons) 302 - // password = "plc:<id>:<real-password>" 303 298 rest := strings.TrimPrefix(password, "plc:") 304 299 if idx := strings.Index(rest, ":"); idx > 0 { 305 300 return "did:plc:" + rest[:idx], rest[idx+1:] 306 301 } 307 302 } else if strings.HasPrefix(password, "web:") { 308 - // did:web:<hostname> — hostname uses dots not colons 309 - // password = "web:<hostname>:<real-password>" 310 303 rest := strings.TrimPrefix(password, "web:") 311 304 if idx := strings.Index(rest, ":"); idx > 0 { 312 305 return "did:web:" + rest[:idx], rest[idx+1:] ··· 315 308 316 309 return username, password 317 310 } 311 + 312 + // DecodeDIDFromHyphens converts a hyphen-encoded DID back to colon-separated form. 313 + // "did-plc-abc123" → "did:plc:abc123", "did-web-example.com" → "did:web:example.com" 314 + // Returns the decoded DID and true if the input matched, or ("", false) otherwise. 315 + func DecodeDIDFromHyphens(s string) (string, bool) { 316 + if strings.HasPrefix(s, "did-plc-") { 317 + return "did:plc:" + strings.TrimPrefix(s, "did-plc-"), true 318 + } 319 + if strings.HasPrefix(s, "did-web-") { 320 + return "did:web:" + strings.TrimPrefix(s, "did-web-"), true 321 + } 322 + return "", false 323 + }
+4 -4
pkg/auth/token/handler_test.go
··· 659 659 wantPassword: "mypassword", 660 660 }, 661 661 { 662 - name: "URL-encoded did:plc", 663 - username: "did%3Aplc%3Aabc123", 662 + name: "hyphen-encoded did:plc", 663 + username: "did-plc-abc123", 664 664 password: "mypassword", 665 665 wantUsername: "did:plc:abc123", 666 666 wantPassword: "mypassword", 667 667 }, 668 668 { 669 - name: "URL-encoded did:web", 670 - username: "did%3Aweb%3Aexample.com", 669 + name: "hyphen-encoded did:web", 670 + username: "did-web-example.com", 671 671 password: "mypassword", 672 672 wantUsername: "did:web:example.com", 673 673 wantPassword: "mypassword",