diff options
author | FChannel <> | 2022-05-08 14:57:40 -0700 |
---|---|---|
committer | FChannel <> | 2022-06-19 12:53:29 -0700 |
commit | 580dec5b89215310ce34341e11ff17fe38bdb63a (patch) | |
tree | 894424df66a9d9f7e41805822f29adac8fb490fe /activitypub/activity.go | |
parent | f7bf818d29393ceaccf4d2906557351fa6a4f49f (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.go | 343 |
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") +} |