aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client.go10
-rw-r--r--db/database.go79
-rw-r--r--db/outbox.go116
-rw-r--r--main.go592
-rw-r--r--outboxGet.go119
-rw-r--r--routes/util.go12
-rw-r--r--util/util.go42
7 files changed, 589 insertions, 381 deletions
diff --git a/client.go b/client.go
index 93b72f5..d4462d7 100644
--- a/client.go
+++ b/client.go
@@ -26,11 +26,14 @@ func MediaProxy(url string) string {
return url
}
- MediaHashs[HashMedia(url)] = url
- return "/api/media?hash=" + HashMedia(url)
+ 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 ""
}
@@ -105,7 +108,7 @@ func ParseAttachment(obj activitypub.ObjectBase, catalog bool) template.HTML {
}
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, `<`, "&lt;")
nContent, err := ParseLinkComments(board, op, nContent, thread)
@@ -221,6 +224,7 @@ func ParseLinkTitle(actorName string, op string, content string) string {
content = strings.Replace(content, match[i][0], ">>"+util.ShortURL(actorName, link)+isOP, 1)
}
+ // TODO: this drops more than we need to
content = strings.ReplaceAll(content, "'", "")
content = strings.ReplaceAll(content, "\"", "")
content = strings.ReplaceAll(content, ">", `/\&lt;`)
diff --git a/db/database.go b/db/database.go
index bd302aa..dfa66aa 100644
--- a/db/database.go
+++ b/db/database.go
@@ -18,7 +18,9 @@ import (
_ "github.com/lib/pq"
)
+// TODO: merge these
var db *sql.DB
+var DB *sql.DB
type NewsItem struct {
Title string
@@ -48,6 +50,7 @@ func ConnectDB() error {
fmt.Println("Successfully connected DB")
db = _db
+ DB = _db
return nil
}
@@ -289,10 +292,12 @@ func WriteObjectToDB(obj activitypub.ObjectBase) (activitypub.ObjectBase, error)
obj.Preview.Published = time.Now().UTC()
obj.Preview.Updated = time.Now().UTC()
obj.Preview.AttributedTo = obj.Id
- WritePreviewToDB(*obj.Preview)
+ if err := WritePreviewToDB(*obj.Preview); err != nil {
+ return obj, err
+ }
}
- for i, _ := range obj.Attachment {
+ for i := range obj.Attachment {
id, err := CreateUniqueID(obj.Actor)
if err != nil {
return obj, err
@@ -563,15 +568,11 @@ func WriteAttachmentToDB(obj activitypub.ObjectBase) {
}
}
-func WritePreviewToDB(obj activitypub.NestedObjectBase) {
+func WritePreviewToDB(obj activitypub.NestedObjectBase) error {
query := `insert into activitystream (id, type, name, href, published, updated, attributedTo, mediatype, size) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
- _, e := db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Href, obj.Published, obj.Updated, obj.AttributedTo, obj.MediaType, obj.Size)
-
- if e != nil {
- fmt.Println("error inserting new attachment")
- panic(e)
- }
+ _, err := db.Exec(query, obj.Id, obj.Type, obj.Name, obj.Href, obj.Published, obj.Updated, obj.AttributedTo, obj.MediaType, obj.Size)
+ return err
}
func GetActivityFromDB(id string) (activitypub.Collection, error) {
@@ -2477,3 +2478,63 @@ func CheckInactiveInstances() (map[string]string, error) {
return instances, nil
}
+
+func GetAdminAuth() (string, string, error) {
+ query := fmt.Sprintf("select identifier, code from boardaccess where board='%s' and type='admin'", config.Domain)
+
+ rows, err := db.Query(query)
+ if err != nil {
+ return "", "", err
+ }
+
+ var code string
+ var identifier string
+
+ rows.Next()
+ err = rows.Scan(&identifier, &code)
+
+ return code, identifier, err
+}
+
+func UpdateObjectWithPreview(id string, preview string) error {
+ query := `update activitystream set preview=$1 where attachment=$2`
+
+ _, err := db.Exec(query, preview, id)
+ return err
+}
+
+func GetObjectsWithoutPreviewsCallback(callback func(id string, href string, mediatype string, name string, size int, published time.Time) error) error {
+ query := `select id, href, mediatype, name, size, published from activitystream where id in (select attachment from activitystream where attachment!='' and preview='')`
+
+ rows, err := db.Query(query)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var id string
+ var href string
+ var mediatype string
+ var name string
+ var size int
+ var published time.Time
+
+ if err := rows.Scan(&id, &href, &mediatype, &name, &size, &published); err != nil {
+ return err
+ }
+
+ if err := callback(id, href, mediatype, name, size, published); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func AddFollower(id string, follower string) error {
+ query := `insert into follower (id, follower) values ($1, $2)`
+
+ _, err := db.Exec(query, id, follower)
+ return err
+}
diff --git a/db/outbox.go b/db/outbox.go
new file mode 100644
index 0000000..e8189d9
--- /dev/null
+++ b/db/outbox.go
@@ -0,0 +1,116 @@
+package db
+
+import (
+ "github.com/FChannel0/FChannel-Server/activitypub"
+)
+
+func GetCollectionFromPath(path string) (activitypub.Collection, error) {
+ var nColl activitypub.Collection
+ var result []activitypub.ObjectBase
+
+ query := `select id, name, content, type, published, attributedto, attachment, preview, actor from activitystream where id=$1 order by published desc`
+
+ rows, err := db.Query(query, path)
+ if err != nil {
+ return nColl, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var actor activitypub.Actor
+ var post activitypub.ObjectBase
+ var attachID string
+ var previewID string
+
+ if err := rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.AttributedTo, &attachID, &previewID, &actor.Id); err != nil {
+ return nColl, err
+ }
+
+ post.Actor = actor.Id
+
+ post.InReplyTo, err = GetInReplyToDB(post)
+ if err != nil {
+ return nColl, err
+ }
+
+ var postCnt int
+ var imgCnt int
+ post.Replies, postCnt, imgCnt, err = GetObjectRepliesDB(post)
+ if err != nil {
+ return nColl, err
+ }
+
+ post.Replies.TotalItems, post.Replies.TotalImgs, err = GetObjectRepliesCount(post)
+ if err != nil {
+ return nColl, err
+ }
+
+ post.Replies.TotalItems = post.Replies.TotalItems + postCnt
+ post.Replies.TotalImgs = post.Replies.TotalImgs + imgCnt
+
+ post.Attachment, err = GetObjectAttachment(attachID)
+ if err != nil {
+ return nColl, err
+ }
+
+ post.Preview, err = GetObjectPreview(previewID)
+ if err != nil {
+ return nColl, err
+ }
+
+ result = append(result, post)
+ }
+
+ nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+
+ nColl.OrderedItems = result
+
+ return nColl, nil
+}
+
+func GetObjectFromPath(path string) (activitypub.ObjectBase, error) {
+ var nObj activitypub.ObjectBase
+
+ query := `select id, name, content, type, published, attributedto, attachment, preview, actor from activitystream where id=$1 order by published desc`
+
+ rows, err := db.Query(query, path)
+ if err != nil {
+ return nObj, err
+ }
+
+ defer rows.Close()
+ rows.Next()
+ var attachID string
+ var previewID string
+
+ var nActor activitypub.Actor
+ nObj.Actor = nActor.Id
+
+ if err := rows.Scan(&nObj.Id, &nObj.Name, &nObj.Content, &nObj.Type, &nObj.Published, &nObj.AttributedTo, &attachID, &previewID, &nObj.Actor); err != nil {
+ return nObj, err
+ }
+
+ var postCnt int
+ var imgCnt int
+
+ nObj.Replies, postCnt, imgCnt, err = GetObjectRepliesDB(nObj)
+ if err != nil {
+ return nObj, err
+ }
+
+ nObj.Replies.TotalItems, nObj.Replies.TotalImgs, err = GetObjectRepliesCount(nObj)
+ if err != nil {
+ return nObj, err
+ }
+
+ nObj.Replies.TotalItems = nObj.Replies.TotalItems + postCnt
+ nObj.Replies.TotalImgs = nObj.Replies.TotalImgs + imgCnt
+
+ nObj.Attachment, err = GetObjectAttachment(attachID)
+ if err != nil {
+ return nObj, err
+ }
+
+ nObj.Preview, err = GetObjectPreview(previewID)
+ return nObj, err
+}
diff --git a/main.go b/main.go
index fae442f..5025832 100644
--- a/main.go
+++ b/main.go
@@ -1,10 +1,8 @@
package main
import (
- "crypto/sha256"
- "database/sql"
- "encoding/hex"
"encoding/json"
+ "errors"
"fmt"
"github.com/FChannel0/FChannel-Server/activitypub"
@@ -12,6 +10,7 @@ import (
"github.com/FChannel0/FChannel-Server/db"
"github.com/FChannel0/FChannel-Server/routes"
"github.com/FChannel0/FChannel-Server/util"
+ "github.com/FChannel0/FChannel-Server/webfinger"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html"
@@ -211,13 +210,15 @@ func main() {
actorDomain[0] = "/" + actorDomain[0]
}
- if !IsActorLocal(config.TP + "" + actorDomain[1] + "" + actorDomain[0]) {
+ if res, err := db.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
- var link WebfingerLink
+ var finger webfinger.Webfinger
+ var link webfinger.WebfingerLink
finger.Subject = "acct:" + actorDomain[0] + "@" + actorDomain[1]
link.Rel = "self"
@@ -242,18 +243,7 @@ func main() {
fmt.Println("Mod key: " + config.Key)
PrintAdminAuth()
- app.Listen(Port)
-}
-
-func CheckError(e error, m string) error {
- if e != nil {
- fmt.Println()
- fmt.Println(m)
- fmt.Println()
- panic(e)
- }
-
- return e
+ app.Listen(config.Port)
}
func neuter(next http.Handler) http.Handler {
@@ -302,20 +292,36 @@ func CreateNewActor(board string, prefName string, summary string, authReq []str
return actor
}
-func GetActorInfo(w http.ResponseWriter, db *sql.DB, id string) {
- actor := GetActorFromDB(id)
+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\"")
- w.Write(enc)
+ _, err = w.Write(enc)
+ return err
}
-func GetActorPost(w http.ResponseWriter, db *sql.DB, path string) {
- collection := GetCollectionFromPath(Domain + "" + path)
+func GetActorPost(w http.ResponseWriter, path string) error {
+ collection, err := db.GetCollectionFromPath(config.Domain + "" + path)
+ if err != nil {
+ return err
+ }
+
if len(collection.OrderedItems) > 0 {
- enc, _ := json.MarshalIndent(collection, "", "\t")
+ enc, err := json.MarshalIndent(collection, "", "\t")
+ if err != nil {
+ return err
+ }
+
w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
- w.Write(enc)
+ _, err = w.Write(enc)
+ return err
}
+
+ return nil
}
func CreateObject(objType string) activitypub.ObjectBase {
@@ -328,12 +334,15 @@ func CreateObject(objType string) activitypub.ObjectBase {
return nObj
}
-func AddFollowersToActivity(activity activitypub.Activity) activitypub.Activity {
-
+func AddFollowersToActivity(activity activitypub.Activity) (activitypub.Activity, error) {
activity.To = append(activity.To, activity.Actor.Id)
for _, e := range activity.To {
- aFollowers := GetActorCollection(e + "/followers")
+ aFollowers, err := webfinger.GetActorCollection(e + "/followers")
+ if err != nil {
+ return activity, err
+ }
+
for _, k := range aFollowers.Items {
activity.To = append(activity.To, k.Id)
}
@@ -356,12 +365,16 @@ func AddFollowersToActivity(activity activitypub.Activity) activitypub.Activity
activity.To = nActivity.To
- return activity
+ return activity, nil
}
-func CreateActivity(activityType string, obj activitypub.ObjectBase) activitypub.Activity {
+func CreateActivity(activityType string, obj activitypub.ObjectBase) (activitypub.Activity, error) {
var newActivity activitypub.Activity
- actor := FingerActor(obj.Actor)
+
+ actor, err := webfinger.FingerActor(obj.Actor)
+ if err != nil {
+ return newActivity, err
+ }
newActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
newActivity.Type = activityType
@@ -381,29 +394,33 @@ func CreateActivity(activityType string, obj activitypub.ObjectBase) activitypub
}
}
- return newActivity
+ return newActivity, nil
}
-func ProcessActivity(activity activitypub.Activity) {
+func ProcessActivity(activity activitypub.Activity) error {
activityType := activity.Type
if activityType == "Create" {
for _, e := range activity.To {
- if GetActorFromDB(e).Id != "" {
+ if res, err := db.GetActorFromDB(e); err == nil && res.Id != "" {
fmt.Println("actor is in the database")
+ } else if err != nil {
+ return err
} else {
fmt.Println("actor is NOT in the database")
}
}
} else if activityType == "Follow" {
-
+ // TODO: okay?
+ return errors.New("not implemented")
} else if activityType == "Delete" {
-
+ return errors.New("not implemented")
}
+
+ return nil
}
func CreatePreviewObject(obj activitypub.ObjectBase) *activitypub.NestedObjectBase {
-
re := regexp.MustCompile(`/.+$`)
mimetype := re.ReplaceAllString(obj.MediaType, "")
@@ -418,7 +435,7 @@ func CreatePreviewObject(obj activitypub.ObjectBase) *activitypub.NestedObjectBa
file := re.ReplaceAllString(obj.MediaType, "")
- href := GetUniqueFilename(file)
+ href := util.GetUniqueFilename(file)
nPreview.Type = "Preview"
nPreview.Name = obj.Name
@@ -433,9 +450,8 @@ func CreatePreviewObject(obj activitypub.ObjectBase) *activitypub.NestedObjectBa
cmd := exec.Command("convert", "."+objFile, "-resize", "250x250>", "-strip", "."+href)
- err := cmd.Run()
-
- if CheckError(err, "error with resize attachment preview") != nil {
+ if err := cmd.Run(); err != nil {
+ // TODO: previously we would call CheckError here
var preview activitypub.NestedObjectBase
return &preview
}
@@ -443,8 +459,12 @@ func CreatePreviewObject(obj activitypub.ObjectBase) *activitypub.NestedObjectBa
return &nPreview
}
-func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) ([]activitypub.ObjectBase, *os.File) {
- contentType, _ := GetFileContentType(file)
+func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) ([]activitypub.ObjectBase, *os.File, error) {
+ contentType, err := GetFileContentType(file)
+ if err != nil {
+ return nil, nil, err
+ }
+
filename := header.Filename
size := header.Size
@@ -452,7 +472,10 @@ func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) (
fileType := re.ReplaceAllString(contentType, "")
- tempFile, _ := ioutil.TempFile("./public", "*."+fileType)
+ tempFile, err := ioutil.TempFile("./public", "*."+fileType)
+ if err != nil {
+ return nil, nil, err
+ }
var nAttachment []activitypub.ObjectBase
var image activitypub.ObjectBase
@@ -466,10 +489,10 @@ func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) (
nAttachment = append(nAttachment, image)
- return nAttachment, tempFile
+ return nAttachment, tempFile, nil
}
-func ParseCommentForReplies(comment string, op string) []activitypub.ObjectBase {
+func ParseCommentForReplies(comment string, op string) ([]activitypub.ObjectBase, 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(comment, -1)
@@ -482,71 +505,87 @@ func ParseCommentForReplies(comment string, op string) []activitypub.ObjectBase
str = strings.Replace(str, "http://", "", 1)
str = strings.Replace(str, "https://", "", 1)
str = config.TP + "" + str
- _, isReply := IsReplyToOP(op, str)
- if !IsInStringArray(links, str) && isReply {
+ _, isReply, err := db.IsReplyToOP(op, str)
+ if err != nil {
+ return nil, err
+ }
+
+ if !util.IsInStringArray(links, str) && isReply {
links = append(links, str)
}
}
var validLinks []activitypub.ObjectBase
for i := 0; i < len(links); i++ {
- _, isValid := CheckValidActivity(links[i])
+ _, isValid, err := webfinger.CheckValidActivity(links[i])
+ if err != nil {
+ return nil, err
+ }
+
if isValid {
- var reply = new(activitypub.ObjectBase)
+ var reply activitypub.ObjectBase
reply.Id = links[i]
reply.Published = time.Now().UTC()
- validLinks = append(validLinks, *reply)
+ validLinks = append(validLinks, reply)
}
}
- return validLinks
+ return validLinks, nil
}
-func IsValidActor(id string) (activitypub.Actor, bool) {
-
- actor := FingerActor(id)
-
- if actor.Id != "" {
- return actor, true
- }
-
- return actor, false
+func IsValidActor(id string) (activitypub.Actor, bool, error) {
+ actor, err := webfinger.FingerActor(id)
+ return actor, actor.Id != "", err
}
-func IsActivityLocal(activity activitypub.Activity) bool {
+func IsActivityLocal(activity activitypub.Activity) (bool, error) {
for _, e := range activity.To {
- if GetActorFromDB(e).Id != "" {
- return true
+ if res, err := db.GetActorFromDB(e); err == nil && res.Id != "" {
+ return true, nil
+ } else if err != nil {
+ return false, err
}
}
for _, e := range activity.Cc {
- if GetActorFromDB(e).Id != "" {
- return true
+ if res, err := db.GetActorFromDB(e); err == nil && res.Id != "" {
+ return true, nil
+ } else if err != nil {
+ return false, err
}
}
- if activity.Actor != nil && GetActorFromDB(activity.Actor.Id).Id != "" {
- return true
+ if res, err := db.GetActorFromDB(activity.Actor.Id); err == nil && activity.Actor != nil && res.Id != "" {
+ return true, nil
+ } else if err != nil {
+ return false, err
}
- return false
+ return false, nil
}
func GetObjectFromActivity(activity activitypub.Activity) activitypub.ObjectBase {
return *activity.Object
}
-func MakeCaptchas(total int) {
- difference := total - GetCaptchaTotal(db)
+func MakeCaptchas(total int) error {
+ dbtotal, err := db.GetCaptchaTotal()
+ if err != nil {
+ return err
+ }
+
+ difference := total - dbtotal
for i := 0; i < difference; i++ {
- CreateNewCaptcha(db)
+ if err := db.CreateNewCaptcha(); err != nil {
+ return err
+ }
}
+
+ return nil
}
func GetFileContentType(out multipart.File) (string, error) {
-
buffer := make([]byte, 512)
_, err := out.Read(buffer)
@@ -562,7 +601,7 @@ func GetFileContentType(out multipart.File) (string, error) {
}
func SupportedMIMEType(mime string) bool {
- for _, e := range supportedFiles {
+ for _, e := range config.SupportedFiles {
if e == mime {
return true
}
@@ -571,48 +610,63 @@ func SupportedMIMEType(mime string) bool {
return false
}
-func GetActorReported(w http.ResponseWriter, r *http.Request, db *sql.DB, id string) {
-
+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)
- w.Write([]byte(""))
- return
+ _, err := w.Write([]byte(""))
+ return err
}
- if !HasAuth(verification[1], id) {
+ if res, err := db.HasAuth(verification[1], id); err == nil && !res {
w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(""))
- return
+ _, 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 = GetActorReportedTotal(id)
- following.Items = GetActorReportedDB(id)
+ following.TotalItems, err = db.GetActorReportedTotal(id)
+ if err != nil {
+ return err
+ }
+
+ following.Items, err = db.GetActorReportedDB(id)
+ if err != nil {
+ return err
+ }
+
+ enc, err := json.MarshalIndent(following, "", "\t")
+ if err != nil {
+ return err
+ }
- enc, _ := json.MarshalIndent(following, "", "\t")
w.Header().Set("Content-Type", config.ActivityStreams)
- w.Write(enc)
+
+ _, err = w.Write(enc)
+ return err
}
-func GetCollectionFromID(id string) activitypub.Collection {
+func GetCollectionFromID(id string) (activitypub.Collection, error) {
var nColl activitypub.Collection
req, err := http.NewRequest("GET", id, nil)
-
- CheckError(err, "could not get collection from id req")
+ if err != nil {
+ return nColl, err
+ }
req.Header.Set("Accept", config.ActivityStreams)
- resp, err := RouteProxy(req)
-
+ resp, err := util.RouteProxy(req)
if err != nil {
- return nColl
+ return nColl, err
}
if resp.StatusCode == 200 {
@@ -621,128 +675,109 @@ func GetCollectionFromID(id string) activitypub.Collection {
body, _ := ioutil.ReadAll(resp.Body)
if len(body) > 0 {
- err = json.Unmarshal(body, &nColl)
-
- CheckError(err, "error getting collection resp from json body")
+ if err := json.Unmarshal(body, &nColl); err != nil {
+ return nColl, err
+ }
}
}
- return nColl
-}
-
-func PrintAdminAuth(db *sql.DB) {
- query := fmt.Sprintf("select identifier, code from boardaccess where board='%s' and type='admin'", config.Domain)
-
- rows, err := db.Query(query)
-
- CheckError(err, "Error getting config.Domain auth")
-
- var code string
- var identifier string
-
- rows.Next()
- rows.Scan(&identifier, &code)
-
- fmt.Println("Admin Login: " + identifier + ", Code: " + code)
+ return nColl, nil
}
-func IsInStringArray(array []string, value string) bool {
- for _, e := range array {
- if e == value {
- return true
- }
- }
- return false
-}
-
-func GetUniqueFilename(_type string) string {
- id := util.RandomID(8)
- file := "/public/" + id + "." + _type
-
- for true {
- if _, err := os.Stat("." + file); err == nil {
- id = util.RandomID(8)
- file = "/public/" + id + "." + _type
- } else {
- return "/public/" + id + "." + _type
- }
+func PrintAdminAuth() error {
+ identifier, code, err := db.GetAdminAuth()
+ if err != nil {
+ return err
}
- return ""
+ fmt.Println("Admin Login: " + identifier + ", Code: " + code)
+ return nil
}
-func DeleteObjectRequest(id string) {
+func DeleteObjectRequest(id string) error {
var nObj activitypub.ObjectBase
var nActor activitypub.Actor
nObj.Id = id
nObj.Actor = nActor.Id
- activity := CreateActivity("Delete", nObj)
+ activity, err := CreateActivity("Delete", nObj)
+ if err != nil {
+ return err
+ }
- obj := GetObjectFromPath(id)
+ obj, err := db.GetObjectFromPath(id)
+ if err != nil {
+ return err
+ }
- actor := FingerActor(obj.Actor)
+ actor, err := webfinger.FingerActor(obj.Actor)
+ if err != nil {
+ return err
+ }
activity.Actor = &actor
- followers := GetActorFollowDB(obj.Actor)
+ followers, err := db.GetActorFollowDB(obj.Actor)
+ if err != nil {
+ return err
+ }
+
for _, e := range followers {
activity.To = append(activity.To, e.Id)
}
- following := GetActorFollowingDB(obj.Actor)
+ following, err := db.GetActorFollowingDB(obj.Actor)
+ if err != nil {
+ return err
+ }
for _, e := range following {
activity.To = append(activity.To, e.Id)
}
- MakeActivityRequest(activity)
+ return db.MakeActivityRequest(activity)
}
-func DeleteObjectAndRepliesRequest(id string) {
+func DeleteObjectAndRepliesRequest(id string) error {
var nObj activitypub.ObjectBase
var nActor activitypub.Actor
nObj.Id = id
nObj.Actor = nActor.Id
- activity := CreateActivity("Delete", nObj)
+ activity, err := CreateActivity("Delete", nObj)
+ if err != nil {
+ return err
+ }
- obj := GetObjectByIDFromDB(id)
+ obj, err := db.GetObjectByIDFromDB(id)
+ if err != nil {
+ return err
+ }
activity.Actor.Id = obj.OrderedItems[0].Actor
activity.Object = &obj.OrderedItems[0]
- followers := GetActorFollowDB(obj.OrderedItems[0].Actor)
+ followers, err := db.GetActorFollowDB(obj.OrderedItems[0].Actor)
+ if err != nil {
+ return err
+ }
for _, e := range followers {
activity.To = append(activity.To, e.Id)
}
- following := GetActorFollowingDB(obj.OrderedItems[0].Actor)
+ following, err := db.GetActorFollowingDB(obj.OrderedItems[0].Actor)
+ if err != nil {
+ return err
+ }
+
for _, e := range following {
activity.To = append(activity.To, e.Id)
}
- MakeActivityRequest(activity)
+ return db.MakeActivityRequest(activity)
}
-func ResizeAttachmentToPreview(db *sql.DB) {
- query := `select id, href, mediatype, name, size, published from activitystream where id in (select attachment from activitystream where attachment!='' and preview='')`
-
- rows, err := db.Query(query)
-
- CheckError(err, "error getting attachments")
-
- defer rows.Close()
- for rows.Next() {
-
- var id string
- var href string
- var mediatype string
- var name string
- var size int
- var published time.Time
-
- rows.Scan(&id, &href, &mediatype, &name, &size, &published)
-
+func ResizeAttachmentToPreview() error {
+ return db.GetObjectsWithoutPreviewsCallback(func(id, href, mediatype, name string, size int, published time.Time) error {
re := regexp.MustCompile(`^\w+`)
_type := re.FindString(mediatype)
@@ -753,7 +788,7 @@ func ResizeAttachmentToPreview(db *sql.DB) {
file := re.ReplaceAllString(mediatype, "")
- nHref := GetUniqueFilename(file)
+ nHref := util.GetUniqueFilename(file)
var nPreview activitypub.NestedObjectBase
@@ -761,7 +796,12 @@ func ResizeAttachmentToPreview(db *sql.DB) {
actor := re.ReplaceAllString(id, "")
nPreview.Type = "Preview"
- nPreview.Id = fmt.Sprintf("%s/%s", actor, CreateUniqueID(actor))
+ uid, err := db.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
@@ -776,31 +816,25 @@ func ResizeAttachmentToPreview(db *sql.DB) {
if id != "" {
cmd := exec.Command("convert", "."+objFile, "-resize", "250x250>", "-strip", "."+nHref)
- err := cmd.Run()
-
- CheckError(err, "error with resize attachment preview")
-
- if err == nil {
+ if err := cmd.Run(); err == nil {
fmt.Println(objFile + " -> " + nHref)
- WritePreviewToDB(nPreview)
- UpdateObjectWithPreview(id, nPreview.Id)
+ if err := db.WritePreviewToDB(nPreview); err != nil {
+ return err
+ }
+ if err := db.UpdateObjectWithPreview(id, nPreview.Id); err != nil {
+ return err
+ }
+ } else {
+ return err
}
}
}
- }
-}
-
-func UpdateObjectWithPreview(id string, preview string) {
- query := `update activitystream set preview=$1 where attachment=$2`
-
- _, err := db.Exec(query, preview, id)
-
- CheckError(err, "could not update activity stream with preview")
+ return nil
+ })
}
-func ParseCommentForReply(comment string) string {
-
+func ParseCommentForReply(comment string) (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(comment, -1)
@@ -812,45 +846,50 @@ func ParseCommentForReply(comment string) string {
}
if len(links) > 0 {
- _, isValid := CheckValidActivity(strings.ReplaceAll(links[0], ">", ""))
+ _, isValid, err := webfinger.CheckValidActivity(strings.ReplaceAll(links[0], ">", ""))
+ if err != nil {
+ return "", err
+ }
if isValid {
- return links[0]
+ return links[0], nil
}
}
- return ""
+ return "", nil
}
-func GetActorCollectionReq(r *http.Request, collection string) activitypub.Collection {
+func GetActorCollectionReq(r *http.Request, collection string) (activitypub.Collection, error) {
var nCollection activitypub.Collection
req, err := http.NewRequest("GET", collection, nil)
+ if err != nil {
+ return nCollection, err
+ }
- CheckError(err, "error with getting actor collection req "+collection)
-
- _, pass := GetPasswordFromSession(r)
+ // TODO: rewrite this for fiber
+ pass := "FIXME"
+ //_, pass := GetPasswordFromSession(r)
req.Header.Set("Accept", config.ActivityStreams)
req.Header.Set("Authorization", "Basic "+pass)
- resp, err := RouteProxy(req)
-
- CheckError(err, "error with getting actor collection resp "+collection)
+ resp, err := util.RouteProxy(req)
+ if err != nil {
+ return nCollection, err
+ }
+ defer resp.Body.Close()
if resp.StatusCode == 200 {
-
- defer resp.Body.Close()
-
body, _ := ioutil.ReadAll(resp.Body)
- err = json.Unmarshal(body, &nCollection)
-
- CheckError(err, "error getting actor collection from body "+collection)
+ if err := json.Unmarshal(body, &nCollection); err != nil {
+ return nCollection, err
+ }
}
- return nCollection
+ return nCollection, nil
}
func CreatedNeededDirectories() {
@@ -863,14 +902,23 @@ func CreatedNeededDirectories() {
}
}
-func AddInstanceToIndex(actor string) {
+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
+
// if local testing enviroment do not add to index
re := regexp.MustCompile(`(.+)?(localhost|\d+\.\d+\.\d+\.\d+)(.+)?`)
if re.MatchString(actor) {
- return
+ return nil
}
- followers := GetCollectionFromID("https://fchan.xyz/followers")
+ // also while i'm here
+ // TODO: maybe allow different indexes?
+ followers, err := GetCollectionFromID("https://fchan.xyz/followers")
+ if err != nil {
+ return err
+ }
var alreadyIndex = false
for _, e := range followers.Items {
@@ -881,28 +929,41 @@ func AddInstanceToIndex(actor string) {
if !alreadyIndex {
req, err := http.NewRequest("GET", "https://fchan.xyz/addtoindex?id="+actor, nil)
+ if err != nil {
+ return err
+ }
- CheckError(err, "error with add instance to actor index req")
-
- _, err = http.DefaultClient.Do(req)
-
- CheckError(err, "error with add instance to actor index resp")
+ if _, err := http.DefaultClient.Do(req); err != nil {
+ return err
+ }
}
+
+ return nil
}
-func AddInstanceToIndexDB(actor string) {
+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 := FingerActor(actor)
+ nActor, err := webfinger.FingerActor(actor)
+ if err != nil {
+ return err
+ }
if nActor.Id == "" {
- return
+ return nil
}
- followers := GetCollectionFromID("https://fchan.xyz/followers")
+ // TODO: maybe allow different indexes?
+ followers, err := GetCollectionFromID("https://fchan.xyz/followers")
+ if err != nil {
+ return err
+ }
var alreadyIndex = false
for _, e := range followers.Items {
@@ -912,49 +973,38 @@ func AddInstanceToIndexDB(actor string) {
}
if !alreadyIndex {
- query := `insert into follower (id, follower) values ($1, $2)`
-
- _, err := db.Exec(query, "https://fchan.xyz", nActor.Id)
-
- CheckError(err, "Error with add to index query")
+ return db.AddFollower("https://fchan.xyz", nActor.Id)
}
-}
-func HashMedia(media string) string {
- h := sha256.New()
- h.Write([]byte(media))
- return hex.EncodeToString(h.Sum(nil))
+ return nil
}
-func HashBytes(media []byte) string {
- h := sha256.New()
- h.Write(media)
- return hex.EncodeToString(h.Sum(nil))
-}
-
-func RouteImages(w http.ResponseWriter, media string) {
-
+func RouteImages(w http.ResponseWriter, media string) error {
req, err := http.NewRequest("GET", MediaHashs[media], nil)
-
- CheckError(err, "error with Route Images req")
+ 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 err != nil || resp.StatusCode != 200 {
+ if resp.StatusCode != 200 {
fileBytes, err := ioutil.ReadFile("./static/notfound.png")
+ if err != nil {
+ return err
+ }
- CheckError(err, "could not get /static/notfound.png file bytes")
-
- w.Write(fileBytes)
- return
+ _, err = w.Write(fileBytes)
+ return err
}
- defer resp.Body.Close()
-
body, _ := ioutil.ReadAll(resp.Body)
for name, values := range resp.Header {
for _, value := range values {
@@ -962,18 +1012,8 @@ func RouteImages(w http.ResponseWriter, media string) {
}
}
- w.Write(body)
-}
-
-func HasValidation(w http.ResponseWriter, r *http.Request, actor activitypub.Actor) bool {
- id, _ := GetPasswordFromSession(r)
-
- if id == "" || (id != actor.Id && id != config.Domain) {
- http.Redirect(w, r, "/", http.StatusSeeOther)
- return false
- }
-
- return true
+ _, err = w.Write(body)
+ return err
}
func TemplateFunctions(engine *html.Engine) {
@@ -1017,39 +1057,43 @@ func TemplateFunctions(engine *html.Engine) {
engine.AddFunc("isOnion", util.IsOnion)
engine.AddFunc("parseReplyLink", func(actorId string, op string, id string, content string) template.HTML {
- actor := FingerActor(actorId)
+ actor, err := webfinger.FingerActor(actorId)
+ if err != nil {
+ // TODO: figure out what to do here
+ panic(err)
+ }
+
title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\&lt;`, ">")
link := fmt.Sprintf("<a href=\"%s/%s#%s\" title=\"%s\" class=\"replyLink\">&gt;&gt;%s</a>", actor.Name, util.ShortURL(actor.Outbox, op), util.ShortURL(actor.Outbox, id), title, util.ShortURL(actor.Outbox, id))
return template.HTML(link)
})
- engine.AddFunc("shortExcerpt",
- func(post activitypub.ObjectBase) string {
- var returnString string
+ engine.AddFunc("shortExcerpt", func(post activitypub.ObjectBase) string {
+ var returnString string
- if post.Name != "" {
- returnString = post.Name + "| " + post.Content
- } else {
- returnString = post.Content
- }
+ if post.Name != "" {
+ returnString = post.Name + "| " + post.Content
+ } else {
+ returnString = post.Content
+ }
- re := regexp.MustCompile(`(^(.|\r\n|\n){100})`)
+ re := regexp.MustCompile(`(^(.|\r\n|\n){100})`)
- match := re.FindStringSubmatch(returnString)
+ match := re.FindStringSubmatch(returnString)
- if len(match) > 0 {
- returnString = match[0] + "..."
- }
+ if len(match) > 0 {
+ returnString = match[0] + "..."
+ }
- re = regexp.MustCompile(`(^.+\|)`)
+ re = regexp.MustCompile(`(^.+\|)`)
- match = re.FindStringSubmatch(returnString)
+ match = re.FindStringSubmatch(returnString)
- if len(match) > 0 {
- returnString = strings.Replace(returnString, match[0], "<b>"+match[0]+"</b>", 1)
- returnString = strings.Replace(returnString, "|", ":", 1)
- }
+ if len(match) > 0 {
+ returnString = strings.Replace(returnString, match[0], "<b>"+match[0]+"</b>", 1)
+ returnString = strings.Replace(returnString, "|", ":", 1)
+ }
- return returnString
- })
+ return returnString
+ })
}
diff --git a/outboxGet.go b/outboxGet.go
index 576a98b..6e7bd47 100644
--- a/outboxGet.go
+++ b/outboxGet.go
@@ -1,117 +1,46 @@
package main
import (
- "database/sql"
"net/http"
"encoding/json"
"github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/config"
"github.com/FChannel0/FChannel-Server/db"
_ "github.com/lib/pq"
)
-func GetActorOutbox(w http.ResponseWriter, r *http.Request, db *sql.DB) {
- actor := GetActorFromPath(r.URL.Path, "/")
+func GetActorOutbox(w http.ResponseWriter, r *http.Request) error {
+ actor, err := db.GetActorFromPath(r.URL.Path, "/")
+ if err != nil {
+ return err
+ }
+
var collection activitypub.Collection
- collection.OrderedItems = GetActorObjectCollectionFromDB(actor.Id).OrderedItems
+ c, err := db.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 = GetObjectPostsTotalDB(actor)
- collection.TotalImgs = GetObjectImgsTotalDB(actor)
-
- enc, _ := json.Marshal(collection)
-
- w.Header().Set("Content-Type", activitystreams)
- w.Write(enc)
-}
-
-func GetCollectionFromPath(path string) activitypub.Collection {
-
- var nColl activitypub.Collection
- var result []activitypub.ObjectBase
-
- query := `select id, name, content, type, published, attributedto, attachment, preview, actor from activitystream where id=$1 order by published desc`
-
- rows, err := db.Query(query, path)
-
- CheckError(err, "error query collection path from db")
-
- defer rows.Close()
-
- for rows.Next() {
- var actor activitypub.Actor
- var post activitypub.ObjectBase
- var attachID string
- var previewID string
-
- err = rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.AttributedTo, &attachID, &previewID, &actor.Id)
-
- CheckError(err, "error scan object into post struct from path")
-
- post.Actor = actor.Id
-
- post.InReplyTo = GetInReplyToDB(post)
-
- var postCnt int
- var imgCnt int
- post.Replies, postCnt, imgCnt = GetObjectRepliesDB(post)
-
- post.Replies.TotalItems, post.Replies.TotalImgs = GetObjectRepliesCount(post)
-
- post.Replies.TotalItems = post.Replies.TotalItems + postCnt
- post.Replies.TotalImgs = post.Replies.TotalImgs + imgCnt
-
- post.Attachment = GetObjectAttachment(attachID)
-
- post.Preview = GetObjectPreview(previewID)
-
- result = append(result, post)
+ collection.TotalItems, err = db.GetObjectPostsTotalDB(actor)
+ if err != nil {
+ return err
}
- nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
-
- nColl.OrderedItems = result
-
- return nColl
-}
-
-func GetObjectFromPath(path string) activitypub.ObjectBase {
- var nObj activitypub.ObjectBase
-
- query := `select id, name, content, type, published, attributedto, attachment, preview, actor from activitystream where id=$1 order by published desc`
-
- rows, err := db.Query(query, path)
-
- CheckError(err, "error query collection path from db")
-
- defer rows.Close()
- rows.Next()
- var attachID string
- var previewID string
-
- var nActor activitypub.Actor
- nObj.Actor = nActor.Id
-
- err = rows.Scan(&nObj.Id, &nObj.Name, &nObj.Content, &nObj.Type, &nObj.Published, &nObj.AttributedTo, &attachID, &previewID, &nObj.Actor)
-
- CheckError(err, "error scan object into post struct from path")
-
- var postCnt int
- var imgCnt int
-
- nObj.Replies, postCnt, imgCnt = GetObjectRepliesDB(nObj)
-
- nObj.Replies.TotalItems, nObj.Replies.TotalImgs = GetObjectRepliesCount(nObj)
-
- nObj.Replies.TotalItems = nObj.Replies.TotalItems + postCnt
- nObj.Replies.TotalImgs = nObj.Replies.TotalImgs + imgCnt
-
- nObj.Attachment = GetObjectAttachment(attachID)
+ collection.TotalImgs, err = db.GetObjectImgsTotalDB(actor)
+ if err != nil {
+ return err
+ }
- nObj.Preview = GetObjectPreview(previewID)
+ enc, _ := json.Marshal(collection)
- return nObj
+ w.Header().Set("Content-Type", config.ActivityStreams)
+ _, err = w.Write(enc)
+ return err
}
diff --git a/routes/util.go b/routes/util.go
index 0a8dc9c..3d03795 100644
--- a/routes/util.go
+++ b/routes/util.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/config"
"github.com/FChannel0/FChannel-Server/db"
"github.com/gofiber/fiber/v2"
)
@@ -113,3 +114,14 @@ func wantToServeArchive(actorName string) (activitypub.Collection, bool, error)
return collection, serve, nil
}
+
+func hasValidation(ctx *fiber.Ctx, actor activitypub.Actor) bool {
+ id, _ := getPassword(ctx)
+
+ if id == "" || (id != actor.Id && id != config.Domain) {
+ //http.Redirect(w, r, "/", http.StatusSeeOther)
+ return false
+ }
+
+ return true
+}
diff --git a/util/util.go b/util/util.go
index 8f32363..7da4671 100644
--- a/util/util.go
+++ b/util/util.go
@@ -1,7 +1,10 @@
package util
import (
+ "crypto/sha256"
+ "encoding/hex"
"fmt"
+ "os"
"regexp"
"strings"
)
@@ -196,3 +199,42 @@ func ConvertSize(size int64) string {
return rValue
}
+
+// IsInStringArray looks for a string in a string array and returns true if it is found.
+func IsInStringArray(haystack []string, needle string) bool {
+ for _, e := range haystack {
+ if e == needle {
+ return true
+ }
+ }
+ return false
+}
+
+// GetUniqueFilename will look for an available random filename in the /public/ directory.
+func GetUniqueFilename(ext string) string {
+ id := RandomID(8)
+ file := "/public/" + id + "." + ext
+
+ for true {
+ if _, err := os.Stat("." + file); err == nil {
+ id = RandomID(8)
+ file = "/public/" + id + "." + ext
+ } else {
+ return "/public/" + id + "." + ext
+ }
+ }
+
+ return ""
+}
+
+func HashMedia(media string) string {
+ h := sha256.New()
+ h.Write([]byte(media))
+ return hex.EncodeToString(h.Sum(nil))
+}
+
+func HashBytes(media []byte) string {
+ h := sha256.New()
+ h.Write(media)
+ return hex.EncodeToString(h.Sum(nil))
+}