cleanup more auth

This commit is contained in:
Evan Jarrett
2025-10-07 10:58:11 -05:00
parent 5b18538a8b
commit 2d16bbfee3
31 changed files with 2524 additions and 918 deletions
+27 -18
View File
@@ -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)
}
-57
View File
@@ -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
}