161 lines
4.3 KiB
Go
161 lines
4.3 KiB
Go
package federation
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"pocketbase/util"
|
|
"time"
|
|
|
|
pub "github.com/go-ap/activitypub"
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
"github.com/pocketbase/pocketbase/tools/security"
|
|
)
|
|
|
|
// create outgoing follow activity
|
|
func CreateFollowActivity(app core.App, follow *core.Record) error {
|
|
origin := os.Getenv("ORIGIN")
|
|
if origin == "" {
|
|
return fmt.Errorf("ORIGIN not set")
|
|
}
|
|
|
|
follower := follow.GetString("follower")
|
|
followee := follow.GetString("followee")
|
|
|
|
followerActor, err := app.FindRecordById("activitypub_actors", follower)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
followeeActor, err := app.FindRecordById("activitypub_actors", followee)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
|
|
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
|
|
|
activity := pub.FollowNew(pub.IRI(id), pub.IRI(followeeActor.GetString("iri")))
|
|
activity.Actor = pub.IRI(followerActor.GetString("iri"))
|
|
|
|
err = PostActivity(app, followerActor, activity, []string{followeeActor.GetString("inbox")})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
record := core.NewRecord(collection)
|
|
record.Set("id", recordId)
|
|
record.Set("iri", id)
|
|
record.Set("type", string(pub.FollowType))
|
|
record.Set("object", followeeActor.GetString("iri"))
|
|
record.Set("actor", followerActor.GetString("iri"))
|
|
record.Set("published", time.Now())
|
|
|
|
return app.Save(record)
|
|
}
|
|
|
|
// process incoming follow activity
|
|
func ProcessFollowActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
|
origin := os.Getenv("ORIGIN")
|
|
if origin == "" {
|
|
return fmt.Errorf("ORIGIN not set")
|
|
}
|
|
|
|
// find the followee in our db
|
|
object, err := app.FindFirstRecordByData("activitypub_actors", "iri", activity.Object)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// a remote actor has requested the follow
|
|
// this means we have not yet created a follow entry in our db
|
|
// we accept it immediately
|
|
if !actor.GetBool("isLocal") {
|
|
followCollection, err := app.FindCollectionByNameOrId("follows")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
followRecord := core.NewRecord(followCollection)
|
|
followRecord.Set("follower", actor.Id)
|
|
followRecord.Set("followee", object.Id)
|
|
followRecord.Set("status", "accepted")
|
|
err = app.Save(followRecord)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
|
|
|
// send the accept activity back to the actor's inbox
|
|
acceptActivity := pub.AcceptNew(pub.IRI(id), activity)
|
|
acceptActivity.Actor = activity.Object
|
|
err = PostActivity(app, object, acceptActivity, []string{actor.GetString("inbox")})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// create record of the accept activity in our db
|
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
record := core.NewRecord(collection)
|
|
record.Set("id", recordId)
|
|
record.Set("iri", id)
|
|
record.Set("type", string(pub.AcceptType))
|
|
record.Set("object", activity)
|
|
record.Set("actor", object.GetString("iri"))
|
|
record.Set("published", time.Now())
|
|
|
|
err = app.Save(record)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// send a notification to the followee
|
|
notification := util.Notification{
|
|
Type: util.NewFollower,
|
|
Metadata: map[string]string{
|
|
"follower": fmt.Sprintf("@%s@%s", actor.GetString("preferred_username"), actor.GetString("domain")),
|
|
},
|
|
Seen: false,
|
|
Author: actor.Id,
|
|
}
|
|
return util.SendNotification(app, notification, object)
|
|
|
|
}
|
|
|
|
func ProcessAcceptActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
|
|
|
followActivity := activity.Object.(*pub.Activity)
|
|
|
|
follower, err := app.FindFirstRecordByData("activitypub_actors", "iri", followActivity.Actor)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
follow, err := app.FindFirstRecordByFilter("follows", "follower={:follower} && followee={:followee}", dbx.Params{"follower": follower.Id, "followee": actor.Id})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
follow.Set("status", "accepted")
|
|
err = app.Save(follow)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// err = util.SyncOutbox(app, actor)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
return nil
|
|
}
|