commit eec649355b1ab496b58a8e65abc64f9ee7e635ac from: Oliver Lowe date: Sat Mar 16 07:45:22 2024 UTC apub: correctly marshal followers collection from an email recipients The receiving server can forward the message for us. For us to resolve the entire collection is a lot of work, especially since paginated followers collections only contain like 12 entries per page! Lots of people have over 300 followers. commit - b526632b614889f059e5aa5d29e84a9f416572da commit + eec649355b1ab496b58a8e65abc64f9ee7e635ac blob - 4948c36d47177385965204af8e12e103b013082e blob + 1e5c0bd4dd580bc4c32e1c2d03f777ca0e989d5e --- mail.go +++ mail.go @@ -112,10 +112,13 @@ func UnmarshalMail(msg *mail.Message) (*Activity, erro return nil, fmt.Errorf("webfinger To addresses: %w", err) } wto = make([]string, len(actors)) - tags = make([]Activity, len(actors)) for i, a := range actors { addr := strings.Trim(to[i].Address, "<>") - tags[i] = Activity{Type: "Mention", Href: a.ID, Name: "@" + addr} + if strings.Contains(addr, "+followers") { + wto[i] = a.Followers + continue + } + tags = append(tags, Activity{Type: "Mention", Href: a.ID, Name: "@" + addr}) wto[i] = a.ID } } @@ -130,6 +133,10 @@ func UnmarshalMail(msg *mail.Message) (*Activity, erro } wcc = make([]string, len(actors)) for i, a := range actors { + if strings.Contains(cc[i].Address, "+followers") { + wcc[i] = a.Followers + continue + } wcc[i] = a.ID } } blob - 16154099f40f206a7ceb3e7f4bc6645e68288f8b blob + 0d990da5a71ad9c617d9fe01e40e1e36be087099 --- testdata/outbound.eml +++ testdata/outbound.eml @@ -1,7 +1,7 @@ From: Oliver Lowe Date: Wed, 6 Mar 2024 14:03:33 +1100 To: -CC: "Programming" , +CC: "Programming" , , In-Reply-To: Subject: blob - 1010ca293ad511037e6e90babb868bf19bad25e4 blob + f872625d946401146d5e4c6104e37b8065d32476 --- webfinger.go +++ webfinger.go @@ -8,17 +8,22 @@ import ( "webfinger.net/go/webfinger" ) -// Finger is convenience function returning the corresponding Actor, +// Finger wraps defaultClient.Finger. +func Finger(address string) (*Actor, error) { + return defaultClient.Finger(address) +} + +// Finger is convenience method returning the corresponding Actor, // if any, of an address resolvable by WebFinger. // It is equivalent to doing webfinger.Lookup then LookupActor. -func Finger(address string) (*Actor, error) { +func (c *Client) Finger(address string) (*Actor, error) { jrd, err := webfinger.Lookup(address, nil) if err != nil { return nil, err } for i := range jrd.Links { if jrd.Links[i].Type == ContentType { - return LookupActor(jrd.Links[i].Href) + return c.LookupActor(jrd.Links[i].Href) } } return nil, ErrNotExist @@ -27,18 +32,14 @@ func Finger(address string) (*Actor, error) { func fingerAll(alist []*mail.Address) ([]Actor, error) { actors := make([]Actor, len(alist)) for i, addr := range alist { + q := addr.Address if strings.Contains(addr.Address, "+followers") { - addr.Address = strings.Replace(addr.Address, "+followers", "", 1) - a, err := Finger(addr.Address) - if err != nil { - return actors, fmt.Errorf("finger %s: %w", addr.Address, err) - } - actors[i] = *a - continue + // strip "+followers" to get the regular address that can be fingered. + q = strings.Replace(addr.Address, "+followers", "", 1) } - actor, err := Finger(addr.Address) + actor, err := Finger(q) if err != nil { - return actors, fmt.Errorf("finger %s: %w", addr.Address, err) + return actors, fmt.Errorf("finger %s: %w", q, err) } actors[i] = *actor }