From a66b676481d273508927e64a22e388dc302890ba Mon Sep 17 00:00:00 2001 From: FChannel <> Date: Sun, 22 May 2022 14:08:36 -0700 Subject: route organization --- route/util.go | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 route/util.go (limited to 'route/util.go') diff --git a/route/util.go b/route/util.go new file mode 100644 index 0000000..5bd15d6 --- /dev/null +++ b/route/util.go @@ -0,0 +1,377 @@ +package route + +import ( + "encoding/json" + "fmt" + "html/template" + "regexp" + "strings" + "time" + + "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/gofiber/fiber/v2" + "github.com/gofiber/template/html" +) + +func GetThemeCookie(c *fiber.Ctx) string { + cookie := c.Cookies("theme") + if cookie != "" { + cookies := strings.SplitN(cookie, "=", 2) + return cookies[0] + } + + return "default" +} + +func WantToServeCatalog(actorName string) (activitypub.Collection, bool, error) { + var collection activitypub.Collection + serve := false + + actor, err := activitypub.GetActorByNameFromDB(actorName) + if err != nil { + return collection, false, util.MakeError(err, "WantToServeCatalog") + } + + if actor.Id != "" { + collection, err = actor.GetCatalogCollection() + if err != nil { + return collection, false, util.MakeError(err, "WantToServeCatalog") + } + + collection.Actor = actor + return collection, true, nil + } + + return collection, serve, nil +} + +func WantToServeArchive(actorName string) (activitypub.Collection, bool, error) { + var collection activitypub.Collection + serve := false + + actor, err := activitypub.GetActorByNameFromDB(actorName) + if err != nil { + return collection, false, util.MakeError(err, "WantToServeArchive") + } + + if actor.Id != "" { + collection, err = actor.GetCollectionType("Archive") + if err != nil { + return collection, false, util.MakeError(err, "WantToServeArchive") + } + + collection.Actor = actor + return collection, true, nil + } + + return collection, serve, nil +} + +func GetActorPost(ctx *fiber.Ctx, path string) error { + obj := activitypub.ObjectBase{Id: config.Domain + "" + path} + collection, err := obj.GetCollectionFromPath() + + if err != nil { + return util.MakeError(err, "GetActorPost") + } + + if len(collection.OrderedItems) > 0 { + enc, err := json.MarshalIndent(collection, "", "\t") + if err != nil { + return util.MakeError(err, "GetActorPost") + } + + ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") + _, err = ctx.Write(enc) + return util.MakeError(err, "GetActorPost") + } + + return nil +} + +func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error { + contentType := util.GetContentType(ctx.Get("content-type")) + + if contentType == "multipart/form-data" || contentType == "application/x-www-form-urlencoded" { + hasCaptcha, err := util.BoardHasAuthType(actor.Name, "captcha") + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + valid, err := post.CheckCaptcha(ctx.FormValue("captcha")) + if err == nil && hasCaptcha && valid { + header, _ := ctx.FormFile("file") + if header != nil { + f, _ := header.Open() + defer f.Close() + if header.Size > (7 << 20) { + ctx.Response().Header.SetStatusCode(403) + _, err := ctx.Write([]byte("7MB max file size")) + return util.MakeError(err, "ParseOutboxRequest") + } else if isBanned, err := post.IsMediaBanned(f); err == nil && isBanned { + //Todo add logging + config.Log.Println("media banned") + ctx.Response().Header.SetStatusCode(403) + _, err := ctx.Write([]byte("media banned")) + return util.MakeError(err, "ParseOutboxRequest") + } else if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + contentType, _ := util.GetFileContentType(f) + + if !post.SupportedMIMEType(contentType) { + ctx.Response().Header.SetStatusCode(403) + _, err := ctx.Write([]byte("file type not supported")) + return util.MakeError(err, "ParseOutboxRequest") + } + } + + var nObj = activitypub.CreateObject("Note") + nObj, err := post.ObjectFromForm(ctx, nObj) + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + nObj.Actor = config.Domain + "/" + actor.Name + + nObj, err = nObj.Write() + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + if len(nObj.To) == 0 { + if err := actor.ArchivePosts(); err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + } + + activity, err := nObj.CreateActivity("Create") + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + activity, err = activity.AddFollowersTo() + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + go activity.MakeRequestInbox() + + var id string + op := len(nObj.InReplyTo) - 1 + if op >= 0 { + if nObj.InReplyTo[op].Id == "" { + id = nObj.Id + } else { + id = nObj.InReplyTo[0].Id + "|" + nObj.Id + } + } + + ctx.Response().Header.Set("Status", "200") + _, err = ctx.Write([]byte(id)) + return util.MakeError(err, "ParseOutboxRequest") + } + + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("captcha could not auth")) + return util.MakeError(err, "") + } else { // json request + activity, err := activitypub.GetActivityFromJson(ctx) + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + if res, err := activity.IsLocal(); err == nil && res { + if res := activity.Actor.VerifyHeaderSignature(ctx); err == nil && !res { + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("")) + return util.MakeError(err, "ParseOutboxRequest") + } + + switch activity.Type { + case "Create": + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("")) + break + + case "Follow": + validActor := (activity.Object.Actor != "") + validLocalActor := (activity.Actor.Id == actor.Id) + + var rActivity activitypub.Activity + + if validActor && validLocalActor { + rActivity = activity.AcceptFollow() + rActivity, err = rActivity.SetActorFollowing() + + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + if err := activity.MakeRequestInbox(); err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + } + + actor, _ := activitypub.GetActorFromDB(config.Domain) + webfinger.FollowingBoards, err = actor.GetFollowing() + + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + webfinger.Boards, err = webfinger.GetBoardCollection() + + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + break + + case "Delete": + config.Log.Println("This is a delete") + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("could not process activity")) + break + + case "Note": + ctx.Response().Header.Set("Satus", "403") + _, err = ctx.Write([]byte("could not process activity")) + break + + case "New": + name := activity.Object.Alias + prefname := activity.Object.Name + summary := activity.Object.Summary + restricted := activity.Object.Sensitive + + actor, err := db.CreateNewBoard(*activitypub.CreateNewActor(name, prefname, summary, config.AuthReq, restricted)) + if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } + + if actor.Id != "" { + var board []activitypub.ObjectBase + var item activitypub.ObjectBase + var removed bool = false + + item.Id = actor.Id + for _, e := range webfinger.FollowingBoards { + if e.Id != item.Id { + board = append(board, e) + } else { + removed = true + } + } + + if !removed { + board = append(board, item) + } + + webfinger.FollowingBoards = board + webfinger.Boards, err = webfinger.GetBoardCollection() + return util.MakeError(err, "ParseOutboxRequest") + } + + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("")) + break + + default: + ctx.Response().Header.Set("status", "403") + _, err = ctx.Write([]byte("could not process activity")) + } + } else if err != nil { + return util.MakeError(err, "ParseOutboxRequest") + } else { + config.Log.Println("is NOT activity") + ctx.Response().Header.Set("Status", "403") + _, err = ctx.Write([]byte("could not process activity")) + return util.MakeError(err, "ParseOutboxRequest") + } + } + + return nil +} + +func TemplateFunctions(engine *html.Engine) { + engine.AddFunc("mod", func(i, j int) bool { + return i%j == 0 + }) + + engine.AddFunc("sub", func(i, j int) int { + return i - j + }) + + engine.AddFunc("add", func(i, j int) int { + return i + j + }) + + engine.AddFunc("unixtoreadable", func(u int) string { + return time.Unix(int64(u), 0).Format("Jan 02, 2006") + }) + + engine.AddFunc("timeToReadableLong", func(t time.Time) string { + return t.Format("01/02/06(Mon)15:04:05") + }) + + engine.AddFunc("timeToUnix", func(t time.Time) string { + return fmt.Sprint(t.Unix()) + }) + + engine.AddFunc("proxy", util.MediaProxy) + + // previously short + engine.AddFunc("shortURL", util.ShortURL) + + engine.AddFunc("parseAttachment", post.ParseAttachment) + + engine.AddFunc("parseContent", post.ParseContent) + + engine.AddFunc("shortImg", util.ShortImg) + + engine.AddFunc("convertSize", util.ConvertSize) + + engine.AddFunc("isOnion", util.IsOnion) + + engine.AddFunc("parseReplyLink", func(actorId string, op string, id string, content string) template.HTML { + actor, _ := activitypub.FingerActor(actorId) + title := strings.ReplaceAll(post.ParseLinkTitle(actor.Id+"/", op, content), `/\<`, ">") + link := ">>" + util.ShortURL(actor.Outbox, id) + "" + return template.HTML(link) + }) + + engine.AddFunc("shortExcerpt", func(post activitypub.ObjectBase) string { + var returnString string + + if post.Name != "" { + returnString = post.Name + "| " + post.Content + } else { + returnString = post.Content + } + + re := regexp.MustCompile(`(^(.|\r\n|\n){100})`) + + match := re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = match[0] + "..." + } + + re = regexp.MustCompile(`(^.+\|)`) + + match = re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = strings.Replace(returnString, match[0], ""+match[0]+"", 1) + returnString = strings.Replace(returnString, "|", ":", 1) + } + + return returnString + }) +} -- cgit v1.2.3