Go boilerplate library for building atproto apps
atproto go
1
fork

Configure Feed

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

feat: resolve handle and client-metadata handler

authored by

Patrick Dewey and committed by tangled.org a8326394 2abb4c13

+56 -4
+2 -4
jetstream/jetstream.go
··· 159 159 160 160 // Start begins consuming events in a background goroutine. 161 161 func (c *Consumer) Start(ctx context.Context) { 162 - c.wg.Add(1) 163 - go func() { 164 - defer c.wg.Done() 162 + c.wg.Go(func() { 165 163 c.run(ctx) 166 - }() 164 + }) 167 165 } 168 166 169 167 // Stop gracefully shuts down the consumer and waits for it to finish.
+14
middleware/auth.go
··· 3 3 4 4 import ( 5 5 "context" 6 + "encoding/json" 6 7 "net/http" 7 8 8 9 "github.com/bluesky-social/indigo/atproto/syntax" ··· 91 92 sid, ok := ctx.Value(ctxKeySessionID).(string) 92 93 return sid, ok && sid != "" 93 94 } 95 + 96 + // ClientMetadataHandler returns an http.Handler that serves the OAuth client 97 + // metadata JSON document. Register it at both your client_id URL and 98 + // /.well-known/oauth-client-metadata. 99 + // 100 + // mux.Handle("GET /client-metadata.json", middleware.ClientMetadataHandler(app)) 101 + // mux.Handle("GET /.well-known/oauth-client-metadata", middleware.ClientMetadataHandler(app)) 102 + func ClientMetadataHandler(app *atp.OAuthApp) http.Handler { 103 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 104 + w.Header().Set("Content-Type", "application/json") 105 + json.NewEncoder(w).Encode(app.ClientMetadata()) 106 + }) 107 + }
+34
middleware/auth_test.go
··· 176 176 t.Fatalf("got DID %q with custom cookie names", gotDID) 177 177 } 178 178 } 179 + 180 + func TestClientMetadataHandler(t *testing.T) { 181 + app, _ := atp.NewOAuthApp(atp.OAuthConfig{ 182 + RedirectURI: "http://127.0.0.1:9999/cb", 183 + Scopes: []string{"atproto"}, 184 + AppName: "TestApp", 185 + }) 186 + 187 + handler := ClientMetadataHandler(app) 188 + r := httptest.NewRequest("GET", "/client-metadata.json", nil) 189 + w := httptest.NewRecorder() 190 + handler.ServeHTTP(w, r) 191 + 192 + if w.Code != http.StatusOK { 193 + t.Fatalf("expected 200, got %d", w.Code) 194 + } 195 + ct := w.Header().Get("Content-Type") 196 + if ct != "application/json" { 197 + t.Fatalf("expected application/json, got %q", ct) 198 + } 199 + body := w.Body.String() 200 + if !containsStr(body, "client_id") { 201 + t.Fatalf("response missing client_id: %s", body) 202 + } 203 + } 204 + 205 + func containsStr(s, substr string) bool { 206 + for i := 0; i <= len(s)-len(substr); i++ { 207 + if s[i:i+len(substr)] == substr { 208 + return true 209 + } 210 + } 211 + return false 212 + }
+6
public.go
··· 25 25 // ErrSSRFBlocked is returned when a request is blocked due to a private/internal destination. 26 26 var ErrSSRFBlocked = errors.New("request blocked: potential SSRF detected") 27 27 28 + // ResolveHandle is a convenience that resolves an AT Protocol handle to a DID 29 + // without needing to construct a PublicClient. 30 + func ResolveHandle(ctx context.Context, handle string) (string, error) { 31 + return NewPublicClient().ResolveHandle(ctx, handle) 32 + } 33 + 28 34 // PublicClient provides unauthenticated read access to public AT Protocol APIs. 29 35 // Use this to resolve handles, look up profiles, and read public records without 30 36 // requiring an OAuth session.