aboutsummaryrefslogtreecommitdiff
path: root/activitypub/activity.go
diff options
context:
space:
mode:
authorFChannel <>2022-05-08 14:57:40 -0700
committerFChannel <>2022-06-19 12:53:29 -0700
commit580dec5b89215310ce34341e11ff17fe38bdb63a (patch)
tree894424df66a9d9f7e41805822f29adac8fb490fe /activitypub/activity.go
parentf7bf818d29393ceaccf4d2906557351fa6a4f49f (diff)
more cleanup, logging and error logging everywhere
things are mostly in place can work on "features" and polish
Diffstat (limited to 'activitypub/activity.go')
-rw-r--r--activitypub/activity.go343
1 files changed, 330 insertions, 13 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")
+}