Federated via graft
0

Configure Feed

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

1.5 kB 45 lines
1package activitypub 2 3import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8) 9 10// FetchActor retrieves a remote actor object. actorURL is attacker 11// influenced (it comes straight off an inbound activity's "actor" field), 12// so it's validated before any network call, and client is expected to be 13// one from NewSafeClient. An unsigned GET is used — acceptable here since 14// this is only for resolving a Follow request's actor (to get their 15// public key and inbox URL) and most servers permit unauthenticated actor 16// fetches; authenticated fetches ("secure mode") are out of scope for now. 17func FetchActor(client *http.Client, actorURL string) (*Actor, error) { 18 if err := ValidateExternalURL(actorURL); err != nil { 19 return nil, fmt.Errorf("actor URL: %w", err) 20 } 21 22 req, err := http.NewRequest(http.MethodGet, actorURL, nil) 23 if err != nil { 24 return nil, fmt.Errorf("build request: %w", err) 25 } 26 req.Header.Set("Accept", activityContentType) 27 28 resp, err := client.Do(req) 29 if err != nil { 30 return nil, fmt.Errorf("fetch actor %s: %w", actorURL, err) 31 } 32 defer resp.Body.Close() 33 if resp.StatusCode >= 300 { 34 return nil, fmt.Errorf("fetch actor %s: HTTP %d", actorURL, resp.StatusCode) 35 } 36 37 var a Actor 38 if err := json.NewDecoder(io.LimitReader(resp.Body, maxResponseBody)).Decode(&a); err != nil { 39 return nil, fmt.Errorf("decode actor %s: %w", actorURL, err) 40 } 41 if err := ValidateExternalURL(a.Inbox); err != nil { 42 return nil, fmt.Errorf("actor inbox URL: %w", err) 43 } 44 return &a, nil 45}