diff options
author | FChannel <> | 2022-05-02 12:07:00 -0700 |
---|---|---|
committer | FChannel <> | 2022-06-19 12:53:29 -0700 |
commit | 733f911fadc872933481bcbe087d519ce00372df (patch) | |
tree | 54788da4f730bd11934401c1eca48a3c87f08027 | |
parent | e80fe14f7985f9e85bfb9582926acd7891455786 (diff) |
cleaned up main
-rw-r--r-- | client.go | 2 | ||||
-rw-r--r-- | config/config.go | 1 | ||||
-rw-r--r-- | db/database.go | 169 | ||||
-rw-r--r-- | main.go | 527 | ||||
-rw-r--r-- | post/util.go | 59 | ||||
-rw-r--r-- | routes/api.go | 54 | ||||
-rw-r--r-- | routes/webfinger.go | 57 | ||||
-rw-r--r-- | util/util.go | 10 | ||||
-rw-r--r-- | webfinger/webfinger.go | 44 |
9 files changed, 430 insertions, 493 deletions
@@ -27,7 +27,7 @@ func MediaProxy(url string) string { return url } - MediaHashs[util.HashMedia(url)] = url + config.MediaHashs[util.HashMedia(url)] = url return "/api/media?hash=" + util.HashMedia(url) } diff --git a/config/config.go b/config/config.go index eb8cbdf..0fba1c1 100644 --- a/config/config.go +++ b/config/config.go @@ -30,6 +30,7 @@ var Redis = GetConfigValue("redis", "redis://localhost") var ActivityStreams = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" var AuthReq = []string{"captcha", "email", "passphrase"} var SupportedFiles = []string{"image/gif", "image/jpeg", "image/png", "image/webp", "image/apng", "video/mp4", "video/ogg", "video/webm", "audio/mpeg", "audio/ogg", "audio/wav", "audio/wave", "audio/x-wav"} +var MediaHashs = make(map[string]string) var Key string var Themes []string var DB *sql.DB diff --git a/db/database.go b/db/database.go index fcdb5f9..eb0bb98 100644 --- a/db/database.go +++ b/db/database.go @@ -2,9 +2,11 @@ package db import ( "database/sql" + "encoding/json" "fmt" "html/template" "io/ioutil" + "net/http" "os" "regexp" "strings" @@ -572,18 +574,13 @@ func CheckInactiveInstances() (map[string]string, error) { func GetAdminAuth() (string, string, error) { query := fmt.Sprintf("select identifier, code from boardaccess where board='%s' and type='admin'", config.Domain) - rows, err := config.DB.Query(query) - if err != nil { - return "", "", err - } - var code string var identifier string + if err := config.DB.QueryRow(query).Scan(&identifier, &code); err != nil { + return "", "", err + } - rows.Next() - err = rows.Scan(&identifier, &code) - - return code, identifier, err + return code, identifier, nil } func IsHashBanned(hash string) (bool, error) { @@ -595,3 +592,157 @@ func IsHashBanned(hash string) (bool, error) { return h == hash, nil } + +func MakeCaptchas(total int) error { + dbtotal, err := GetCaptchaTotal() + if err != nil { + return err + } + + difference := total - dbtotal + + for i := 0; i < difference; i++ { + if err := CreateNewCaptcha(); err != nil { + return err + } + } + + return nil +} + +func GetActorReported(w http.ResponseWriter, r *http.Request, id string) error { + auth := r.Header.Get("Authorization") + verification := strings.Split(auth, " ") + + if len(verification) < 2 { + w.WriteHeader(http.StatusBadRequest) + _, err := w.Write([]byte("")) + return err + } + + if res, err := HasAuth(verification[1], id); err == nil && !res { + w.WriteHeader(http.StatusBadRequest) + _, err = w.Write([]byte("")) + return err + } else if err != nil { + return err + } + + var following activitypub.Collection + var err error + + following.AtContext.Context = "https://www.w3.org/ns/activitystreams" + following.Type = "Collection" + following.TotalItems, err = activitypub.GetActorReportedTotal(id) + if err != nil { + return err + } + + following.Items, err = activitypub.GetActorReportedDB(id) + if err != nil { + return err + } + + enc, err := json.MarshalIndent(following, "", "\t") + if err != nil { + return err + } + + w.Header().Set("Content-Type", config.ActivityStreams) + + _, err = w.Write(enc) + return err +} + +func PrintAdminAuth() error { + identifier, code, err := GetAdminAuth() + if err != nil { + return err + } + + fmt.Println("Mod key: " + config.Key) + fmt.Println("Admin Login: " + identifier + ", Code: " + code) + return nil +} + +func DeleteObjectRequest(id string) error { + var nObj activitypub.ObjectBase + var nActor activitypub.Actor + nObj.Id = id + nObj.Actor = nActor.Id + + activity, err := webfinger.CreateActivity("Delete", nObj) + if err != nil { + return err + } + + obj, err := activitypub.GetObjectFromPath(id) + if err != nil { + return err + } + + actor, err := webfinger.FingerActor(obj.Actor) + if err != nil { + return err + } + activity.Actor = &actor + + followers, err := activitypub.GetActorFollowDB(obj.Actor) + if err != nil { + return err + } + + for _, e := range followers { + activity.To = append(activity.To, e.Id) + } + + following, err := activitypub.GetActorFollowingDB(obj.Actor) + if err != nil { + return err + } + for _, e := range following { + activity.To = append(activity.To, e.Id) + } + + return MakeActivityRequest(activity) +} + +func DeleteObjectAndRepliesRequest(id string) error { + var nObj activitypub.ObjectBase + var nActor activitypub.Actor + nObj.Id = id + nObj.Actor = nActor.Id + + activity, err := webfinger.CreateActivity("Delete", nObj) + if err != nil { + return err + } + + obj, err := activitypub.GetObjectByIDFromDB(id) + if err != nil { + return err + } + + activity.Actor.Id = obj.OrderedItems[0].Actor + + activity.Object = &obj.OrderedItems[0] + + followers, err := activitypub.GetActorFollowDB(obj.OrderedItems[0].Actor) + if err != nil { + return err + } + for _, e := range followers { + activity.To = append(activity.To, e.Id) + } + + following, err := activitypub.GetActorFollowingDB(obj.OrderedItems[0].Actor) + if err != nil { + return err + } + + for _, e := range following { + activity.To = append(activity.To, e.Id) + } + + return MakeActivityRequest(activity) +} @@ -1,8 +1,14 @@ package main import ( - "encoding/json" "fmt" + "html/template" + "io/ioutil" + "math/rand" + "path" + "regexp" + "strings" + "time" "github.com/FChannel0/FChannel-Server/activitypub" "github.com/FChannel0/FChannel-Server/config" @@ -15,91 +21,17 @@ import ( "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/template/html" - // "github.com/gofrs/uuid" _ "github.com/lib/pq" - - "html/template" - // "io" - "io/ioutil" - // "log" - "math/rand" - "net/http" - "os" - "os/exec" - "path" - "regexp" - "strings" - "time" ) -var MediaHashs = make(map[string]string) - -var Themes []string - -func init() { - rand.Seed(time.Now().UnixNano()) -} - func main() { - var err error - CreatedNeededDirectories() + Init() - db.ConnectDB() defer db.Close() - - db.InitCache() defer db.CloseCache() - db.RunDatabaseSchema() - - go MakeCaptchas(100) - - config.Key = util.CreateKey(32) - - webfinger.FollowingBoards, err = activitypub.GetActorFollowingDB(config.Domain) - - if err != nil { - panic(err) - } - - go db.StartupArchive() - - go db.CheckInactive() - - webfinger.Boards, err = webfinger.GetBoardCollection() - - if err != nil { - panic(err) - } - - // root actor is used to follow remote feeds that are not local - //name, prefname, summary, auth requirements, restricted - if config.InstanceName != "" { - if _, err = db.CreateNewBoardDB(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil { - //panic(err) - } - - if config.PublicIndexing == "true" { - // TODO: comment out later - //AddInstanceToIndex(config.Domain) - } - } - - // get list of themes - themes, err := ioutil.ReadDir("./static/css/themes") - if err != nil { - panic(err) - } - - for _, f := range themes { - if e := path.Ext(f.Name()); e == ".css" { - config.Themes = append(config.Themes, strings.TrimSuffix(f.Name(), e)) - } - } - - /* Routing and templates */ - + // Routing and templates template := html.New("./views", ".html") template.Debug(true) @@ -116,485 +48,114 @@ func main() { app.Static("/static", "./static") app.Static("/public", "./public") - /* - Main actor - */ - + // Main actor app.Get("/", routes.Index) - app.Get("/inbox", routes.Inbox) app.Get("/outbox", routes.Outbox) - app.Get("/following", routes.Following) app.Get("/followers", routes.Followers) - /* - Admin routes - */ - + // Admin routes app.Get("/verify", routes.AdminVerify) - app.Get("/auth", routes.AdminAuth) - app.Get("/"+config.Key+"/", routes.AdminIndex) - app.Get("/"+config.Key+"/addboard", routes.AdminAddBoard) - app.Get("/"+config.Key+"/postnews", routes.AdminPostNews) app.Get("/"+config.Key+"/newsdelete", routes.AdminNewsDelete) app.Get("/news", routes.NewsGet) - /* - Board managment - */ - + // Board managment app.Get("/banmedia", routes.BoardBanMedia) app.Get("/delete", routes.BoardDelete) - app.Get("/deleteattach", routes.BoardDeleteAttach) app.Get("/marksensitive", routes.BoardMarkSensitive) - app.Get("/remove", routes.BoardRemove) app.Get("/removeattach", routes.BoardRemoveAttach) - app.Get("/addtoindex", routes.BoardAddToIndex) - app.Get("/poparchive", routes.BoardPopArchive) - app.Get("/autosubscribe", routes.BoardAutoSubscribe) - app.Get("/blacklist", routes.BoardBlacklist) app.Get("/report", routes.BoardBlacklist) + app.Get("/.well-known/webfinger", routes.Webfinger) + app.Get("/api/media", routes.Media) - app.Get("/.well-known/webfinger", func(c *fiber.Ctx) error { - acct := c.Query("resource") - - if len(acct) < 1 { - c.Status(fiber.StatusBadRequest) - return c.Send([]byte("resource needs a value")) - } - - acct = strings.Replace(acct, "acct:", "", -1) - - actorDomain := strings.Split(acct, "@") - - if len(actorDomain) < 2 { - c.Status(fiber.StatusBadRequest) - return c.Send([]byte("accpets only subject form of acct:board@instance")) - } - - if actorDomain[0] == "main" { - actorDomain[0] = "" - } else { - actorDomain[0] = "/" + actorDomain[0] - } - - if res, err := activitypub.IsActorLocal(config.TP + "" + actorDomain[1] + "" + actorDomain[0]); err == nil && !res { - c.Status(fiber.StatusBadRequest) - return c.Send([]byte("actor not local")) - } else if err != nil { - return err - } - - var finger webfinger.Webfinger - var link webfinger.WebfingerLink - - finger.Subject = "acct:" + actorDomain[0] + "@" + actorDomain[1] - link.Rel = "self" - link.Type = "application/activity+json" - link.Href = config.TP + "" + actorDomain[1] + "" + actorDomain[0] - - finger.Links = append(finger.Links, link) - - enc, _ := json.Marshal(finger) - - c.Set("Content-Type", config.ActivityStreams) - return c.Send(enc) - }) - - app.Get("/api/media", func(c *fiber.Ctx) error { - if c.Query("hash") != "" { - return RouteImages(c, c.Query("hash")) - } - - return c.SendStatus(404) - }) - - /* - Board actor - */ - + // Board actor app.Get("/:actor", routes.OutboxGet) 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/outbox", routes.ActorOutbox) - app.Get("/:actor/following", routes.ActorFollowing) app.Get("/:actor/followers", routes.ActorFollowers) - app.Get("/:actor/reported", routes.ActorReported) app.Get("/:actor/archive", routes.ActorArchive) //404 handler app.Use(routes.NotFound) - fmt.Println("Mod key: " + config.Key) - PrintAdminAuth() + db.PrintAdminAuth() app.Listen(config.Port) } -func neuter(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if strings.HasSuffix(r.URL.Path, "/") { - http.NotFound(w, r) - return - } - - next.ServeHTTP(w, r) - }) -} - -func IsValidActor(id string) (activitypub.Actor, bool, error) { - actor, err := webfinger.FingerActor(id) - return actor, actor.Id != "", err -} - -func MakeCaptchas(total int) error { - dbtotal, err := db.GetCaptchaTotal() - if err != nil { - return err - } - - difference := total - dbtotal - - for i := 0; i < difference; i++ { - if err := db.CreateNewCaptcha(); err != nil { - return err - } - } - - return nil -} - -func GetActorReported(w http.ResponseWriter, r *http.Request, id string) error { - auth := r.Header.Get("Authorization") - verification := strings.Split(auth, " ") - - if len(verification) < 2 { - w.WriteHeader(http.StatusBadRequest) - _, err := w.Write([]byte("")) - return err - } - - if res, err := db.HasAuth(verification[1], id); err == nil && !res { - w.WriteHeader(http.StatusBadRequest) - _, err = w.Write([]byte("")) - return err - } else if err != nil { - return err - } - - var following activitypub.Collection +func Init() { var err error - following.AtContext.Context = "https://www.w3.org/ns/activitystreams" - following.Type = "Collection" - following.TotalItems, err = activitypub.GetActorReportedTotal(id) - if err != nil { - return err - } - - following.Items, err = activitypub.GetActorReportedDB(id) - if err != nil { - return err - } - - enc, err := json.MarshalIndent(following, "", "\t") - if err != nil { - return err - } - - w.Header().Set("Content-Type", config.ActivityStreams) - - _, err = w.Write(enc) - return err -} - -func PrintAdminAuth() error { - identifier, code, err := db.GetAdminAuth() - if err != nil { - return err - } - - fmt.Println("Admin Login: " + identifier + ", Code: " + code) - return nil -} - -func DeleteObjectRequest(id string) error { - var nObj activitypub.ObjectBase - var nActor activitypub.Actor - nObj.Id = id - nObj.Actor = nActor.Id - - activity, err := webfinger.CreateActivity("Delete", nObj) - if err != nil { - return err - } - - obj, err := activitypub.GetObjectFromPath(id) - if err != nil { - return err - } - - actor, err := webfinger.FingerActor(obj.Actor) - if err != nil { - return err - } - activity.Actor = &actor - - followers, err := activitypub.GetActorFollowDB(obj.Actor) - if err != nil { - return err - } - - for _, e := range followers { - activity.To = append(activity.To, e.Id) - } - - following, err := activitypub.GetActorFollowingDB(obj.Actor) - if err != nil { - return err - } - for _, e := range following { - activity.To = append(activity.To, e.Id) - } + rand.Seed(time.Now().UnixNano()) - return db.MakeActivityRequest(activity) -} + util.CreatedNeededDirectories() -func DeleteObjectAndRepliesRequest(id string) error { - var nObj activitypub.ObjectBase - var nActor activitypub.Actor - nObj.Id = id - nObj.Actor = nActor.Id + db.ConnectDB() - activity, err := webfinger.CreateActivity("Delete", nObj) - if err != nil { - return err - } + db.InitCache() - obj, err := activitypub.GetObjectByIDFromDB(id) - if err != nil { - return err - } + db.RunDatabaseSchema() - activity.Actor.Id = obj.OrderedItems[0].Actor + go db.MakeCaptchas(100) - activity.Object = &obj.OrderedItems[0] + config.Key = util.CreateKey(32) - followers, err := activitypub.GetActorFollowDB(obj.OrderedItems[0].Actor) - if err != nil { - return err - } - for _, e := range followers { - activity.To = append(activity.To, e.Id) - } + webfinger.FollowingBoards, err = activitypub.GetActorFollowingDB(config.Domain) - following, err := activitypub.GetActorFollowingDB(obj.OrderedItems[0].Actor) if err != nil { - return err - } - - for _, e := range following { - activity.To = append(activity.To, e.Id) - } - - return db.MakeActivityRequest(activity) -} - -func ResizeAttachmentToPreview() error { - return activitypub.GetObjectsWithoutPreviewsCallback(func(id, href, mediatype, name string, size int, published time.Time) error { - re := regexp.MustCompile(`^\w+`) - - _type := re.FindString(mediatype) - - if _type == "image" { - - re = regexp.MustCompile(`.+/`) - - file := re.ReplaceAllString(mediatype, "") - - nHref := util.GetUniqueFilename(file) - - var nPreview activitypub.NestedObjectBase - - re = regexp.MustCompile(`/\w+$`) - actor := re.ReplaceAllString(id, "") - - nPreview.Type = "Preview" - uid, err := util.CreateUniqueID(actor) - if err != nil { - return err - } - - nPreview.Id = fmt.Sprintf("%s/%s", actor, uid) - nPreview.Name = name - nPreview.Href = config.Domain + "" + nHref - nPreview.MediaType = mediatype - nPreview.Size = int64(size) - nPreview.Published = published - nPreview.Updated = published - - re = regexp.MustCompile(`/public/.+`) - - objFile := re.FindString(href) - - if id != "" { - cmd := exec.Command("convert", "."+objFile, "-resize", "250x250>", "-strip", "."+nHref) - - if err := cmd.Run(); err == nil { - fmt.Println(objFile + " -> " + nHref) - if err := activitypub.WritePreviewToDB(nPreview); err != nil { - return err - } - if err := activitypub.UpdateObjectWithPreview(id, nPreview.Id); err != nil { - return err - } - } else { - return err - } - } - } - - return nil - }) -} - -func CreatedNeededDirectories() { - if _, err := os.Stat("./public"); os.IsNotExist(err) { - os.Mkdir("./public", 0755) + panic(err) } - if _, err := os.Stat("./pem/board"); os.IsNotExist(err) { - os.MkdirAll("./pem/board", 0700) - } -} + go db.StartupArchive() -func AddInstanceToIndex(actor string) error { - // TODO: completely disabling this until it is actually reasonable to turn it on - // only actually allow this when it more or less works, i.e. can post, make threads, manage boards, etc - return nil + go db.CheckInactive() - // if local testing enviroment do not add to index - re := regexp.MustCompile(`(.+)?(localhost|\d+\.\d+\.\d+\.\d+)(.+)?`) - if re.MatchString(actor) { - return nil - } + webfinger.Boards, err = webfinger.GetBoardCollection() - // also while i'm here - // TODO: maybe allow different indexes? - followers, err := activitypub.GetCollectionFromID("https://fchan.xyz/followers") if err != nil { - return err - } - - var alreadyIndex = false - for _, e := range followers.Items { - if e.Id == actor { - alreadyIndex = true - } + panic(err) } - if !alreadyIndex { - req, err := http.NewRequest("GET", "https://fchan.xyz/addtoindex?id="+actor, nil) - if err != nil { - return err - } - - if _, err := http.DefaultClient.Do(req); err != nil { - return err + // root actor is used to follow remote feeds that are not local + //name, prefname, summary, auth requirements, restricted + if config.InstanceName != "" { + if _, err = db.CreateNewBoardDB(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil { + //panic(err) } - } - - return nil -} - -func AddInstanceToIndexDB(actor string) error { - // TODO: completely disabling this until it is actually reasonable to turn it on - // only actually allow this when it more or less works, i.e. can post, make threads, manage boards, etc - return nil - //sleep to be sure the webserver is fully initialized - //before making finger request - time.Sleep(15 * time.Second) - - nActor, err := webfinger.FingerActor(actor) - if err != nil { - return err - } - - if nActor.Id == "" { - return nil - } - - // TODO: maybe allow different indexes? - followers, err := activitypub.GetCollectionFromID("https://fchan.xyz/followers") - if err != nil { - return err - } - - var alreadyIndex = false - for _, e := range followers.Items { - if e.Id == nActor.Id { - alreadyIndex = true + if config.PublicIndexing == "true" { + // TODO: comment out later + //AddInstanceToIndex(config.Domain) } } - if !alreadyIndex { - return activitypub.AddFollower("https://fchan.xyz", nActor.Id) - } - - return nil -} - -func RouteImages(ctx *fiber.Ctx, media string) error { - req, err := http.NewRequest("GET", MediaHashs[media], nil) - if err != nil { - return err - } - - client := http.Client{ - Timeout: 5 * time.Second, - } - - resp, err := client.Do(req) + // get list of themes + themes, err := ioutil.ReadDir("./static/css/themes") if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - fileBytes, err := ioutil.ReadFile("./static/notfound.png") - if err != nil { - return err - } - - return ctx.Send(fileBytes) + panic(err) } - body, _ := ioutil.ReadAll(resp.Body) - for name, values := range resp.Header { - for _, value := range values { - ctx.Append(name, value) + for _, f := range themes { + if e := path.Ext(f.Name()); e == ".css" { + config.Themes = append(config.Themes, strings.TrimSuffix(f.Name(), e)) } } - - return ctx.Send(body) } func TemplateFunctions(engine *html.Engine) { diff --git a/post/util.go b/post/util.go index a9d326a..c653276 100644 --- a/post/util.go +++ b/post/util.go @@ -1,6 +1,7 @@ package post import ( + "fmt" "io/ioutil" "mime/multipart" "os" @@ -323,3 +324,61 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj return obj, nil } + +func ResizeAttachmentToPreview() error { + return activitypub.GetObjectsWithoutPreviewsCallback(func(id, href, mediatype, name string, size int, published time.Time) error { + re := regexp.MustCompile(`^\w+`) + + _type := re.FindString(mediatype) + + if _type == "image" { + + re = regexp.MustCompile(`.+/`) + + file := re.ReplaceAllString(mediatype, "") + + nHref := util.GetUniqueFilename(file) + + var nPreview activitypub.NestedObjectBase + + re = regexp.MustCompile(`/\w+$`) + actor := re.ReplaceAllString(id, "") + + nPreview.Type = "Preview" + uid, err := util.CreateUniqueID(actor) + if err != nil { + return err + } + + nPreview.Id = fmt.Sprintf("%s/%s", actor, uid) + nPreview.Name = name + nPreview.Href = config.Domain + "" + nHref + nPreview.MediaType = mediatype + nPreview.Size = int64(size) + nPreview.Published = published + nPreview.Updated = published + + re = regexp.MustCompile(`/public/.+`) + + objFile := re.FindString(href) + + if id != "" { + cmd := exec.Command("convert", "."+objFile, "-resize", "250x250>", "-strip", "."+nHref) + + if err := cmd.Run(); err == nil { + fmt.Println(objFile + " -> " + nHref) + if err := activitypub.WritePreviewToDB(nPreview); err != nil { + return err + } + if err := activitypub.UpdateObjectWithPreview(id, nPreview.Id); err != nil { + return err + } + } else { + return err + } + } + } + + return nil + }) +} diff --git a/routes/api.go b/routes/api.go new file mode 100644 index 0000000..2fb0f3f --- /dev/null +++ b/routes/api.go @@ -0,0 +1,54 @@ +package routes + +import ( + "io/ioutil" + "net/http" + "time" + + "github.com/FChannel0/FChannel-Server/config" + "github.com/gofiber/fiber/v2" +) + +func Media(c *fiber.Ctx) error { + if c.Query("hash") != "" { + return RouteImages(c, c.Query("hash")) + } + + return c.SendStatus(404) +} + +func RouteImages(ctx *fiber.Ctx, media string) error { + req, err := http.NewRequest("GET", config.MediaHashs[media], nil) + if err != nil { + return err + } + + client := http.Client{ + Timeout: 5 * time.Second, + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + fileBytes, err := ioutil.ReadFile("./static/notfound.png") + if err != nil { + return err + } + + _, err = ctx.Write(fileBytes) + return err + } + + body, _ := ioutil.ReadAll(resp.Body) + for name, values := range resp.Header { + for _, value := range values { + ctx.Append(name, value) + } + } + + return ctx.Send(body) +} diff --git a/routes/webfinger.go b/routes/webfinger.go new file mode 100644 index 0000000..221b7dc --- /dev/null +++ b/routes/webfinger.go @@ -0,0 +1,57 @@ +package routes + +import ( + "encoding/json" + "strings" + + "github.com/FChannel0/FChannel-Server/activitypub" + "github.com/FChannel0/FChannel-Server/config" + "github.com/FChannel0/FChannel-Server/webfinger" + "github.com/gofiber/fiber/v2" +) + +func Webfinger(c *fiber.Ctx) error { + acct := c.Query("resource") + + if len(acct) < 1 { + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("resource needs a value")) + } + + acct = strings.Replace(acct, "acct:", "", -1) + + actorDomain := strings.Split(acct, "@") + + if len(actorDomain) < 2 { + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("accpets only subject form of acct:board@instance")) + } + + if actorDomain[0] == "main" { + actorDomain[0] = "" + } else { + actorDomain[0] = "/" + actorDomain[0] + } + + if res, err := activitypub.IsActorLocal(config.TP + "" + actorDomain[1] + "" + actorDomain[0]); err == nil && !res { + c.Status(fiber.StatusBadRequest) + return c.Send([]byte("actor not local")) + } else if err != nil { + return err + } + + var finger webfinger.Webfinger + var link webfinger.WebfingerLink + + finger.Subject = "acct:" + actorDomain[0] + "@" + actorDomain[1] + link.Rel = "self" + link.Type = "application/activity+json" + link.Href = config.TP + "" + actorDomain[1] + "" + actorDomain[0] + + finger.Links = append(finger.Links, link) + + enc, _ := json.Marshal(finger) + + c.Set("Content-Type", config.ActivityStreams) + return c.Send(enc) +} diff --git a/util/util.go b/util/util.go index ade5eae..0ffbf01 100644 --- a/util/util.go +++ b/util/util.go @@ -251,3 +251,13 @@ func GetContentType(location string) string { return location } } + +func CreatedNeededDirectories() { + if _, err := os.Stat("./public"); os.IsNotExist(err) { + os.Mkdir("./public", 0755) + } + + if _, err := os.Stat("./pem/board"); os.IsNotExist(err) { + os.MkdirAll("./pem/board", 0700) + } +} diff --git a/webfinger/webfinger.go b/webfinger/webfinger.go index 7e58d00..a58c9ab 100644 --- a/webfinger/webfinger.go +++ b/webfinger/webfinger.go @@ -6,6 +6,7 @@ import ( "net/http" "regexp" "strings" + "time" "github.com/FChannel0/FChannel-Server/activitypub" "github.com/FChannel0/FChannel-Server/config" @@ -239,3 +240,46 @@ func AddFollowersToActivity(activity activitypub.Activity) (activitypub.Activity return activity, nil } + +func IsValidActor(id string) (activitypub.Actor, bool, error) { + actor, err := FingerActor(id) + return actor, actor.Id != "", err +} + +func AddInstanceToIndexDB(actor string) error { + // TODO: completely disabling this until it is actually reasonable to turn it on + // only actually allow this when it more or less works, i.e. can post, make threads, manage boards, etc + return nil + + //sleep to be sure the webserver is fully initialized + //before making finger request + time.Sleep(15 * time.Second) + + nActor, err := FingerActor(actor) + if err != nil { + return err + } + + if nActor.Id == "" { + return nil + } + + // TODO: maybe allow different indexes? + followers, err := activitypub.GetCollectionFromID("https://fchan.xyz/followers") + if err != nil { + return err + } + + var alreadyIndex = false + for _, e := range followers.Items { + if e.Id == nActor.Id { + alreadyIndex = true + } + } + + if !alreadyIndex { + return activitypub.AddFollower("https://fchan.xyz", nActor.Id) + } + + return nil +} |