diff options
-rw-r--r-- | activitypub/actor.go | 30 | ||||
-rw-r--r-- | client.go | 210 | ||||
-rw-r--r-- | db/follow.go | 32 | ||||
-rw-r--r-- | main.go | 8 | ||||
-rw-r--r-- | outboxGet.go | 46 | ||||
-rw-r--r-- | outboxPost.go | 245 | ||||
-rw-r--r-- | post/util.go | 179 | ||||
-rw-r--r-- | routes/actor.go | 177 | ||||
-rw-r--r-- | util/proxy.go | 17 | ||||
-rw-r--r-- | webfinger/webfinger.go | 25 |
10 files changed, 461 insertions, 508 deletions
diff --git a/activitypub/actor.go b/activitypub/actor.go index e837df5..3fbcb75 100644 --- a/activitypub/actor.go +++ b/activitypub/actor.go @@ -863,3 +863,33 @@ func WriteActorObjectToCache(obj ObjectBase) (ObjectBase, error) { return obj, nil } + +func GetActorOutbox(ctx *fiber.Ctx, actor Actor) error { + + var collection Collection + + c, err := GetActorObjectCollectionFromDB(actor.Id) + if err != nil { + return err + } + collection.OrderedItems = c.OrderedItems + + collection.AtContext.Context = "https://www.w3.org/ns/activitystreams" + collection.Actor = &actor + + collection.TotalItems, err = GetObjectPostsTotalDB(actor) + if err != nil { + return err + } + + collection.TotalImgs, err = GetObjectImgsTotalDB(actor) + if err != nil { + return err + } + + enc, _ := json.Marshal(collection) + + ctx.Response().Header.Set("Content-Type", config.ActivityStreams) + _, err = ctx.Write(enc) + return err +} diff --git a/client.go b/client.go deleted file mode 100644 index f4094ba..0000000 --- a/client.go +++ /dev/null @@ -1,210 +0,0 @@ -package main - -import ( - "html/template" - "regexp" - "strings" - - "github.com/FChannel0/FChannel-Server/activitypub" - "github.com/FChannel0/FChannel-Server/config" - "github.com/FChannel0/FChannel-Server/db" - "github.com/FChannel0/FChannel-Server/post" - "github.com/FChannel0/FChannel-Server/util" - "github.com/FChannel0/FChannel-Server/webfinger" - _ "github.com/lib/pq" -) - -func MediaProxy(url string) string { - re := regexp.MustCompile("(.+)?" + config.Domain + "(.+)?") - - if re.MatchString(url) { - return url - } - - re = regexp.MustCompile("(.+)?\\.onion(.+)?") - - if re.MatchString(url) { - return url - } - - config.MediaHashs[util.HashMedia(url)] = url - return "/api/media?hash=" + util.HashMedia(url) -} - -func ParseAttachment(obj activitypub.ObjectBase, catalog bool) template.HTML { - // TODO: convert all of these to Sprintf statements, or use strings.Builder or something, anything but this really - // string concatenation is highly inefficient _especially_ when being used like this - - if len(obj.Attachment) < 1 { - return "" - } - - var media string - if regexp.MustCompile(`image\/`).MatchString(obj.Attachment[0].MediaType) { - media = "<img " - media += "id=\"img\" " - media += "main=\"1\" " - media += "enlarge=\"0\" " - media += "attachment=\"" + obj.Attachment[0].Href + "\"" - if catalog { - media += "style=\"max-width: 180px; max-height: 180px;\" " - } else { - media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\"" - } - if obj.Preview.Id != "" { - media += "src=\"" + MediaProxy(obj.Preview.Href) + "\"" - media += "preview=\"" + MediaProxy(obj.Preview.Href) + "\"" - } else { - media += "src=\"" + MediaProxy(obj.Attachment[0].Href) + "\"" - media += "preview=\"" + MediaProxy(obj.Attachment[0].Href) + "\"" - } - - media += ">" - - return template.HTML(media) - } - - if regexp.MustCompile(`audio\/`).MatchString(obj.Attachment[0].MediaType) { - media = "<audio " - media += "controls=\"controls\" " - media += "preload=\"metadta\" " - if catalog { - media += "style=\"margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;\" " - } else { - media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\" " - } - media += ">" - media += "<source " - media += "src=\"" + MediaProxy(obj.Attachment[0].Href) + "\" " - media += "type=\"" + obj.Attachment[0].MediaType + "\" " - media += ">" - media += "Audio is not supported." - media += "</audio>" - - return template.HTML(media) - } - - if regexp.MustCompile(`video\/`).MatchString(obj.Attachment[0].MediaType) { - media = "<video " - media += "controls=\"controls\" " - media += "preload=\"metadta\" " - media += "muted=\"muted\" " - if catalog { - media += "style=\"margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;\" " - } else { - media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\" " - } - media += ">" - media += "<source " - media += "src=\"" + MediaProxy(obj.Attachment[0].Href) + "\" " - media += "type=\"" + obj.Attachment[0].MediaType + "\" " - media += ">" - media += "Video is not supported." - media += "</video>" - - return template.HTML(media) - } - - return template.HTML(media) -} - -func ParseContent(board activitypub.Actor, op string, content string, thread activitypub.ObjectBase) (template.HTML, error) { - // TODO: should escape more than just < and >, should also escape &, ", and ' - nContent := strings.ReplaceAll(content, `<`, "<") - - nContent, err := ParseLinkComments(board, op, nContent, thread) - if err != nil { - return "", err - } - - nContent = ParseCommentQuotes(nContent) - - nContent = strings.ReplaceAll(nContent, `/\<`, ">") - - return template.HTML(nContent), nil -} - -func ParseLinkComments(board activitypub.Actor, op string, content string, thread activitypub.ObjectBase) (string, error) { - re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)(f[A-Za-z0-9_.\-~]+-)?([A-Za-z0-9_.\-~]+)?#?([A-Za-z0-9_.\-~]+)?)`) - match := re.FindAllStringSubmatch(content, -1) - - //add url to each matched reply - for i, _ := range match { - link := strings.Replace(match[i][0], ">>", "", 1) - isOP := "" - - domain := match[i][2] - - if link == op { - isOP = " (OP)" - } - - parsedLink := post.ConvertHashLink(domain, link) - - //formate the hover title text - var quoteTitle string - - // if the quoted content is local get it - // else get it from the database - if thread.Id == link { - quoteTitle = post.ParseLinkTitle(board.Outbox, op, thread.Content) - } else { - for _, e := range thread.Replies.OrderedItems { - if e.Id == parsedLink { - quoteTitle = post.ParseLinkTitle(board.Outbox, op, e.Content) - break - } - } - - if quoteTitle == "" { - obj, err := activitypub.GetObjectFromDBFromID(parsedLink) - if err != nil { - return "", err - } - - if len(obj.OrderedItems) > 0 { - quoteTitle = post.ParseLinkTitle(board.Outbox, op, obj.OrderedItems[0].Content) - } else { - quoteTitle = post.ParseLinkTitle(board.Outbox, op, parsedLink) - } - } - } - - if replyID, isReply, err := db.IsReplyToOP(op, parsedLink); err == nil || !isReply { - id := util.ShortURL(board.Outbox, replyID) - - content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\"/"+board.Name+"/"+util.ShortURL(board.Outbox, op)+"#"+id+"\">>>"+id+""+isOP+"</a>", -1) - } else { - //this is a cross post - - parsedOP, err := db.GetReplyOP(parsedLink) - if err == nil { - link = parsedOP + "#" + util.ShortURL(parsedOP, parsedLink) - } - - actor, err := webfinger.FingerActor(parsedLink) - if err == nil && actor.Id != "" { - content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\""+link+"\">>>"+util.ShortURL(board.Outbox, parsedLink)+isOP+" →</a>", -1) - } - } - } - - return content, nil -} - -func ParseCommentQuotes(content string) string { - // replace quotes - re := regexp.MustCompile(`((\r\n|\r|\n|^)>(.+)?[^\r\n])`) - match := re.FindAllStringSubmatch(content, -1) - - for i, _ := range match { - quote := strings.Replace(match[i][0], ">", ">", 1) - line := re.ReplaceAllString(match[i][0], "<span class=\"quote\">"+quote+"</span>") - content = strings.Replace(content, match[i][0], line, 1) - } - - //replace isolated greater than symboles - re = regexp.MustCompile(`(\r\n|\n|\r)>`) - - return re.ReplaceAllString(content, "\r\n<span class=\"quote\">></span>") -} diff --git a/db/follow.go b/db/follow.go index 1aa9965..3f7868d 100644 --- a/db/follow.go +++ b/db/follow.go @@ -270,3 +270,35 @@ func MakeActivityRequest(activity activitypub.Activity) error { return nil } + +func SendToFollowers(actor string, activity activitypub.Activity) error { + nActor, err := activitypub.GetActorFromDB(actor) + if err != nil { + return err + } + + activity.Actor = &nActor + + followers, err := activitypub.GetActorFollowDB(actor) + if err != nil { + return err + } + + var to []string + + for _, e := range followers { + for _, k := range activity.To { + if e.Id != k { + to = append(to, e.Id) + } + } + } + + activity.To = to + + if len(activity.Object.InReplyTo) > 0 { + err = MakeActivityRequest(activity) + } + + return err +} @@ -84,7 +84,7 @@ func main() { app.Post("/:actor", routes.ActorPost) app.Get("/:actor/catalog", routes.CatalogGet) app.Get("/:actor/:post", routes.PostGet) - app.Get("/:actor/inbox", routes.ActorInbox) + app.Post("/:actor/inbox", routes.ActorInbox) app.Post("/:actor/outbox", routes.ActorOutbox) app.Get("/:actor/following", routes.ActorFollowing) app.Get("/:actor/followers", routes.ActorFollowers) @@ -183,14 +183,14 @@ func TemplateFunctions(engine *html.Engine) { return fmt.Sprint(t.Unix()) }) - engine.AddFunc("proxy", MediaProxy) + engine.AddFunc("proxy", util.MediaProxy) // previously short engine.AddFunc("shortURL", util.ShortURL) - engine.AddFunc("parseAttachment", ParseAttachment) + engine.AddFunc("parseAttachment", post.ParseAttachment) - engine.AddFunc("parseContent", ParseContent) + engine.AddFunc("parseContent", post.ParseContent) engine.AddFunc("shortImg", util.ShortImg) diff --git a/outboxGet.go b/outboxGet.go deleted file mode 100644 index 27e9cc4..0000000 --- a/outboxGet.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "net/http" - - "encoding/json" - - "github.com/FChannel0/FChannel-Server/activitypub" - "github.com/FChannel0/FChannel-Server/config" - "github.com/FChannel0/FChannel-Server/webfinger" - _ "github.com/lib/pq" -) - -func GetActorOutbox(w http.ResponseWriter, r *http.Request) error { - actor, err := webfinger.GetActorFromPath(r.URL.Path, "/") - if err != nil { - return err - } - - var collection activitypub.Collection - - c, err := activitypub.GetActorObjectCollectionFromDB(actor.Id) - if err != nil { - return err - } - collection.OrderedItems = c.OrderedItems - - collection.AtContext.Context = "https://www.w3.org/ns/activitystreams" - collection.Actor = &actor - - collection.TotalItems, err = activitypub.GetObjectPostsTotalDB(actor) - if err != nil { - return err - } - - collection.TotalImgs, err = activitypub.GetObjectImgsTotalDB(actor) - if err != nil { - return err - } - - enc, _ := json.Marshal(collection) - - w.Header().Set("Content-Type", config.ActivityStreams) - _, err = w.Write(enc) - return err -} diff --git a/outboxPost.go b/outboxPost.go deleted file mode 100644 index 677fa79..0000000 --- a/outboxPost.go +++ /dev/null @@ -1,245 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/FChannel0/FChannel-Server/activitypub" - "github.com/FChannel0/FChannel-Server/config" - "github.com/FChannel0/FChannel-Server/db" - "github.com/FChannel0/FChannel-Server/util" - "github.com/FChannel0/FChannel-Server/webfinger" - "github.com/gofiber/fiber/v2" - _ "github.com/lib/pq" -) - -func ParseInboxRequest(ctx *fiber.Ctx) error { - activity, err := activitypub.GetActivityFromJson(ctx) - if err != nil { - return err - } - - if activity.Actor.PublicKey.Id == "" { - nActor, err := webfinger.FingerActor(activity.Actor.Id) - if err != nil { - return err - } - - activity.Actor = &nActor - } - - if !db.VerifyHeaderSignature(ctx, *activity.Actor) { - response := activitypub.RejectActivity(activity) - - return db.MakeActivityRequest(response) - } - - switch activity.Type { - case "Create": - - for _, e := range activity.To { - if res, err := activitypub.IsActorLocal(e); err == nil && res { - if res, err := activitypub.IsActorLocal(activity.Actor.Id); err == nil && res { - col, err := activitypub.GetCollectionFromID(activity.Object.Id) - if err != nil { - return err - } - - if len(col.OrderedItems) < 1 { - break - } - - if _, err := activitypub.WriteObjectToCache(*activity.Object); err != nil { - return err - } - - actor, err := activitypub.GetActorFromDB(e) - if err != nil { - return err - } - - if err := db.ArchivePosts(actor); err != nil { - return err - } - - //SendToFollowers(e, activity) - } else if err != nil { - return err - } - } else if err != nil { - return err - } - } - - break - - case "Delete": - for _, e := range activity.To { - actor, err := activitypub.GetActorFromDB(e) - if err != nil { - return err - } - - if actor.Id != "" && actor.Id != config.Domain { - if activity.Object.Replies != nil { - for _, k := range activity.Object.Replies.OrderedItems { - if err := activitypub.TombstoneObject(k.Id); err != nil { - return err - } - } - } - - if err := activitypub.TombstoneObject(activity.Object.Id); err != nil { - return err - } - if err := db.UnArchiveLast(actor.Id); err != nil { - return err - } - break - } - } - break - - case "Follow": - for _, e := range activity.To { - if res, err := activitypub.GetActorFromDB(e); err == nil && res.Id != "" { - response := db.AcceptFollow(activity) - response, err := activitypub.SetActorFollowerDB(response) - if err != nil { - return err - } - - if err := db.MakeActivityRequest(response); err != nil { - return err - } - - alreadyFollow := false - alreadyFollowing := false - autoSub, err := activitypub.GetActorAutoSubscribeDB(response.Actor.Id) - if err != nil { - return err - } - - following, err := activitypub.GetActorFollowingDB(response.Actor.Id) - if err != nil { - return err - } - - for _, e := range following { - if e.Id == response.Object.Id { - alreadyFollow = true - } - } - - actor, err := webfinger.FingerActor(response.Object.Actor) - if err != nil { - return err - } - - remoteActorFollowingCol, err := webfinger.GetCollectionFromReq(actor.Following) - if err != nil { - return err - } - - for _, e := range remoteActorFollowingCol.Items { - if e.Id == response.Actor.Id { - alreadyFollowing = true - } - } - - if autoSub && !alreadyFollow && alreadyFollowing { - followActivity, err := db.MakeFollowActivity(response.Actor.Id, response.Object.Actor) - if err != nil { - return err - } - - if res, err := webfinger.FingerActor(response.Object.Actor); err == nil && res.Id != "" { - if err := db.MakeActivityRequestOutbox(followActivity); err != nil { - return err - } - } else if err != nil { - return err - } - } - } else if err != nil { - return err - } else { - fmt.Println("follow request for rejected") - response := activitypub.RejectActivity(activity) - - return db.MakeActivityRequest(response) - } - } - break - - case "Reject": - if activity.Object.Object.Type == "Follow" { - fmt.Println("follow rejected") - if _, err := db.SetActorFollowingDB(activity); err != nil { - return err - } - } - break - } - - return nil -} - -func MakeActivityFollowingReq(w http.ResponseWriter, r *http.Request, activity activitypub.Activity) (bool, error) { - actor, err := webfinger.GetActor(activity.Object.Id) - if err != nil { - return false, err - } - - req, err := http.NewRequest("POST", actor.Inbox, nil) - if err != nil { - return false, err - } - - resp, err := util.RouteProxy(req) - if err != nil { - return false, err - } - defer resp.Body.Close() - - body, _ := ioutil.ReadAll(resp.Body) - - var respActivity activitypub.Activity - - err = json.Unmarshal(body, &respActivity) - return respActivity.Type == "Accept", err -} - -func SendToFollowers(actor string, activity activitypub.Activity) error { - nActor, err := activitypub.GetActorFromDB(actor) - if err != nil { - return err - } - - activity.Actor = &nActor - - followers, err := activitypub.GetActorFollowDB(actor) - if err != nil { - return err - } - - var to []string - - for _, e := range followers { - for _, k := range activity.To { - if e.Id != k { - to = append(to, e.Id) - } - } - } - - activity.To = to - - if len(activity.Object.InReplyTo) > 0 { - err = db.MakeActivityRequest(activity) - } - - return err -} diff --git a/post/util.go b/post/util.go index c653276..b9d9b80 100644 --- a/post/util.go +++ b/post/util.go @@ -2,6 +2,7 @@ package post import ( "fmt" + "html/template" "io/ioutil" "mime/multipart" "os" @@ -382,3 +383,181 @@ func ResizeAttachmentToPreview() error { return nil }) } + +func ParseAttachment(obj activitypub.ObjectBase, catalog bool) template.HTML { + // TODO: convert all of these to Sprintf statements, or use strings.Builder or something, anything but this really + // string concatenation is highly inefficient _especially_ when being used like this + + if len(obj.Attachment) < 1 { + return "" + } + + var media string + if regexp.MustCompile(`image\/`).MatchString(obj.Attachment[0].MediaType) { + media = "<img " + media += "id=\"img\" " + media += "main=\"1\" " + media += "enlarge=\"0\" " + media += "attachment=\"" + obj.Attachment[0].Href + "\"" + if catalog { + media += "style=\"max-width: 180px; max-height: 180px;\" " + } else { + media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\"" + } + if obj.Preview.Id != "" { + media += "src=\"" + util.MediaProxy(obj.Preview.Href) + "\"" + media += "preview=\"" + util.MediaProxy(obj.Preview.Href) + "\"" + } else { + media += "src=\"" + util.MediaProxy(obj.Attachment[0].Href) + "\"" + media += "preview=\"" + util.MediaProxy(obj.Attachment[0].Href) + "\"" + } + + media += ">" + + return template.HTML(media) + } + + if regexp.MustCompile(`audio\/`).MatchString(obj.Attachment[0].MediaType) { + media = "<audio " + media += "controls=\"controls\" " + media += "preload=\"metadta\" " + if catalog { + media += "style=\"margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;\" " + } else { + media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\" " + } + media += ">" + media += "<source " + media += "src=\"" + util.MediaProxy(obj.Attachment[0].Href) + "\" " + media += "type=\"" + obj.Attachment[0].MediaType + "\" " + media += ">" + media += "Audio is not supported." + media += "</audio>" + + return template.HTML(media) + } + + if regexp.MustCompile(`video\/`).MatchString(obj.Attachment[0].MediaType) { + media = "<video " + media += "controls=\"controls\" " + media += "preload=\"metadta\" " + media += "muted=\"muted\" " + if catalog { + media += "style=\"margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;\" " + } else { + media += "style=\"float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;\" " + } + media += ">" + media += "<source " + media += "src=\"" + util.MediaProxy(obj.Attachment[0].Href) + "\" " + media += "type=\"" + obj.Attachment[0].MediaType + "\" " + media += ">" + media += "Video is not supported." + media += "</video>" + + return template.HTML(media) + } + + return template.HTML(media) +} + +func ParseContent(board activitypub.Actor, op string, content string, thread activitypub.ObjectBase) (template.HTML, error) { + // TODO: should escape more than just < and >, should also escape &, ", and ' + nContent := strings.ReplaceAll(content, `<`, "<") + + nContent, err := ParseLinkComments(board, op, nContent, thread) + if err != nil { + return "", err + } + + nContent = ParseCommentQuotes(nContent) + + nContent = strings.ReplaceAll(nContent, `/\<`, ">") + + return template.HTML(nContent), nil +} + +func ParseLinkComments(board activitypub.Actor, op string, content string, thread activitypub.ObjectBase) (string, error) { + re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)(f[A-Za-z0-9_.\-~]+-)?([A-Za-z0-9_.\-~]+)?#?([A-Za-z0-9_.\-~]+)?)`) + match := re.FindAllStringSubmatch(content, -1) + + //add url to each matched reply + for i, _ := range match { + link := strings.Replace(match[i][0], ">>", "", 1) + isOP := "" + + domain := match[i][2] + + if link == op { + isOP = " (OP)" + } + + parsedLink := ConvertHashLink(domain, link) + + //formate the hover title text + var quoteTitle string + + // if the quoted content is local get it + // else get it from the database + if thread.Id == link { + quoteTitle = ParseLinkTitle(board.Outbox, op, thread.Content) + } else { + for _, e := range thread.Replies.OrderedItems { + if e.Id == parsedLink { + quoteTitle = ParseLinkTitle(board.Outbox, op, e.Content) + break + } + } + + if quoteTitle == "" { + obj, err := activitypub.GetObjectFromDBFromID(parsedLink) + if err != nil { + return "", err + } + + if len(obj.OrderedItems) > 0 { + quoteTitle = ParseLinkTitle(board.Outbox, op, obj.OrderedItems[0].Content) + } else { + quoteTitle = ParseLinkTitle(board.Outbox, op, parsedLink) + } + } + } + + if replyID, isReply, err := db.IsReplyToOP(op, parsedLink); err == nil || !isReply { + id := util.ShortURL(board.Outbox, replyID) + + content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\"/"+board.Name+"/"+util.ShortURL(board.Outbox, op)+"#"+id+"\">>>"+id+""+isOP+"</a>", -1) + } else { + //this is a cross post + + parsedOP, err := db.GetReplyOP(parsedLink) + if err == nil { + link = parsedOP + "#" + util.ShortURL(parsedOP, parsedLink) + } + + actor, err := webfinger.FingerActor(parsedLink) + if err == nil && actor.Id != "" { + content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\""+link+"\">>>"+util.ShortURL(board.Outbox, parsedLink)+isOP+" →</a>", -1) + } + } + } + + return content, nil +} + +func ParseCommentQuotes(content string) string { + // replace quotes + re := regexp.MustCompile(`((\r\n|\r|\n|^)>(.+)?[^\r\n])`) + match := re.FindAllStringSubmatch(content, -1) + + for i, _ := range match { + quote := strings.Replace(match[i][0], ">", ">", 1) + line := re.ReplaceAllString(match[i][0], "<span class=\"quote\">"+quote+"</span>") + content = strings.Replace(content, match[i][0], line, 1) + } + + //replace isolated greater than symboles + re = regexp.MustCompile(`(\r\n|\n|\r)>`) + + return re.ReplaceAllString(content, "\r\n<span class=\"quote\">></span>") +} diff --git a/routes/actor.go b/routes/actor.go index 7b57309..d8b6631 100644 --- a/routes/actor.go +++ b/routes/actor.go @@ -18,10 +18,176 @@ import ( "github.com/gofiber/fiber/v2" ) -func ActorInbox(c *fiber.Ctx) error { - // STUB +func ActorInbox(ctx *fiber.Ctx) error { + activity, err := activitypub.GetActivityFromJson(ctx) + if err != nil { + return err + } + + if activity.Actor.PublicKey.Id == "" { + nActor, err := webfinger.FingerActor(activity.Actor.Id) + if err != nil { + return err + } + + activity.Actor = &nActor + } + + if !db.VerifyHeaderSignature(ctx, *activity.Actor) { + response := activitypub.RejectActivity(activity) + + return db.MakeActivityRequest(response) + } + + switch activity.Type { + case "Create": + + for _, e := range activity.To { + if res, err := activitypub.IsActorLocal(e); err == nil && res { + if res, err := activitypub.IsActorLocal(activity.Actor.Id); err == nil && res { + col, err := activitypub.GetCollectionFromID(activity.Object.Id) + if err != nil { + return err + } + + if len(col.OrderedItems) < 1 { + break + } + + if _, err := activitypub.WriteObjectToCache(*activity.Object); err != nil { + return err + } + + actor, err := activitypub.GetActorFromDB(e) + if err != nil { + return err + } + + if err := db.ArchivePosts(actor); err != nil { + return err + } + + //SendToFollowers(e, activity) + } else if err != nil { + return err + } + } else if err != nil { + return err + } + } + + break + + case "Delete": + for _, e := range activity.To { + actor, err := activitypub.GetActorFromDB(e) + if err != nil { + return err + } + + if actor.Id != "" && actor.Id != config.Domain { + if activity.Object.Replies != nil { + for _, k := range activity.Object.Replies.OrderedItems { + if err := activitypub.TombstoneObject(k.Id); err != nil { + return err + } + } + } + + if err := activitypub.TombstoneObject(activity.Object.Id); err != nil { + return err + } + if err := db.UnArchiveLast(actor.Id); err != nil { + return err + } + break + } + } + break + + case "Follow": + for _, e := range activity.To { + if res, err := activitypub.GetActorFromDB(e); err == nil && res.Id != "" { + response := db.AcceptFollow(activity) + response, err := activitypub.SetActorFollowerDB(response) + if err != nil { + return err + } + + if err := db.MakeActivityRequest(response); err != nil { + return err + } + + alreadyFollow := false + alreadyFollowing := false + autoSub, err := activitypub.GetActorAutoSubscribeDB(response.Actor.Id) + if err != nil { + return err + } + + following, err := activitypub.GetActorFollowingDB(response.Actor.Id) + if err != nil { + return err + } + + for _, e := range following { + if e.Id == response.Object.Id { + alreadyFollow = true + } + } + + actor, err := webfinger.FingerActor(response.Object.Actor) + if err != nil { + return err + } + + remoteActorFollowingCol, err := webfinger.GetCollectionFromReq(actor.Following) + if err != nil { + return err + } + + for _, e := range remoteActorFollowingCol.Items { + if e.Id == response.Actor.Id { + alreadyFollowing = true + } + } + + if autoSub && !alreadyFollow && alreadyFollowing { + followActivity, err := db.MakeFollowActivity(response.Actor.Id, response.Object.Actor) + if err != nil { + return err + } + + if res, err := webfinger.FingerActor(response.Object.Actor); err == nil && res.Id != "" { + if err := db.MakeActivityRequestOutbox(followActivity); err != nil { + return err + } + } else if err != nil { + return err + } + } + } else if err != nil { + return err + } else { + fmt.Println("follow request for rejected") + response := activitypub.RejectActivity(activity) - return c.SendString("actor inbox") + return db.MakeActivityRequest(response) + } + } + break + + case "Reject": + if activity.Object.Object.Type == "Follow" { + fmt.Println("follow rejected") + if _, err := db.SetActorFollowingDB(activity); err != nil { + return err + } + } + break + } + + return nil } func ActorOutbox(ctx *fiber.Ctx) error { @@ -31,6 +197,11 @@ func ActorOutbox(ctx *fiber.Ctx) error { return err } + if activitypub.AcceptActivity(ctx.Get("Accept")) { + activitypub.GetActorOutbox(ctx, actor) + return nil + } + contentType := util.GetContentType(ctx.Get("content-type")) if contentType == "multipart/form-data" || contentType == "application/x-www-form-urlencoded" { diff --git a/util/proxy.go b/util/proxy.go index 1fc9b03..0f4a648 100644 --- a/util/proxy.go +++ b/util/proxy.go @@ -37,3 +37,20 @@ func GetPathProxyType(path string) string { return "clearnet" } + +func MediaProxy(url string) string { + re := regexp.MustCompile("(.+)?" + config.Domain + "(.+)?") + + if re.MatchString(url) { + return url + } + + re = regexp.MustCompile("(.+)?\\.onion(.+)?") + + if re.MatchString(url) { + return url + } + + config.MediaHashs[HashMedia(url)] = url + return "/api/media?hash=" + HashMedia(url) +} diff --git a/webfinger/webfinger.go b/webfinger/webfinger.go index a58c9ab..5b96d62 100644 --- a/webfinger/webfinger.go +++ b/webfinger/webfinger.go @@ -283,3 +283,28 @@ func AddInstanceToIndexDB(actor string) error { return nil } + +func MakeActivityFollowingReq(w http.ResponseWriter, r *http.Request, activity activitypub.Activity) (bool, error) { + actor, err := GetActor(activity.Object.Id) + if err != nil { + return false, err + } + + req, err := http.NewRequest("POST", actor.Inbox, nil) + if err != nil { + return false, err + } + + resp, err := util.RouteProxy(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + var respActivity activitypub.Activity + + err = json.Unmarshal(body, &respActivity) + return respActivity.Type == "Accept", err +} |