diff --git a/activitypub.go b/activitypub.go index e37fb97..68ac7c9 100644 --- a/activitypub.go +++ b/activitypub.go @@ -26,6 +26,7 @@ import ( "github.com/gorilla/mux" "github.com/writeas/activity/streams" + "github.com/writeas/activityserve" "github.com/writeas/httpsig" "github.com/writeas/impart" "github.com/writeas/nerds/store" @@ -594,12 +595,12 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { } } + var activity *activitystreams.Activity for si, instFolls := range inboxes { na.CC = []string{} for _, f := range instFolls { na.CC = append(na.CC, f) } - var activity *activitystreams.Activity if isUpdate { activity = activitystreams.NewUpdateActivity(na) } else { @@ -612,6 +613,28 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { log.Error("Couldn't post! %v", err) } } + + for _, tag := range na.Tag { + if tag.Type == "Mention" { + activity = activitystreams.NewCreateActivity(na) + activity.To = na.To + activity.CC = na.CC + // This here might be redundant in some cases as we might have already + // sent this to the sharedInbox of this instance above, but we need too + // much logic to catch this at the expense of the odd extra request. + // I don't believe we'd ever have too many mentions in a single post that this + // could become a burden. + remoteActor, err := activityserve.NewRemoteActor(tag.HRef) + if err != nil { + log.Error("Couldn't fetch remote actor", err) + } + err = makeActivityPost(app.cfg.App.Host, actor, remoteActor.GetInbox(), activity) + if err != nil { + log.Error("Couldn't post! %v", err) + } + } + } + return nil } diff --git a/go.mod b/go.mod index 9c67aeb..6711795 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,13 @@ require ( github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/captncraig/cors v0.0.0-20180620154129-376d45073b49 // indirect github.com/clbanning/mxj v1.8.4 // indirect + github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 // indirect github.com/dustin/go-humanize v1.0.0 github.com/fatih/color v1.7.0 github.com/go-sql-driver/mysql v1.4.1 github.com/go-test/deep v1.0.1 // indirect github.com/golang/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect + github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 // indirect github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/gorilla/feeds v1.1.0 github.com/gorilla/mux v1.7.0 @@ -36,6 +38,7 @@ require ( github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect github.com/stretchr/testify v1.3.0 // indirect github.com/writeas/activity v0.1.2 + github.com/writeas/activityserve v0.0.0-20191008122325-5fc3b48e70c5 github.com/writeas/go-strip-markdown v2.0.1+incompatible github.com/writeas/go-webfinger v0.0.0-20190106002315-85cf805c86d2 github.com/writeas/httpsig v1.0.0 @@ -58,3 +61,5 @@ require ( gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect gopkg.in/yaml.v2 v2.2.2 // indirect ) + +go 1.13 diff --git a/go.sum b/go.sum index ec1e19d..356c06f 100644 --- a/go.sum +++ b/go.sum @@ -23,12 +23,15 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9 h1:74lLNRzvsdIlkTgfDSMuaPjBr4cf6k7pwQQANm/yLKU= +github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/go-fed/httpsig v0.1.0 h1:6F2OxRVnNTN4OPN+Mc2jxs2WEay9/qiHT/jphlvAwIY= github.com/go-fed/httpsig v0.1.0/go.mod h1:T56HUNYZUQ1AGUzhAYPugZfp36sKApVnGBgKlIY+aIE= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -38,6 +41,8 @@ github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200j github.com/golang/lint v0.0.0-20181217174547-8f45f776aaf1 h1:6DVPu65tee05kY0/rciBQ47ue+AnuY8KTayV6VHikIo= github.com/golang/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 h1:WD8iJ37bRNwvETMfVTusVSAi0WdXTpfNVGY2aHycNKY= +github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= @@ -115,6 +120,8 @@ github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9 h1:vY5WqiEon0ZSTG github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk= github.com/writeas/activity v0.1.2 h1:Y12B5lIrabfqKE7e7HFCWiXrlfXljr9tlkFm2mp7DgY= github.com/writeas/activity v0.1.2/go.mod h1:mYYgiewmEM+8tlifirK/vl6tmB2EbjYaxwb+ndUw5T0= +github.com/writeas/activityserve v0.0.0-20191008122325-5fc3b48e70c5 h1:nG84xWpxBM8YU/FJchezJqg7yZH8ImSRow6NoYtbSII= +github.com/writeas/activityserve v0.0.0-20191008122325-5fc3b48e70c5/go.mod h1:Kz62mzYsCnrFTSTSFLXFj3fGYBQOntmBWTDDq57b46A= github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw= github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE= github.com/writeas/go-webfinger v0.0.0-20190106002315-85cf805c86d2 h1:DUsp4OhdfI+e6iUqcPQlwx8QYXuUDsToTz/x82D3Zuo= diff --git a/posts.go b/posts.go index 88730f7..520f716 100644 --- a/posts.go +++ b/posts.go @@ -1108,6 +1108,24 @@ func (p *PublicPost) ActivityObject(cfg *config.Config) *activitystreams.Object }) } } + // Find mentioned users + mentionedUsers := make(map[string]string) + //:= map[string]string{"@qwazix@pleroma.site": "https://pleroma.site/users/qwazix", "@tzo@cybre.space": "https://cybre.space/users/tzo"} + + stripper := bluemonday.StrictPolicy() + content := stripper.Sanitize(p.Content) + mentionRegex := regexp.MustCompile(`@[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}`) + mentions := mentionRegex.FindAllString(content, -1) + + for _, handle := range mentions { + actorIRI := RemoteLookup(handle) + mentionedUsers[handle] = actorIRI + } + + for handle, iri := range mentionedUsers { + o.CC = append(o.CC, iri) + o.Tag = append(o.Tag, activitystreams.Tag{"Mention", iri, handle}) + } return o } diff --git a/webfinger.go b/webfinger.go index c95d88e..c3f8530 100644 --- a/webfinger.go +++ b/webfinger.go @@ -11,11 +11,15 @@ package writefreely import ( + "encoding/json" + "io/ioutil" + "net/http" + "strings" + "github.com/writeas/go-webfinger" "github.com/writeas/impart" "github.com/writeas/web-core/log" "github.com/writeas/writefreely/config" - "net/http" ) type wfResolver struct { @@ -80,3 +84,28 @@ func (wfr wfResolver) DummyUser(username string, hostname string, r []webfinger. func (wfr wfResolver) IsNotFoundError(err error) bool { return err == wfUserNotFoundErr } + +// RemoteLookup looks up a user by handle at a remote server +// and returns the actor URL +// TODO make this work +func RemoteLookup(handle string) string { + handle = strings.TrimLeft(handle, "@") + // let's take the server part of the handle + parts := strings.Split(handle, "@") + resp, err := http.Get("https://" + parts[1] + "/.well-known/webfinger?resource=acct:" + handle) + if err != nil { + log.Error("Error performing webfinger request", err) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Error("Error reading webfinger response", err) + } + + var result map[string]interface{} + json.Unmarshal(body, &result) + + aliases := result["aliases"].([]interface{}) + + return aliases[0].(string) +}