GoAT Site is library that implements Standard.site in Go.
atprotocol standard-site atproto library
1
fork

Configure Feed

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

feat(verify): verification method for publication

+74 -5
+50 -4
publication.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "encoding/json" 5 6 "fmt" 7 + "io" 6 8 "net/http" 9 + "net/url" 7 10 "strings" 8 11 9 12 "github.com/bluesky-social/indigo/atproto/syntax" ··· 22 25 // Base URL of the [Publication]. 23 26 // This value will be combined with the [Document.Path] to construct a full URL for the document. 24 27 // Avoid trailing slashes. 25 - URL string `json:"url"` 28 + URL *url.URL `json:"-"` 26 29 // Name of the [Publication]. 27 30 // Max length: 5000. 28 31 // Max graphemes: 500. ··· 46 49 47 50 func (p *Publication) MarshalMap() (map[string]any, error) { 48 51 type t Publication 49 - pp := t(*p) 50 - pp.URL = strings.TrimSuffix(pp.URL, "/") 52 + pp := struct { 53 + t 54 + URL string `json:"url"` 55 + }{t(*p), strings.TrimSuffix(p.URL.String(), "/")} 51 56 return MarshalToMap(pp) 52 57 } 53 58 59 + func (p *Publication) UnmarshalJSON(b []byte) error { 60 + type t Publication 61 + var pp struct { 62 + t 63 + URL string `json:"url"` 64 + } 65 + err := json.Unmarshal(b, &pp) 66 + if err != nil { 67 + return err 68 + } 69 + *p = Publication(pp.t) 70 + p.URL, err = url.Parse(pp.URL) 71 + if err != nil { 72 + return err 73 + } 74 + p.URL.Path = strings.TrimSuffix(p.URL.Path, "/") 75 + return nil 76 + } 77 + 78 + // Verify the [Publication]. 79 + func (p *Publication) Verify(ctx context.Context, client *http.Client, repo syntax.AtIdentifier, rkey syntax.RecordKey) (bool, error) { 80 + req, err := http.NewRequest(http.MethodGet, p.URL.String()+GetPublicationVerificationURI(p.URL.Path), nil) 81 + if err != nil { 82 + return false, err 83 + } 84 + resp, err := client.Do(req.WithContext(ctx)) 85 + if err != nil { 86 + return false, err 87 + } 88 + b, err := io.ReadAll(resp.Body) 89 + if err != nil { 90 + return false, err 91 + } 92 + return string(b) == getPublicationVerification(repo, rkey), nil 93 + } 94 + 54 95 // Preferences of the [Publication]. 55 96 type Preferences struct { 56 97 // ShowInDiscover decides whether the [Publication] should appear in discovery feeds. ··· 89 130 return deleteRecord(ctx, client, CollectionPublication, repo, rkey) 90 131 } 91 132 133 + // getPublicationVerification returns the string used during the verification of the [Publication]. 134 + func getPublicationVerification(repo syntax.AtIdentifier, rkey syntax.RecordKey) string { 135 + return createAtURI(repo, CollectionPublication, rkey) 136 + } 137 + 92 138 // HandlePublicationVerification returns an [http.Handler] used during the verification of the [Publication]. 93 139 // 94 140 // See [GetPublicationVerificationURI]. 95 141 func HandlePublicationVerification(repo syntax.AtIdentifier, rkey syntax.RecordKey) http.Handler { 96 142 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 97 - fmt.Fprint(w, createAtURI(repo, CollectionPublication, rkey)) 143 + fmt.Fprint(w, getPublicationVerification(repo, rkey)) 98 144 }) 99 145 } 100 146
+24 -1
publication_test.go
··· 3 3 import ( 4 4 "context" 5 5 "encoding/json" 6 + "net/http" 6 7 "testing" 7 8 8 9 "github.com/bluesky-social/indigo/atproto/atclient" ··· 86 87 if pub.Name != "pckt - Dev Journal" { 87 88 t.Errorf("invalid name: %s", pub.Name) 88 89 } 89 - if pub.URL != "https://devlog.pckt.blog" { 90 + if pub.URL.String() != "https://devlog.pckt.blog" { 90 91 t.Errorf("invalid url: %s", pub.URL) 91 92 } 92 93 if *pub.Description != "the latest and greatest from pckt !" { ··· 160 161 c := lexutil.LexClient(atclient.NewAPIClient(id.PDSEndpoint())) 161 162 *client = &c 162 163 return *uri, **client 164 + } 165 + 166 + func httpClient(client lexutil.LexClient) *http.Client { 167 + return client.(*atclient.APIClient).Client 163 168 } 164 169 165 170 func TestGetPublication(t *testing.T) { ··· 209 214 t.Errorf("invalid uri: %s", uri) 210 215 } 211 216 } 217 + 218 + func TestPublication_Verify(t *testing.T) { 219 + if testing.Short() { 220 + t.Skip() 221 + } 222 + id, client := getClient(t, testPub, &pubURI, &pubClient) 223 + pub, err := site.GetPublication(context.Background(), client, id.Authority(), id.RecordKey()) 224 + if err != nil { 225 + t.Fatal(err) 226 + } 227 + v, err := pub.Verify(context.Background(), httpClient(client), id.Authority(), id.RecordKey()) 228 + if err != nil { 229 + t.Fatal(err) 230 + } 231 + if !v { 232 + t.Errorf("cannot verify %s", id) 233 + } 234 + }