mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-30 14:05:35 +00:00
cleanup more auth
This commit is contained in:
+27
-18
@@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/bluesky-social/indigo/atproto/identity"
|
||||
"github.com/bluesky-social/indigo/atproto/syntax"
|
||||
"github.com/distribution/distribution/v3"
|
||||
registrymw "github.com/distribution/distribution/v3/registry/middleware/registry"
|
||||
"github.com/distribution/distribution/v3/registry/storage/driver"
|
||||
@@ -34,14 +36,15 @@ func init() {
|
||||
// NamespaceResolver wraps a namespace and resolves names
|
||||
type NamespaceResolver struct {
|
||||
distribution.Namespace
|
||||
resolver *atproto.Resolver
|
||||
directory identity.Directory
|
||||
defaultStorageEndpoint string
|
||||
repositories sync.Map // Cache of RoutingRepository instances by key (did:reponame)
|
||||
}
|
||||
|
||||
// initATProtoResolver initializes the name resolution middleware
|
||||
func initATProtoResolver(ctx context.Context, ns distribution.Namespace, _ driver.StorageDriver, options map[string]any) (distribution.Namespace, error) {
|
||||
resolver := atproto.NewResolver()
|
||||
// Use indigo's default directory (includes caching)
|
||||
directory := identity.DefaultDirectory()
|
||||
|
||||
// Get default storage endpoint from config (optional)
|
||||
defaultStorageEndpoint := ""
|
||||
@@ -51,7 +54,7 @@ func initATProtoResolver(ctx context.Context, ns distribution.Namespace, _ drive
|
||||
|
||||
return &NamespaceResolver{
|
||||
Namespace: ns,
|
||||
resolver: resolver,
|
||||
directory: directory,
|
||||
defaultStorageEndpoint: defaultStorageEndpoint,
|
||||
}, nil
|
||||
}
|
||||
@@ -70,21 +73,28 @@ func (nr *NamespaceResolver) Repository(ctx context.Context, name reference.Name
|
||||
return nil, fmt.Errorf("repository name must include user: %s", repoPath)
|
||||
}
|
||||
|
||||
identity := parts[0]
|
||||
identityStr := parts[0]
|
||||
imageName := parts[1]
|
||||
|
||||
// Resolve identity to DID and PDS
|
||||
did, pdsEndpoint, err := nr.resolver.ResolveIdentity(ctx, identity)
|
||||
// Parse identity (handle or DID)
|
||||
atID, err := syntax.ParseAtIdentifier(identityStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve identity %s: %w", identity, err)
|
||||
return nil, fmt.Errorf("invalid identity %s: %w", identityStr, err)
|
||||
}
|
||||
|
||||
// Store resolved DID and PDS in context for downstream use
|
||||
ctx = context.WithValue(ctx, "atproto.did", did)
|
||||
ctx = context.WithValue(ctx, "atproto.pds", pdsEndpoint)
|
||||
ctx = context.WithValue(ctx, "atproto.identity", identity)
|
||||
// Resolve identity to DID and PDS using indigo's directory
|
||||
ident, err := nr.directory.Lookup(ctx, *atID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve identity %s: %w", identityStr, err)
|
||||
}
|
||||
|
||||
fmt.Printf("DEBUG [registry/middleware]: Set context values: did=%s, pds=%s, identity=%s\n", did, pdsEndpoint, identity)
|
||||
did := ident.DID.String()
|
||||
pdsEndpoint := ident.PDSEndpoint()
|
||||
if pdsEndpoint == "" {
|
||||
return nil, fmt.Errorf("no PDS endpoint found for %s", identityStr)
|
||||
}
|
||||
|
||||
fmt.Printf("DEBUG [registry/middleware]: Resolved identity: did=%s, pds=%s, handle=%s\n", did, pdsEndpoint, ident.Handle.String())
|
||||
|
||||
// Query for storage endpoint - either user's hold or default hold service
|
||||
storageEndpoint := nr.findStorageEndpoint(ctx, did, pdsEndpoint)
|
||||
@@ -98,7 +108,7 @@ func (nr *NamespaceResolver) Repository(ctx context.Context, name reference.Name
|
||||
// Create a new reference with identity/image format
|
||||
// Use the identity (or DID) as the namespace to ensure canonical format
|
||||
// This transforms: evan.jarrett.net/debian -> evan.jarrett.net/debian (keeps full path)
|
||||
canonicalName := fmt.Sprintf("%s/%s", identity, imageName)
|
||||
canonicalName := fmt.Sprintf("%s/%s", identityStr, imageName)
|
||||
ref, err := reference.ParseNamed(canonicalName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid image name %s: %w", imageName, err)
|
||||
@@ -119,11 +129,10 @@ func (nr *NamespaceResolver) Repository(ctx context.Context, name reference.Name
|
||||
// Try OAuth flow first
|
||||
session, err := globalRefresher.GetSession(ctx, did)
|
||||
if err == nil {
|
||||
// OAuth session available
|
||||
accessToken, _ := session.GetHostAccessData()
|
||||
httpClient := session.APIClient().Client
|
||||
fmt.Printf("DEBUG [registry/middleware]: Using OAuth access token for DID=%s (length=%d, first_20=%q)\n", did, len(accessToken), accessToken[:min(20, len(accessToken))])
|
||||
atprotoClient = atproto.NewClientWithHTTPClient(pdsEndpoint, did, accessToken, httpClient)
|
||||
// OAuth session available - use indigo's API client (handles DPoP automatically)
|
||||
apiClient := session.APIClient()
|
||||
fmt.Printf("DEBUG [registry/middleware]: Using OAuth session with indigo API client for DID=%s\n", did)
|
||||
atprotoClient = atproto.NewClientWithIndigoClient(pdsEndpoint, did, apiClient)
|
||||
} else {
|
||||
fmt.Printf("DEBUG [registry/middleware]: OAuth refresh failed for DID=%s: %v, falling back to Basic Auth\n", did, err)
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
repositorymw "github.com/distribution/distribution/v3/registry/middleware/repository"
|
||||
|
||||
"atcr.io/pkg/atproto"
|
||||
"atcr.io/pkg/storage"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register the ATProto routing middleware
|
||||
repositorymw.Register("atproto-router", initATProtoRouter)
|
||||
}
|
||||
|
||||
// initATProtoRouter initializes the ATProto routing middleware
|
||||
func initATProtoRouter(ctx context.Context, repo distribution.Repository, options map[string]any) (distribution.Repository, error) {
|
||||
fmt.Printf("DEBUG [repository/middleware]: Initializing atproto-router for repo=%s\n", repo.Named().Name())
|
||||
fmt.Printf("DEBUG [repository/middleware]: Context values: atproto.did=%v, atproto.pds=%v\n",
|
||||
ctx.Value("atproto.did"), ctx.Value("atproto.pds"))
|
||||
|
||||
// Extract DID and PDS from context (set by registry middleware)
|
||||
did, ok := ctx.Value("atproto.did").(string)
|
||||
if !ok || did == "" {
|
||||
fmt.Printf("DEBUG [repository/middleware]: DID not found in context, ok=%v, did=%q\n", ok, did)
|
||||
return nil, fmt.Errorf("did is required for atproto-router middleware")
|
||||
}
|
||||
|
||||
pdsEndpoint, ok := ctx.Value("atproto.pds").(string)
|
||||
if !ok || pdsEndpoint == "" {
|
||||
return nil, fmt.Errorf("pds is required for atproto-router middleware")
|
||||
}
|
||||
|
||||
// For now, use empty access token (we'll add auth later)
|
||||
accessToken := ""
|
||||
|
||||
// Create ATProto client
|
||||
atprotoClient := atproto.NewClient(pdsEndpoint, did, accessToken)
|
||||
|
||||
// Get repository name
|
||||
repoName := repo.Named().Name()
|
||||
|
||||
// Get storage endpoint from context
|
||||
storageEndpoint, ok := ctx.Value("storage.endpoint").(string)
|
||||
if !ok || storageEndpoint == "" {
|
||||
return nil, fmt.Errorf("storage.endpoint not found in context")
|
||||
}
|
||||
|
||||
// Create routing repository - no longer uses storage driver
|
||||
// All blobs are routed through hold service
|
||||
routingRepo := storage.NewRoutingRepository(repo, atprotoClient, repoName, storageEndpoint, did)
|
||||
|
||||
return routingRepo, nil
|
||||
}
|
||||
Reference in New Issue
Block a user