From 3db517715bef6a53225c5c3c06e8fc5fd0bf71e3 Mon Sep 17 00:00:00 2001 From: FChannel <> Date: Sun, 24 Apr 2022 00:46:49 -0700 Subject: basic pass over view posts, post, catalog and manage page connections --- accept.go | 21 ---------- config/config.go | 2 +- db/actor.go | 16 +++++++ db/database.go | 7 +++- db/redis.go | 64 ++++++++++++++++++++-------- main.go | 54 ++++++++++-------------- routes/404.go | 4 +- routes/admin.go | 50 ++++++++++++++++++++-- routes/index.go | 7 ++++ routes/outbox.go | 21 +++++++--- routes/post.go | 8 ++-- util/accept.go | 21 ++++++++++ util/util.go | 2 +- views/admin.html | 78 ++++++++++++++++++++++++++++++++++ views/catalog.html | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ views/index.html | 3 ++ views/layouts/main.html | 1 - webfinger/webfinger.go | 1 + 18 files changed, 380 insertions(+), 89 deletions(-) delete mode 100644 accept.go create mode 100644 util/accept.go create mode 100644 views/admin.html create mode 100644 views/catalog.html diff --git a/accept.go b/accept.go deleted file mode 100644 index 6a15857..0000000 --- a/accept.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "regexp" - "strings" -) - -// False positive for application/ld+ld, application/activity+ld, application/json+json -var activityRegexp = regexp.MustCompile("application\\/(ld|json|activity)((\\+(ld|json))|$)") - -func acceptActivity(header string) bool { - accept := false - if strings.Contains(header, ";") { - split := strings.Split(header, ";") - accept = accept || activityRegexp.MatchString(split[0]) - accept = accept || strings.Contains(split[len(split)-1], "profile=\"https://www.w3.org/ns/activitystreams\"") - } else { - accept = accept || activityRegexp.MatchString(header) - } - return accept -} diff --git a/config/config.go b/config/config.go index d9e5a94..93531b8 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( var Port = ":" + GetConfigValue("instanceport", "3000") var TP = GetConfigValue("instancetp", "") -var Domain = GetConfigValue("instance", "") +var Domain = TP + "" + GetConfigValue("instance", "") var InstanceName = GetConfigValue("instancename", "") var InstanceSummary = GetConfigValue("instancesummary", "") var SiteEmail = GetConfigValue("emailaddress", "") //contact@fchan.xyz diff --git a/db/actor.go b/db/actor.go index 51c8f41..7e36090 100644 --- a/db/actor.go +++ b/db/actor.go @@ -1,11 +1,13 @@ package db import ( + "encoding/json" "fmt" "regexp" "strings" "github.com/FChannel0/FChannel-Server/activitypub" + "github.com/gofiber/fiber/v2" ) func GetActorFromPath(location string, prefix string) (activitypub.Actor, error) { @@ -49,3 +51,17 @@ func GetActorByName(name string) activitypub.Actor { return actor } + +func GetActorInfo(ctx *fiber.Ctx, id string) error { + actor, err := GetActorFromDB(id) + if err != nil { + return err + } + + enc, _ := json.MarshalIndent(actor, "", "\t") + ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") + + _, err = ctx.Write(enc) + + return err +} diff --git a/db/database.go b/db/database.go index 0b44404..db7e715 100644 --- a/db/database.go +++ b/db/database.go @@ -858,6 +858,7 @@ func GetObjectFromDBCatalog(id string) (activitypub.Collection, error) { query := `select x.id, x.name, x.content, x.type, x.published, x.updated, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note' union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note') as x order by x.updated desc limit 165` rows, err := db.Query(query, id) + if err != nil { return nColl, err } @@ -880,6 +881,7 @@ func GetObjectFromDBCatalog(id string) (activitypub.Collection, error) { post.Replies = &replies post.Replies.TotalItems, post.Replies.TotalImgs, err = GetObjectRepliesCount(post) + if err != nil { return nColl, err } @@ -1229,8 +1231,9 @@ func GetObjectRepliesCount(parent activitypub.ObjectBase) (int, int, error) { defer rows.Close() - rows.Next() - err = rows.Scan(&countId, &countImg) + for rows.Next() { + err = rows.Scan(&countId, &countImg) + } return countId, countImg, err } diff --git a/db/redis.go b/db/redis.go index 873ca27..1650b4f 100644 --- a/db/redis.go +++ b/db/redis.go @@ -3,10 +3,11 @@ package db import ( "bufio" "fmt" - "net/http" "os" + "strings" "github.com/FChannel0/FChannel-Server/config" + "github.com/gofiber/fiber/v2" "github.com/gomodule/redigo/redis" ) @@ -22,6 +23,50 @@ func CloseCache() error { return Cache.Close() } +func GetClientKey() (string, error) { + file, err := os.Open("clientkey") + if err != nil { + return "", err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var line string + for scanner.Scan() { + line = fmt.Sprintf("%s", scanner.Text()) + } + + return line, nil +} + +func GetPasswordFromSession(c *fiber.Ctx) (string, string) { + + cookie := c.Cookies("session_token") + + if cookie == "" { + return "", "" + } + + sessionToken := cookie + + response, err := Cache.Do("GET", sessionToken) + + if err != nil { + return "", "" + } + + token := fmt.Sprintf("%s", response) + + parts := strings.Split(token, "|") + + if len(parts) > 1 { + return parts[0], parts[1] + } + + return "", "" +} + +/* TODO: Convert to fiber ctx func CheckSession(w http.ResponseWriter, r *http.Request) (interface{}, error) { c, err := r.Cookie("session_token") @@ -49,20 +94,5 @@ func CheckSession(w http.ResponseWriter, r *http.Request) (interface{}, error) { } return response, nil -} - -func GetClientKey() (string, error) { - file, err := os.Open("clientkey") - if err != nil { - return "", err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - var line string - for scanner.Scan() { - line = fmt.Sprintf("%s", scanner.Text()) } - - return line, nil -} +*/ diff --git a/main.go b/main.go index 3049d71..a08ed57 100644 --- a/main.go +++ b/main.go @@ -105,6 +105,8 @@ func main() { TemplateFunctions(template) + template.Reload(true) + app := fiber.New(fiber.Config{ AppName: "FChannel", Views: template, @@ -127,25 +129,6 @@ func main() { app.Get("/following", routes.Following) app.Get("/followers", routes.Followers) - /* - Board actor - */ - - app.Get("/:actor", routes.OutboxGet) - app.Get("/:actor/catalog", routes.CatalogGet) - - app.Get("/:actor/:post", routes.PostGet) - app.Get("/post", routes.ActorPost) - - app.Get("/:actor/inbox", routes.ActorInbox) - app.Get("/: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) - /* Admin routes */ @@ -238,7 +221,26 @@ func main() { return c.SendStatus(404) }) - // 404 handler + /* + Board actor + */ + + app.Get("/:actor", routes.OutboxGet) + app.Get("/:actor/catalog", routes.CatalogGet) + + app.Get("/:actor/:post", routes.PostGet) + app.Get("/post", routes.ActorPost) + + app.Get("/:actor/inbox", routes.ActorInbox) + app.Get("/: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) @@ -293,18 +295,6 @@ func CreateNewActor(board string, prefName string, summary string, authReq []str return actor } -func GetActorInfo(w http.ResponseWriter, id string) error { - actor, err := db.GetActorFromDB(id) - if err != nil { - return err - } - - enc, _ := json.MarshalIndent(actor, "", "\t") - w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") - _, err = w.Write(enc) - return err -} - func GetActorPost(w http.ResponseWriter, path string) error { collection, err := db.GetCollectionFromPath(config.Domain + "" + path) if err != nil { diff --git a/routes/404.go b/routes/404.go index 64ea167..94b96e8 100644 --- a/routes/404.go +++ b/routes/404.go @@ -1,6 +1,8 @@ package routes -import "github.com/gofiber/fiber/v2" +import ( + "github.com/gofiber/fiber/v2" +) func NotFound(c *fiber.Ctx) error { return c.Status(404).Render("404", fiber.Map{}, "layouts/main") diff --git a/routes/admin.go b/routes/admin.go index 068dda3..528e40c 100644 --- a/routes/admin.go +++ b/routes/admin.go @@ -1,6 +1,11 @@ package routes -import "github.com/gofiber/fiber/v2" +import ( + "github.com/FChannel0/FChannel-Server/config" + "github.com/FChannel0/FChannel-Server/db" + "github.com/FChannel0/FChannel-Server/webfinger" + "github.com/gofiber/fiber/v2" +) func AdminVerify(c *fiber.Ctx) error { // STUB @@ -14,10 +19,47 @@ func AdminAuth(c *fiber.Ctx) error { return c.SendString("admin auth") } -func AdminIndex(c *fiber.Ctx) error { - // STUB +func AdminIndex(ctx *fiber.Ctx) error { + actor, err := webfinger.GetActor(config.Domain) + + if err != nil { + return err + } + + follow, _ := webfinger.GetActorCollection(actor.Following) + follower, _ := webfinger.GetActorCollection(actor.Followers) + + var following []string + var followers []string + + for _, e := range follow.Items { + following = append(following, e.Id) + } + + for _, e := range follower.Items { + followers = append(followers, e.Id) + } + + var adminData AdminPage + adminData.Following = following + adminData.Followers = followers + adminData.Actor = actor.Id + adminData.Key = config.Key + adminData.Domain = config.Domain + adminData.Board.ModCred, _ = db.GetPasswordFromSession(ctx) + adminData.Title = actor.Name + " Admin page" + + adminData.Boards = db.Boards + + adminData.Board.Post.Actor = actor.Id + + adminData.PostBlacklist, _ = db.GetRegexBlacklistDB() + + adminData.Themes = &config.Themes - return c.SendString("admin index") + return ctx.Render("admin", fiber.Map{ + "page": adminData, + }) } func AdminAddBoard(c *fiber.Ctx) error { diff --git a/routes/index.go b/routes/index.go index 3599455..5ff2bd4 100644 --- a/routes/index.go +++ b/routes/index.go @@ -3,6 +3,7 @@ package routes import ( "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" ) @@ -13,6 +14,12 @@ func Index(ctx *fiber.Ctx) error { return err } + // this is a activitpub json request return json instead of html page + if util.AcceptActivity(ctx.Get("Accept")) { + db.GetActorInfo(ctx, actor.Id) + return nil + } + var data PageData data.Title = "Welcome to " + actor.PreferredUsername data.PreferredUsername = actor.PreferredUsername diff --git a/routes/outbox.go b/routes/outbox.go index b00f946..1277011 100644 --- a/routes/outbox.go +++ b/routes/outbox.go @@ -16,6 +16,14 @@ func Outbox(ctx *fiber.Ctx) error { } func OutboxGet(ctx *fiber.Ctx) error { + + actor := db.GetActorByName(ctx.Params("actor")) + + if util.AcceptActivity(ctx.Get("Accept")) { + db.GetActorInfo(ctx, actor.Id) + return nil + } + collection, valid, err := wantToServePage(ctx.Params("actor"), 0) if err != nil { return err @@ -24,12 +32,13 @@ func OutboxGet(ctx *fiber.Ctx) error { return ctx.SendString("404") } - actor := collection.Actor - + var page int postNum := ctx.Query("page") - page, err := strconv.Atoi(postNum) - if err != nil { - return err + if postNum != "" { + page, err = strconv.Atoi(postNum) + if err != nil { + return err + } } var returnData PageData @@ -39,7 +48,7 @@ func OutboxGet(ctx *fiber.Ctx) error { returnData.Board.Summary = actor.Summary returnData.Board.InReplyTo = "" returnData.Board.To = actor.Outbox - returnData.Board.Actor = *actor + returnData.Board.Actor = actor returnData.Board.ModCred, _ = getPassword(ctx) returnData.Board.Domain = config.Domain returnData.Board.Restricted = actor.Restricted diff --git a/routes/post.go b/routes/post.go index 24dbbc3..e074f67 100644 --- a/routes/post.go +++ b/routes/post.go @@ -1,13 +1,13 @@ package routes import ( - "regexp" - + "fmt" "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" + "regexp" ) func PostGet(ctx *fiber.Ctx) error { @@ -112,6 +112,8 @@ func CatalogGet(ctx *fiber.Ctx) error { collection, err := db.GetObjectFromDBCatalog(actor.Id) + fmt.Println(err) + // TODO: implement this in template functions // "showArchive": func() bool { // col, err := db.GetActorCollectionDBTypeLimit(collection.Actor.Id, "Archive", 1) @@ -162,7 +164,7 @@ func CatalogGet(ctx *fiber.Ctx) error { returnData.Themes = &config.Themes returnData.ThemeCookie = getThemeCookie(ctx) - return ctx.Render("ncatalog", fiber.Map{ + return ctx.Render("catalog", fiber.Map{ "page": returnData, }, "layouts/main") } diff --git a/util/accept.go b/util/accept.go new file mode 100644 index 0000000..2765c32 --- /dev/null +++ b/util/accept.go @@ -0,0 +1,21 @@ +package util + +import ( + "regexp" + "strings" +) + +// False positive for application/ld+ld, application/activity+ld, application/json+json +var activityRegexp = regexp.MustCompile("application\\/(ld|json|activity)((\\+(ld|json))|$)") + +func AcceptActivity(header string) bool { + accept := false + if strings.Contains(header, ";") { + split := strings.Split(header, ";") + accept = accept || activityRegexp.MatchString(split[0]) + accept = accept || strings.Contains(split[len(split)-1], "profile=\"https://www.w3.org/ns/activitystreams\"") + } else { + accept = accept || activityRegexp.MatchString(header) + } + return accept +} diff --git a/util/util.go b/util/util.go index a56e871..1feb53a 100644 --- a/util/util.go +++ b/util/util.go @@ -29,7 +29,7 @@ func GetActorInstance(path string) (string, string) { } } - re = regexp.MustCompile(`(https?://)(www)?([\w\d-_.:]+)(/|\s+|\r|\r\n)?$`) + re = regexp.MustCompile(`(https?://)?(www)?([\w\d-_.:]+)(/|\s+|\r|\r\n)?$`) mainActor := re.MatchString(path) if mainActor { match := re.FindStringSubmatch(path) diff --git a/views/admin.html b/views/admin.html new file mode 100644 index 0000000..191444b --- /dev/null +++ b/views/admin.html @@ -0,0 +1,78 @@ +
+

Add Board

+
+
+
+
+
+
+
+
+ +
+ +
+ +
+

Subscribed

+
+
+ +
+ +
+ + + +
+

Create News

+
+
+
+
+
+
+
+ +
+

Regex Post Blacklist

+
+
+
+
+
+
+ {{ if .page.PostBlacklist }} + + {{ end }} + + + + + + diff --git a/views/catalog.html b/views/catalog.html new file mode 100644 index 0000000..c70471e --- /dev/null +++ b/views/catalog.html @@ -0,0 +1,109 @@ +{{ define "header" }} +/{{ .page.Board.Name }}/ - catalog + + + + + + + + + + + + +{{ end }} + +{{ $board := .page.Board }} +
+ + + +
+ +
+ {{ range .page.Posts }} +
+ {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} + [Delete Post] + {{ end }} + {{ if .Attachment }} + {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} + [Delete Attachment] + [Mark Sensitive] + {{ end }} + + + +
{{ parseAttachment . true }}
+
+ + {{ end }} + +
+ {{ $replies := .Replies }} + {{ if $replies }} + R: {{ $replies.TotalItems }}{{ if $replies.TotalImgs }}/ A: {{ $replies.TotalImgs }}{{ end }} + {{ end }} + {{ if .Name }} +
+ {{ .Name }} + {{ end }} + + {{ if .Content }} +
+ {{.Content}} + {{ end }} +
+
+
+ {{ end }} +
+
+ + + +
diff --git a/views/index.html b/views/index.html index f426d5d..e928ace 100644 --- a/views/index.html +++ b/views/index.html @@ -1,3 +1,6 @@ +{{ define "header" }} +{{ .page.Title }} +{{ end }}

{{ .page.Title }}

{{ .page.PreferredUsername }} is a federated image board based on ActivityPub. The current version of the code running on the server is still a work-in-progress product, expect a bumpy ride for the time being. Get the server code here: https://github.com/FChannel0.

diff --git a/views/layouts/main.html b/views/layouts/main.html index 4cd48f9..41e3412 100644 --- a/views/layouts/main.html +++ b/views/layouts/main.html @@ -45,6 +45,5 @@ {{ template "partials/footer" .page }} - {{ template "scripts" .page }} diff --git a/webfinger/webfinger.go b/webfinger/webfinger.go index 9e8d67d..d937ae4 100644 --- a/webfinger/webfinger.go +++ b/webfinger/webfinger.go @@ -43,6 +43,7 @@ func GetActor(id string) (activitypub.Actor, error) { if err != nil { return respActor, err } + req.Header.Set("Accept", config.ActivityStreams) resp, err := util.RouteProxy(req) -- cgit v1.2.3