aboutsummaryrefslogtreecommitdiff
path: root/routes
diff options
context:
space:
mode:
Diffstat (limited to 'routes')
-rw-r--r--routes/actor.go381
-rw-r--r--routes/admin.go4
-rw-r--r--routes/post.go6
-rw-r--r--routes/structs.go4
4 files changed, 384 insertions, 11 deletions
diff --git a/routes/actor.go b/routes/actor.go
index f107ed7..6e5955e 100644
--- a/routes/actor.go
+++ b/routes/actor.go
@@ -1,6 +1,22 @@
package routes
-import "github.com/gofiber/fiber/v2"
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "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/post"
+ "github.com/FChannel0/FChannel-Server/util"
+ "github.com/FChannel0/FChannel-Server/webfinger"
+ "github.com/gofiber/fiber/v2"
+)
func ActorInbox(c *fiber.Ctx) error {
// STUB
@@ -8,10 +24,211 @@ func ActorInbox(c *fiber.Ctx) error {
return c.SendString("actor inbox")
}
-func ActorOutbox(c *fiber.Ctx) error {
- // STUB
+func ActorOutbox(ctx *fiber.Ctx) error {
+ //var activity activitypub.Activity
+ actor, err := webfinger.GetActorFromPath(ctx.Path(), "/")
+ if err != nil {
+ return err
+ }
+
+ contentType := util.GetContentType(ctx.Get("content-type"))
+
+ if contentType == "multipart/form-data" || contentType == "application/x-www-form-urlencoded" {
+ hasCaptcha, err := db.BoardHasAuthType(actor.Name, "captcha")
+ if err != nil {
+ return err
+ }
+
+ 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) {
+ return ctx.Render("403", fiber.Map{
+ "message": "7MB max file size",
+ })
+ } else if res, err := post.IsMediaBanned(f); err == nil && res {
+ //Todo add logging
+ fmt.Println("media banned")
+ return ctx.Redirect("/", 301)
+ } else if err != nil {
+ return err
+ }
+
+ contentType, _ := util.GetFileContentType(f)
+
+ if !post.SupportedMIMEType(contentType) {
+ return ctx.Render("403", fiber.Map{
+ "message": "file type not supported",
+ })
+ }
+ }
+
+ var nObj = activitypub.CreateObject("Note")
+ nObj, err := post.ObjectFromForm(ctx, nObj)
+ if err != nil {
+ return err
+ }
+
+ nObj.Actor = config.Domain + "/" + actor.Name
+
+ nObj, err = activitypub.WriteObjectToDB(nObj)
+ if err != nil {
+ return err
+ }
+
+ if len(nObj.To) == 0 {
+ if err := db.ArchivePosts(actor); err != nil {
+ return err
+ }
+ }
+
+ activity, err := webfinger.CreateActivity("Create", nObj)
+ if err != nil {
+ return err
+ }
+
+ activity, err = webfinger.AddFollowersToActivity(activity)
+ if err != nil {
+ return err
+ }
+
+ go db.MakeActivityRequest(activity)
+
+ 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 err
+ }
+
+ ctx.Response().Header.Set("Status", "403")
+ _, err = ctx.Write([]byte("captcha could not auth"))
+ return err
+ } else { // json request
+ activity, err := activitypub.GetActivityFromJson(ctx)
+ if err != nil {
+ return err
+ }
+
+ if res, err := activitypub.IsActivityLocal(activity); err == nil && res {
+ if res := db.VerifyHeaderSignature(ctx, *activity.Actor); err == nil && !res {
+ ctx.Response().Header.Set("Status", "403")
+ _, err = ctx.Write([]byte(""))
+ return err
+ }
+
+ switch activity.Type {
+ case "Create":
+ ctx.Response().Header.Set("Status", "403")
+ _, err = ctx.Write([]byte(""))
+ break
+
+ case "Follow":
+ var validActor bool
+ var validLocalActor bool
+
+ validActor = (activity.Object.Actor != "")
+ validLocalActor = (activity.Actor.Id == actor.Id)
+
+ var rActivity activitypub.Activity
+ if validActor && validLocalActor {
+ rActivity = db.AcceptFollow(activity)
+ rActivity, err = db.SetActorFollowingDB(rActivity)
+ if err != nil {
+ return err
+ }
+ if err := db.MakeActivityRequest(activity); err != nil {
+ return err
+ }
+ }
+
+ webfinger.FollowingBoards, err = activitypub.GetActorFollowingDB(config.Domain)
+ if err != nil {
+ return err
+ }
+
+ webfinger.Boards, err = webfinger.GetBoardCollection()
+ if err != nil {
+ return err
+ }
+ break
+
+ case "Delete":
+ fmt.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.CreateNewBoardDB(*activitypub.CreateNewActor(name, prefname, summary, config.AuthReq, restricted))
+ if err != nil {
+ return err
+ }
+
+ 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 err
+ }
+
+ 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 err
+ } else {
+ fmt.Println("is NOT activity")
+ ctx.Response().Header.Set("Status", "403")
+ _, err = ctx.Write([]byte("could not process activity"))
+ return err
+ }
+ }
- return c.SendString("actor outbox")
+ return nil
}
func ActorFollowing(c *fiber.Ctx) error {
@@ -38,8 +255,158 @@ func ActorArchive(c *fiber.Ctx) error {
return c.SendString("actor archive")
}
-func ActorPost(c *fiber.Ctx) error {
- // STUB
+func ActorPost(ctx *fiber.Ctx) error {
+ header, _ := ctx.FormFile("file")
+
+ if ctx.FormValue("inReplyTo") == "" && header == nil {
+ return ctx.Render("403", fiber.Map{
+ "message": "Media is required for new posts",
+ })
+ }
+
+ var file multipart.File
+
+ if header != nil {
+ file, _ = header.Open()
+ }
+
+ if file != nil && header.Size > (7<<20) {
+ return ctx.Render("403", fiber.Map{
+ "message": "7MB max file size",
+ })
+ }
+
+ if is, _ := util.IsPostBlacklist(ctx.FormValue("comment")); is {
+ errors.New("\n\nBlacklist post blocked\n\n")
+ return ctx.Redirect("/", 301)
+ }
+
+ if ctx.FormValue("inReplyTo") == "" || file == nil {
+ if ctx.FormValue("comment") == "" && ctx.FormValue("subject") == "" {
+ return ctx.Render("403", fiber.Map{
+ "message": "Comment or Subject required",
+ })
+ }
+ }
+
+ if len(ctx.FormValue("comment")) > 2000 {
+ return ctx.Render("403", fiber.Map{
+ "message": "Comment limit 2000 characters",
+ })
+ }
+
+ if len(ctx.FormValue("subject")) > 100 || len(ctx.FormValue("name")) > 100 || len(ctx.FormValue("options")) > 100 {
+ return ctx.Render("403", fiber.Map{
+ "message": "Name, Subject or Options limit 100 characters",
+ })
+ }
+
+ if ctx.FormValue("captcha") == "" {
+ return ctx.Render("403", fiber.Map{
+ "message": "Incorrect Captcha",
+ })
+ }
+
+ b := bytes.Buffer{}
+ we := multipart.NewWriter(&b)
+
+ if file != nil {
+ var fw io.Writer
+
+ fw, err := we.CreateFormFile("file", header.Filename)
+
+ if err != nil {
+ errors.New("error with form file create")
+ }
+ _, err = io.Copy(fw, file)
+
+ if err != nil {
+ errors.New("error with form file copy")
+ }
+ }
+
+ reply, _ := post.ParseCommentForReply(ctx.FormValue("comment"))
+
+ form, _ := ctx.MultipartForm()
+
+ for key, r0 := range form.Value {
+ if key == "captcha" {
+ err := we.WriteField(key, ctx.FormValue("captchaCode")+":"+ctx.FormValue("captcha"))
+ if err != nil {
+ errors.New("error with writing captcha field")
+ }
+ } else if key == "name" {
+ name, tripcode, _ := post.CreateNameTripCode(ctx)
+
+ err := we.WriteField(key, name)
+ if err != nil {
+ errors.New("error with writing name field")
+ }
+
+ err = we.WriteField("tripcode", tripcode)
+ if err != nil {
+ errors.New("error with writing tripcode field")
+ }
+ } else {
+ err := we.WriteField(key, r0[0])
+ if err != nil {
+ errors.New("error with writing field")
+ }
+ }
+ }
+
+ if ctx.FormValue("inReplyTo") == "" && reply != "" {
+ err := we.WriteField("inReplyTo", reply)
+ if err != nil {
+ errors.New("error with writing inReplyTo field")
+ }
+ }
+
+ we.Close()
+
+ sendTo := ctx.FormValue("sendTo")
+
+ req, err := http.NewRequest("POST", sendTo, &b)
+
+ if err != nil {
+ errors.New("error with post form req")
+ }
+
+ req.Header.Set("Content-Type", we.FormDataContentType())
+
+ resp, err := util.RouteProxy(req)
+
+ if err != nil {
+ errors.New("error with post form resp")
+ }
+
+ defer resp.Body.Close()
+
+ if resp.StatusCode == 200 {
+
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ var obj activitypub.ObjectBase
+
+ obj = post.ParseOptions(ctx, obj)
+ for _, e := range obj.Option {
+ if e == "noko" || e == "nokosage" {
+ return ctx.Redirect(config.Domain+"/"+ctx.FormValue("boardName")+"/"+util.ShortURL(ctx.FormValue("sendTo"), string(body)), 301)
+ }
+ }
+
+ if ctx.FormValue("returnTo") == "catalog" {
+ return ctx.Redirect(config.Domain+"/"+ctx.FormValue("boardName")+"/catalog", 301)
+ } else {
+ return ctx.Redirect(config.Domain+"/"+ctx.FormValue("boardName"), 301)
+ }
+ }
+
+ if resp.StatusCode == 403 {
+ return ctx.Render("403", fiber.Map{
+ "message": "Incorrect Captcha",
+ })
+ }
- return c.SendString("actor post")
+ return ctx.Redirect(config.Domain+"/"+ctx.FormValue("boardName"), 301)
}
diff --git a/routes/admin.go b/routes/admin.go
index c714b06..a2f7cd2 100644
--- a/routes/admin.go
+++ b/routes/admin.go
@@ -3,7 +3,7 @@ package routes
import (
"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"
)
@@ -54,7 +54,7 @@ func AdminIndex(ctx *fiber.Ctx) error {
adminData.Board.Post.Actor = actor.Id
- adminData.PostBlacklist, _ = post.GetRegexBlacklistDB()
+ adminData.PostBlacklist, _ = util.GetRegexBlacklistDB()
adminData.Themes = &config.Themes
diff --git a/routes/post.go b/routes/post.go
index 016e533..64df600 100644
--- a/routes/post.go
+++ b/routes/post.go
@@ -17,6 +17,12 @@ func PostGet(ctx *fiber.Ctx) error {
return err
}
+ // this is a activitpub json request return json instead of html page
+ if activitypub.AcceptActivity(ctx.Get("Accept")) {
+ activitypub.GetActorPost(ctx, ctx.Path())
+ return nil
+ }
+
postId := ctx.Params("post")
inReplyTo := actor.Id + "/" + postId
diff --git a/routes/structs.go b/routes/structs.go
index 8cfb6ee..7c6e980 100644
--- a/routes/structs.go
+++ b/routes/structs.go
@@ -3,7 +3,7 @@ package routes
import (
"github.com/FChannel0/FChannel-Server/activitypub"
"github.com/FChannel0/FChannel-Server/db"
- "github.com/FChannel0/FChannel-Server/post"
+ "github.com/FChannel0/FChannel-Server/util"
"github.com/FChannel0/FChannel-Server/webfinger"
)
@@ -40,7 +40,7 @@ type AdminPage struct {
Reported []db.Report
Domain string
IsLocal bool
- PostBlacklist []post.PostBlacklist
+ PostBlacklist []util.PostBlacklist
AutoSubscribe bool
Themes *[]string