aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFChannel <>2022-05-08 14:57:40 -0700
committerFChannel <>2022-06-19 12:53:29 -0700
commit580dec5b89215310ce34341e11ff17fe38bdb63a (patch)
tree894424df66a9d9f7e41805822f29adac8fb490fe
parentf7bf818d29393ceaccf4d2906557351fa6a4f49f (diff)
more cleanup, logging and error logging everywhere
things are mostly in place can work on "features" and polish
-rw-r--r--activitypub/activity.go343
-rw-r--r--activitypub/actor.go772
-rw-r--r--activitypub/object.go201
-rw-r--r--activitypub/pem.go5
-rw-r--r--activitypub/util.go12
-rw-r--r--activitypub/webfinger.go180
-rw-r--r--config/config.go3
-rw-r--r--db/cache.go72
-rw-r--r--db/database.go584
-rw-r--r--db/follow.go306
-rw-r--r--db/pem.go95
-rw-r--r--db/report.go112
-rw-r--r--main.go48
-rw-r--r--post/tripcode.go106
-rw-r--r--post/util.go111
-rw-r--r--routes/actor.go86
-rw-r--r--routes/admin.go83
-rw-r--r--routes/api.go9
-rw-r--r--routes/archive.go11
-rw-r--r--routes/index.go14
-rw-r--r--routes/news.go18
-rw-r--r--routes/outbox.go16
-rw-r--r--routes/post.go36
-rw-r--r--routes/util.go90
-rw-r--r--routes/webfinger.go8
-rw-r--r--util/blacklist.go33
-rw-r--r--util/key.go30
-rw-r--r--util/proxy.go40
-rw-r--r--util/util.go79
-rw-r--r--util/verification.go (renamed from db/verification.go)554
-rw-r--r--webfinger/comm.go88
-rw-r--r--webfinger/util.go36
-rw-r--r--webfinger/webfinger.go313
33 files changed, 2123 insertions, 2371 deletions
diff --git a/activitypub/activity.go b/activitypub/activity.go
index 06e061b..1650f14 100644
--- a/activitypub/activity.go
+++ b/activitypub/activity.go
@@ -1,26 +1,135 @@
package activitypub
import (
+ "bytes"
+ "encoding/json"
"errors"
"fmt"
+ "io/ioutil"
+ "net/http"
+ "regexp"
"strings"
+ "time"
"github.com/FChannel0/FChannel-Server/config"
"github.com/FChannel0/FChannel-Server/util"
)
-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)
- }
+func (activity Activity) AcceptFollow() Activity {
+ var accept Activity
+ accept.AtContext.Context = activity.AtContext.Context
+ accept.Type = "Accept"
+ var nActor Actor
+ accept.Actor = &nActor
+ accept.Actor.Id = activity.Object.Actor
+ var nObj ObjectBase
+ accept.Object = &nObj
+ accept.Object.Actor = activity.Actor.Id
+ var nNested NestedObjectBase
+ accept.Object.Object = &nNested
+ accept.Object.Object.Actor = activity.Object.Actor
+ accept.Object.Object.Type = "Follow"
+ accept.To = append(accept.To, activity.Object.Actor)
+
return accept
}
+func (activity Activity) AddFollowersTo() (Activity, error) {
+ activity.To = append(activity.To, activity.Actor.Id)
+
+ for _, e := range activity.To {
+ reqActivity := Activity{Id: e + "/followers"}
+ aFollowers, err := reqActivity.GetCollection()
+ if err != nil {
+ return activity, util.MakeError(err, "AddFollowersTo")
+ }
+
+ for _, k := range aFollowers.Items {
+ activity.To = append(activity.To, k.Id)
+ }
+ }
+
+ var nActivity Activity
+
+ for _, e := range activity.To {
+ var alreadyTo = false
+ for _, k := range nActivity.To {
+ if e == k || e == activity.Actor.Id {
+ alreadyTo = true
+ }
+ }
+
+ if !alreadyTo {
+ nActivity.To = append(nActivity.To, e)
+ }
+ }
+
+ activity.To = nActivity.To
+
+ return activity, nil
+}
+
+func (activity Activity) CheckValid() (Collection, bool, error) {
+ var respCollection Collection
+
+ re := regexp.MustCompile(`.+\.onion(.+)?`)
+ if re.MatchString(activity.Id) {
+ activity.Id = strings.Replace(activity.Id, "https", "http", 1)
+ }
+
+ req, err := http.NewRequest("GET", activity.Id, nil)
+ if err != nil {
+ return respCollection, false, util.MakeError(err, "CheckValid")
+ }
+
+ req.Header.Set("Accept", config.ActivityStreams)
+
+ resp, err := util.RouteProxy(req)
+ if err != nil {
+ return respCollection, false, util.MakeError(err, "CheckValid")
+ }
+ defer resp.Body.Close()
+
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ if err := json.Unmarshal(body, &respCollection); err != nil {
+ return respCollection, false, util.MakeError(err, "CheckValid")
+ }
+
+ if respCollection.AtContext.Context == "https://www.w3.org/ns/activitystreams" && respCollection.OrderedItems[0].Id != "" {
+ return respCollection, true, nil
+ }
+
+ return respCollection, false, nil
+}
+
+func (activity Activity) GetCollection() (Collection, error) {
+ var nColl Collection
+
+ req, err := http.NewRequest("GET", activity.Id, nil)
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ req.Header.Set("Accept", config.ActivityStreams)
+ resp, err := util.RouteProxy(req)
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ if resp.StatusCode == 200 {
+ defer resp.Body.Close()
+ body, _ := ioutil.ReadAll(resp.Body)
+ if len(body) > 0 {
+ if err := json.Unmarshal(body, &nColl); err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+ }
+ }
+
+ return nColl, nil
+}
+
func (activity Activity) IsLocal() (bool, error) {
for _, e := range activity.To {
@@ -50,11 +159,11 @@ func (activity Activity) Process() error {
if activityType == "Create" {
for _, e := range activity.To {
if res, err := GetActorFromDB(e); res.Id != "" {
- fmt.Println("actor is in the database")
+ config.Log.Println("actor is in the database")
} else if err != nil {
return util.MakeError(err, "Process")
} else {
- fmt.Println("actor is NOT in the database")
+ config.Log.Println("actor is NOT in the database")
}
}
} else if activityType == "Follow" {
@@ -91,7 +200,9 @@ func (activity Activity) Report(reason string) (bool, error) {
return false, util.MakeError(err, "Report")
}
- activityCol, err := activity.Object.GetCollection()
+ reqActivity := Activity{Id: activity.Object.Id}
+ activityCol, err := reqActivity.GetCollection()
+
if err != nil {
return false, util.MakeError(err, "Report")
}
@@ -104,7 +215,7 @@ func (activity Activity) Report(reason string) (bool, error) {
return true, nil
}
-func (activity Activity) SetFollower() (Activity, error) {
+func (activity Activity) SetActorFollower() (Activity, error) {
var query string
alreadyFollow, err := activity.Actor.IsAlreadyFollower(activity.Object.Actor)
@@ -140,3 +251,209 @@ func (activity Activity) SetFollower() (Activity, error) {
activity.Type = "Accept"
return activity, nil
}
+
+func (activity Activity) SetActorFollowing() (Activity, error) {
+ var query string
+
+ alreadyFollowing := false
+ alreadyFollower := false
+ objActor, _ := GetActor(activity.Object.Actor)
+ following, err := objActor.GetFollowing()
+
+ if err != nil {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ actor, err := FingerActor(activity.Actor.Id)
+
+ if err != nil {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ reqActivity := Activity{Id: actor.Followers}
+ remoteActorFollowerCol, err := reqActivity.GetCollection()
+
+ if err != nil {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ for _, e := range following {
+ if e.Id == activity.Actor.Id {
+ alreadyFollowing = true
+ }
+ }
+
+ for _, e := range remoteActorFollowerCol.Items {
+ if e.Id == activity.Object.Actor {
+ alreadyFollower = true
+ }
+ }
+
+ activity.Type = "Reject"
+
+ if activity.Actor.Id == activity.Object.Actor {
+ return activity, nil
+ }
+
+ if alreadyFollowing && alreadyFollower {
+ query = `delete from following where id=$1 and following=$2`
+ activity.Summary = activity.Object.Actor + " Unfollowing " + activity.Actor.Id
+
+ if res, err := activity.Actor.IsLocal(); err == nil && !res {
+ go activity.Actor.DeleteCache()
+ } else {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ if _, err := config.DB.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ activity.Type = "Accept"
+
+ return activity, nil
+ }
+
+ if !alreadyFollowing && !alreadyFollower {
+
+ query = `insert into following (id, following) values ($1, $2)`
+ activity.Summary = activity.Object.Actor + " Following " + activity.Actor.Id
+
+ if res, err := activity.Actor.IsLocal(); err == nil && !res {
+ go activity.Actor.WriteCache()
+ }
+ if _, err := config.DB.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
+ return activity, util.MakeError(err, "SetActorFollowing")
+ }
+
+ activity.Type = "Accept"
+
+ return activity, nil
+ }
+
+ return activity, nil
+}
+
+func (activity Activity) MakeFollowingReq() (bool, error) {
+ actor, err := GetActor(activity.Object.Id)
+
+ if err != nil {
+ return false, util.MakeError(err, "MakeFollowingReq")
+ }
+
+ req, err := http.NewRequest("POST", actor.Inbox, nil)
+
+ if err != nil {
+ return false, util.MakeError(err, "MakeFollowingReq")
+ }
+
+ resp, err := util.RouteProxy(req)
+
+ if err != nil {
+ return false, util.MakeError(err, "MakeFollowingReq")
+ }
+
+ defer resp.Body.Close()
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ var respActivity Activity
+ err = json.Unmarshal(body, &respActivity)
+
+ return respActivity.Type == "Accept", util.MakeError(err, "MakeFollowingReq")
+}
+
+func (activity Activity) MakeRequestInbox() error {
+ j, _ := json.MarshalIndent(activity, "", "\t")
+
+ for _, e := range activity.To {
+ if e != activity.Actor.Id {
+ actor, err := FingerActor(e)
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequest")
+ }
+
+ if actor.Id != "" {
+ _, instance := GetActorAndInstance(actor.Id)
+
+ if actor.Inbox != "" {
+ req, err := http.NewRequest("POST", actor.Inbox, bytes.NewBuffer(j))
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequest")
+ }
+
+ date := time.Now().UTC().Format(time.RFC1123)
+ path := strings.Replace(actor.Inbox, instance, "", 1)
+ re := regexp.MustCompile("https?://(www.)?")
+ path = re.ReplaceAllString(path, "")
+ sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
+ encSig, err := activity.Actor.ActivitySign(sig)
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequest")
+ }
+
+ signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
+
+ req.Header.Set("Content-Type", config.ActivityStreams)
+ req.Header.Set("Date", date)
+ req.Header.Set("Signature", signature)
+ req.Host = instance
+
+ _, err = util.RouteProxy(req)
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequest")
+ }
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+func (activity Activity) MakeRequestOutbox() error {
+ j, _ := json.Marshal(activity)
+
+ if activity.Actor.Outbox == "" {
+ return util.MakeError(errors.New("invalid outbox"), "MakeRequestOutbox")
+ }
+
+ req, err := http.NewRequest("POST", activity.Actor.Outbox, bytes.NewBuffer(j))
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequestOutbox")
+ }
+
+ re := regexp.MustCompile("https?://(www.)?")
+
+ var instance string
+ if activity.Actor.Id == config.Domain {
+ instance = re.ReplaceAllString(config.Domain, "")
+ } else {
+ _, instance = GetActorAndInstance(activity.Actor.Id)
+ }
+
+ date := time.Now().UTC().Format(time.RFC1123)
+ path := strings.Replace(activity.Actor.Outbox, instance, "", 1)
+ path = re.ReplaceAllString(path, "")
+ sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
+ encSig, err := activity.Actor.ActivitySign(sig)
+
+ if err != nil {
+ return util.MakeError(err, "MakeRequestOutbox")
+ }
+
+ signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
+
+ req.Header.Set("Content-Type", config.ActivityStreams)
+ req.Header.Set("Date", date)
+ req.Header.Set("Signature", signature)
+ req.Host = instance
+
+ _, err = util.RouteProxy(req)
+
+ return util.MakeError(err, "MakeRequestOutbox")
+}
diff --git a/activitypub/actor.go b/activitypub/actor.go
index 120c9fd..bc7ba8a 100644
--- a/activitypub/actor.go
+++ b/activitypub/actor.go
@@ -11,16 +11,20 @@ import (
"encoding/json"
"encoding/pem"
"errors"
- "fmt"
"io/ioutil"
+ "net/http"
"os"
+ "regexp"
"strings"
+ "time"
"github.com/FChannel0/FChannel-Server/config"
"github.com/FChannel0/FChannel-Server/util"
"github.com/gofiber/fiber/v2"
)
+var ActorCache = make(map[string]Actor)
+
func (actor Actor) AddFollower(follower string) error {
query := `insert into follower (id, follower) values ($1, $2)`
_, err := config.DB.Exec(query, actor.Id, follower)
@@ -39,7 +43,7 @@ func (actor Actor) ActivitySign(signature string) (string, error) {
_, err := os.Stat(file)
if err != nil {
- fmt.Println(`\n Unable to locate private key. Now,
+ config.Log.Println(`\n Unable to locate private key. Now,
this means that you are now missing the proof that you are the
owner of the "` + actor.Name + `" board. If you are the developer,
then your job is just as easy as generating a new keypair, but
@@ -65,6 +69,75 @@ accepting your posts from your board from this site. Good luck ;)`)
return base64.StdEncoding.EncodeToString(cipher), nil
}
+func (actor Actor) ArchivePosts() error {
+ if actor.Id != "" && actor.Id != config.Domain {
+ col, err := actor.GetAllArchive(165)
+
+ if err != nil {
+ return util.MakeError(err, "ArchivePosts")
+ }
+
+ for _, e := range col.OrderedItems {
+ for _, k := range e.Replies.OrderedItems {
+ if err := k.UpdateType("Archive"); err != nil {
+ return util.MakeError(err, "ArchivePosts")
+ }
+ }
+
+ if err := e.UpdateType("Archive"); err != nil {
+ return util.MakeError(err, "ArchivePosts")
+ }
+ }
+ }
+
+ return nil
+}
+
+func (actor Actor) AutoFollow() error {
+ nActor, _ := GetActor(actor.Id)
+ following, err := nActor.GetFollowing()
+
+ if err != nil {
+ return util.MakeError(err, "AutoFollow")
+ }
+
+ follower, err := nActor.GetFollow()
+
+ if err != nil {
+ return util.MakeError(err, "AutoFollow")
+ }
+
+ isFollowing := false
+
+ for _, e := range follower {
+ for _, k := range following {
+ if e.Id == k.Id {
+ isFollowing = true
+ }
+ }
+
+ if !isFollowing && e.Id != config.Domain && e.Id != nActor.Id {
+ followActivity, err := nActor.MakeFollowActivity(e.Id)
+
+ if err != nil {
+ return util.MakeError(err, "AutoFollow")
+ }
+
+ nActor, err := FingerActor(e.Id)
+
+ if err != nil {
+ return util.MakeError(err, "AutoFollow")
+ }
+
+ if nActor.Id != "" {
+ followActivity.MakeRequestOutbox()
+ }
+ }
+ }
+
+ return nil
+}
+
func (actor Actor) DeleteCache() error {
query := `select id from cacheactivitystream where id in (select id from cacheactivitystream where actor=$1)`
rows, err := config.DB.Query(query, actor.Id)
@@ -88,6 +161,37 @@ func (actor Actor) DeleteCache() error {
return nil
}
+func (actor Actor) GetAllArchive(offset int) (Collection, error) {
+ var nColl Collection
+ var result []ObjectBase
+
+ query := `select x.id, x.updated from (select id, updated from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' union select id, updated 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, updated 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 offset $2`
+ rows, err := config.DB.Query(query, actor.Id, offset)
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetAllArchive")
+ }
+
+ defer rows.Close()
+ for rows.Next() {
+ var post ObjectBase
+
+ if err := rows.Scan(&post.Id, &post.Updated); err != nil {
+ return nColl, util.MakeError(err, "GetAllArchive")
+ }
+
+ post.Replies, _, _, err = post.GetReplies()
+
+ result = append(result, post)
+ }
+
+ nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+
+ nColl.OrderedItems = result
+
+ return nColl, nil
+}
+
func (actor Actor) GetAutoSubscribe() (bool, error) {
var subscribed bool
@@ -99,6 +203,188 @@ func (actor Actor) GetAutoSubscribe() (bool, error) {
return subscribed, nil
}
+func (actor Actor) GetCatalogCollection() (Collection, error) {
+ var nColl Collection
+ var result []ObjectBase
+
+ var err error
+ var rows *sql.Rows
+
+ 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`
+ if rows, err = config.DB.Query(query, actor.Id); err != nil {
+ return nColl, util.MakeError(err, "GetCatalogCollection")
+ }
+
+ defer rows.Close()
+ for rows.Next() {
+ var post ObjectBase
+ var actor Actor
+
+ var attch ObjectBase
+ post.Attachment = append(post.Attachment, attch)
+
+ var prev NestedObjectBase
+ post.Preview = &prev
+
+ err = rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive)
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCatalogCollection")
+ }
+
+ post.Actor = actor.Id
+
+ var replies CollectionBase
+
+ post.Replies = replies
+
+ post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetRepliesCount()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCatalogCollection")
+ }
+
+ post.Attachment, err = post.Attachment[0].GetAttachment()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCatalogCollection")
+ }
+
+ post.Preview, err = post.Preview.GetPreview()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCatalogCollection")
+ }
+
+ result = append(result, post)
+ }
+
+ nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+
+ nColl.OrderedItems = result
+
+ return nColl, nil
+}
+
+func (actor Actor) GetCollectionPage(page int) (Collection, error) {
+ var nColl Collection
+ var result []ObjectBase
+
+ var err error
+ var rows *sql.Rows
+
+ query := `select count (x.id) over(), 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 15 offset $2`
+
+ if rows, err = config.DB.Query(query, actor.Id, page*15); err != nil {
+ return nColl, util.MakeError(err, "GetCollectionPage")
+ }
+
+ var count int
+ defer rows.Close()
+ for rows.Next() {
+ var post ObjectBase
+ var actor Actor
+
+ var attch ObjectBase
+ post.Attachment = append(post.Attachment, attch)
+
+ var prev NestedObjectBase
+ post.Preview = &prev
+
+ err = rows.Scan(&count, &post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive)
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollectionPage")
+ }
+
+ post.Actor = actor.Id
+
+ post.Replies, post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetRepliesLimit(5)
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollectionPage")
+ }
+
+ post.Attachment, err = post.Attachment[0].GetAttachment()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollectionPage")
+ }
+
+ post.Preview, err = post.Preview.GetPreview()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollectionPage")
+ }
+
+ result = append(result, post)
+ }
+
+ nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+
+ nColl.TotalItems = count
+
+ nColl.OrderedItems = result
+
+ return nColl, nil
+}
+
+func (actor Actor) GetCollection() (Collection, error) {
+ var nColl Collection
+ var result []ObjectBase
+
+ query := `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' order by updated desc`
+ rows, err := config.DB.Query(query, actor.Id)
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ defer rows.Close()
+ for rows.Next() {
+ var post ObjectBase
+ var actor Actor
+
+ var attch ObjectBase
+ post.Attachment = append(post.Attachment, attch)
+
+ var prev NestedObjectBase
+ post.Preview = &prev
+
+ if err := rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive); err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ post.Actor = actor.Id
+
+ post.Replies, post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetReplies()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ post.Attachment, err = post.Attachment[0].GetAttachment()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ post.Preview, err = post.Preview.GetPreview()
+
+ if err != nil {
+ return nColl, util.MakeError(err, "GetCollection")
+ }
+
+ result = append(result, post)
+ }
+
+ nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+
+ nColl.OrderedItems = result
+
+ return nColl, nil
+}
+
func (actor Actor) GetCollectionType(nType string) (Collection, error) {
var nColl Collection
var result []ObjectBase
@@ -232,6 +518,50 @@ func (actor Actor) GetFollow() ([]ObjectBase, error) {
return followerCollection, nil
}
+func (actor Actor) GetFollowing() ([]ObjectBase, error) {
+ var followingCollection []ObjectBase
+
+ query := `select following from following where id=$1`
+ rows, err := config.DB.Query(query, actor.Id)
+
+ if err != nil {
+ return followingCollection, util.MakeError(err, "GetFollowing")
+ }
+
+ defer rows.Close()
+ for rows.Next() {
+ var obj ObjectBase
+
+ if err := rows.Scan(&obj.Id); err != nil {
+ return followingCollection, util.MakeError(err, "GetFollowing")
+ }
+
+ followingCollection = append(followingCollection, obj)
+ }
+
+ return followingCollection, nil
+}
+
+func (actor Actor) GetFollowFromName(name string) ([]string, error) {
+ var followingActors []string
+
+ activity := Activity{Id: actor.Following}
+ follow, err := activity.GetCollection()
+ if err != nil {
+ return followingActors, util.MakeError(err, "GetFollowFromName")
+ }
+
+ re := regexp.MustCompile("\\w+?$")
+
+ for _, e := range follow.Items {
+ if re.FindString(e.Id) == name {
+ followingActors = append(followingActors, e.Id)
+ }
+ }
+
+ return followingActors, nil
+}
+
func (actor Actor) GetFollowingTotal() (int, error) {
var following int
@@ -276,7 +606,7 @@ func (actor Actor) GetFollowersResp(ctx *fiber.Ctx) error {
ctx.Response().Header.Set("Content-Type", config.ActivityStreams)
_, err = ctx.Write(enc)
- return err
+ return util.MakeError(err, "")
}
func (actor Actor) GetFollowingResp(ctx *fiber.Ctx) error {
@@ -304,28 +634,15 @@ func (actor Actor) GetFollowingResp(ctx *fiber.Ctx) error {
return util.MakeError(err, "GetFollowingResp")
}
-func (actor Actor) GetFollowing() ([]ObjectBase, error) {
- var followingCollection []ObjectBase
-
- query := `select following from following where id=$1`
- rows, err := config.DB.Query(query, actor.Id)
-
- if err != nil {
- return followingCollection, util.MakeError(err, "GetFollowing")
- }
-
- defer rows.Close()
- for rows.Next() {
- var obj ObjectBase
-
- if err := rows.Scan(&obj.Id); err != nil {
- return followingCollection, util.MakeError(err, "GetFollowing")
- }
+func (actor Actor) GetImgTotal() (int, error) {
+ var count int
- followingCollection = append(followingCollection, obj)
+ query := `select count(attachment) from activitystream where actor=$1 and id in (select id from replies where inreplyto='' and type='Note' )`
+ if err := config.DB.QueryRow(query, actor.Id).Scan(&count); err != nil {
+ return count, util.MakeError(err, "GetImgTotal")
}
- return followingCollection, nil
+ return count, nil
}
func (actor Actor) GetInfoResp(ctx *fiber.Ctx) error {
@@ -337,60 +654,47 @@ func (actor Actor) GetInfoResp(ctx *fiber.Ctx) error {
return util.MakeError(err, "GetInfoResp")
}
-func (actor Actor) GetCollection() (Collection, error) {
- var nColl Collection
- var result []ObjectBase
-
- query := `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' order by updated desc`
- rows, err := config.DB.Query(query, actor.Id)
+func (actor Actor) GetPostTotal() (int, error) {
+ var count int
- if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
+ query := `select count(id) from activitystream where actor=$1 and id in (select id from replies where inreplyto='' and type='Note')`
+ if err := config.DB.QueryRow(query, actor.Id).Scan(&count); err != nil {
+ return count, util.MakeError(err, "GetPostTotal")
}
- defer rows.Close()
- for rows.Next() {
- var post ObjectBase
- var actor Actor
-
- var attch ObjectBase
- post.Attachment = append(post.Attachment, attch)
-
- var prev NestedObjectBase
- post.Preview = &prev
-
- if err := rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive); err != nil {
- return nColl, util.MakeError(err, "GetCollection")
- }
+ return count, nil
+}
- post.Actor = actor.Id
+func (actor Actor) GetOutbox(ctx *fiber.Ctx) error {
+ var collection Collection
- post.Replies, post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetReplies()
+ c, err := actor.GetCollection()
- if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
- }
+ if err != nil {
+ return util.MakeError(err, "GetOutbox")
+ }
- post.Attachment, err = post.Attachment[0].GetAttachment()
+ collection.OrderedItems = c.OrderedItems
+ collection.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ collection.Actor = actor
- if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
- }
+ collection.TotalItems, err = actor.GetPostTotal()
- post.Preview, err = post.Preview.GetPreview()
+ if err != nil {
+ return util.MakeError(err, "GetOutbox")
+ }
- if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
- }
+ collection.TotalImgs, err = actor.GetImgTotal()
- result = append(result, post)
+ if err != nil {
+ return util.MakeError(err, "GetOutbox")
}
- nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
-
- nColl.OrderedItems = result
+ enc, _ := json.Marshal(collection)
+ ctx.Response().Header.Set("Content-Type", config.ActivityStreams)
+ _, err = ctx.Write(enc)
- return nColl, nil
+ return util.MakeError(err, "GetOutbox")
}
func (actor Actor) GetRecentPosts() ([]ObjectBase, error) {
@@ -467,35 +771,14 @@ func (actor Actor) GetReportedTotal() (int, error) {
return count, nil
}
-func (actor Actor) GetAllArchive(offset int) (Collection, error) {
- var nColl Collection
- var result []ObjectBase
-
- query := `select x.id, x.updated from (select id, updated from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' union select id, updated 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, updated 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 offset $2`
- rows, err := config.DB.Query(query, actor.Id, offset)
-
- if err != nil {
- return nColl, util.MakeError(err, "GetAllArchive")
- }
-
- defer rows.Close()
- for rows.Next() {
- var post ObjectBase
-
- if err := rows.Scan(&post.Id, &post.Updated); err != nil {
- return nColl, util.MakeError(err, "GetAllArchive")
- }
-
- post.Replies, _, _, err = post.GetReplies()
+func (actor Actor) HasValidation(ctx *fiber.Ctx) bool {
+ id, _ := util.GetPasswordFromSession(ctx)
- result = append(result, post)
+ if id == "" || (id != actor.Id && id != config.Domain) {
+ return false
}
- nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
-
- nColl.OrderedItems = result
-
- return nColl, nil
+ return true
}
func (actor Actor) IsAlreadyFollowing(follow string) (bool, error) {
@@ -530,6 +813,70 @@ func (actor Actor) IsAlreadyFollower(follow string) (bool, error) {
return false, nil
}
+func (actor Actor) IsLocal() (bool, error) {
+ actor, err := GetActorFromDB(actor.Id)
+ return actor.Id != "", util.MakeError(err, "IsLocal")
+}
+
+func (actor Actor) IsValid() (Actor, bool, error) {
+ actor, err := FingerActor(actor.Id)
+ return actor, actor.Id != "", util.MakeError(err, "IsValid")
+}
+
+func (actor Actor) ReportedResp(ctx *fiber.Ctx) error {
+ var err error
+
+ auth := ctx.Get("Authorization")
+ verification := strings.Split(auth, " ")
+
+ if len(verification) < 2 {
+ ctx.Response().Header.SetStatusCode(http.StatusBadRequest)
+ _, err := ctx.Write([]byte(""))
+ return util.MakeError(err, "GetReported")
+ }
+
+ if hasAuth, err := util.HasAuth(verification[1], actor.Id); !hasAuth {
+ ctx.Response().Header.SetStatusCode(http.StatusBadRequest)
+ _, err := ctx.Write([]byte(""))
+ return util.MakeError(err, "GetReported")
+ } else if err != nil {
+ return util.MakeError(err, "GetReported")
+ }
+
+ actor, err = GetActorFromDB(actor.Id)
+
+ if err != nil {
+ return util.MakeError(err, "GetReported")
+ }
+
+ var following Collection
+
+ following.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ following.Type = "Collection"
+ following.TotalItems, err = actor.GetReportedTotal()
+
+ if err != nil {
+ return util.MakeError(err, "GetReported")
+ }
+
+ following.Items, err = actor.GetReported()
+
+ if err != nil {
+ return util.MakeError(err, "GetReported")
+ }
+
+ enc, err := json.MarshalIndent(following, "", "\t")
+
+ if err != nil {
+ return util.MakeError(err, "GetReported")
+ }
+
+ ctx.Response().Header.Set("Content-Type", config.ActivityStreams)
+ _, err = ctx.Write(enc)
+
+ return util.MakeError(err, "GetReported")
+}
+
func (actor Actor) SetActorAutoSubscribeDB() error {
current, err := actor.GetAutoSubscribe()
@@ -543,36 +890,37 @@ func (actor Actor) SetActorAutoSubscribeDB() error {
return util.MakeError(err, "SetActorAutoSubscribeDB")
}
-func (actor Actor) GetOutbox(ctx *fiber.Ctx) error {
- var collection Collection
-
- c, err := actor.GetCollection()
+func (actor Actor) SendToFollowers(activity Activity) error {
+ nActor, err := GetActorFromDB(actor.Id)
if err != nil {
- return util.MakeError(err, "GetOutbox")
+ return util.MakeError(err, "SendToFollowers")
}
- collection.OrderedItems = c.OrderedItems
- collection.AtContext.Context = "https://www.w3.org/ns/activitystreams"
- collection.Actor = actor
-
- collection.TotalItems, err = actor.GetPostTotal()
+ activity.Actor = &nActor
+ followers, err := nActor.GetFollow()
if err != nil {
- return util.MakeError(err, "GetOutbox")
+ return util.MakeError(err, "SendToFollowers")
}
- collection.TotalImgs, err = actor.GetImgTotal()
+ var to []string
- if err != nil {
- return util.MakeError(err, "GetOutbox")
+ for _, e := range followers {
+ for _, k := range activity.To {
+ if e.Id != k {
+ to = append(to, e.Id)
+ }
+ }
}
- enc, _ := json.Marshal(collection)
- ctx.Response().Header.Set("Content-Type", config.ActivityStreams)
- _, err = ctx.Write(enc)
+ activity.To = to
- return util.MakeError(err, "GetOutbox")
+ if len(activity.Object.InReplyTo) > 0 {
+ err = activity.MakeRequestInbox()
+ }
+
+ return util.MakeError(err, "SendToFollowers")
}
func (actor Actor) UnArchiveLast() error {
@@ -597,135 +945,135 @@ func (actor Actor) UnArchiveLast() error {
return nil
}
-func (actor Actor) IsLocal() (bool, error) {
- actor, err := GetActorFromDB(actor.Id)
- return actor.Id != "", util.MakeError(err, "IsLocal")
-}
-
-func (actor Actor) GetCatalogCollection() (Collection, error) {
- var nColl Collection
- var result []ObjectBase
-
- var err error
- var rows *sql.Rows
-
- 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`
- if rows, err = config.DB.Query(query, actor.Id); err != nil {
- return nColl, util.MakeError(err, "GetCatalogCollection")
- }
-
- defer rows.Close()
- for rows.Next() {
- var post ObjectBase
- var actor Actor
-
- var attch ObjectBase
- post.Attachment = append(post.Attachment, attch)
-
- var prev NestedObjectBase
- post.Preview = &prev
-
- err = rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive)
+func (actor Actor) Verify(signature string, verify string) error {
+ sig, _ := base64.StdEncoding.DecodeString(signature)
+ if actor.PublicKey.PublicKeyPem == "" {
+ _actor, err := FingerActor(actor.Id)
if err != nil {
- return nColl, util.MakeError(err, "GetCatalogCollection")
+ return util.MakeError(err, "Verify")
}
+ actor = _actor
+ }
- post.Actor = actor.Id
-
- var replies CollectionBase
+ block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem))
+ pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
- post.Replies = replies
+ hashed := sha256.New()
+ hashed.Write([]byte(verify))
- post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetRepliesCount()
+ return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig)
+}
- if err != nil {
- return nColl, util.MakeError(err, "GetCatalogCollection")
+func (actor Actor) VerifyHeaderSignature(ctx *fiber.Ctx) bool {
+ var sig string
+ var path string
+ var host string
+ var date string
+ var method string
+ var digest string
+ var contentLength string
+
+ s := ParseHeaderSignature(ctx.Get("Signature"))
+
+ for i, e := range s.Headers {
+ var nl string
+ if i < len(s.Headers)-1 {
+ nl = "\n"
}
- post.Attachment, err = post.Attachment[0].GetAttachment()
-
- if err != nil {
- return nColl, util.MakeError(err, "GetCatalogCollection")
+ switch e {
+ case "(request-target)":
+ method = strings.ToLower(ctx.Method())
+ path = ctx.Path()
+ sig += "(request-target): " + method + " " + path + "" + nl
+ break
+ case "host":
+ host = ctx.Hostname()
+ sig += "host: " + host + "" + nl
+ break
+ case "date":
+ date = ctx.Get("date")
+ sig += "date: " + date + "" + nl
+ break
+ case "digest":
+ digest = ctx.Get("digest")
+ sig += "digest: " + digest + "" + nl
+ break
+ case "content-length":
+ contentLength = ctx.Get("content-length")
+ sig += "content-length: " + contentLength + "" + nl
+ break
}
+ }
- post.Preview, err = post.Preview.GetPreview()
+ if s.KeyId != actor.PublicKey.Id {
+ return false
+ }
- if err != nil {
- return nColl, util.MakeError(err, "GetCatalogCollection")
- }
+ t, _ := time.Parse(time.RFC1123, date)
- result = append(result, post)
+ if time.Now().UTC().Sub(t).Seconds() > 75 {
+ return false
}
- nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
-
- nColl.OrderedItems = result
+ if actor.Verify(s.Signature, sig) != nil {
+ return false
+ }
- return nColl, nil
+ return true
}
-func (actor Actor) GetCollectionPage(page int) (Collection, error) {
- var nColl Collection
- var result []ObjectBase
-
- var err error
- var rows *sql.Rows
-
- query := `select count (x.id) over(), 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 15 offset $2`
+func (actor Actor) WriteCache() error {
+ actor, err := FingerActor(actor.Id)
- if rows, err = config.DB.Query(query, actor.Id, page*15); err != nil {
- return nColl, util.MakeError(err, "GetCollectionPage")
+ if err != nil {
+ return util.MakeError(err, "WriteCache")
}
- var count int
- defer rows.Close()
- for rows.Next() {
- var post ObjectBase
- var actor Actor
+ reqActivity := Activity{Id: actor.Outbox}
+ collection, err := reqActivity.GetCollection()
- var attch ObjectBase
- post.Attachment = append(post.Attachment, attch)
-
- var prev NestedObjectBase
- post.Preview = &prev
-
- err = rows.Scan(&count, &post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &post.Attachment[0].Id, &post.Preview.Id, &actor.Id, &post.TripCode, &post.Sensitive)
-
- if err != nil {
- return nColl, util.MakeError(err, "GetCollectionPage")
- }
-
- post.Actor = actor.Id
-
- post.Replies, post.Replies.TotalItems, post.Replies.TotalImgs, err = post.GetRepliesLimit(5)
+ if err != nil {
+ return util.MakeError(err, "WriteCache")
+ }
- if err != nil {
- return nColl, util.MakeError(err, "GetCollectionPage")
+ for _, e := range collection.OrderedItems {
+ if err := e.WriteCache(); err != nil {
+ return util.MakeError(err, "WriteCache")
}
+ }
- post.Attachment, err = post.Attachment[0].GetAttachment()
+ return nil
+}
- if err != nil {
- return nColl, util.MakeError(err, "GetCollectionPage")
- }
+func (actor Actor) MakeFollowActivity(follow string) (Activity, error) {
+ var followActivity Activity
+ var err error
- post.Preview, err = post.Preview.GetPreview()
+ followActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ followActivity.Type = "Follow"
- if err != nil {
- return nColl, util.MakeError(err, "GetCollectionPage")
- }
+ var obj ObjectBase
+ var nactor Actor
- result = append(result, post)
+ if actor.Id == config.Domain {
+ nactor, err = GetActorFromDB(actor.Id)
+ } else {
+ nactor, err = FingerActor(actor.Id)
}
- nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ if err != nil {
+ return followActivity, util.MakeError(err, "MakeFollowActivity")
+ }
- nColl.TotalItems = count
+ followActivity.Actor = &nactor
+ followActivity.Object = &obj
- nColl.OrderedItems = result
+ followActivity.Object.Actor = follow
+ followActivity.To = append(followActivity.To, follow)
- return nColl, nil
+ return followActivity, nil
}
func (actor Actor) WantToServePage(page int) (Collection, error) {
@@ -744,25 +1092,3 @@ func (actor Actor) WantToServePage(page int) (Collection, error) {
return collection, nil
}
-
-func (actor Actor) GetImgTotal() (int, error) {
- var count int
-
- query := `select count(attachment) from activitystream where actor=$1 and id in (select id from replies where inreplyto='' and type='Note' )`
- if err := config.DB.QueryRow(query, actor.Id).Scan(&count); err != nil {
- return count, util.MakeError(err, "GetImgTotal")
- }
-
- return count, nil
-}
-
-func (actor Actor) GetPostTotal() (int, error) {
- var count int
-
- query := `select count(id) from activitystream where actor=$1 and id in (select id from replies where inreplyto='' and type='Note')`
- if err := config.DB.QueryRow(query, actor.Id).Scan(&count); err != nil {
- return count, util.MakeError(err, "GetPostTotal")
- }
-
- return count, nil
-}
diff --git a/activitypub/object.go b/activitypub/object.go
index a873ce0..29a17e4 100644
--- a/activitypub/object.go
+++ b/activitypub/object.go
@@ -2,10 +2,7 @@ package activitypub
import (
"database/sql"
- "encoding/json"
"fmt"
- "io/ioutil"
- "net/http"
"os"
"os/exec"
"regexp"
@@ -17,6 +14,35 @@ import (
"github.com/FChannel0/FChannel-Server/util"
)
+func (obj ObjectBase) CreateActivity(activityType string) (Activity, error) {
+ var newActivity Activity
+
+ actor, err := FingerActor(obj.Actor)
+ if err != nil {
+ return newActivity, util.MakeError(err, "CreateActivity")
+ }
+
+ newActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
+ newActivity.Type = activityType
+ newActivity.Published = obj.Published
+ newActivity.Actor = &actor
+ newActivity.Object = &obj
+
+ for _, e := range obj.To {
+ if obj.Actor != e {
+ newActivity.To = append(newActivity.To, e)
+ }
+ }
+
+ for _, e := range obj.Cc {
+ if obj.Actor != e {
+ newActivity.Cc = append(newActivity.Cc, e)
+ }
+ }
+
+ return newActivity, nil
+}
+
func (obj ObjectBase) CheckIfOP() (bool, error) {
var count int
@@ -63,6 +89,44 @@ func (obj ObjectBase) CreatePreview() *NestedObjectBase {
return &nPreview
}
+func (obj ObjectBase) DeleteAndRepliesRequest() error {
+ activity, err := obj.CreateActivity("Delete")
+
+ if err != nil {
+ return util.MakeError(err, "DeleteAndRepliesRequest")
+ }
+
+ nObj, err := obj.GetCollectionFromPath()
+ if err != nil {
+ return util.MakeError(err, "DeleteAndRepliesRequest")
+ }
+
+ activity.Actor.Id = nObj.OrderedItems[0].Actor
+ activity.Object = &nObj.OrderedItems[0]
+ objActor, _ := GetActor(nObj.OrderedItems[0].Actor)
+ followers, err := objActor.GetFollow()
+
+ if err != nil {
+ return util.MakeError(err, "DeleteAndRepliesRequest")
+ }
+ for _, e := range followers {
+ activity.To = append(activity.To, e.Id)
+ }
+
+ following, err := objActor.GetFollowing()
+ if err != nil {
+ return util.MakeError(err, "DeleteAndRepliesRequest")
+ }
+
+ for _, e := range following {
+ activity.To = append(activity.To, e.Id)
+ }
+
+ err = activity.MakeRequestInbox()
+
+ return util.MakeError(err, "DeleteAndRepliesRequest")
+}
+
//TODO break this off into seperate for Cache
func (obj ObjectBase) DeleteAttachment() error {
query := `delete from activitystream where id in (select attachment from activitystream where id=$1)`
@@ -167,49 +231,65 @@ func (obj ObjectBase) Delete() error {
return util.MakeError(err, "Delete")
}
-func (obj ObjectBase) DeleteRepliedTo() error {
- query := `delete from replies where id=$1`
- _, err := config.DB.Exec(query, obj.Id)
- return util.MakeError(err, "DeleteRepliedTo")
-}
-
func (obj ObjectBase) DeleteInReplyTo() error {
query := `delete from replies where id in (select id from replies where inreplyto=$1)`
_, err := config.DB.Exec(query, obj.Id)
return util.MakeError(err, "DeleteInReplyTo")
}
-func (obj ObjectBase) DeleteReported() error {
- query := `delete from reported where id=$1`
+func (obj ObjectBase) DeleteRepliedTo() error {
+ query := `delete from replies where id=$1`
_, err := config.DB.Exec(query, obj.Id)
- return util.MakeError(err, "DeleteReported")
+ return util.MakeError(err, "DeleteRepliedTo")
}
-func (obj ObjectBase) GetCollection() (Collection, error) {
- var nColl Collection
+func (obj ObjectBase) DeleteRequest() error {
+ activity, err := obj.CreateActivity("Delete")
- req, err := http.NewRequest("GET", obj.Id, nil)
if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
+ return util.MakeError(err, "DeleteRequest")
}
- req.Header.Set("Accept", config.ActivityStreams)
- resp, err := util.RouteProxy(req)
+ nObj, err := obj.GetFromPath()
+
if err != nil {
- return nColl, util.MakeError(err, "GetCollection")
+ return util.MakeError(err, "DeleteRequest")
}
- if resp.StatusCode == 200 {
- defer resp.Body.Close()
- body, _ := ioutil.ReadAll(resp.Body)
- if len(body) > 0 {
- if err := json.Unmarshal(body, &nColl); err != nil {
- return nColl, util.MakeError(err, "GetCollection")
- }
- }
+ actor, err := FingerActor(nObj.Actor)
+
+ if err != nil {
+ return util.MakeError(err, "DeleteRequest")
+ }
+ activity.Actor = &actor
+ objActor, _ := GetActor(nObj.Actor)
+ followers, err := objActor.GetFollow()
+ if err != nil {
+ return util.MakeError(err, "DeleteRequest")
}
- return nColl, nil
+ for _, e := range followers {
+ activity.To = append(activity.To, e.Id)
+ }
+
+ following, err := objActor.GetFollowing()
+ if err != nil {
+ return util.MakeError(err, "DeleteRequest")
+ }
+ for _, e := range following {
+ activity.To = append(activity.To, e.Id)
+ }
+
+ err = activity.MakeRequestInbox()
+
+ return util.MakeError(err, "DeleteRequest")
+}
+
+func (obj ObjectBase) DeleteReported() error {
+ query := `delete from reported where id=$1`
+ _, err := config.DB.Exec(query, obj.Id)
+
+ return util.MakeError(err, "DeleteReported")
}
func (obj ObjectBase) GetCollectionLocal() (Collection, error) {
@@ -646,6 +726,23 @@ func (obj ObjectBase) IsLocal() (bool, error) {
return true, nil
}
+func (obj ObjectBase) IsReplyInThread(id string) (bool, error) {
+ reqActivity := Activity{Id: obj.InReplyTo[0].Id}
+ coll, _, err := reqActivity.CheckValid()
+
+ if err != nil {
+ return false, util.MakeError(err, "IsReplyInThread")
+ }
+
+ for _, e := range coll.OrderedItems[0].Replies.OrderedItems {
+ if e.Id == id {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
//TODO break this off into seperate for Cache
func (obj ObjectBase) MarkSensitive(sensitive bool) error {
var query = `update activitystream set sensitive=$1 where id=$2`
@@ -1151,6 +1248,50 @@ func (obj ObjectBase) WriteReply() error {
return nil
}
+func (obj ObjectBase) WriteReplyCache() error {
+ for i, e := range obj.InReplyTo {
+ res, err := obj.InReplyTo[0].IsReplyInThread(e.Id)
+ if err != nil {
+ return util.MakeError(err, "WriteReplyCache")
+ }
+
+ if i == 0 || res {
+ query := `select id from replies where id=$1`
+
+ rows, err := config.DB.Query(query, obj.Id)
+ if err != nil {
+ return util.MakeError(err, "WriteReplyCache")
+ }
+ defer rows.Close()
+
+ var id string
+ rows.Next()
+ err = rows.Scan(&id)
+ if err != nil {
+ return util.MakeError(err, "WriteReplyCache")
+ } else if id != "" {
+ return nil // TODO: error?
+ }
+
+ query = `insert into cachereplies (id, inreplyto) values ($1, $2)`
+
+ _, err = config.DB.Exec(query, obj.Id, e.Id)
+ if err != nil {
+ return util.MakeError(err, "WriteReplyCache")
+ }
+ }
+ }
+
+ if len(obj.InReplyTo) < 1 {
+ query := `insert into cachereplies (id, inreplyto) values ($1, $2)`
+
+ _, err := config.DB.Exec(query, obj.Id, "")
+ return util.MakeError(err, "WriteReplyCache")
+ }
+
+ return nil
+}
+
func (obj ObjectBase) WriteReplyLocal(replyto string) error {
var nID string
@@ -1179,7 +1320,7 @@ func (obj ObjectBase) WriteReplyLocal(replyto string) error {
func (obj ObjectBase) WriteObjectToCache() (ObjectBase, error) {
if isBlacklisted, err := util.IsPostBlacklist(obj.Content); err != nil || isBlacklisted {
- fmt.Println("\n\nBlacklist post blocked\n\n")
+ config.Log.Println("\n\nBlacklist post blocked\n\n")
return obj, util.MakeError(err, "WriteObjectToCache")
}
@@ -1243,7 +1384,7 @@ func (obj ObjectBase) WriteWithAttachment(attachment ObjectBase) {
_, e := config.DB.Exec(query, obj.Id, obj.Type, obj.Name, obj.Content, attachment.Id, obj.Preview.Id, obj.Published, obj.Updated, obj.AttributedTo, obj.Actor, obj.TripCode, obj.Sensitive)
if e != nil {
- fmt.Println("error inserting new activity with attachment")
+ config.Log.Println("error inserting new activity with attachment")
panic(e)
}
}
diff --git a/activitypub/pem.go b/activitypub/pem.go
index 408be0c..f99643e 100644
--- a/activitypub/pem.go
+++ b/activitypub/pem.go
@@ -6,7 +6,6 @@ import (
"crypto/x509"
"encoding/pem"
"errors"
- "fmt"
"io/ioutil"
"os"
"regexp"
@@ -72,7 +71,7 @@ func CreatePem(actor Actor) error {
return StorePemToDB(actor)
}
- fmt.Println(`Created PEM keypair for the "` + actor.Name + `" board. Please keep in mind that
+ config.Log.Println(`Created PEM keypair for the "` + actor.Name + `" board. Please keep in mind that
the PEM key is crucial in identifying yourself as the legitimate owner of the board,
so DO NOT LOSE IT!!! If you lose it, YOU WILL LOSE ACCESS TO YOUR BOARD!`)
@@ -123,7 +122,7 @@ func CreatePublicKeyFromPrivate(actor *Actor, publicKeyPem string) error {
return util.MakeError(err, "CreatePublicKeyFromPrivate")
}
} else {
- fmt.Println(`\nUnable to locate private key from public key generation. Now,
+ config.Log.Println(`\nUnable to locate private key from public key generation. Now,
this means that you are now missing the proof that you are the
owner of the "` + actor.Name + `" board. If you are the developer,
then your job is just as easy as generating a new keypair, but
diff --git a/activitypub/util.go b/activitypub/util.go
index 7aee666..9dfa1ae 100644
--- a/activitypub/util.go
+++ b/activitypub/util.go
@@ -19,6 +19,18 @@ import (
// 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
+}
+
func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) ([]ObjectBase, *os.File, error) {
contentType, err := util.GetFileContentType(file)
if err != nil {
diff --git a/activitypub/webfinger.go b/activitypub/webfinger.go
new file mode 100644
index 0000000..276a791
--- /dev/null
+++ b/activitypub/webfinger.go
@@ -0,0 +1,180 @@
+package activitypub
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
+)
+
+type Webfinger struct {
+ Subject string `json:"subject,omitempty"`
+ Links []WebfingerLink `json:"links,omitempty"`
+}
+
+type WebfingerLink struct {
+ Rel string `json:"rel,omitempty"`
+ Type string `json:"type,omitempty"`
+ Href string `json:"href,omitempty"`
+}
+
+func GetActor(id string) (Actor, error) {
+ var respActor Actor
+
+ if id == "" {
+ return respActor, nil
+ }
+
+ actor, instance := GetActorAndInstance(id)
+
+ if ActorCache[actor+"@"+instance].Id != "" {
+ respActor = ActorCache[actor+"@"+instance]
+ return respActor, nil
+ }
+
+ req, err := http.NewRequest("GET", strings.TrimSpace(id), nil)
+ if err != nil {
+ return respActor, util.MakeError(err, "GetActor")
+ }
+
+ req.Header.Set("Accept", config.ActivityStreams)
+
+ resp, err := util.RouteProxy(req)
+
+ if err != nil {
+ return respActor, util.MakeError(err, "GetActor")
+ }
+
+ defer resp.Body.Close()
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ if err := json.Unmarshal(body, &respActor); err != nil {
+ return respActor, util.MakeError(err, "GetActor")
+ }
+
+ ActorCache[actor+"@"+instance] = respActor
+
+ return respActor, nil
+}
+
+//looks for actor with pattern of board@instance
+func FingerActor(path string) (Actor, error) {
+ var nActor Actor
+
+ actor, instance := GetActorAndInstance(path)
+
+ if actor == "" && instance == "" {
+ return nActor, nil
+ }
+
+ if ActorCache[actor+"@"+instance].Id != "" {
+ nActor = ActorCache[actor+"@"+instance]
+ } else {
+ resp, _ := FingerRequest(actor, instance)
+
+ if resp != nil && resp.StatusCode == 200 {
+ defer resp.Body.Close()
+
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ if err := json.Unmarshal(body, &nActor); err != nil {
+ return nActor, util.MakeError(err, "FingerActor")
+ }
+
+ ActorCache[actor+"@"+instance] = nActor
+ }
+ }
+
+ return nActor, nil
+}
+
+func FingerRequest(actor string, instance string) (*http.Response, error) {
+ acct := "acct:" + actor + "@" + instance
+
+ // TODO: respect https
+ req, err := http.NewRequest("GET", "http://"+instance+"/.well-known/webfinger?resource="+acct, nil)
+
+ if err != nil {
+ return nil, util.MakeError(err, "FingerRequest")
+ }
+
+ resp, err := util.RouteProxy(req)
+ if err != nil {
+ return resp, nil
+ }
+
+ var finger Webfinger
+
+ if resp.StatusCode == 200 {
+ defer resp.Body.Close()
+
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ if err := json.Unmarshal(body, &finger); err != nil {
+ return resp, util.MakeError(err, "FingerRequest")
+ }
+ }
+
+ if len(finger.Links) > 0 {
+ for _, e := range finger.Links {
+ if e.Type == "application/activity+json" {
+ req, err := http.NewRequest("GET", e.Href, nil)
+
+ if err != nil {
+ return resp, util.MakeError(err, "FingerRequest")
+ }
+
+ req.Header.Set("Accept", config.ActivityStreams)
+ resp, _ := util.RouteProxy(req)
+
+ return resp, nil
+ }
+ }
+ }
+
+ return resp, 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 := FingerActor(actor)
+ if err != nil {
+ return util.MakeError(err, "IsValidActor")
+ }
+
+ if nActor.Id == "" {
+ return nil
+ }
+
+ // TODO: maybe allow different indexes?
+ reqActivity := Activity{Id: "https://fchan.xyz/followers"}
+ followers, err := reqActivity.GetCollection()
+ if err != nil {
+ return util.MakeError(err, "IsValidActor")
+ }
+
+ var alreadyIndex = false
+ for _, e := range followers.Items {
+ if e.Id == nActor.Id {
+ alreadyIndex = true
+ }
+ }
+
+ if !alreadyIndex {
+ actor := Actor{Id: "https://fchan.xyz"}
+ return actor.AddFollower(nActor.Id)
+ }
+
+ return nil
+}
diff --git a/config/config.go b/config/config.go
index 16a1261..11f4792 100644
--- a/config/config.go
+++ b/config/config.go
@@ -31,6 +31,7 @@ var ActivityStreams = "application/ld+json; profile=\"https://www.w3.org/ns/acti
var AuthReq = []string{"captcha", "email", "passphrase"}
var PostCountPerPage = 10
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 Log = log.New(os.Stdout, "", log.Ltime)
var MediaHashs = make(map[string]string)
var Key string
var Themes []string
@@ -40,7 +41,7 @@ func GetConfigValue(value string, ifnone string) string {
file, err := os.Open("config/config-init")
if err != nil {
- log.Print(err)
+ Log.Println(err)
return ifnone
}
diff --git a/db/cache.go b/db/cache.go
deleted file mode 100644
index d1c1fe7..0000000
--- a/db/cache.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package db
-
-import (
- "github.com/FChannel0/FChannel-Server/activitypub"
- "github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/webfinger"
- _ "github.com/lib/pq"
-)
-
-func WriteObjectReplyToCache(obj activitypub.ObjectBase) error {
- for i, e := range obj.InReplyTo {
- res, err := IsReplyInThread(obj.InReplyTo[0].Id, e.Id)
- if err != nil {
- return err
- }
-
- if i == 0 || res {
- query := `select id from replies where id=$1`
-
- rows, err := config.DB.Query(query, obj.Id)
- if err != nil {
- return err
- }
- defer rows.Close()
-
- var id string
- rows.Next()
- err = rows.Scan(&id)
- if err != nil {
- return err
- } else if id != "" {
- return nil // TODO: error?
- }
-
- query = `insert into cachereplies (id, inreplyto) values ($1, $2)`
-
- _, err = config.DB.Exec(query, obj.Id, e.Id)
- if err != nil {
- return err
- }
- }
- }
-
- if len(obj.InReplyTo) < 1 {
- query := `insert into cachereplies (id, inreplyto) values ($1, $2)`
-
- _, err := config.DB.Exec(query, obj.Id, "")
- return err
- }
-
- return nil
-}
-
-func WriteActorToCache(actorID string) error {
- actor, err := webfinger.FingerActor(actorID)
- if err != nil {
- return err
- }
-
- collection, err := webfinger.GetActorCollection(actor.Outbox)
- if err != nil {
- return err
- }
-
- for _, e := range collection.OrderedItems {
- if err := e.WriteCache(); err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/db/database.go b/db/database.go
index 5d53f46..c6c2fc7 100644
--- a/db/database.go
+++ b/db/database.go
@@ -2,11 +2,9 @@ package db
import (
"database/sql"
- "encoding/json"
"fmt"
"html/template"
"io/ioutil"
- "net/http"
"os"
"regexp"
"strings"
@@ -15,7 +13,6 @@ import (
"github.com/FChannel0/FChannel-Server/activitypub"
"github.com/FChannel0/FChannel-Server/config"
"github.com/FChannel0/FChannel-Server/util"
- "github.com/FChannel0/FChannel-Server/webfinger"
_ "github.com/lib/pq"
)
@@ -25,8 +22,7 @@ type NewsItem struct {
Time int
}
-// ConnectDB connects to the PostgreSQL database configured.
-func ConnectDB() error {
+func Connect() error {
host := config.DBHost
port := config.DBPort
user := config.DBUser
@@ -37,89 +33,98 @@ func ConnectDB() error {
"dbname=%s sslmode=disable", host, port, user, password, dbname)
_db, err := sql.Open("postgres", psqlInfo)
+
if err != nil {
- return err
+ return util.MakeError(err, "Connect")
}
if err := _db.Ping(); err != nil {
- return err
+ return util.MakeError(err, "Connect")
}
- fmt.Println("Successfully connected DB")
+ config.Log.Println("Successfully connected DB")
config.DB = _db
+
return nil
}
-// Close closes the database connection.
func Close() error {
- return config.DB.Close()
+ err := config.DB.Close()
+
+ return util.MakeError(err, "Close")
}
func RunDatabaseSchema() error {
query, err := ioutil.ReadFile("databaseschema.psql")
if err != nil {
- return err
+ return util.MakeError(err, "RunDatabaseSchema")
}
_, err = config.DB.Exec(string(query))
- return err
+ return util.MakeError(err, "RunDatabaseSchema")
}
-func CreateNewBoardDB(actor activitypub.Actor) (activitypub.Actor, error) {
- query := `insert into actor (type, id, name, preferedusername, inbox, outbox, following, followers, summary, restricted) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`
+func CreateNewBoard(actor activitypub.Actor) (activitypub.Actor, error) {
+ if _, err := activitypub.GetActorFromDB(actor.Id); err == nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ } else {
+ query := `insert into actor (type, id, name, preferedusername, inbox, outbox, following, followers, summary, restricted) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`
+ _, err := config.DB.Exec(query, actor.Type, actor.Id, actor.Name, actor.PreferredUsername, actor.Inbox, actor.Outbox, actor.Following, actor.Followers, actor.Summary, actor.Restricted)
- _, err := config.DB.Exec(query, actor.Type, actor.Id, actor.Name, actor.PreferredUsername, actor.Inbox, actor.Outbox, actor.Following, actor.Followers, actor.Summary, actor.Restricted)
+ if err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
- if err != nil {
- // TODO: board exists error
- return activitypub.Actor{}, err
- } else {
- fmt.Println("board added")
+ config.Log.Println("board added")
for _, e := range actor.AuthRequirement {
query = `insert into actorauth (type, board) values ($1, $2)`
-
if _, err := config.DB.Exec(query, e, actor.Name); err != nil {
- return activitypub.Actor{}, err
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
}
}
- var verify Verify
+ var verify util.Verify
- verify.Identifier = actor.Id
- verify.Code = util.CreateKey(50)
verify.Type = "admin"
-
- CreateVerification(verify)
-
verify.Identifier = actor.Id
- verify.Code = util.CreateKey(50)
- verify.Type = "janitor"
- CreateVerification(verify)
+ if verify.Code, err = util.CreateKey(50); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
+
+ if err := verify.Create(); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
+ verify.Type = "janitor"
verify.Identifier = actor.Id
- verify.Code = util.CreateKey(50)
- verify.Type = "post"
- CreateVerification(verify)
+ if verify.Code, err = util.CreateKey(50); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
+
+ if err := verify.Create(); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
- var nverify Verify
+ var nverify util.Verify
nverify.Board = actor.Id
nverify.Identifier = "admin"
nverify.Type = "admin"
- CreateBoardMod(nverify)
+
+ if err := nverify.CreateBoardMod(); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
nverify.Board = actor.Id
nverify.Identifier = "janitor"
nverify.Type = "janitor"
- CreateBoardMod(nverify)
- nverify.Board = actor.Id
- nverify.Identifier = "post"
- nverify.Type = "post"
- CreateBoardMod(nverify)
+ if err := nverify.CreateBoardMod(); err != nil {
+ return activitypub.Actor{}, util.MakeError(err, "CreateNewBoardDB")
+ }
activitypub.CreatePem(actor)
@@ -128,165 +133,90 @@ func CreateNewBoardDB(actor activitypub.Actor) (activitypub.Actor, error) {
var nActivity activitypub.Activity
nActor, err := activitypub.GetActorFromDB(config.Domain)
+
if err != nil {
- return actor, err
+ return actor, util.MakeError(err, "CreateNewBoardDB")
}
nActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
nActivity.Type = "Follow"
nActivity.Actor = &nActor
nActivity.Object = &nObject
-
mActor, err := activitypub.GetActorFromDB(actor.Id)
+
if err != nil {
- return actor, err
+ return actor, util.MakeError(err, "CreateNewBoardDB")
}
nActivity.Object.Actor = mActor.Id
nActivity.To = append(nActivity.To, actor.Id)
- response := AcceptFollow(nActivity)
- if _, err := SetActorFollowingDB(response); err != nil {
- return actor, err
+ activityRequest := nActivity.AcceptFollow()
+
+ if _, err := activityRequest.SetActorFollowing(); err != nil {
+ return actor, util.MakeError(err, "CreateNewBoardDB")
}
- if err := MakeActivityRequest(nActivity); err != nil {
- return actor, err
+
+ if err := activityRequest.MakeRequestInbox(); err != nil {
+ return actor, util.MakeError(err, "CreateNewBoardDB")
}
}
-
}
return actor, nil
}
func RemovePreviewFromFile(id string) error {
+ var href string
+
query := `select href from activitystream where id in (select preview from activitystream where id=$1)`
- rows, err := config.DB.Query(query, id)
- if err != nil {
- return err
+ if err := config.DB.QueryRow(query, id).Scan(&href); err != nil {
+ return nil
}
- defer rows.Close()
- for rows.Next() {
- var href string
+ href = strings.Replace(href, config.Domain+"/", "", 1)
- if err := rows.Scan(&href); err != nil {
- return err
+ if href != "static/notfound.png" {
+ if _, err := os.Stat(href); err != nil {
+ return util.MakeError(err, "RemovePreviewFromFile")
}
- href = strings.Replace(href, config.Domain+"/", "", 1)
-
- if href != "static/notfound.png" {
- _, err = os.Stat(href)
- if err == nil {
- return os.Remove(href)
- }
- return err
- }
+ err := os.Remove(href)
+ return util.MakeError(err, "RemovePreviewFromFile")
}
obj := activitypub.ObjectBase{Id: id}
- return obj.DeletePreview()
-}
-
-func GetRandomCaptcha() (string, error) {
- var verify string
-
- query := `select identifier from verification where type='captcha' order by random() limit 1`
-
- rows, err := config.DB.Query(query)
- if err != nil {
- return verify, err
- }
- defer rows.Close()
-
- rows.Next()
- if err := rows.Scan(&verify); err != nil {
- return verify, err
- }
-
- return verify, nil
-}
-
-func GetCaptchaTotal() (int, error) {
- query := `select count(*) from verification where type='captcha'`
-
- rows, err := config.DB.Query(query)
- if err != nil {
- return 0, err
- }
-
- defer rows.Close()
-
- var count int
- for rows.Next() {
- if err := rows.Scan(&count); err != nil {
- return count, err
- }
- }
-
- return count, nil
-}
-
-func GetCaptchaCodeDB(verify string) (string, error) {
- query := `select code from verification where identifier=$1 limit 1`
-
- rows, err := config.DB.Query(query, verify)
- if err != nil {
- return "", err
- }
- defer rows.Close()
-
- var code string
-
- rows.Next()
- if err := rows.Scan(&code); err != nil {
- fmt.Println("Could not get verification captcha")
- }
-
- return code, nil
-}
-
-func DeleteCaptchaCodeDB(verify string) error {
- query := `delete from verification where identifier=$1`
-
- _, err := config.DB.Exec(query, verify)
- if err != nil {
- return err
- }
-
- return os.Remove("./" + verify)
+ err := obj.DeletePreview()
+ return util.MakeError(err, "RemovePreviewFromFile")
}
//if limit less than 1 return all news items
-func GetNewsFromDB(limit int) ([]NewsItem, error) {
+func GetNews(limit int) ([]NewsItem, error) {
var news []NewsItem
-
var query string
- if limit > 0 {
- query = `select title, content, time from newsItem order by time desc limit $1`
- } else {
- query = `select title, content, time from newsItem order by time desc`
- }
var rows *sql.Rows
var err error
+
if limit > 0 {
+ query = `select title, content, time from newsItem order by time desc limit $1`
rows, err = config.DB.Query(query, limit)
} else {
+ query = `select title, content, time from newsItem order by time desc`
rows, err = config.DB.Query(query)
}
if err != nil {
- return news, nil
+ return news, util.MakeError(err, "GetNews")
}
defer rows.Close()
for rows.Next() {
- n := NewsItem{}
var content string
+ n := NewsItem{}
+
if err := rows.Scan(&n.Title, &content, &n.Time); err != nil {
- return news, err
+ return news, util.MakeError(err, "GetNews")
}
content = strings.ReplaceAll(content, "\n", "<br>")
@@ -298,21 +228,13 @@ func GetNewsFromDB(limit int) ([]NewsItem, error) {
return news, nil
}
-func GetNewsItemFromDB(timestamp int) (NewsItem, error) {
+func GetNewsItem(timestamp int) (NewsItem, error) {
var news NewsItem
var content string
- query := `select title, content, time from newsItem where time=$1 limit 1`
-
- rows, err := config.DB.Query(query, timestamp)
- if err != nil {
- return news, err
- }
-
- defer rows.Close()
- rows.Next()
- if err := rows.Scan(&news.Title, &content, &news.Time); err != nil {
- return news, err
+ query := `select title, content, time from newsItem where time=$1 limit 1`
+ if err := config.DB.QueryRow(query, timestamp).Scan(&news.Title, &content, &news.Time); err != nil {
+ return news, util.MakeError(err, "GetNewsItem")
}
content = strings.ReplaceAll(content, "\n", "<br>")
@@ -321,65 +243,54 @@ func GetNewsItemFromDB(timestamp int) (NewsItem, error) {
return news, nil
}
-func deleteNewsItemFromDB(timestamp int) error {
+func DeleteNewsItem(timestamp int) error {
query := `delete from newsItem where time=$1`
_, err := config.DB.Exec(query, timestamp)
- return err
+
+ return util.MakeError(err, "DeleteNewsItem")
}
-func WriteNewsToDB(news NewsItem) error {
+func WriteNews(news NewsItem) error {
query := `insert into newsItem (title, content, time) values ($1, $2, $3)`
-
_, err := config.DB.Exec(query, news.Title, news.Content, time.Now().Unix())
- return err
-}
-
-func AddInstanceToInactiveDB(instance string) error {
- query := `select timestamp from inactive where instance=$1`
- rows, err := config.DB.Query(query, instance)
- if err != nil {
- return err
- }
+ return util.MakeError(err, "WriteNews")
+}
+func AddInstanceToInactive(instance string) error {
var timeStamp string
- defer rows.Close()
- rows.Next()
- rows.Scan(&timeStamp)
- if timeStamp == "" {
+ query := `select timestamp from inactive where instance=$1`
+ if err := config.DB.QueryRow(query, instance).Scan(&timeStamp); err != nil {
query := `insert into inactive (instance, timestamp) values ($1, $2)`
-
_, err := config.DB.Exec(query, instance, time.Now().UTC().Format(time.RFC3339))
- return err
+
+ return util.MakeError(err, "AddInstanceToInactive")
}
if !IsInactiveTimestamp(timeStamp) {
return nil
}
- query = `delete from following where following like $1`
- if _, err := config.DB.Exec(query, "%"+instance+"%"); err != nil {
- return err
- }
-
query = `delete from follower where follower like $1`
- if _, err = config.DB.Exec(query, "%"+instance+"%"); err != nil {
- return err
+ if _, err := config.DB.Exec(query, "%"+instance+"%"); err != nil {
+ return util.MakeError(err, "AddInstanceToInactive")
}
- return DeleteInstanceFromInactiveDB(instance)
+ err := DeleteInstanceFromInactive(instance)
+ return util.MakeError(err, "AddInstanceToInactive")
}
-func DeleteInstanceFromInactiveDB(instance string) error {
+func DeleteInstanceFromInactive(instance string) error {
query := `delete from inactive where instance=$1`
-
_, err := config.DB.Exec(query, instance)
- return err
+
+ return util.MakeError(err, "DeleteInstanceFromInactive")
}
func IsInactiveTimestamp(timeStamp string) bool {
stamp, _ := time.Parse(time.RFC3339, timeStamp)
+
if time.Now().UTC().Sub(stamp).Hours() > 48 {
return true
}
@@ -387,45 +298,9 @@ func IsInactiveTimestamp(timeStamp string) bool {
return false
}
-func ArchivePosts(actor activitypub.Actor) error {
- if actor.Id != "" && actor.Id != config.Domain {
- col, err := actor.GetAllArchive(165)
- if err != nil {
- return err
- }
-
- for _, e := range col.OrderedItems {
- for _, k := range e.Replies.OrderedItems {
- if err := k.UpdateType("Archive"); err != nil {
- return err
- }
- }
-
- if err := e.UpdateType("Archive"); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-func IsReplyInThread(inReplyTo string, id string) (bool, error) {
- obj, _, err := webfinger.CheckValidActivity(inReplyTo)
- if err != nil {
- return false, err
- }
-
- for _, e := range obj.OrderedItems[0].Replies.OrderedItems {
- if e.Id == id {
- return true, nil
- }
- }
-
- return false, nil
-}
-
func IsReplyToOP(op string, link string) (string, bool, error) {
+ var id string
+
if op == link {
return link, true, nil
}
@@ -440,52 +315,22 @@ func IsReplyToOP(op string, link string) (string, bool, error) {
}
query := `select id from replies where id like $1 and inreplyto=$2`
-
- rows, err := config.DB.Query(query, link, op)
- if err != nil {
- return op, false, err
- }
-
- defer rows.Close()
-
- var id string
- rows.Next()
- if err := rows.Scan(&id); err != nil {
- return id, false, err
+ if err := config.DB.QueryRow(query, link, op).Scan(&id); err != nil {
+ return op, false, nil
}
return id, id != "", nil
}
func GetReplyOP(link string) (string, error) {
- query := `select id from replies where id in (select inreplyto from replies where id=$1) and inreplyto=''`
-
- rows, err := config.DB.Query(query, link)
- if err != nil {
- return "", err
- }
- defer rows.Close()
-
var id string
- rows.Next()
- err = rows.Scan(&id)
- return id, err
-}
-
-func StartupArchive() error {
- for _, e := range webfinger.FollowingBoards {
- actor, err := activitypub.GetActorFromDB(e.Id)
- if err != nil {
- return err
- }
-
- if err := ArchivePosts(actor); err != nil {
- return err
- }
+ query := `select id from replies where id in (select inreplyto from replies where id=$1) and inreplyto=''`
+ if err := config.DB.QueryRow(query, link).Scan(&id); err != nil {
+ return "", nil
}
- return nil
+ return id, nil
}
func CheckInactive() {
@@ -496,54 +341,59 @@ func CheckInactive() {
}
func CheckInactiveInstances() (map[string]string, error) {
+ var rows *sql.Rows
+ var err error
+
instances := make(map[string]string)
- query := `select following from following`
- rows, err := config.DB.Query(query)
- if err != nil {
- return instances, err
+ query := `select following from following`
+ if rows, err = config.DB.Query(query); err != nil {
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
- defer rows.Close()
+ defer rows.Close()
for rows.Next() {
var instance string
+
if err := rows.Scan(&instance); err != nil {
- return instances, err
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
instances[instance] = instance
}
query = `select follower from follower`
- rows, err = config.DB.Query(query)
- if err != nil {
- return instances, err
+ if rows, err = config.DB.Query(query); err != nil {
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
- defer rows.Close()
+ defer rows.Close()
for rows.Next() {
var instance string
+
if err := rows.Scan(&instance); err != nil {
- return instances, err
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
instances[instance] = instance
}
re := regexp.MustCompile(config.Domain + `(.+)?`)
+
for _, e := range instances {
- actor, err := webfinger.GetActor(e)
+ actor, err := activitypub.GetActor(e)
+
if err != nil {
- return instances, err
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
if actor.Id == "" && !re.MatchString(e) {
- if err := AddInstanceToInactiveDB(e); err != nil {
- return instances, err
+ if err := AddInstanceToInactive(e); err != nil {
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
} else {
- if err := DeleteInstanceFromInactiveDB(e); err != nil {
- return instances, err
+ if err := DeleteInstanceFromInactive(e); err != nil {
+ return instances, util.MakeError(err, "CheckInactiveInstances")
}
}
}
@@ -552,12 +402,12 @@ 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)
-
var code string
var identifier string
- if err := config.DB.QueryRow(query).Scan(&identifier, &code); err != nil {
- return "", "", err
+
+ query := `select identifier, code from boardaccess where board=$1 and type='admin'`
+ if err := config.DB.QueryRow(query, config.Domain).Scan(&identifier, &code); err != nil {
+ return "", "", nil
}
return code, identifier, nil
@@ -567,175 +417,27 @@ func IsHashBanned(hash string) (bool, error) {
var h string
query := `select hash from bannedmedia where hash=$1`
-
_ = config.DB.QueryRow(query, hash).Scan(&h)
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
- }
-
- actor, _ := activitypub.GetActorFromDB(id)
-
- var following activitypub.Collection
- var err error
-
- following.AtContext.Context = "https://www.w3.org/ns/activitystreams"
- following.Type = "Collection"
- following.TotalItems, err = actor.GetReportedTotal()
- if err != nil {
- return err
- }
-
- following.Items, err = actor.GetReported()
- 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 := nObj.GetFromPath()
- if err != nil {
- return err
- }
+ code, identifier, err := GetAdminAuth()
- actor, err := webfinger.FingerActor(obj.Actor)
if err != nil {
- return err
- }
- activity.Actor = &actor
- objActor, _ := webfinger.GetActor(obj.Actor)
- followers, err := objActor.GetFollow()
- if err != nil {
- return err
- }
-
- for _, e := range followers {
- activity.To = append(activity.To, e.Id)
- }
-
- following, err := objActor.GetFollowing()
- if err != nil {
- return err
- }
- for _, e := range following {
- activity.To = append(activity.To, e.Id)
+ return util.MakeError(err, "PrintAdminAuth")
}
- 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 := nObj.GetCollectionFromPath()
- if err != nil {
- return err
- }
-
- activity.Actor.Id = obj.OrderedItems[0].Actor
-
- activity.Object = &obj.OrderedItems[0]
-
- objActor, _ := webfinger.GetActor(obj.OrderedItems[0].Actor)
- followers, err := objActor.GetFollow()
- if err != nil {
- return err
- }
- for _, e := range followers {
- activity.To = append(activity.To, e.Id)
- }
-
- following, err := objActor.GetFollowing()
- if err != nil {
- return err
- }
-
- for _, e := range following {
- activity.To = append(activity.To, e.Id)
- }
-
- return MakeActivityRequest(activity)
+ config.Log.Println("Mod key: " + config.Key)
+ config.Log.Println("Admin Login: " + identifier + ", Code: " + code)
+ return nil
}
-// root actor is used to follow remote feeds that are not local
-//name, prefname, summary, auth requirements, restricted
-func InitInstance() {
+func InitInstance() error {
if config.InstanceName != "" {
- if _, err := CreateNewBoardDB(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil {
- //panic(err)
+ if _, err := CreateNewBoard(*activitypub.CreateNewActor("", config.InstanceName, config.InstanceSummary, config.AuthReq, false)); err != nil {
+ return util.MakeError(err, "InitInstance")
}
if config.PublicIndexing == "true" {
@@ -743,4 +445,6 @@ func InitInstance() {
//AddInstanceToIndex(config.Domain)
}
}
+
+ return nil
}
diff --git a/db/follow.go b/db/follow.go
deleted file mode 100644
index 3932ea1..0000000
--- a/db/follow.go
+++ /dev/null
@@ -1,306 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "regexp"
- "strings"
- "time"
-
- "github.com/FChannel0/FChannel-Server/activitypub"
- "github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/util"
- "github.com/FChannel0/FChannel-Server/webfinger"
- _ "github.com/lib/pq"
-)
-
-func AcceptFollow(activity activitypub.Activity) activitypub.Activity {
- var accept activitypub.Activity
- accept.AtContext.Context = activity.AtContext.Context
- accept.Type = "Accept"
- var nActor activitypub.Actor
- accept.Actor = &nActor
- accept.Actor.Id = activity.Object.Actor
- var nObj activitypub.ObjectBase
- accept.Object = &nObj
- accept.Object.Actor = activity.Actor.Id
- var nNested activitypub.NestedObjectBase
- accept.Object.Object = &nNested
- accept.Object.Object.Actor = activity.Object.Actor
- accept.Object.Object.Type = "Follow"
- accept.To = append(accept.To, activity.Object.Actor)
-
- return accept
-}
-
-func SetActorFollowingDB(activity activitypub.Activity) (activitypub.Activity, error) {
- var query string
- alreadyFollowing := false
- alreadyFollower := false
- objActor, _ := webfinger.GetActor(activity.Object.Actor)
- following, err := objActor.GetFollowing()
- if err != nil {
- return activity, err
- }
-
- actor, err := webfinger.FingerActor(activity.Actor.Id)
- if err != nil {
- return activity, err
- }
-
- remoteActorFollowerCol, err := webfinger.GetCollectionFromReq(actor.Followers)
- if err != nil {
- return activity, err
- }
-
- for _, e := range following {
- if e.Id == activity.Actor.Id {
- alreadyFollowing = true
- }
- }
-
- for _, e := range remoteActorFollowerCol.Items {
- if e.Id == activity.Object.Actor {
- alreadyFollower = true
- }
- }
-
- activity.Type = "Reject"
-
- if activity.Actor.Id == activity.Object.Actor {
- return activity, nil
- }
-
- if alreadyFollowing && alreadyFollower {
- query = `delete from following where id=$1 and following=$2`
- activity.Summary = activity.Object.Actor + " Unfollowing " + activity.Actor.Id
- if res, err := activity.Actor.IsLocal(); err == nil && !res {
- go activity.Actor.DeleteCache()
- } else {
- return activity, err
- }
-
- if _, err := config.DB.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
- return activity, err
- }
-
- activity.Type = "Accept"
- return activity, nil
- }
-
- if !alreadyFollowing && !alreadyFollower {
-
- query = `insert into following (id, following) values ($1, $2)`
- activity.Summary = activity.Object.Actor + " Following " + activity.Actor.Id
- if res, err := activity.Actor.IsLocal(); err == nil && !res {
- go WriteActorToCache(activity.Actor.Id)
- }
- if _, err := config.DB.Exec(query, activity.Object.Actor, activity.Actor.Id); err != nil {
- return activity, err
- }
-
- activity.Type = "Accept"
- return activity, nil
- }
-
- return activity, nil
-}
-
-func AutoFollow(actorID string) error {
- actor, _ := webfinger.GetActor(actorID)
- following, err := actor.GetFollowing()
- if err != nil {
- return err
- }
-
- follower, err := actor.GetFollow()
- if err != nil {
- return err
- }
-
- isFollowing := false
-
- for _, e := range follower {
- for _, k := range following {
- if e.Id == k.Id {
- isFollowing = true
- }
- }
-
- if !isFollowing && e.Id != config.Domain && e.Id != actor.Id {
- followActivity, err := MakeFollowActivity(actor.Id, e.Id)
- if err != nil {
- return err
- }
-
- nActor, err := webfinger.FingerActor(e.Id)
- if err != nil {
- return err
- }
-
- if nActor.Id != "" {
- MakeActivityRequestOutbox(followActivity)
- }
- }
- }
-
- return nil
-}
-
-func MakeFollowActivity(actor string, follow string) (activitypub.Activity, error) {
- var followActivity activitypub.Activity
- var err error
-
- followActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
- followActivity.Type = "Follow"
-
- var obj activitypub.ObjectBase
- var nactor activitypub.Actor
- if actor == config.Domain {
- nactor, err = activitypub.GetActorFromDB(actor)
- } else {
- nactor, err = webfinger.FingerActor(actor)
- }
-
- if err != nil {
- return followActivity, err
- }
-
- followActivity.Actor = &nactor
- followActivity.Object = &obj
-
- followActivity.Object.Actor = follow
- followActivity.To = append(followActivity.To, follow)
-
- return followActivity, nil
-}
-
-func MakeActivityRequestOutbox(activity activitypub.Activity) error {
- j, _ := json.Marshal(activity)
-
- if activity.Actor.Outbox == "" {
- // TODO: good enough?
- return errors.New("invalid outbox")
- }
-
- req, err := http.NewRequest("POST", activity.Actor.Outbox, bytes.NewBuffer(j))
- if err != nil {
- return err
- }
-
- re := regexp.MustCompile("https?://(www.)?")
-
- var instance string
- if activity.Actor.Id == config.Domain {
- instance = re.ReplaceAllString(config.Domain, "")
- } else {
- _, instance = activitypub.GetActorAndInstance(activity.Actor.Id)
- }
-
- date := time.Now().UTC().Format(time.RFC1123)
- path := strings.Replace(activity.Actor.Outbox, instance, "", 1)
-
- path = re.ReplaceAllString(path, "")
-
- sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
- encSig, err := activity.Actor.ActivitySign(sig)
- if err != nil {
- return err
- }
-
- signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
-
- req.Header.Set("Content-Type", config.ActivityStreams)
- req.Header.Set("Date", date)
- req.Header.Set("Signature", signature)
- req.Host = instance
-
- _, err = util.RouteProxy(req)
- return err
-}
-
-func MakeActivityRequest(activity activitypub.Activity) error {
- j, _ := json.MarshalIndent(activity, "", "\t")
-
- for _, e := range activity.To {
- if e != activity.Actor.Id {
- actor, err := webfinger.FingerActor(e)
- if err != nil {
- return err
- }
-
- if actor.Id != "" {
- _, instance := activitypub.GetActorAndInstance(actor.Id)
-
- if actor.Inbox != "" {
- req, err := http.NewRequest("POST", actor.Inbox, bytes.NewBuffer(j))
- if err != nil {
- return err
- }
-
- date := time.Now().UTC().Format(time.RFC1123)
- path := strings.Replace(actor.Inbox, instance, "", 1)
-
- re := regexp.MustCompile("https?://(www.)?")
- path = re.ReplaceAllString(path, "")
-
- sig := fmt.Sprintf("(request-target): %s %s\nhost: %s\ndate: %s", "post", path, instance, date)
- encSig, err := activity.Actor.ActivitySign(sig)
- if err != nil {
- return err
- }
-
- signature := fmt.Sprintf("keyId=\"%s\",headers=\"(request-target) host date\",signature=\"%s\"", activity.Actor.PublicKey.Id, encSig)
-
- req.Header.Set("Content-Type", config.ActivityStreams)
- req.Header.Set("Date", date)
- req.Header.Set("Signature", signature)
- req.Host = instance
-
- _, err = util.RouteProxy(req)
- if err != nil {
- fmt.Println("error with sending activity resp to actor " + instance)
- return err // TODO: needs further testing
- }
- }
- }
- }
- }
-
- return nil
-}
-
-func SendToFollowers(actorID string, activity activitypub.Activity) error {
- nActor, err := activitypub.GetActorFromDB(actorID)
- if err != nil {
- return err
- }
-
- activity.Actor = &nActor
-
- followers, err := nActor.GetFollow()
- if err != nil {
- return err
- }
-
- var to []string
-
- for _, e := range followers {
- for _, k := range activity.To {
- if e.Id != k {
- to = append(to, e.Id)
- }
- }
- }
-
- activity.To = to
-
- if len(activity.Object.InReplyTo) > 0 {
- err = MakeActivityRequest(activity)
- }
-
- return err
-}
diff --git a/db/pem.go b/db/pem.go
deleted file mode 100644
index 66bf25a..0000000
--- a/db/pem.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package db
-
-import (
- "crypto"
- "crypto/rsa"
- "crypto/sha256"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "strings"
- "time"
-
- "github.com/FChannel0/FChannel-Server/activitypub"
- "github.com/FChannel0/FChannel-Server/webfinger"
- "github.com/gofiber/fiber/v2"
-)
-
-func VerifyHeaderSignature(ctx *fiber.Ctx, actor activitypub.Actor) bool {
- s := activitypub.ParseHeaderSignature(ctx.Get("Signature"))
-
- var method string
- var path string
- var host string
- var date string
- var digest string
- var contentLength string
-
- var sig string
- for i, e := range s.Headers {
- var nl string
- if i < len(s.Headers)-1 {
- nl = "\n"
- }
-
- switch e {
- case "(request-target)":
- method = strings.ToLower(ctx.Method())
- path = ctx.Path()
- sig += "(request-target): " + method + " " + path + "" + nl
- break
- case "host":
- host = ctx.Hostname()
- sig += "host: " + host + "" + nl
- break
- case "date":
- date = ctx.Get("date")
- sig += "date: " + date + "" + nl
- break
- case "digest":
- digest = ctx.Get("digest")
- sig += "digest: " + digest + "" + nl
- break
- case "content-length":
- contentLength = ctx.Get("content-length")
- sig += "content-length: " + contentLength + "" + nl
- break
- }
- }
-
- if s.KeyId != actor.PublicKey.Id {
- return false
- }
-
- t, _ := time.Parse(time.RFC1123, date)
-
- if time.Now().UTC().Sub(t).Seconds() > 75 {
- return false
- }
-
- if ActivityVerify(actor, s.Signature, sig) != nil {
- return false
- }
-
- return true
-}
-
-func ActivityVerify(actor activitypub.Actor, signature string, verify string) error {
- sig, _ := base64.StdEncoding.DecodeString(signature)
-
- if actor.PublicKey.PublicKeyPem == "" {
- _actor, err := webfinger.FingerActor(actor.Id)
- if err != nil {
- return err
- }
- actor = _actor
- }
-
- block, _ := pem.Decode([]byte(actor.PublicKey.PublicKeyPem))
- pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
-
- hashed := sha256.New()
- hashed.Write([]byte(verify))
-
- return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed.Sum(nil), sig)
-}
diff --git a/db/report.go b/db/report.go
index 4120d9a..958b619 100644
--- a/db/report.go
+++ b/db/report.go
@@ -1,6 +1,9 @@
package db
-import "github.com/FChannel0/FChannel-Server/config"
+import (
+ "github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
+)
type Report struct {
ID string
@@ -14,57 +17,53 @@ type Removed struct {
Board string
}
-func CreateLocalDeleteDB(id string, _type string) error {
- query := `select id from removed where id=$1`
-
- rows, err := config.DB.Query(query, id)
- if err != nil {
- return err
- }
- defer rows.Close()
-
- if rows.Next() {
- var i string
+func CloseLocalReport(id string, board string) error {
+ query := `delete from reported where id=$1 and board=$2`
+ _, err := config.DB.Exec(query, id, board)
- if err := rows.Scan(&i); err != nil {
- return err
- }
+ return util.MakeError(err, "CloseLocalReportDB")
+}
- if i != "" {
- query := `update removed set type=$1 where id=$2`
+func CreateLocalDelete(id string, _type string) error {
+ var i string
- if _, err := config.DB.Exec(query, _type, id); err != nil {
- return err
- }
- }
- } else {
+ query := `select id from removed where id=$1`
+ if err := config.DB.QueryRow(query, id).Scan(&i); err != nil {
query := `insert into removed (id, type) values ($1, $2)`
-
if _, err := config.DB.Exec(query, id, _type); err != nil {
- return err
+ return util.MakeError(err, "CreateLocalDeleteDB")
}
}
- return nil
+ query = `update removed set type=$1 where id=$2`
+ _, err := config.DB.Exec(query, _type, id)
+
+ return util.MakeError(err, "CreateLocalDeleteDB")
+}
+
+func CreateLocalReport(id string, board string, reason string) error {
+ query := `insert into reported (id, count, board, reason) values ($1, $2, $3, $4)`
+ _, err := config.DB.Exec(query, id, 1, board, reason)
+
+ return util.MakeError(err, "CreateLocalReportDB")
}
-func GetLocalDeleteDB() ([]Removed, error) {
+func GetLocalDelete() ([]Removed, error) {
var deleted []Removed
query := `select id, type from removed`
-
rows, err := config.DB.Query(query)
+
if err != nil {
- return deleted, err
+ return deleted, util.MakeError(err, "GetLocalDeleteDB")
}
defer rows.Close()
-
for rows.Next() {
var r Removed
if err := rows.Scan(&r.ID, &r.Type); err != nil {
- return deleted, err
+ return deleted, util.MakeError(err, "GetLocalDeleteDB")
}
deleted = append(deleted, r)
@@ -73,58 +72,22 @@ func GetLocalDeleteDB() ([]Removed, error) {
return deleted, nil
}
-func CreateLocalReportDB(id string, board string, reason string) error {
- query := `select id, count from reported where id=$1 and board=$2`
-
- rows, err := config.DB.Query(query, id, board)
- if err != nil {
- return err
- }
- defer rows.Close()
-
- if rows.Next() {
- var i string
- var count int
-
- if err := rows.Scan(&i, &count); err != nil {
- return err
- }
-
- if i != "" {
- count = count + 1
- query := `update reported set count=$1 where id=$2`
-
- if _, err := config.DB.Exec(query, count, id); err != nil {
- return err
- }
- }
- } else {
- query := `insert into reported (id, count, board, reason) values ($1, $2, $3, $4)`
-
- if _, err := config.DB.Exec(query, id, 1, board, reason); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func GetLocalReportDB(board string) ([]Report, error) {
+func GetLocalReport(board string) ([]Report, error) {
var reported []Report
query := `select id, count, reason from reported where board=$1`
-
rows, err := config.DB.Query(query, board)
+
if err != nil {
- return reported, err
+ return reported, util.MakeError(err, "GetLocalReportDB")
}
- defer rows.Close()
+ defer rows.Close()
for rows.Next() {
var r Report
if err := rows.Scan(&r.ID, &r.Count, &r.Reason); err != nil {
- return reported, err
+ return reported, util.MakeError(err, "GetLocalReportDB")
}
reported = append(reported, r)
@@ -132,10 +95,3 @@ func GetLocalReportDB(board string) ([]Report, error) {
return reported, nil
}
-
-func CloseLocalReportDB(id string, board string) error {
- query := `delete from reported where id=$1 and board=$2`
-
- _, err := config.DB.Exec(query, id, board)
- return err
-}
diff --git a/main.go b/main.go
index c1ebcef..039ee61 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,6 @@
package main
import (
- "log"
"math/rand"
"time"
@@ -41,7 +40,7 @@ func main() {
cookieKey, err := util.GetCookieKey()
if err != nil {
- log.Println(err)
+ config.Log.Println(err)
}
app.Use(encryptcookie.New(encryptcookie.Config{
@@ -107,38 +106,51 @@ func main() {
}
func Init() {
+ var actor activitypub.Actor
var err error
rand.Seed(time.Now().UnixNano())
- util.CreatedNeededDirectories()
+ if err = util.CreatedNeededDirectories(); err != nil {
+ config.Log.Println(err)
+ }
- db.ConnectDB()
+ if err = db.Connect(); err != nil {
+ config.Log.Println(err)
+ }
- db.RunDatabaseSchema()
+ if err = db.RunDatabaseSchema(); err != nil {
+ config.Log.Println(err)
+ }
- actor, _ := activitypub.GetActorFromDB(config.Domain)
- webfinger.FollowingBoards, err = actor.GetFollowing()
+ if actor, err = activitypub.GetActorFromDB(config.Domain); err != nil {
+ config.Log.Println(err)
+ }
- if err != nil {
- panic(err)
+ if webfinger.FollowingBoards, err = actor.GetFollowing(); err != nil {
+ config.Log.Println(err)
}
- webfinger.Boards, err = webfinger.GetBoardCollection()
+ if webfinger.Boards, err = webfinger.GetBoardCollection(); err != nil {
+ config.Log.Println(err)
+ }
- if err != nil {
- panic(err)
+ if config.Key, err = util.CreateKey(32); err != nil {
+ config.Log.Println(err)
}
- config.Key = util.CreateKey(32)
+ if err = util.LoadThemes(); err != nil {
+ config.Log.Println(err)
+ }
- go db.MakeCaptchas(100)
+ if err = db.InitInstance(); err != nil {
+ config.Log.Println(err)
+ }
- go db.StartupArchive()
+ go webfinger.StartupArchive()
- go db.CheckInactive()
+ go util.MakeCaptchas(100)
- db.InitInstance()
+ go db.CheckInactive()
- util.LoadThemes()
}
diff --git a/post/tripcode.go b/post/tripcode.go
index 3b7e48b..d5ae2e2 100644
--- a/post/tripcode.go
+++ b/post/tripcode.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
"github.com/gofiber/fiber/v2"
_ "github.com/lib/pq"
"github.com/simia-tech/crypt"
@@ -23,34 +24,63 @@ const SaltTable = "" +
"................................" +
"................................"
-func TripCode(pass string) (string, error) {
- pass = TripCodeConvert(pass)
+func CreateNameTripCode(ctx *fiber.Ctx) (string, string, error) {
+ input := ctx.FormValue("name")
+ tripSecure := regexp.MustCompile("##(.+)?")
- var salt [2]rune
+ if tripSecure.MatchString(input) {
+ chunck := tripSecure.FindString(input)
+ chunck = strings.Replace(chunck, "##", "", 1)
+ ce := regexp.MustCompile(`(?i)Admin`)
+ admin := ce.MatchString(chunck)
+ board, modcred := util.GetPasswordFromSession(ctx)
- s := []rune(pass + "H..")[1:3]
+ if hasAuth, _ := util.HasAuth(modcred, board); hasAuth && admin {
+ return tripSecure.ReplaceAllString(input, ""), "#Admin", nil
+ }
- for i, r := range s {
- salt[i] = rune(SaltTable[r%256])
+ hash, err := TripCodeSecure(chunck)
+
+ return tripSecure.ReplaceAllString(input, ""), "!!" + hash, util.MakeError(err, "CreateNameTripCode")
}
- enc, err := crypt.Crypt(pass, "$1$"+string(salt[:]))
- if err != nil {
- return "", err
+ trip := regexp.MustCompile("#(.+)?")
+
+ if trip.MatchString(input) {
+ chunck := trip.FindString(input)
+ chunck = strings.Replace(chunck, "#", "", 1)
+ ce := regexp.MustCompile(`(?i)Admin`)
+ admin := ce.MatchString(chunck)
+ board, modcred := util.GetPasswordFromSession(ctx)
+
+ if hasAuth, _ := util.HasAuth(modcred, board); hasAuth && admin {
+ return trip.ReplaceAllString(input, ""), "#Admin", nil
+ }
+
+ hash, err := TripCode(chunck)
+ return trip.ReplaceAllString(input, ""), "!" + hash, util.MakeError(err, "CreateNameTripCode")
}
- // normally i would just return error here but if the encrypt fails, this operation may fail and as a result cause a panic
- return enc[len(enc)-10 : len(enc)], nil
+ return input, "", nil
}
-func TripCodeSecure(pass string) (string, error) {
+func TripCode(pass string) (string, error) {
+ var salt [2]rune
+
pass = TripCodeConvert(pass)
+ s := []rune(pass + "H..")[1:3]
+
+ for i, r := range s {
+ salt[i] = rune(SaltTable[r%256])
+ }
+
+ enc, err := crypt.Crypt(pass, "$1$"+string(salt[:]))
- enc, err := crypt.Crypt(pass, "$1$"+config.Salt)
if err != nil {
- return "", err
+ return "", util.MakeError(err, "TripCode")
}
+ // normally i would just return error here but if the encrypt fails, this operation may fail and as a result cause a panic
return enc[len(enc)-10 : len(enc)], nil
}
@@ -58,7 +88,6 @@ func TripCodeConvert(str string) string {
var s bytes.Buffer
transform.NewWriter(&s, japanese.ShiftJIS.NewEncoder()).Write([]byte(str))
-
re := strings.NewReplacer(
"&", "&amp;",
"\"", "&quot;",
@@ -69,48 +98,13 @@ func TripCodeConvert(str string) string {
return re.Replace(s.String())
}
-func CreateNameTripCode(ctx *fiber.Ctx) (string, string, error) {
- // TODO: to allow this to compile, this will fail for the case of the admin
- // this can be easily fixed when the rest of the code gets converted to fiber
-
- input := ctx.FormValue("name")
-
- tripSecure := regexp.MustCompile("##(.+)?")
-
- if tripSecure.MatchString(input) {
- chunck := tripSecure.FindString(input)
- chunck = strings.Replace(chunck, "##", "", 1)
-
- //ce := regexp.MustCompile(`(?i)Admin`)
- //admin := ce.MatchString(chunck)
-
- //board, modcred := GetPasswordFromSession(r)
-
- //if admin && HasAuth(modcred, board) {
- // return tripSecure.ReplaceAllString(input, ""), "#Admin"
- //}
-
- hash, err := TripCodeSecure(chunck)
- return tripSecure.ReplaceAllString(input, ""), "!!" + hash, err
- }
-
- trip := regexp.MustCompile("#(.+)?")
-
- if trip.MatchString(input) {
- chunck := trip.FindString(input)
- chunck = strings.Replace(chunck, "#", "", 1)
-
- //ce := regexp.MustCompile(`(?i)Admin`)
- //admin := ce.MatchString(chunck)
- //board, modcred := GetPasswordFromSession(r)
-
- //if admin && HasAuth(db, modcred, board) {
- // return trip.ReplaceAllString(input, ""), "#Admin"
- //}
+func TripCodeSecure(pass string) (string, error) {
+ pass = TripCodeConvert(pass)
+ enc, err := crypt.Crypt(pass, "$1$"+config.Salt)
- hash, err := TripCode(chunck)
- return trip.ReplaceAllString(input, ""), "!" + hash, err
+ if err != nil {
+ return "", util.MakeError(err, "TripCodeSecure")
}
- return input, "", nil
+ return enc[len(enc)-10 : len(enc)], nil
}
diff --git a/post/util.go b/post/util.go
index 6c3e6a0..67822b0 100644
--- a/post/util.go
+++ b/post/util.go
@@ -15,7 +15,6 @@ 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"
)
@@ -46,8 +45,9 @@ func ParseCommentForReplies(comment string, op string) ([]activitypub.ObjectBase
str = strings.Replace(str, "https://", "", 1)
str = config.TP + "" + str
_, isReply, err := db.IsReplyToOP(op, str)
+
if err != nil {
- return nil, err
+ return nil, util.MakeError(err, "ParseCommentForReplies")
}
if !util.IsInStringArray(links, str) && isReply {
@@ -57,13 +57,16 @@ func ParseCommentForReplies(comment string, op string) ([]activitypub.ObjectBase
var validLinks []activitypub.ObjectBase
for i := 0; i < len(links); i++ {
- _, isValid, err := webfinger.CheckValidActivity(links[i])
+ reqActivity := activitypub.Activity{Id: links[i]}
+ _, isValid, err := reqActivity.CheckValid()
+
if err != nil {
- return nil, err
+ return nil, util.MakeError(err, "ParseCommentForReplies")
}
if isValid {
var reply activitypub.ObjectBase
+
reply.Id = links[i]
reply.Published = time.Now().UTC()
validLinks = append(validLinks, reply)
@@ -85,9 +88,11 @@ func ParseCommentForReply(comment string) (string, error) {
}
if len(links) > 0 {
- _, isValid, err := webfinger.CheckValidActivity(strings.ReplaceAll(links[0], ">", ""))
+ reqActivity := activitypub.Activity{Id: strings.ReplaceAll(links[0], ">", "")}
+ _, isValid, err := reqActivity.CheckValid()
+
if err != nil {
- return "", err
+ return "", util.MakeError(err, "ParseCommentForReply")
}
if isValid {
@@ -125,11 +130,13 @@ func ParseLinkTitle(actorName string, op string, content string) string {
func ParseOptions(ctx *fiber.Ctx, obj activitypub.ObjectBase) activitypub.ObjectBase {
options := util.EscapeString(ctx.FormValue("options"))
+
if options != "" {
option := strings.Split(options, ";")
email := regexp.MustCompile(".+@.+\\..+")
wallet := regexp.MustCompile("wallet:.+")
delete := regexp.MustCompile("delete:.+")
+
for _, e := range option {
if e == "noko" {
obj.Option = append(obj.Option, "noko")
@@ -163,20 +170,21 @@ func CheckCaptcha(captcha string) (bool, error) {
}
path := "public/" + parts[0] + ".png"
- code, err := db.GetCaptchaCodeDB(path)
+ code, err := util.GetCaptchaCode(path)
+
if err != nil {
- return false, err
+ return false, util.MakeError(err, "ParseOptions")
}
if code != "" {
- err = db.DeleteCaptchaCodeDB(path)
+ err = util.DeleteCaptchaCode(path)
if err != nil {
- return false, err
+ return false, util.MakeError(err, "ParseOptions")
}
- err = db.CreateNewCaptcha()
+ err = util.CreateNewCaptcha()
if err != nil {
- return false, err
+ return false, util.MakeError(err, "ParseOptions")
}
}
@@ -184,19 +192,28 @@ func CheckCaptcha(captcha string) (bool, error) {
return code == strings.ToUpper(parts[1]), nil
}
+func GetCaptchaCode(captcha string) string {
+ re := regexp.MustCompile("\\w+\\.\\w+$")
+ code := re.FindString(captcha)
+
+ re = regexp.MustCompile("\\w+")
+ code = re.FindString(code)
+
+ return code
+}
+
func IsMediaBanned(f multipart.File) (bool, error) {
f.Seek(0, 0)
-
fileBytes := make([]byte, 2048)
-
_, err := f.Read(fileBytes)
+
if err != nil {
- return true, err
+ return true, util.MakeError(err, "IsMediaBanned")
}
hash := util.HashBytes(fileBytes)
-
f.Seek(0, 0)
+
return db.IsHashBanned(hash)
}
@@ -211,30 +228,28 @@ func SupportedMIMEType(mime string) bool {
}
func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.ObjectBase, error) {
+ var err error
+ var file multipart.File
header, _ := ctx.FormFile("file")
- var file multipart.File
-
if header != nil {
file, _ = header.Open()
}
- var err error
-
if file != nil {
defer file.Close()
-
var tempFile = new(os.File)
+
obj.Attachment, tempFile, err = activitypub.CreateAttachmentObject(file, header)
+
if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
defer tempFile.Close()
fileBytes, _ := ioutil.ReadAll(file)
-
tempFile.Write(fileBytes)
re := regexp.MustCompile(`image/(jpe?g|png|webp)`)
@@ -244,7 +259,7 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj
cmd := exec.Command("exiv2", "rm", "."+fileLoc)
if err := cmd.Run(); err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
}
@@ -256,12 +271,11 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj
obj.Name = util.EscapeString(ctx.FormValue("subject"))
obj.Content = util.EscapeString(ctx.FormValue("comment"))
obj.Sensitive = (ctx.FormValue("sensitive") != "")
-
obj = ParseOptions(ctx, obj)
var originalPost activitypub.ObjectBase
- originalPost.Id = util.EscapeString(ctx.FormValue("inReplyTo"))
+ originalPost.Id = util.EscapeString(ctx.FormValue("inReplyTo"))
obj.InReplyTo = append(obj.InReplyTo, originalPost)
var activity activitypub.Activity
@@ -272,23 +286,23 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj
if originalPost.Id != "" {
if local, _ := activity.IsLocal(); !local {
- actor, err := webfinger.FingerActor(originalPost.Id)
+ actor, err := activitypub.FingerActor(originalPost.Id)
if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
if !util.IsInStringArray(obj.To, actor.Id) {
obj.To = append(obj.To, actor.Id)
}
} else if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
}
replyingTo, err := ParseCommentForReplies(ctx.FormValue("comment"), originalPost.Id)
if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
for _, e := range replyingTo {
@@ -309,16 +323,16 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj
activity.To = append(activity.To, e.Id)
if local, err := activity.IsLocal(); err == nil && !local {
- actor, err := webfinger.FingerActor(e.Id)
+ actor, err := activitypub.FingerActor(e.Id)
if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
if !util.IsInStringArray(obj.To, actor.Id) {
obj.To = append(obj.To, actor.Id)
}
} else if err != nil {
- return obj, err
+ return obj, util.MakeError(err, "ObjectFromForm")
}
}
}
@@ -329,26 +343,22 @@ func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.Obj
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
+ return util.MakeError(err, "ResizeAttachmentToPreview")
}
nPreview.Id = fmt.Sprintf("%s/%s", actor, uid)
@@ -358,25 +368,23 @@ func ResizeAttachmentToPreview() error {
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)
+ config.Log.Println(objFile + " -> " + nHref)
if err := nPreview.WritePreview(); err != nil {
- return err
+ return util.MakeError(err, "ResizeAttachmentToPreview")
}
obj := activitypub.ObjectBase{Id: id}
if err := obj.UpdatePreview(nPreview.Id); err != nil {
- return err
+ return util.MakeError(err, "ResizeAttachmentToPreview")
}
} else {
- return err
+ return util.MakeError(err, "ResizeAttachmentToPreview")
}
}
}
@@ -394,6 +402,7 @@ func ParseAttachment(obj activitypub.ObjectBase, catalog bool) template.HTML {
}
var media string
+
if regexp.MustCompile(`image\/`).MatchString(obj.Attachment[0].MediaType) {
media = "<img "
media += "id=\"img\" "
@@ -465,14 +474,13 @@ 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)
+
if err != nil {
- return "", err
+ return "", util.MakeError(err, "ParseContent")
}
nContent = ParseCommentQuotes(nContent)
-
nContent = strings.ReplaceAll(nContent, `/\&lt;`, ">")
return template.HTML(nContent), nil
@@ -484,10 +492,9 @@ func ParseLinkComments(board activitypub.Actor, op string, content string, threa
//add url to each matched reply
for i, _ := range match {
- link := strings.Replace(match[i][0], ">>", "", 1)
isOP := ""
-
domain := match[i][2]
+ link := strings.Replace(match[i][0], ">>", "", 1)
if link == op {
isOP = " (OP)"
@@ -514,7 +521,7 @@ func ParseLinkComments(board activitypub.Actor, op string, content string, threa
obj := activitypub.ObjectBase{Id: parsedLink}
col, err := obj.GetCollectionFromPath()
if err != nil {
- return "", err
+ return "", util.MakeError(err, "ParseLinkComments")
}
if len(col.OrderedItems) > 0 {
@@ -537,7 +544,7 @@ func ParseLinkComments(board activitypub.Actor, op string, content string, threa
link = parsedOP + "#" + util.ShortURL(parsedOP, parsedLink)
}
- actor, err := webfinger.FingerActor(parsedLink)
+ actor, err := activitypub.FingerActor(parsedLink)
if err == nil && actor.Id != "" {
content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\""+link+"\">&gt;&gt;"+util.ShortURL(board.Outbox, parsedLink)+isOP+" →</a>", -1)
}
diff --git a/routes/actor.go b/routes/actor.go
index 81f6dbe..0200d93 100644
--- a/routes/actor.go
+++ b/routes/actor.go
@@ -3,7 +3,6 @@ package routes
import (
"bytes"
"errors"
- "fmt"
"io"
"io/ioutil"
"mime/multipart"
@@ -11,7 +10,6 @@ import (
"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"
@@ -21,21 +19,21 @@ import (
func ActorInbox(ctx *fiber.Ctx) error {
activity, err := activitypub.GetActivityFromJson(ctx)
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
if activity.Actor.PublicKey.Id == "" {
- nActor, err := webfinger.FingerActor(activity.Actor.Id)
+ nActor, err := activitypub.FingerActor(activity.Actor.Id)
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
activity.Actor = &nActor
}
- if !db.VerifyHeaderSignature(ctx, *activity.Actor) {
+ if !activity.Actor.VerifyHeaderSignature(ctx) {
response := activity.Reject()
- return db.MakeActivityRequest(response)
+ return response.MakeRequestInbox()
}
switch activity.Type {
@@ -44,9 +42,10 @@ func ActorInbox(ctx *fiber.Ctx) error {
actor := activitypub.Actor{Id: e}
if res, err := actor.IsLocal(); err == nil && res {
if res, err := activity.Actor.IsLocal(); err == nil && res {
- col, err := activity.Object.GetCollection()
+ reqActivity := activitypub.Activity{Id: activity.Object.Id}
+ col, err := reqActivity.GetCollection()
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
if len(col.OrderedItems) < 1 {
@@ -54,24 +53,24 @@ func ActorInbox(ctx *fiber.Ctx) error {
}
if err := activity.Object.WriteCache(); err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
actor, err := activitypub.GetActorFromDB(e)
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
- if err := db.ArchivePosts(actor); err != nil {
- return err
+ if err := actor.ArchivePosts(); err != nil {
+ return util.MakeError(err, "ActorInbox")
}
//SendToFollowers(e, activity)
} else if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
} else if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
}
@@ -81,23 +80,23 @@ func ActorInbox(ctx *fiber.Ctx) error {
for _, e := range activity.To {
actor, err := activitypub.GetActorFromDB(e)
if err != nil {
- return err
+ return util.MakeError(err, "")
}
if actor.Id != "" && actor.Id != config.Domain {
if activity.Object.Replies.OrderedItems != nil {
for _, k := range activity.Object.Replies.OrderedItems {
if err := k.Tombstone(); err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
}
}
if err := activity.Object.Tombstone(); err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
if err := actor.UnArchiveLast(); err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
break
}
@@ -107,26 +106,26 @@ func ActorInbox(ctx *fiber.Ctx) error {
case "Follow":
for _, e := range activity.To {
if res, err := activitypub.GetActorFromDB(e); err == nil && res.Id != "" {
- response := db.AcceptFollow(activity)
- response, err := response.SetFollower()
+ response := activity.AcceptFollow()
+ response, err := response.SetActorFollower()
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
- if err := db.MakeActivityRequest(response); err != nil {
- return err
+ if err := response.MakeRequestInbox(); err != nil {
+ return util.MakeError(err, "ActorInbox")
}
alreadyFollow := false
alreadyFollowing := false
autoSub, err := response.Actor.GetAutoSubscribe()
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
following, err := response.Actor.GetFollowing()
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
for _, e := range following {
@@ -135,14 +134,15 @@ func ActorInbox(ctx *fiber.Ctx) error {
}
}
- actor, err := webfinger.FingerActor(response.Object.Actor)
+ actor, err := activitypub.FingerActor(response.Object.Actor)
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
- remoteActorFollowingCol, err := webfinger.GetCollectionFromReq(actor.Following)
+ reqActivity := activitypub.Activity{Id: actor.Following}
+ remoteActorFollowingCol, err := reqActivity.GetCollection()
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
for _, e := range remoteActorFollowingCol.Items {
@@ -152,34 +152,34 @@ func ActorInbox(ctx *fiber.Ctx) error {
}
if autoSub && !alreadyFollow && alreadyFollowing {
- followActivity, err := db.MakeFollowActivity(response.Actor.Id, response.Object.Actor)
+ followActivity, err := response.Actor.MakeFollowActivity(response.Object.Actor)
if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
- if res, err := webfinger.FingerActor(response.Object.Actor); err == nil && res.Id != "" {
- if err := db.MakeActivityRequestOutbox(followActivity); err != nil {
- return err
+ if res, err := activitypub.FingerActor(response.Object.Actor); err == nil && res.Id != "" {
+ if err := followActivity.MakeRequestOutbox(); err != nil {
+ return util.MakeError(err, "ActorInbox")
}
} else if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
}
}
} else if err != nil {
- return err
+ return util.MakeError(err, "ActorInbox")
} else {
- fmt.Println("follow request for rejected")
+ config.Log.Println("follow request for rejected")
response := activity.Reject()
- return db.MakeActivityRequest(response)
+ return response.MakeRequestInbox()
}
}
break
case "Reject":
if activity.Object.Object.Type == "Follow" {
- fmt.Println("follow rejected")
- if _, err := db.SetActorFollowingDB(activity); err != nil {
- return err
+ config.Log.Println("follow rejected")
+ if _, err := activity.SetActorFollowing(); err != nil {
+ return util.MakeError(err, "ActorInbox")
}
}
break
@@ -192,7 +192,7 @@ func ActorOutbox(ctx *fiber.Ctx) error {
//var activity activitypub.Activity
actor, err := webfinger.GetActorFromPath(ctx.Path(), "/")
if err != nil {
- return err
+ return util.MakeError(err, "ActorOutbox")
}
if activitypub.AcceptActivity(ctx.Get("Accept")) {
diff --git a/routes/admin.go b/routes/admin.go
index bd489a5..24c1479 100644
--- a/routes/admin.go
+++ b/routes/admin.go
@@ -20,7 +20,7 @@ func AdminVerify(ctx *fiber.Ctx) error {
identifier := ctx.FormValue("id")
code := ctx.FormValue("code")
- var verify db.Verify
+ var verify util.Verify
verify.Identifier = identifier
verify.Code = code
@@ -29,7 +29,7 @@ func AdminVerify(ctx *fiber.Ctx) error {
req, err := http.NewRequest("POST", config.Domain+"/auth", bytes.NewBuffer(j))
if err != nil {
- return err
+ return util.MakeError(err, "AdminVerify")
}
req.Header.Set("Content-Type", config.ActivityStreams)
@@ -37,7 +37,7 @@ func AdminVerify(ctx *fiber.Ctx) error {
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return err
+ return util.MakeError(err, "AdminVerify")
}
defer resp.Body.Close()
@@ -61,29 +61,29 @@ func AdminVerify(ctx *fiber.Ctx) error {
// TODO remove this route it is mostly unneeded
func AdminAuth(ctx *fiber.Ctx) error {
- var verify db.Verify
+ var verify util.Verify
err := json.Unmarshal(ctx.Body(), &verify)
if err != nil {
- return err
+ return util.MakeError(err, "AdminAuth")
}
- v, _ := db.GetVerificationByCode(verify.Code)
+ v, _ := util.GetVerificationByCode(verify.Code)
if v.Identifier == verify.Identifier {
_, err := ctx.Write([]byte(v.Board))
- return err
+ return util.MakeError(err, "AdminAuth")
}
ctx.Response().Header.SetStatusCode(http.StatusBadRequest)
_, err = ctx.Write([]byte(""))
- return err
+ return util.MakeError(err, "AdminAuth")
}
func AdminIndex(ctx *fiber.Ctx) error {
- id, _ := db.GetPasswordFromSession(ctx)
+ id, _ := util.GetPasswordFromSession(ctx)
actor, _ := webfinger.GetActorFromPath(ctx.Path(), "/"+config.Key+"/")
if actor.Id == "" {
@@ -94,14 +94,15 @@ func AdminIndex(ctx *fiber.Ctx) error {
return ctx.Render("verify", fiber.Map{})
}
- actor, err := webfinger.GetActor(config.Domain)
+ actor, err := activitypub.GetActor(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "AdminIndex")
}
- follow, _ := webfinger.GetActorCollection(actor.Following)
- follower, _ := webfinger.GetActorCollection(actor.Followers)
+ reqActivity := activitypub.Activity{Id: actor.Following}
+ follow, _ := reqActivity.GetCollection()
+ follower, _ := reqActivity.GetCollection()
var following []string
var followers []string
@@ -120,14 +121,14 @@ func AdminIndex(ctx *fiber.Ctx) error {
adminData.Actor = actor.Id
adminData.Key = config.Key
adminData.Domain = config.Domain
- adminData.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ adminData.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
adminData.Title = actor.Name + " Admin page"
adminData.Boards = webfinger.Boards
adminData.Board.Post.Actor = actor.Id
- adminData.PostBlacklist, _ = util.GetRegexBlacklistDB()
+ adminData.PostBlacklist, _ = util.GetRegexBlacklist()
adminData.Themes = &config.Themes
@@ -147,8 +148,9 @@ func AdminFollow(ctx *fiber.Ctx) error {
//follow all of boards following
if following.MatchString(follow) {
- followingActor, _ := webfinger.FingerActor(follow)
- col, _ := webfinger.GetActorCollection(followingActor.Following)
+ followingActor, _ := activitypub.FingerActor(follow)
+ reqActivity := activitypub.Activity{Id: followingActor.Following}
+ col, _ := reqActivity.GetCollection()
var nObj activitypub.ObjectBase
nObj.Id = followingActor.Id
@@ -157,18 +159,20 @@ func AdminFollow(ctx *fiber.Ctx) error {
for _, e := range col.Items {
if isFollowing, _ := actor.IsAlreadyFollowing(e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId {
- followActivity, _ := db.MakeFollowActivity(actorId, e.Id)
+ actor := activitypub.Actor{Id: actorId}
+ followActivity, _ := actor.MakeFollowActivity(e.Id)
- if actor, _ := webfinger.FingerActor(e.Id); actor.Id != "" {
- db.MakeActivityRequestOutbox(followActivity)
+ if actor, _ := activitypub.FingerActor(e.Id); actor.Id != "" {
+ followActivity.MakeRequestOutbox()
}
}
}
//follow all of boards followers
} else if followers.MatchString(follow) {
- followersActor, _ := webfinger.FingerActor(follow)
- col, _ := webfinger.GetActorCollection(followersActor.Followers)
+ followersActor, _ := activitypub.FingerActor(follow)
+ reqActivity := activitypub.Activity{Id: followersActor.Followers}
+ col, _ := reqActivity.GetCollection()
var nObj activitypub.ObjectBase
nObj.Id = followersActor.Id
@@ -177,25 +181,27 @@ func AdminFollow(ctx *fiber.Ctx) error {
for _, e := range col.Items {
if isFollowing, _ := actor.IsAlreadyFollowing(e.Id); !isFollowing && e.Id != config.Domain && e.Id != actorId {
- followActivity, _ := db.MakeFollowActivity(actorId, e.Id)
- if actor, _ := webfinger.FingerActor(e.Id); actor.Id != "" {
- db.MakeActivityRequestOutbox(followActivity)
+ actor := activitypub.Actor{Id: actorId}
+ followActivity, _ := actor.MakeFollowActivity(e.Id)
+ if actor, _ := activitypub.FingerActor(e.Id); actor.Id != "" {
+ followActivity.MakeRequestOutbox()
}
}
}
//do a normal follow to a single board
} else {
- followActivity, _ := db.MakeFollowActivity(actorId, follow)
+ actor := activitypub.Actor{Id: actorId}
+ followActivity, _ := actor.MakeFollowActivity(follow)
- actor := activitypub.Actor{Id: followActivity.Object.Actor}
+ actor = activitypub.Actor{Id: followActivity.Object.Actor}
if isLocal, _ := actor.IsLocal(); !isLocal && followActivity.Actor.Id == config.Domain {
_, err := ctx.Write([]byte("main board can only follow local boards. Create a new board and then follow outside boards from it."))
- return err
+ return util.MakeError(err, "AdminIndex")
}
- if actor, _ := webfinger.FingerActor(follow); actor.Id != "" {
- db.MakeActivityRequestOutbox(followActivity)
+ if actor, _ := activitypub.FingerActor(follow); actor.Id != "" {
+ followActivity.MakeRequestOutbox()
}
}
@@ -211,7 +217,7 @@ func AdminFollow(ctx *fiber.Ctx) error {
func AdminAddBoard(ctx *fiber.Ctx) error {
actor, _ := activitypub.GetActorFromDB(config.Domain)
- if hasValidation := db.HasValidation(ctx, actor); !hasValidation {
+ if hasValidation := actor.HasValidation(ctx); !hasValidation {
return nil
}
@@ -242,7 +248,7 @@ func AdminAddBoard(ctx *fiber.Ctx) error {
newActorActivity.Object.Summary = board.Summary
newActorActivity.Object.Sensitive = board.Restricted
- db.MakeActivityRequestOutbox(newActorActivity)
+ newActorActivity.MakeRequestOutbox()
return ctx.Redirect("/"+config.Key, http.StatusSeeOther)
}
@@ -261,9 +267,14 @@ func AdminNewsDelete(c *fiber.Ctx) error {
func AdminActorIndex(ctx *fiber.Ctx) error {
actor, _ := webfinger.GetActorFromPath(ctx.Path(), "/"+config.Key+"/")
- follow, _ := webfinger.GetActorCollection(actor.Following)
- follower, _ := webfinger.GetActorCollection(actor.Followers)
- reported, _ := activitypub.GetActorCollectionReq(actor.Id + "/reported")
+ reqActivity := activitypub.Activity{Id: actor.Following}
+ follow, _ := reqActivity.GetCollection()
+
+ reqActivity.Id = actor.Followers
+ follower, _ := reqActivity.GetCollection()
+
+ reqActivity.Id = actor.Id + "/reported"
+ reported, _ := activitypub.GetActorCollectionReq(reqActivity.Id)
var following []string
var followers []string
@@ -285,7 +296,7 @@ func AdminActorIndex(ctx *fiber.Ctx) error {
reports = append(reports, r)
}
- localReports, _ := db.GetLocalReportDB(actor.Name)
+ localReports, _ := db.GetLocalReport(actor.Name)
for _, e := range localReports {
var r db.Report
diff --git a/routes/api.go b/routes/api.go
index 2fb0f3f..080d88d 100644
--- a/routes/api.go
+++ b/routes/api.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/util"
"github.com/gofiber/fiber/v2"
)
@@ -20,7 +21,7 @@ func Media(c *fiber.Ctx) error {
func RouteImages(ctx *fiber.Ctx, media string) error {
req, err := http.NewRequest("GET", config.MediaHashs[media], nil)
if err != nil {
- return err
+ return util.MakeError(err, "RouteImages")
}
client := http.Client{
@@ -29,18 +30,18 @@ func RouteImages(ctx *fiber.Ctx, media string) error {
resp, err := client.Do(req)
if err != nil {
- return err
+ return util.MakeError(err, "RouteImages")
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
fileBytes, err := ioutil.ReadFile("./static/notfound.png")
if err != nil {
- return err
+ return util.MakeError(err, "RouteImages")
}
_, err = ctx.Write(fileBytes)
- return err
+ return util.MakeError(err, "RouteImages")
}
body, _ := ioutil.ReadAll(resp.Body)
diff --git a/routes/archive.go b/routes/archive.go
index c0f4ff6..c4950b4 100644
--- a/routes/archive.go
+++ b/routes/archive.go
@@ -3,14 +3,13 @@ package routes
import (
"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 ArchiveGet(ctx *fiber.Ctx) error {
- // TODO
collection := ctx.Locals("collection").(activitypub.Collection)
actor := collection.Actor
@@ -21,7 +20,7 @@ func ArchiveGet(ctx *fiber.Ctx) error {
returnData.Board.To = actor.Outbox
returnData.Board.Actor = actor
returnData.Board.Summary = actor.Summary
- returnData.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ returnData.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
returnData.Board.Domain = config.Domain
returnData.Board.Restricted = actor.Restricted
returnData.Key = config.Key
@@ -32,12 +31,12 @@ func ArchiveGet(ctx *fiber.Ctx) error {
var err error
returnData.Instance, err = activitypub.GetActorFromDB(config.Domain)
- capt, err := db.GetRandomCaptcha()
+ capt, err := util.GetRandomCaptcha()
if err != nil {
- return err
+ return util.MakeError(err, "ArchiveGet")
}
returnData.Board.Captcha = config.Domain + "/" + capt
- returnData.Board.CaptchaCode = util.GetCaptchaCode(returnData.Board.Captcha)
+ returnData.Board.CaptchaCode = post.GetCaptchaCode(returnData.Board.Captcha)
returnData.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername
diff --git a/routes/index.go b/routes/index.go
index 8f12664..68fcfd0 100644
--- a/routes/index.go
+++ b/routes/index.go
@@ -4,6 +4,7 @@ import (
"github.com/FChannel0/FChannel-Server/activitypub"
"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"
)
@@ -11,7 +12,7 @@ import (
func Index(ctx *fiber.Ctx) error {
actor, err := activitypub.GetActorFromDB(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "Index")
}
// this is a activitpub json request return json instead of html page
@@ -22,18 +23,19 @@ func Index(ctx *fiber.Ctx) error {
var data PageData
- col, err := webfinger.GetCollectionFromReq("https://fchan.xyz/followers")
+ reqActivity := activitypub.Activity{Id: "https://fchan.xyz/followers"}
+ col, err := reqActivity.GetCollection()
if err != nil {
- return err
+ return util.MakeError(err, "Index")
}
if len(col.Items) > 0 {
data.InstanceIndex = col.Items
}
- data.NewsItems, err = db.GetNewsFromDB(3)
+ data.NewsItems, err = db.GetNews(3)
if err != nil {
- return err
+ return util.MakeError(err, "Index")
}
data.Title = "Welcome to " + actor.PreferredUsername
@@ -42,7 +44,7 @@ func Index(ctx *fiber.Ctx) error {
data.Board.Name = ""
data.Key = config.Key
data.Board.Domain = config.Domain
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Actor = actor
data.Board.Post.Actor = actor.Id
data.Board.Restricted = actor.Restricted
diff --git a/routes/news.go b/routes/news.go
index bd037c2..c091605 100644
--- a/routes/news.go
+++ b/routes/news.go
@@ -4,17 +4,17 @@ import (
"github.com/FChannel0/FChannel-Server/activitypub"
"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"
)
func NewsGet(ctx *fiber.Ctx) error {
- // TODO
timestamp := 0
actor, err := activitypub.GetActorFromDB(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "NewsGet")
}
var data PageData
@@ -23,15 +23,15 @@ func NewsGet(ctx *fiber.Ctx) error {
data.Board.Name = ""
data.Key = config.Key
data.Board.Domain = config.Domain
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Actor = actor
data.Board.Post.Actor = actor.Id
data.Board.Restricted = actor.Restricted
data.NewsItems = make([]db.NewsItem, 1)
- data.NewsItems[0], err = db.GetNewsItemFromDB(timestamp)
+ data.NewsItems[0], err = db.GetNewsItem(timestamp)
if err != nil {
- return err
+ return util.MakeError(err, "NewsGet")
}
data.Title = actor.PreferredUsername + ": " + data.NewsItems[0].Title
@@ -45,7 +45,7 @@ func NewsGet(ctx *fiber.Ctx) error {
func AllNewsGet(ctx *fiber.Ctx) error {
actor, err := activitypub.GetActorFromDB(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "AllNewsGet")
}
var data PageData
@@ -55,14 +55,14 @@ func AllNewsGet(ctx *fiber.Ctx) error {
data.Board.Name = ""
data.Key = config.Key
data.Board.Domain = config.Domain
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Actor = actor
data.Board.Post.Actor = actor.Id
data.Board.Restricted = actor.Restricted
- data.NewsItems, err = db.GetNewsFromDB(0)
+ data.NewsItems, err = db.GetNews(0)
if err != nil {
- return err
+ return util.MakeError(err, "AllNewsGet")
}
data.Themes = &config.Themes
diff --git a/routes/outbox.go b/routes/outbox.go
index 902d3e6..1d0d52e 100644
--- a/routes/outbox.go
+++ b/routes/outbox.go
@@ -5,7 +5,7 @@ import (
"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"
@@ -14,7 +14,7 @@ import (
func Outbox(ctx *fiber.Ctx) error {
actor, err := webfinger.GetActorFromPath(ctx.Path(), "/")
if err != nil {
- return err
+ return util.MakeError(err, "Outbox")
}
if activitypub.AcceptActivity(ctx.Get("Accept")) {
@@ -40,13 +40,13 @@ func OutboxGet(ctx *fiber.Ctx) error {
var page int
if postNum := ctx.Query("page"); postNum != "" {
if page, err = strconv.Atoi(postNum); err != nil {
- return err
+ return util.MakeError(err, "OutboxGet")
}
}
collection, err := actor.WantToServePage(page)
if err != nil {
- return err
+ return util.MakeError(err, "OutboxGet")
}
var offset = 15
@@ -68,7 +68,7 @@ func OutboxGet(ctx *fiber.Ctx) error {
data.Board.InReplyTo = ""
data.Board.To = actor.Outbox
data.Board.Actor = actor
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Domain = config.Domain
data.Board.Restricted = actor.Restricted
data.CurrentPage = page
@@ -76,12 +76,12 @@ func OutboxGet(ctx *fiber.Ctx) error {
data.Board.Post.Actor = actor.Id
- capt, err := db.GetRandomCaptcha()
+ capt, err := util.GetRandomCaptcha()
if err != nil {
- return err
+ return util.MakeError(err, "OutboxGet")
}
data.Board.Captcha = config.Domain + "/" + capt
- data.Board.CaptchaCode = util.GetCaptchaCode(data.Board.Captcha)
+ data.Board.CaptchaCode = post.GetCaptchaCode(data.Board.Captcha)
data.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername
diff --git a/routes/post.go b/routes/post.go
index 813f53d..4002be7 100644
--- a/routes/post.go
+++ b/routes/post.go
@@ -5,7 +5,7 @@ import (
"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"
@@ -36,23 +36,23 @@ func PostGet(ctx *fiber.Ctx) error {
if re.MatchString(ctx.Path()) { // if non local actor post
name := activitypub.GetActorFollowNameFromPath(ctx.Path())
- followActors, err := webfinger.GetActorsFollowFromName(actor, name)
+ followActors, err := actor.GetFollowFromName(name)
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
followCollection, err := activitypub.GetActorsFollowPostFromId(followActors, postId)
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
if len(followCollection.OrderedItems) > 0 {
data.Board.InReplyTo = followCollection.OrderedItems[0].Id
data.Posts = append(data.Posts, followCollection.OrderedItems[0])
- actor, err := webfinger.FingerActor(data.Board.InReplyTo)
+ actor, err := activitypub.FingerActor(data.Board.InReplyTo)
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
data.Board.Post.Actor = actor.Id
@@ -61,7 +61,7 @@ func PostGet(ctx *fiber.Ctx) error {
obj := activitypub.ObjectBase{Id: inReplyTo}
collection, err := obj.GetCollectionFromPath()
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
if collection.Actor.Id != "" {
@@ -83,21 +83,21 @@ func PostGet(ctx *fiber.Ctx) error {
data.Board.To = actor.Outbox
data.Board.Actor = actor
data.Board.Summary = actor.Summary
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Domain = config.Domain
data.Board.Restricted = actor.Restricted
data.ReturnTo = "feed"
- capt, err := db.GetRandomCaptcha()
+ capt, err := util.GetRandomCaptcha()
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
data.Board.Captcha = config.Domain + "/" + capt
- data.Board.CaptchaCode = util.GetCaptchaCode(data.Board.Captcha)
+ data.Board.CaptchaCode = post.GetCaptchaCode(data.Board.Captcha)
data.Instance, err = activitypub.GetActorFromDB(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "PostGet")
}
data.Key = config.Key
@@ -124,7 +124,7 @@ func CatalogGet(ctx *fiber.Ctx) error {
actorName := ctx.Params("actor")
actor, err := activitypub.GetActorByNameFromDB(actorName)
if err != nil {
- return err
+ return util.MakeError(err, "CatalogGet")
}
collection, err := actor.GetCatalogCollection()
@@ -150,7 +150,7 @@ func CatalogGet(ctx *fiber.Ctx) error {
data.Board.To = actor.Outbox
data.Board.Actor = actor
data.Board.Summary = actor.Summary
- data.Board.ModCred, _ = db.GetPasswordFromSession(ctx)
+ data.Board.ModCred, _ = util.GetPasswordFromSession(ctx)
data.Board.Domain = config.Domain
data.Board.Restricted = actor.Restricted
data.Key = config.Key
@@ -160,16 +160,16 @@ func CatalogGet(ctx *fiber.Ctx) error {
data.Instance, err = activitypub.GetActorFromDB(config.Domain)
if err != nil {
- return err
+ return util.MakeError(err, "CatalogGet")
}
- capt, err := db.GetRandomCaptcha()
+ capt, err := util.GetRandomCaptcha()
if err != nil {
- return err
+ return util.MakeError(err, "CatalogGet")
}
data.Board.Captcha = config.Domain + "/" + capt
- data.Board.CaptchaCode = util.GetCaptchaCode(data.Board.Captcha)
+ data.Board.CaptchaCode = post.GetCaptchaCode(data.Board.Captcha)
data.Title = "/" + data.Board.Name + "/ - catalog"
diff --git a/routes/util.go b/routes/util.go
index de0c6e0..94337bc 100644
--- a/routes/util.go
+++ b/routes/util.go
@@ -28,19 +28,19 @@ func getThemeCookie(c *fiber.Ctx) string {
return "default"
}
-func wantToServeCatalog(actorName string) (activitypub.Collection, bool, error) {
+func WantToServeCatalog(actorName string) (activitypub.Collection, bool, error) {
var collection activitypub.Collection
serve := false
actor, err := activitypub.GetActorByNameFromDB(actorName)
if err != nil {
- return collection, false, err
+ return collection, false, util.MakeError(err, "WantToServeCatalog")
}
if actor.Id != "" {
collection, err = actor.GetCatalogCollection()
if err != nil {
- return collection, false, err
+ return collection, false, util.MakeError(err, "WantToServeCatalog")
}
collection.Actor = actor
@@ -50,19 +50,19 @@ func wantToServeCatalog(actorName string) (activitypub.Collection, bool, error)
return collection, serve, nil
}
-func wantToServeArchive(actorName string) (activitypub.Collection, bool, error) {
+func WantToServeArchive(actorName string) (activitypub.Collection, bool, error) {
var collection activitypub.Collection
serve := false
actor, err := activitypub.GetActorByNameFromDB(actorName)
if err != nil {
- return collection, false, err
+ return collection, false, util.MakeError(err, "WantToServeArchive")
}
if actor.Id != "" {
collection, err = actor.GetCollectionType("Archive")
if err != nil {
- return collection, false, err
+ return collection, false, util.MakeError(err, "WantToServeArchive")
}
collection.Actor = actor
@@ -77,18 +77,18 @@ func GetActorPost(ctx *fiber.Ctx, path string) error {
collection, err := obj.GetCollectionFromPath()
if err != nil {
- return err
+ return util.MakeError(err, "GetActorPost")
}
if len(collection.OrderedItems) > 0 {
enc, err := json.MarshalIndent(collection, "", "\t")
if err != nil {
- return err
+ return util.MakeError(err, "GetActorPost")
}
ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
_, err = ctx.Write(enc)
- return err
+ return util.MakeError(err, "GetActorPost")
}
return nil
@@ -98,9 +98,9 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
contentType := util.GetContentType(ctx.Get("content-type"))
if contentType == "multipart/form-data" || contentType == "application/x-www-form-urlencoded" {
- hasCaptcha, err := db.BoardHasAuthType(actor.Name, "captcha")
+ hasCaptcha, err := util.BoardHasAuthType(actor.Name, "captcha")
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
valid, err := post.CheckCaptcha(ctx.FormValue("captcha"))
@@ -112,15 +112,15 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
if header.Size > (7 << 20) {
ctx.Response().Header.SetStatusCode(403)
_, err := ctx.Write([]byte("7MB max file size"))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
} else if isBanned, err := post.IsMediaBanned(f); err == nil && isBanned {
//Todo add logging
- fmt.Println("media banned")
+ config.Log.Println("media banned")
ctx.Response().Header.SetStatusCode(403)
_, err := ctx.Write([]byte("media banned"))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
} else if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
contentType, _ := util.GetFileContentType(f)
@@ -128,40 +128,40 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
if !post.SupportedMIMEType(contentType) {
ctx.Response().Header.SetStatusCode(403)
_, err := ctx.Write([]byte("file type not supported"))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
}
var nObj = activitypub.CreateObject("Note")
nObj, err := post.ObjectFromForm(ctx, nObj)
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
nObj.Actor = config.Domain + "/" + actor.Name
nObj, err = nObj.Write()
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
if len(nObj.To) == 0 {
- if err := db.ArchivePosts(actor); err != nil {
- return err
+ if err := actor.ArchivePosts(); err != nil {
+ return util.MakeError(err, "ParseOutboxRequest")
}
}
- activity, err := webfinger.CreateActivity("Create", nObj)
+ activity, err := nObj.CreateActivity("Create")
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
- activity, err = webfinger.AddFollowersToActivity(activity)
+ activity, err = activity.AddFollowersTo()
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
- go db.MakeActivityRequest(activity)
+ go activity.MakeRequestInbox()
var id string
op := len(nObj.InReplyTo) - 1
@@ -175,23 +175,23 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
ctx.Response().Header.Set("Status", "200")
_, err = ctx.Write([]byte(id))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
ctx.Response().Header.Set("Status", "403")
_, err = ctx.Write([]byte("captcha could not auth"))
- return err
+ return util.MakeError(err, "")
} else { // json request
activity, err := activitypub.GetActivityFromJson(ctx)
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
if res, err := activity.IsLocal(); err == nil && res {
- if res := db.VerifyHeaderSignature(ctx, *activity.Actor); err == nil && !res {
+ if res := activity.Actor.VerifyHeaderSignature(ctx); err == nil && !res {
ctx.Response().Header.Set("Status", "403")
_, err = ctx.Write([]byte(""))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
switch activity.Type {
@@ -209,30 +209,30 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
var rActivity activitypub.Activity
if validActor && validLocalActor {
- rActivity = db.AcceptFollow(activity)
- rActivity, err = db.SetActorFollowingDB(rActivity)
+ rActivity = activity.AcceptFollow()
+ rActivity, err = rActivity.SetActorFollowing()
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
- if err := db.MakeActivityRequest(activity); err != nil {
- return err
+ if err := activity.MakeRequestInbox(); err != nil {
+ return util.MakeError(err, "ParseOutboxRequest")
}
}
actor, _ := activitypub.GetActorFromDB(config.Domain)
webfinger.FollowingBoards, err = actor.GetFollowing()
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
webfinger.Boards, err = webfinger.GetBoardCollection()
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
break
case "Delete":
- fmt.Println("This is a delete")
+ config.Log.Println("This is a delete")
ctx.Response().Header.Set("Status", "403")
_, err = ctx.Write([]byte("could not process activity"))
break
@@ -248,9 +248,9 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
summary := activity.Object.Summary
restricted := activity.Object.Sensitive
- actor, err := db.CreateNewBoardDB(*activitypub.CreateNewActor(name, prefname, summary, config.AuthReq, restricted))
+ actor, err := db.CreateNewBoard(*activitypub.CreateNewActor(name, prefname, summary, config.AuthReq, restricted))
if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
if actor.Id != "" {
@@ -273,7 +273,7 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
webfinger.FollowingBoards = board
webfinger.Boards, err = webfinger.GetBoardCollection()
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
ctx.Response().Header.Set("Status", "403")
@@ -285,12 +285,12 @@ func ParseOutboxRequest(ctx *fiber.Ctx, actor activitypub.Actor) error {
_, err = ctx.Write([]byte("could not process activity"))
}
} else if err != nil {
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
} else {
- fmt.Println("is NOT activity")
+ config.Log.Println("is NOT activity")
ctx.Response().Header.Set("Status", "403")
_, err = ctx.Write([]byte("could not process activity"))
- return err
+ return util.MakeError(err, "ParseOutboxRequest")
}
}
@@ -338,7 +338,7 @@ 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, _ := webfinger.FingerActor(actorId)
+ actor, _ := activitypub.FingerActor(actorId)
title := strings.ReplaceAll(post.ParseLinkTitle(actor.Id+"/", op, content), `/\&lt;`, ">")
link := "<a href=\"/" + actor.Name + "/" + util.ShortURL(actor.Outbox, op) + "#" + util.ShortURL(actor.Outbox, id) + "\" title=\"" + title + "\" class=\"replyLink\">&gt;&gt;" + util.ShortURL(actor.Outbox, id) + "</a>"
return template.HTML(link)
diff --git a/routes/webfinger.go b/routes/webfinger.go
index 9789e39..495e6c7 100644
--- a/routes/webfinger.go
+++ b/routes/webfinger.go
@@ -6,7 +6,7 @@ import (
"github.com/FChannel0/FChannel-Server/activitypub"
"github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/webfinger"
+ "github.com/FChannel0/FChannel-Server/util"
"github.com/gofiber/fiber/v2"
)
@@ -38,11 +38,11 @@ func Webfinger(c *fiber.Ctx) error {
c.Status(fiber.StatusBadRequest)
return c.Send([]byte("actor not local"))
} else if err != nil {
- return err
+ return util.MakeError(err, "Webfinger")
}
- var finger webfinger.Webfinger
- var link webfinger.WebfingerLink
+ var finger activitypub.Webfinger
+ var link activitypub.WebfingerLink
finger.Subject = "acct:" + actorDomain[0] + "@" + actorDomain[1]
link.Rel = "self"
diff --git a/util/blacklist.go b/util/blacklist.go
index 5368037..acb0b21 100644
--- a/util/blacklist.go
+++ b/util/blacklist.go
@@ -11,28 +11,28 @@ type PostBlacklist struct {
Regex string
}
-func DeleteRegexBlacklistDB(id int) error {
+func DeleteRegexBlacklist(id int) error {
query := `delete from postblacklist where id=$1`
-
_, err := config.DB.Exec(query, id)
- return err
+
+ return MakeError(err, "DeleteRegexBlacklist")
}
-func GetRegexBlacklistDB() ([]PostBlacklist, error) {
+func GetRegexBlacklist() ([]PostBlacklist, error) {
var list []PostBlacklist
query := `select id, regex from postblacklist`
-
rows, err := config.DB.Query(query)
+
if err != nil {
- return list, err
+ return list, MakeError(err, "GetRegexBlacklist")
}
defer rows.Close()
for rows.Next() {
var temp PostBlacklist
- rows.Scan(&temp.Id, &temp.Regex)
+ rows.Scan(&temp.Id, &temp.Regex)
list = append(list, temp)
}
@@ -40,10 +40,10 @@ func GetRegexBlacklistDB() ([]PostBlacklist, error) {
}
func IsPostBlacklist(comment string) (bool, error) {
- postblacklist, err := GetRegexBlacklistDB()
+ postblacklist, err := GetRegexBlacklist()
if err != nil {
- return false, err
+ return false, MakeError(err, "IsPostBlacklist")
}
for _, e := range postblacklist {
@@ -57,20 +57,15 @@ func IsPostBlacklist(comment string) (bool, error) {
return false, nil
}
-func WriteRegexBlacklistDB(regex string) error {
+func WriteRegexBlacklist(regex string) error {
var re string
query := `select from postblacklist where regex=$1`
if err := config.DB.QueryRow(query, regex).Scan(&re); err != nil {
- return err
- }
-
- if re != "" {
- return nil
+ query = `insert into postblacklist (regex) values ($1)`
+ _, err := config.DB.Exec(query, regex)
+ return MakeError(err, "WriteRegexBlacklist")
}
- query = `insert into postblacklist (regex) values ($1)`
-
- _, err := config.DB.Exec(query, regex)
- return err
+ return nil
}
diff --git a/util/key.go b/util/key.go
index cd8662a..60eeb43 100644
--- a/util/key.go
+++ b/util/key.go
@@ -3,6 +3,7 @@ package util
import (
"crypto/sha512"
"encoding/hex"
+ "errors"
"math/rand"
"os"
"strings"
@@ -13,14 +14,14 @@ import (
const domain = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-func CreateKey(len int) string {
+func CreateKey(len int) (string, error) {
// TODO: provided that CreateTripCode still uses sha512, the max len can be 128 at most.
if len > 128 {
- panic("len is greater than 128") // awful way to do it
+ return "", MakeError(errors.New("len is greater than 128"), "CreateKey")
}
str := CreateTripCode(RandomID(len))
- return str[:len]
+ return str[:len], nil
}
func CreateTripCode(input string) string {
@@ -29,23 +30,13 @@ func CreateTripCode(input string) string {
return hex.EncodeToString(out[:])
}
-func RandomID(size int) string {
- rng := size
- newID := strings.Builder{}
- for i := 0; i < rng; i++ {
- newID.WriteByte(domain[rand.Intn(len(domain))])
- }
-
- return newID.String()
-}
-
func GetCookieKey() (string, error) {
if config.CookieKey == "" {
var file *os.File
var err error
if file, err = os.OpenFile("config/config-init", os.O_APPEND|os.O_WRONLY, 0644); err != nil {
- return "", err
+ return "", MakeError(err, "GetCookieKey")
}
defer file.Close()
@@ -56,3 +47,14 @@ func GetCookieKey() (string, error) {
return config.CookieKey, nil
}
+
+func RandomID(size int) string {
+ rng := size
+ newID := strings.Builder{}
+
+ for i := 0; i < rng; i++ {
+ newID.WriteByte(domain[rand.Intn(len(domain))])
+ }
+
+ return newID.String()
+}
diff --git a/util/proxy.go b/util/proxy.go
index 0f4a648..daa90b5 100644
--- a/util/proxy.go
+++ b/util/proxy.go
@@ -9,27 +9,11 @@ import (
"github.com/FChannel0/FChannel-Server/config"
)
-func RouteProxy(req *http.Request) (*http.Response, error) {
- var proxyType = GetPathProxyType(req.URL.Host)
-
- if proxyType == "tor" {
- proxyUrl, err := url.Parse("socks5://" + config.TorProxy)
- if err != nil {
- return nil, err
- }
-
- proxyTransport := &http.Transport{Proxy: http.ProxyURL(proxyUrl)}
- client := &http.Client{Transport: proxyTransport, Timeout: time.Second * 15}
- return client.Do(req)
- }
-
- return http.DefaultClient.Do(req)
-}
-
func GetPathProxyType(path string) string {
if config.TorProxy != "" {
re := regexp.MustCompile(`(http://|http://)?(www.)?\w+\.onion`)
onion := re.MatchString(path)
+
if onion {
return "tor"
}
@@ -40,17 +24,35 @@ func GetPathProxyType(path string) string {
func MediaProxy(url string) string {
re := regexp.MustCompile("(.+)?" + config.Domain + "(.+)?")
-
if re.MatchString(url) {
return url
}
re = regexp.MustCompile("(.+)?\\.onion(.+)?")
-
if re.MatchString(url) {
return url
}
config.MediaHashs[HashMedia(url)] = url
+
return "/api/media?hash=" + HashMedia(url)
}
+
+func RouteProxy(req *http.Request) (*http.Response, error) {
+ var proxyType = GetPathProxyType(req.URL.Host)
+
+ if proxyType == "tor" {
+ proxyUrl, err := url.Parse("socks5://" + config.TorProxy)
+
+ if err != nil {
+ return nil, MakeError(err, "RouteProxy")
+ }
+
+ proxyTransport := &http.Transport{Proxy: http.ProxyURL(proxyUrl)}
+ client := &http.Client{Transport: proxyTransport, Timeout: time.Second * 15}
+
+ return client.Do(req)
+ }
+
+ return http.DefaultClient.Do(req)
+}
diff --git a/util/util.go b/util/util.go
index 9c1ba97..6d45442 100644
--- a/util/util.go
+++ b/util/util.go
@@ -12,6 +12,7 @@ import (
"os"
"path"
"regexp"
+ "runtime"
"strings"
"github.com/FChannel0/FChannel-Server/config"
@@ -28,34 +29,19 @@ func IsOnion(url string) bool {
func StripTransferProtocol(value string) string {
re := regexp.MustCompile("(http://|https://)?(www.)?")
-
value = re.ReplaceAllString(value, "")
return value
}
-func GetCaptchaCode(captcha string) string {
- re := regexp.MustCompile("\\w+\\.\\w+$")
- code := re.FindString(captcha)
-
- re = regexp.MustCompile("\\w+")
- code = re.FindString(code)
-
- return code
-}
-
func ShortURL(actorName string, url string) string {
+ var reply string
re := regexp.MustCompile(`.+\/`)
-
actor := re.FindString(actorName)
-
urlParts := strings.Split(url, "|")
-
op := urlParts[0]
- var reply string
-
if len(urlParts) > 1 {
reply = urlParts[1]
}
@@ -99,17 +85,11 @@ func LocalShort(url string) string {
func RemoteShort(url string) string {
re := regexp.MustCompile(`\w+$`)
-
id := re.FindString(StripTransferProtocol(url))
-
re = regexp.MustCompile(`.+/.+/`)
-
actorurl := re.FindString(StripTransferProtocol(url))
-
re = regexp.MustCompile(`/.+/`)
-
actorname := re.FindString(actorurl)
-
actorname = strings.Replace(actorname, "/", "", -1)
return "f" + actorname + "-" + id
@@ -117,9 +97,7 @@ func RemoteShort(url string) string {
func ShortImg(url string) string {
nURL := url
-
re := regexp.MustCompile(`(\.\w+$)`)
-
fileName := re.ReplaceAllString(url, "")
if len(fileName) > 26 {
@@ -199,32 +177,19 @@ func HashBytes(media []byte) string {
func EscapeString(text string) string {
// TODO: not enough
-
text = strings.Replace(text, "<", "&lt;", -1)
return text
}
func CreateUniqueID(actor string) (string, error) {
var newID string
- isUnique := false
- for !isUnique {
- newID = RandomID(8)
+ for true {
+ newID = RandomID(8)
query := "select id from activitystream where id=$1"
args := fmt.Sprintf("%s/%s/%s", config.Domain, actor, newID)
- rows, err := config.DB.Query(query, args)
- if err != nil {
- return "", MakeError(err, "CreateUniqueID")
- }
-
- defer rows.Close()
- // reusing a variable here
- // if we encounter a match, it'll get set to false causing the outer for loop to loop and to go through this all over again
- // however if nothing is there, it'll remain true and exit the loop
- isUnique = true
- for rows.Next() {
- isUnique = false
+ if err := config.DB.QueryRow(query, args); err != nil {
break
}
}
@@ -234,14 +199,13 @@ func CreateUniqueID(actor string) (string, error) {
func GetFileContentType(out multipart.File) (string, error) {
buffer := make([]byte, 512)
-
_, err := out.Read(buffer)
+
if err != nil {
return "", MakeError(err, "GetFileContentType")
}
out.Seek(0, 0)
-
contentType := http.DetectContentType(buffer)
return contentType, nil
@@ -249,26 +213,33 @@ func GetFileContentType(out multipart.File) (string, error) {
func GetContentType(location string) string {
elements := strings.Split(location, ";")
+
if len(elements) > 0 {
return elements[0]
- } else {
- return location
}
+
+ return location
}
-func CreatedNeededDirectories() {
+func CreatedNeededDirectories() error {
if _, err := os.Stat("./public"); os.IsNotExist(err) {
- os.Mkdir("./public", 0755)
+ if err = os.Mkdir("./public", 0755); err != nil {
+ return MakeError(err, "CreatedNeededDirectories")
+ }
}
if _, err := os.Stat("./pem/board"); os.IsNotExist(err) {
- os.MkdirAll("./pem/board", 0700)
+ if err = os.MkdirAll("./pem/board", 0700); err != nil {
+ return MakeError(err, "CreatedNeededDirectories")
+ }
}
+
+ return nil
}
-func LoadThemes() {
- // get list of themes
+func LoadThemes() error {
themes, err := ioutil.ReadDir("./static/css/themes")
+
if err != nil {
MakeError(err, "LoadThemes")
}
@@ -278,15 +249,16 @@ func LoadThemes() {
config.Themes = append(config.Themes, strings.TrimSuffix(f.Name(), e))
}
}
+
+ return nil
}
func GetBoardAuth(board string) ([]string, error) {
var auth []string
-
- query := `select type from actorauth where board=$1`
-
var rows *sql.Rows
var err error
+
+ query := `select type from actorauth where board=$1`
if rows, err = config.DB.Query(query, board); err != nil {
return auth, MakeError(err, "GetBoardAuth")
}
@@ -306,7 +278,8 @@ func GetBoardAuth(board string) ([]string, error) {
func MakeError(err error, msg string) error {
if err != nil {
- s := fmt.Sprintf("%s: %s", msg, err.Error())
+ _, _, line, _ := runtime.Caller(1)
+ s := fmt.Sprintf("%s:%d : %s", msg, line, err.Error())
return errors.New(s)
}
diff --git a/db/verification.go b/util/verification.go
index eea22ea..c64b54d 100644
--- a/db/verification.go
+++ b/util/verification.go
@@ -1,4 +1,4 @@
-package db
+package util
import (
"fmt"
@@ -9,9 +9,7 @@ import (
"strings"
"time"
- "github.com/FChannel0/FChannel-Server/activitypub"
"github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/util"
"github.com/gofiber/fiber/v2"
_ "github.com/lib/pq"
)
@@ -37,266 +35,125 @@ type Signature struct {
Algorithm string
}
-func DeleteBoardMod(verify Verify) error {
- query := `select code from boardaccess where identifier=$1 and board=$1`
-
- rows, err := config.DB.Query(query, verify.Identifier, verify.Board)
- if err != nil {
- return err
- }
-
- defer rows.Close()
-
- var code string
- rows.Next()
- rows.Scan(&code)
-
- if code != "" {
- query := `delete from crossverification where code=$1`
-
- if _, err := config.DB.Exec(query, code); err != nil {
- return err
- }
-
- query = `delete from boardaccess where identifier=$1 and board=$2`
-
- if _, err := config.DB.Exec(query, verify.Identifier, verify.Board); err != nil {
- return err
- }
- }
+func (verify Verify) Create() error {
+ query := `insert into verification (type, identifier, code, created) values ($1, $2, $3, $4)`
+ _, err := config.DB.Exec(query, verify.Type, verify.Identifier, verify.Code, time.Now().UTC().Format(time.RFC3339))
- return nil
+ return MakeError(err, "Create")
}
-func GetBoardMod(identifier string) (Verify, error) {
- var nVerify Verify
-
- query := `select code, board, type, identifier from boardaccess where identifier=$1`
-
- rows, err := config.DB.Query(query, identifier)
+func (verify Verify) CreateBoardAccess() error {
+ hasAccess, err := verify.HasBoardAccess()
if err != nil {
- return nVerify, err
+ return MakeError(err, "CreateBoardAccess")
}
- defer rows.Close()
+ if !hasAccess {
+ query := `insert into boardaccess (identifier, board) values($1, $2)`
+ _, err := config.DB.Exec(query, verify.Identifier, verify.Board)
- rows.Next()
- rows.Scan(&nVerify.Code, &nVerify.Board, &nVerify.Type, &nVerify.Identifier)
+ return MakeError(err, "CreateBoardAccess")
+ }
- return nVerify, nil
+ return nil
}
-func CreateBoardMod(verify Verify) error {
- pass := util.CreateKey(50)
+func (verify Verify) CreateBoardMod() error {
+ var pass string
+ var err error
- query := `select code from verification where identifier=$1 and type=$2`
-
- rows, err := config.DB.Query(query, verify.Board, verify.Type)
- if err != nil {
- return err
+ if pass, err = CreateKey(50); err != nil {
+ return MakeError(err, "CreateBoardMod")
}
- defer rows.Close()
-
var code string
- rows.Next()
- rows.Scan(&code)
+ query := `select code from verification where identifier=$1 and type=$2`
+ if err := config.DB.QueryRow(query, verify.Board, verify.Type).Scan(&code); err != nil {
+ return nil
+ }
- if code != "" {
+ var ident string
- query := `select identifier from boardaccess where identifier=$1 and board=$2`
+ query = `select identifier from boardaccess where identifier=$1 and board=$2`
+ if err := config.DB.QueryRow(query, verify.Identifier, verify.Board).Scan(&ident); err != nil {
+ return nil
+ }
- rows, err := config.DB.Query(query, verify.Identifier, verify.Board)
- if err != nil {
- return err
+ if ident != verify.Identifier {
+ query := `insert into crossverification (verificationcode, code) values ($1, $2)`
+ if _, err := config.DB.Exec(query, code, pass); err != nil {
+ return MakeError(err, "CreateBoardMod")
}
- defer rows.Close()
-
- var ident string
- rows.Next()
- rows.Scan(&ident)
-
- if ident != verify.Identifier {
-
- query := `insert into crossverification (verificationcode, code) values ($1, $2)`
-
- if _, err := config.DB.Exec(query, code, pass); err != nil {
- return err
- }
-
- query = `insert into boardaccess (identifier, code, board, type) values ($1, $2, $3, $4)`
-
- if _, err = config.DB.Exec(query, verify.Identifier, pass, verify.Board, verify.Type); err != nil {
- return err
- }
-
- fmt.Printf("Board access - Board: %s, Identifier: %s, Code: %s\n", verify.Board, verify.Identifier, pass)
+ query = `insert into boardaccess (identifier, code, board, type) values ($1, $2, $3, $4)`
+ if _, err = config.DB.Exec(query, verify.Identifier, pass, verify.Board, verify.Type); err != nil {
+ return MakeError(err, "CreateBoardMod")
}
+
+ config.Log.Printf("Board access - Board: %s, Identifier: %s, Code: %s\n", verify.Board, verify.Identifier, pass)
}
return nil
}
-func CreateVerification(verify Verify) error {
- query := `insert into verification (type, identifier, code, created) values ($1, $2, $3, $4)`
-
- _, err := config.DB.Exec(query, verify.Type, verify.Identifier, verify.Code, time.Now().UTC().Format(time.RFC3339))
- return err
-}
-
-func GetVerificationByEmail(email string) (Verify, error) {
- // TODO: this only needs to select one row.
-
- var verify Verify
-
- query := `select type, identifier, code, board from boardaccess where identifier=$1`
-
- rows, err := config.DB.Query(query, email)
- if err != nil {
- return verify, err
- }
-
- defer rows.Close()
+func (verify Verify) DeleteBoardMod() error {
+ var code string
- for rows.Next() {
- if err := rows.Scan(&verify.Type, &verify.Identifier, &verify.Code, &verify.Board); err != nil {
- return verify, err
- }
+ query := `select code from boardaccess where identifier=$1 and board=$1`
+ if err := config.DB.QueryRow(query, verify.Identifier, verify.Board).Scan(&code); err != nil {
+ return nil
}
- return verify, nil
-}
-
-func GetVerificationByCode(code string) (Verify, error) {
- // TODO: this only needs to select one row.
-
- var verify Verify
-
- query := `select type, identifier, code, board from boardaccess where code=$1`
-
- rows, err := config.DB.Query(query, code)
- if err != nil {
- return verify, err
+ query = `delete from crossverification where code=$1`
+ if _, err := config.DB.Exec(query, code); err != nil {
+ return MakeError(err, "DeleteBoardMod")
}
- defer rows.Close()
-
- for rows.Next() {
- if err := rows.Scan(&verify.Type, &verify.Identifier, &verify.Code, &verify.Board); err != nil {
- return verify, err
- }
+ query = `delete from boardaccess where identifier=$1 and board=$2`
+ if _, err := config.DB.Exec(query, verify.Identifier, verify.Board); err != nil {
+ return MakeError(err, "DeleteBoardMod")
}
- return verify, nil
+ return nil
}
-func GetVerificationCode(verify Verify) (Verify, error) {
+func (verify Verify) GetBoardMod() (Verify, error) {
var nVerify Verify
- query := `select type, identifier, code, board from boardaccess where identifier=$1 and board=$2`
-
- rows, err := config.DB.Query(query, verify.Identifier, verify.Board)
- if err != nil {
- return verify, err
- }
-
- defer rows.Close()
-
- for rows.Next() {
- if err := rows.Scan(&nVerify.Type, &nVerify.Identifier, &nVerify.Code, &nVerify.Board); err != nil {
- return nVerify, err
- }
-
+ query := `select code, board, type, identifier from boardaccess where identifier=$1`
+ if err := config.DB.QueryRow(query, verify.Identifier).Scan(&nVerify.Code, &nVerify.Board, &nVerify.Type, &nVerify.Identifier); err != nil {
+ return nVerify, MakeError(err, "GetBoardMod")
}
return nVerify, nil
}
-func VerifyCooldownCurrent(auth string) (VerifyCooldown, error) {
- var current VerifyCooldown
-
- query := `select identifier, code, time from verificationcooldown where code=$1`
-
- rows, err := config.DB.Query(query, auth)
- if err != nil {
- query := `select identifier, code, time from verificationcooldown where identifier=$1`
-
- rows, err := config.DB.Query(query, auth)
-
- if err != nil {
- return current, err
- }
-
- defer rows.Close()
-
- for rows.Next() {
- if err := rows.Scan(&current.Identifier, &current.Code, &current.Time); err != nil {
- return current, err
- }
- }
- } else {
- defer rows.Close()
- }
+func (verify Verify) GetCode() (Verify, error) {
+ var nVerify Verify
- for rows.Next() {
- if err := rows.Scan(&current.Identifier, &current.Code, &current.Time); err != nil {
- return current, err
- }
+ query := `select type, identifier, code, board from boardaccess where identifier=$1 and board=$2`
+ if err := config.DB.QueryRow(query, verify.Identifier, verify.Board).Scan(&nVerify.Type, &nVerify.Identifier, &nVerify.Code, &nVerify.Board); err != nil {
+ return verify, nil
}
- return current, nil
-}
-
-func VerifyCooldownAdd(verify Verify) error {
- query := `insert into verficationcooldown (identifier, code) values ($1, $2)`
-
- _, err := config.DB.Exec(query, verify.Identifier, verify.Code)
- return err
+ return nVerify, nil
}
-func VerficationCooldown() error {
- query := `select identifier, code, time from verificationcooldown`
-
- rows, err := config.DB.Query(query)
- if err != nil {
- return err
- }
-
- defer rows.Close()
-
- for rows.Next() {
- var verify VerifyCooldown
-
- if err := rows.Scan(&verify.Identifier, &verify.Code, &verify.Time); err != nil {
- return err
- }
-
- nTime := verify.Time - 1
-
- query = `update set time=$1 where identifier=$2`
-
- if _, err := config.DB.Exec(query, nTime, verify.Identifier); err != nil {
- return err
- }
+func (verify Verify) HasBoardAccess() (bool, error) {
+ var count int
- VerficationCooldownRemove()
+ query := `select count(*) from boardaccess where identifier=$1 and board=$2`
+ if err := config.DB.QueryRow(query, verify.Identifier, verify.Board).Scan(&count); err != nil {
+ return false, nil
}
- return nil
-}
-
-func VerficationCooldownRemove() error {
- query := `delete from verificationcooldown where time < 1`
-
- _, err := config.DB.Exec(query)
- return err
+ return true, nil
}
-func SendVerification(verify Verify) error {
- fmt.Println("sending email")
+func (verify Verify) SendVerification() error {
+ config.Log.Println("sending email")
from := config.SiteEmail
pass := config.SiteEmailPassword
@@ -308,75 +165,66 @@ func SendVerification(verify Verify) error {
"Subject: Image Board Verification\n\n" +
body
- return smtp.SendMail(config.SiteEmailServer+":"+config.SiteEmailPort,
+ err := smtp.SendMail(config.SiteEmailServer+":"+config.SiteEmailPort,
smtp.PlainAuth("", from, pass, config.SiteEmailServer),
from, []string{to}, []byte(msg))
-}
-func IsEmailSetup() bool {
- return config.SiteEmail != "" || config.SiteEmailPassword != "" || config.SiteEmailServer != "" || config.SiteEmailPort != ""
+ return MakeError(err, "SendVerification")
}
-func HasAuth(code string, board string) (bool, error) {
- verify, err := GetVerificationByCode(code)
- if err != nil {
- return false, err
- }
-
- if res, err := HasBoardAccess(verify); err != nil && (verify.Board == config.Domain || (res && verify.Board == board)) {
- return true, nil
- } else {
- return false, err
- }
+func (verify Verify) VerifyCooldownAdd() error {
+ query := `insert into verficationcooldown (identifier, code) values ($1, $2)`
+ _, err := config.DB.Exec(query, verify.Identifier, verify.Code)
- return false, nil
+ return MakeError(err, "VerifyCooldownAdd")
}
-func HasAuthCooldown(auth string) (bool, error) {
- current, err := VerifyCooldownCurrent(auth)
+func BoardHasAuthType(board string, auth string) (bool, error) {
+ authTypes, err := GetBoardAuth(board)
+
if err != nil {
- return false, err
+ return false, MakeError(err, "BoardHasAuthType")
}
- if current.Time > 0 {
- return true, nil
+ for _, e := range authTypes {
+ if e == auth {
+ return true, nil
+ }
}
- // fmt.Println("has auth is false")
return false, nil
}
-func GetVerify(access string) (Verify, error) {
- verify, err := GetVerificationByCode(access)
- if err != nil {
- return verify, err
- }
+func Captcha() string {
+ rand.Seed(time.Now().UTC().UnixNano())
+ domain := "ABEFHKMNPQRSUVWXYZ#$&"
+ rng := 4
+ newID := ""
- if verify.Identifier == "" {
- verify, err = GetVerificationByEmail(access)
+ for i := 0; i < rng; i++ {
+ newID += string(domain[rand.Intn(len(domain))])
}
- return verify, err
+ return newID
}
func CreateNewCaptcha() error {
- id := util.RandomID(8)
+ id := RandomID(8)
file := "public/" + id + ".png"
for true {
if _, err := os.Stat("./" + file); err == nil {
- id = util.RandomID(8)
+ id = RandomID(8)
file = "public/" + id + ".png"
} else {
break
}
}
- captcha := Captcha()
-
var pattern string
- rnd := fmt.Sprintf("%d", rand.Intn(3))
+ captcha := Captcha()
+ rnd := fmt.Sprintf("%d", rand.Intn(3))
srnd := string(rnd)
switch srnd {
@@ -398,112 +246,214 @@ func CreateNewCaptcha() error {
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
- return err
+ return MakeError(err, "CreateNewCaptcha")
}
cmd = exec.Command("convert", file, "-fill", "blue", "-pointsize", "62", "-annotate", "+0+70", captcha, "-tile", "pattern:left30", "-gravity", "center", "-transparent", "white", file)
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
- return err
+ return MakeError(err, "CreateNewCaptcha")
}
rnd = fmt.Sprintf("%d", rand.Intn(24)-12)
-
cmd = exec.Command("convert", file, "-rotate", rnd, "-wave", "5x35", "-distort", "Arc", "20", "-wave", "2x35", "-transparent", "white", file)
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
- return err
+ return MakeError(err, "CreateNewCaptcha")
}
var verification Verify
+
verification.Type = "captcha"
verification.Code = captcha
verification.Identifier = file
- return CreateVerification(verification)
+ return verification.Create()
}
-func CreateBoardAccess(verify Verify) error {
- hasAccess, err := HasBoardAccess(verify)
- if err != nil {
- return err
+func GetRandomCaptcha() (string, error) {
+ var verify string
+
+ query := `select identifier from verification where type='captcha' order by random() limit 1`
+ if err := config.DB.QueryRow(query).Scan(&verify); err != nil {
+ return verify, MakeError(err, "GetRandomCaptcha")
}
- if !hasAccess {
- query := `insert into boardaccess (identifier, board) values($1, $2)`
+ return verify, nil
+}
- _, err := config.DB.Exec(query, verify.Identifier, verify.Board)
- return err
+func GetCaptchaTotal() (int, error) {
+ var count int
+
+ query := `select count(*) from verification where type='captcha'`
+ if err := config.DB.QueryRow(query).Scan(&count); err != nil {
+ return count, MakeError(err, "GetCaptchaTotal")
}
- return nil
+ return count, nil
}
-func HasBoardAccess(verify Verify) (bool, error) {
- query := `select count(*) from boardaccess where identifier=$1 and board=$2`
+func GetCaptchaCode(verify string) (string, error) {
+ var code string
+
+ query := `select code from verification where identifier=$1 limit 1`
+ if err := config.DB.QueryRow(query, verify).Scan(&code); err != nil {
+ return code, MakeError(err, "GetCaptchaCodeDB")
+ }
+
+ return code, nil
+}
+
+func DeleteCaptchaCode(verify string) error {
+ query := `delete from verification where identifier=$1`
+ _, err := config.DB.Exec(query, verify)
- rows, err := config.DB.Query(query, verify.Identifier, verify.Board)
if err != nil {
- return false, err
+ return MakeError(err, "DeleteCaptchaCode")
+ }
+
+ err = os.Remove("./" + verify)
+ return MakeError(err, "DeleteCaptchaCode")
+}
+
+func GetVerificationByCode(code string) (Verify, error) {
+ // TODO: this only needs to select one row.
+
+ var verify Verify
+
+ query := `select type, identifier, code, board from boardaccess where code=$1`
+
+ rows, err := config.DB.Query(query, code)
+ if err != nil {
+ return verify, MakeError(err, "GetVerificationByCode")
}
defer rows.Close()
- var count int
+ for rows.Next() {
+ if err := rows.Scan(&verify.Type, &verify.Identifier, &verify.Code, &verify.Board); err != nil {
+ return verify, MakeError(err, "GetVerificationByCode")
+ }
+ }
- rows.Next()
- rows.Scan(&count)
+ return verify, nil
+}
- if count > 0 {
- return true, nil
- } else {
- return false, nil
+func GetVerificationByEmail(email string) (Verify, error) {
+ var verify Verify
+
+ query := `select type, identifier, code, board from boardaccess where identifier=$1`
+ if err := config.DB.QueryRow(query, email).Scan(&verify.Type, &verify.Identifier, &verify.Code, &verify.Board); err != nil {
+ return verify, nil
}
+
+ return verify, nil
}
-func BoardHasAuthType(board string, auth string) (bool, error) {
- authTypes, err := util.GetBoardAuth(board)
+func GetVerify(access string) (Verify, error) {
+ verify, err := GetVerificationByCode(access)
+
if err != nil {
- return false, err
+ return verify, MakeError(err, "GetVerify")
}
- for _, e := range authTypes {
- if e == auth {
- return true, nil
- }
+ if verify.Identifier == "" {
+ verify, err = GetVerificationByEmail(access)
+ }
+
+ return verify, MakeError(err, "GetVerify")
+}
+
+func HasAuthCooldown(auth string) (bool, error) {
+ var current VerifyCooldown
+ var err error
+
+ if current, err = VerifyCooldownCurrent(auth); err != nil {
+ return false, MakeError(err, "HasAuthCooldown")
+ }
+
+ if current.Time > 0 {
+ return true, nil
}
return false, nil
}
-func Captcha() string {
- rand.Seed(time.Now().UTC().UnixNano())
- domain := "ABEFHKMNPQRSUVWXYZ#$&"
- rng := 4
- newID := ""
- for i := 0; i < rng; i++ {
- newID += string(domain[rand.Intn(len(domain))])
+func HasAuth(code string, board string) (bool, error) {
+ verify, err := GetVerificationByCode(code)
+ if err != nil {
+ return false, MakeError(err, "HasAuth")
}
- return newID
+ if res, err := verify.HasBoardAccess(); err == nil && (verify.Board == config.Domain || (res && verify.Board == board)) {
+ return true, nil
+ } else {
+ return false, MakeError(err, "HasAuth")
+ }
+
+ return false, nil
}
-func HasValidation(ctx *fiber.Ctx, actor activitypub.Actor) bool {
- id, _ := GetPasswordFromSession(ctx)
+func IsEmailSetup() bool {
+ return config.SiteEmail != "" || config.SiteEmailPassword != "" || config.SiteEmailServer != "" || config.SiteEmailPort != ""
+}
+
+func VerficationCooldown() error {
+ query := `select identifier, code, time from verificationcooldown`
+ rows, err := config.DB.Query(query)
- if id == "" || (id != actor.Id && id != config.Domain) {
- //http.Redirect(w, r, "/", http.StatusSeeOther)
- return false
+ if err != nil {
+ return MakeError(err, "VerficationCooldown")
}
- return true
+ defer rows.Close()
+ for rows.Next() {
+ var verify VerifyCooldown
+
+ if err := rows.Scan(&verify.Identifier, &verify.Code, &verify.Time); err != nil {
+ return MakeError(err, "VerficationCooldown")
+ }
+
+ nTime := verify.Time - 1
+ query = `update set time=$1 where identifier=$2`
+
+ if _, err := config.DB.Exec(query, nTime, verify.Identifier); err != nil {
+ return MakeError(err, "VerficationCooldown")
+ }
+
+ VerficationCooldownRemove()
+ }
+
+ return nil
+}
+
+func VerficationCooldownRemove() error {
+ query := `delete from verificationcooldown where time < 1`
+ _, err := config.DB.Exec(query)
+
+ return MakeError(err, "VerficationCooldownRemove")
}
-func GetPasswordFromSession(r *fiber.Ctx) (string, string) {
- cookie := r.Cookies("session_token")
+func VerifyCooldownCurrent(auth string) (VerifyCooldown, error) {
+ var current VerifyCooldown
+ query := `select identifier, code, time from verificationcooldown where code=$1`
+ if err := config.DB.QueryRow(query, auth).Scan(&current.Identifier, &current.Code, &current.Time); err != nil {
+ query := `select identifier, code, time from verificationcooldown where identifier=$1`
+ if err := config.DB.QueryRow(query, auth).Scan(&current.Identifier, &current.Code, &current.Time); err != nil {
+ return current, nil
+ }
+
+ return current, nil
+ }
+
+ return current, nil
+}
+
+func GetPasswordFromSession(ctx *fiber.Ctx) (string, string) {
+ cookie := ctx.Cookies("session_token")
parts := strings.Split(cookie, "|")
if len(parts) > 1 {
@@ -512,3 +462,21 @@ func GetPasswordFromSession(r *fiber.Ctx) (string, string) {
return "", ""
}
+
+func MakeCaptchas(total int) error {
+ dbtotal, err := GetCaptchaTotal()
+
+ if err != nil {
+ return MakeError(err, "MakeCaptchas")
+ }
+
+ difference := total - dbtotal
+
+ for i := 0; i < difference; i++ {
+ if err := CreateNewCaptcha(); err != nil {
+ return MakeError(err, "MakeCaptchas")
+ }
+ }
+
+ return nil
+}
diff --git a/webfinger/comm.go b/webfinger/comm.go
deleted file mode 100644
index ed20779..0000000
--- a/webfinger/comm.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package webfinger
-
-import (
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/http"
- "regexp"
-
- "github.com/FChannel0/FChannel-Server/activitypub"
- "github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/util"
-)
-
-// TODO: All of these functions in this file I don't know where to place so they'll remain here until I find a better place for them.
-
-func GetActorCollection(collection string) (activitypub.Collection, error) {
- var nCollection activitypub.Collection
-
- if collection == "" {
- return nCollection, errors.New("invalid collection")
- }
-
- req, err := http.NewRequest("GET", collection, nil)
- if err != nil {
- return nCollection, err
- }
-
- req.Header.Set("Accept", config.ActivityStreams)
-
- resp, err := util.RouteProxy(req)
- if err != nil {
- return nCollection, err
- }
-
- defer resp.Body.Close()
-
- if resp.StatusCode == 200 {
- body, _ := ioutil.ReadAll(resp.Body)
- if len(body) > 0 {
- if err := json.Unmarshal(body, &nCollection); err != nil {
- return nCollection, err
- }
- }
- }
-
- return nCollection, nil
-}
-
-func GetCollectionFromReq(path string) (activitypub.Collection, error) {
- var respCollection activitypub.Collection
-
- req, err := http.NewRequest("GET", path, nil)
- if err != nil {
- return respCollection, err
- }
-
- req.Header.Set("Accept", config.ActivityStreams)
-
- resp, err := util.RouteProxy(req)
- if err != nil {
- return respCollection, err
- }
- defer resp.Body.Close()
-
- body, _ := ioutil.ReadAll(resp.Body)
-
- err = json.Unmarshal(body, &respCollection)
- return respCollection, err
-}
-
-func GetActorsFollowFromName(actor activitypub.Actor, name string) ([]string, error) {
- var followingActors []string
- follow, err := GetActorCollection(actor.Following)
- if err != nil {
- return followingActors, err
- }
-
- re := regexp.MustCompile("\\w+?$")
-
- for _, e := range follow.Items {
- if re.FindString(e.Id) == name {
- followingActors = append(followingActors, e.Id)
- }
- }
-
- return followingActors, nil
-}
diff --git a/webfinger/util.go b/webfinger/util.go
index 0fc4948..fa8a625 100644
--- a/webfinger/util.go
+++ b/webfinger/util.go
@@ -7,6 +7,7 @@ import (
"strings"
"github.com/FChannel0/FChannel-Server/activitypub"
+ "github.com/FChannel0/FChannel-Server/util"
)
var Boards []Board
@@ -38,6 +39,7 @@ func (a BoardSortAsc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func GetActorByNameFromBoardCollection(name string) activitypub.Actor {
var actor activitypub.Actor
+
boards, _ := GetBoardCollection()
for _, e := range boards {
if e.Actor.Name == name {
@@ -50,17 +52,21 @@ func GetActorByNameFromBoardCollection(name string) activitypub.Actor {
func GetBoardCollection() ([]Board, error) {
var collection []Board
+
for _, e := range FollowingBoards {
var board Board
+
boardActor, err := activitypub.GetActorFromDB(e.Id)
+
if err != nil {
- return collection, err
+ return collection, util.MakeError(err, "GetBoardCollection")
}
if boardActor.Id == "" {
- boardActor, err = FingerActor(e.Id)
+ boardActor, err = activitypub.FingerActor(e.Id)
+
if err != nil {
- return collection, err
+ return collection, util.MakeError(err, "GetBoardCollection")
}
}
@@ -69,6 +75,7 @@ func GetBoardCollection() ([]Board, error) {
board.Location = "/" + boardActor.Name
board.Actor = boardActor
board.Restricted = boardActor.Restricted
+
collection = append(collection, board)
}
@@ -78,12 +85,12 @@ func GetBoardCollection() ([]Board, error) {
}
func GetActorFromPath(location string, prefix string) (activitypub.Actor, error) {
+ var actor string
+
pattern := fmt.Sprintf("%s([^/\n]+)(/.+)?", prefix)
re := regexp.MustCompile(pattern)
match := re.FindStringSubmatch(location)
- var actor string
-
if len(match) < 1 {
actor = "/"
} else {
@@ -97,8 +104,9 @@ func GetActorFromPath(location string, prefix string) (activitypub.Actor, error)
var nActor activitypub.Actor
nActor, err := activitypub.GetActorByNameFromDB(actor)
+
if err != nil {
- return nActor, err
+ return nActor, util.MakeError(err, "GetActorFromPath")
}
if nActor.Id == "" {
@@ -107,3 +115,19 @@ func GetActorFromPath(location string, prefix string) (activitypub.Actor, error)
return nActor, nil
}
+
+func StartupArchive() error {
+ for _, e := range FollowingBoards {
+ actor, err := activitypub.GetActorFromDB(e.Id)
+
+ if err != nil {
+ return util.MakeError(err, "StartupArchive")
+ }
+
+ if err := actor.ArchivePosts(); err != nil {
+ return util.MakeError(err, "StartupArchive")
+ }
+ }
+
+ return nil
+}
diff --git a/webfinger/webfinger.go b/webfinger/webfinger.go
deleted file mode 100644
index 45650ea..0000000
--- a/webfinger/webfinger.go
+++ /dev/null
@@ -1,313 +0,0 @@
-package webfinger
-
-import (
- "encoding/json"
- "io/ioutil"
- "net/http"
- "regexp"
- "strings"
- "time"
-
- "github.com/FChannel0/FChannel-Server/activitypub"
- "github.com/FChannel0/FChannel-Server/config"
- "github.com/FChannel0/FChannel-Server/util"
-)
-
-type Webfinger struct {
- Subject string `json:"subject,omitempty"`
- Links []WebfingerLink `json:"links,omitempty"`
-}
-
-type WebfingerLink struct {
- Rel string `json:"rel,omitempty"`
- Type string `json:"type,omitempty"`
- Href string `json:"href,omitempty"`
-}
-
-var ActorCache = make(map[string]activitypub.Actor)
-
-func GetActor(id string) (activitypub.Actor, error) {
- var respActor activitypub.Actor
-
- if id == "" {
- return respActor, nil
- }
-
- actor, instance := activitypub.GetActorAndInstance(id)
-
- if ActorCache[actor+"@"+instance].Id != "" {
- respActor = ActorCache[actor+"@"+instance]
- return respActor, nil
- }
-
- req, err := http.NewRequest("GET", strings.TrimSpace(id), nil)
- if err != nil {
- return respActor, err
- }
-
- req.Header.Set("Accept", config.ActivityStreams)
-
- resp, err := util.RouteProxy(req)
-
- if err != nil {
- return respActor, err
- }
-
- defer resp.Body.Close()
-
- body, _ := ioutil.ReadAll(resp.Body)
-
- if err := json.Unmarshal(body, &respActor); err != nil {
- return respActor, err
- }
-
- ActorCache[actor+"@"+instance] = respActor
-
- return respActor, nil
-}
-
-//looks for actor with pattern of board@instance
-func FingerActor(path string) (activitypub.Actor, error) {
- var nActor activitypub.Actor
-
- actor, instance := activitypub.GetActorAndInstance(path)
-
- if actor == "" && instance == "" {
- return nActor, nil
- }
-
- if ActorCache[actor+"@"+instance].Id != "" {
- nActor = ActorCache[actor+"@"+instance]
- } else {
- r, _ := FingerRequest(actor, instance)
-
- if r != nil && r.StatusCode == 200 {
- defer r.Body.Close()
-
- body, _ := ioutil.ReadAll(r.Body)
-
- json.Unmarshal(body, &nActor)
- // if err := json.Unmarshal(body, &nActor); err != nil {
- // return nActor, err
- // }
-
- ActorCache[actor+"@"+instance] = nActor
- }
- }
-
- return nActor, nil
-}
-
-func FingerRequest(actor string, instance string) (*http.Response, error) {
- acct := "acct:" + actor + "@" + instance
-
- // TODO: respect https
- req, _ := http.NewRequest("GET", "http://"+instance+"/.well-known/webfinger?resource="+acct, nil)
- // if err != nil {
- // return nil, err
- // }
-
- resp, err := util.RouteProxy(req)
- if err != nil {
- return resp, nil
- }
-
- var finger Webfinger
-
- if resp.StatusCode == 200 {
- defer resp.Body.Close()
-
- body, _ := ioutil.ReadAll(resp.Body)
-
- json.Unmarshal(body, &finger)
- // if err := json.Unmarshal(body, &finger); err != nil {
- // return resp, err
- // }
- }
-
- if len(finger.Links) > 0 {
- for _, e := range finger.Links {
- if e.Type == "application/activity+json" {
- req, _ := http.NewRequest("GET", e.Href, nil)
- // if err != nil {
- // return resp, err
- // }
-
- req.Header.Set("Accept", config.ActivityStreams)
-
- resp, _ := util.RouteProxy(req)
- return resp, nil
- }
- }
- }
-
- return resp, nil
-}
-
-func CheckValidActivity(id string) (activitypub.Collection, bool, error) {
- var respCollection activitypub.Collection
-
- re := regexp.MustCompile(`.+\.onion(.+)?`)
- if re.MatchString(id) {
- id = strings.Replace(id, "https", "http", 1)
- }
-
- req, err := http.NewRequest("GET", id, nil)
- if err != nil {
- return respCollection, false, err
- }
-
- req.Header.Set("Accept", config.ActivityStreams)
-
- resp, err := util.RouteProxy(req)
- if err != nil {
- return respCollection, false, err
- }
- defer resp.Body.Close()
-
- body, _ := ioutil.ReadAll(resp.Body)
-
- if err := json.Unmarshal(body, &respCollection); err != nil {
- return respCollection, false, err
- }
-
- if respCollection.AtContext.Context == "https://www.w3.org/ns/activitystreams" && respCollection.OrderedItems[0].Id != "" {
- return respCollection, true, nil
- }
-
- return respCollection, false, nil
-}
-
-func CreateActivity(activityType string, obj activitypub.ObjectBase) (activitypub.Activity, error) {
- var newActivity activitypub.Activity
-
- actor, err := FingerActor(obj.Actor)
- if err != nil {
- return newActivity, err
- }
-
- newActivity.AtContext.Context = "https://www.w3.org/ns/activitystreams"
- newActivity.Type = activityType
- newActivity.Published = obj.Published
- newActivity.Actor = &actor
- newActivity.Object = &obj
-
- for _, e := range obj.To {
- if obj.Actor != e {
- newActivity.To = append(newActivity.To, e)
- }
- }
-
- for _, e := range obj.Cc {
- if obj.Actor != e {
- newActivity.Cc = append(newActivity.Cc, e)
- }
- }
-
- return newActivity, nil
-}
-
-func AddFollowersToActivity(activity activitypub.Activity) (activitypub.Activity, error) {
- activity.To = append(activity.To, activity.Actor.Id)
-
- for _, e := range activity.To {
- aFollowers, err := GetActorCollection(e + "/followers")
- if err != nil {
- return activity, err
- }
-
- for _, k := range aFollowers.Items {
- activity.To = append(activity.To, k.Id)
- }
- }
-
- var nActivity activitypub.Activity
-
- for _, e := range activity.To {
- var alreadyTo = false
- for _, k := range nActivity.To {
- if e == k || e == activity.Actor.Id {
- alreadyTo = true
- }
- }
-
- if !alreadyTo {
- nActivity.To = append(nActivity.To, e)
- }
- }
-
- activity.To = nActivity.To
-
- 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?
-
- obj := activitypub.ObjectBase{Id: "https://fchan.xyz/followers"}
- followers, err := obj.GetCollection()
- if err != nil {
- return err
- }
-
- var alreadyIndex = false
- for _, e := range followers.Items {
- if e.Id == nActor.Id {
- alreadyIndex = true
- }
- }
-
- if !alreadyIndex {
- actor := activitypub.Actor{Id: "https://fchan.xyz"}
- return actor.AddFollower(nActor.Id)
- }
-
- return nil
-}
-
-func MakeActivityFollowingReq(w http.ResponseWriter, r *http.Request, activity activitypub.Activity) (bool, error) {
- actor, err := GetActor(activity.Object.Id)
- if err != nil {
- return false, err
- }
-
- req, err := http.NewRequest("POST", actor.Inbox, nil)
- if err != nil {
- return false, err
- }
-
- resp, err := util.RouteProxy(req)
- if err != nil {
- return false, err
- }
- defer resp.Body.Close()
-
- body, _ := ioutil.ReadAll(resp.Body)
-
- var respActivity activitypub.Activity
-
- err = json.Unmarshal(body, &respActivity)
- return respActivity.Type == "Accept", err
-}