A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
0
fork

Configure Feed

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

at refactor 135 lines 3.9 kB view raw
1package main 2 3import ( 4 "context" 5 "flag" 6 "fmt" 7 "log" 8 "net/http" 9 "os" 10 "time" 11 12 "atcr.io/pkg/atproto" 13 "atcr.io/pkg/auth/oauth" 14 indigo_oauth "github.com/bluesky-social/indigo/atproto/auth/oauth" 15) 16 17func main() { 18 handle := flag.String("handle", "", "Your Bluesky handle (e.g., yourname.bsky.social)") 19 holdURL := flag.String("hold-url", "http://localhost:8080", "Hold service URL") 20 repo := flag.String("repo", "", "Repository DID (e.g., did:web:172.28.0.3:8080)") 21 collection := flag.String("collection", "io.atcr.hold.crew", "Collection to delete from") 22 rkey := flag.String("rkey", "", "Record key to delete") 23 24 flag.Parse() 25 26 if *handle == "" { 27 fmt.Println("Usage: oauth-helper --handle yourname.bsky.social [options]") 28 fmt.Println("\nOptions:") 29 flag.PrintDefaults() 30 os.Exit(1) 31 } 32 33 ctx := context.Background() 34 35 fmt.Printf("🔐 Starting OAuth flow for %s...\n\n", *handle) 36 37 // Create a simple HTTP server for the callback 38 mux := http.NewServeMux() 39 server := &http.Server{ 40 Addr: ":8765", 41 Handler: mux, 42 } 43 44 // Channel to receive the result 45 resultChan := make(chan *oauth.InteractiveResult, 1) 46 errorChan := make(chan error, 1) 47 48 // Register callback handler 49 registerCallback := func(handler http.HandlerFunc) error { 50 mux.HandleFunc("/auth/oauth/callback", handler) 51 return nil 52 } 53 54 // Display auth URL (will open browser) 55 displayAuthURL := func(authURL string) error { 56 fmt.Printf("🌐 Opening browser for authorization...\n") 57 fmt.Printf(" URL: %s\n\n", authURL) 58 fmt.Printf(" If the browser doesn't open, visit the URL above.\n\n") 59 return oauth.OpenBrowser(authURL) 60 } 61 62 // Start server in background 63 go func() { 64 if err := server.ListenAndServe(); err != http.ErrServerClosed { 65 errorChan <- fmt.Errorf("server error: %w", err) 66 } 67 }() 68 69 // Give server time to start 70 time.Sleep(100 * time.Millisecond) 71 72 // Run interactive OAuth flow 73 go func() { 74 result, err := oauth.InteractiveFlowWithCallback( 75 ctx, 76 "http://localhost:8765", 77 *handle, 78 nil, // Use default scopes 79 registerCallback, 80 displayAuthURL, 81 ) 82 if err != nil { 83 errorChan <- err 84 return 85 } 86 resultChan <- result 87 }() 88 89 // Wait for result 90 var result *oauth.InteractiveResult 91 select { 92 case result = <-resultChan: 93 fmt.Printf("✅ OAuth successful!\n\n") 94 case err := <-errorChan: 95 log.Fatalf("❌ OAuth failed: %v\n", err) 96 case <-time.After(5 * time.Minute): 97 log.Fatalf("❌ OAuth timed out\n") 98 } 99 100 // Shutdown server 101 server.Shutdown(ctx) 102 103 // Print session information 104 fmt.Printf("DID: %s\n", result.SessionData.AccountDID) 105 fmt.Printf("Access Token: %s\n", result.SessionData.AccessToken) 106 fmt.Printf("DPoP Key: %s\n\n", result.SessionData.DPoPPrivateKeyMultibase) 107 108 // Generate DPoP proof for deleteRecord endpoint if all params provided 109 if *repo != "" && *rkey != "" { 110 deleteURL := fmt.Sprintf("%s%s?repo=%s&collection=%s&rkey=%s", 111 *holdURL, atproto.RepoDeleteRecord, *repo, *collection, *rkey) 112 113 dpopProof, err := generateDPoPProof(result.Session, "POST", deleteURL) 114 if err != nil { 115 log.Fatalf("❌ Failed to generate DPoP proof: %v\n", err) 116 } 117 118 fmt.Printf("📋 Ready-to-use curl command:\n\n") 119 fmt.Printf("curl -X POST \\\n") 120 fmt.Printf(" -H \"Authorization: DPoP %s\" \\\n", result.SessionData.AccessToken) 121 fmt.Printf(" -H \"DPoP: %s\" \\\n", dpopProof) 122 fmt.Printf(" \"%s\"\n", deleteURL) 123 } else { 124 fmt.Printf("💡 To generate a curl command for deleteRecord, provide:\n") 125 fmt.Printf(" --repo <did>\n") 126 fmt.Printf(" --collection <collection>\n") 127 fmt.Printf(" --rkey <rkey>\n") 128 } 129} 130 131// generateDPoPProof generates a DPoP proof JWT for a specific request 132func generateDPoPProof(session *indigo_oauth.ClientSession, method, reqURL string) (string, error) { 133 // Use the session's NewHostDPoP method to generate the proof 134 return session.NewHostDPoP(method, reqURL) 135}