kopia lustrzana https://github.com/reiver/greatape
feat(app): ✨ improve federation
rodzic
39e4ae766e
commit
856480989c
|
@ -0,0 +1,34 @@
|
|||
package activitypub
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Follow struct {
|
||||
Context string `json:"@context" validate:"activitystream"`
|
||||
Id string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Actor string `json:"actor"`
|
||||
Object string `json:"object"`
|
||||
}
|
||||
|
||||
func NewFollow(follower, followee, uuid string) *Follow {
|
||||
return &Follow{
|
||||
Context: ActivityStreams,
|
||||
Id: fmt.Sprintf("%s#follow/%s", follower, uuid),
|
||||
Type: TypeFollow,
|
||||
Actor: follower,
|
||||
Object: followee,
|
||||
}
|
||||
}
|
||||
|
||||
func UnmarshalFollow(data []byte) (Follow, error) {
|
||||
var follow Follow
|
||||
err := json.Unmarshal(data, &follow)
|
||||
return follow, err
|
||||
}
|
||||
|
||||
func (follow *Follow) Marshal() ([]byte, error) {
|
||||
return json.Marshal(follow)
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/reiver/greatape/app/activitypub"
|
||||
|
@ -26,20 +24,62 @@ func FollowActor(x IDispatcher, username string, acct string) (IFollowActorResul
|
|||
webfinger, err := activitypub.UnmarshalWebfinger(data)
|
||||
x.AssertNoError(err)
|
||||
|
||||
template := ""
|
||||
subject := ""
|
||||
for _, link := range webfinger.Links {
|
||||
if link.Rel == OSTATUS_SUBSCRIPTION {
|
||||
template = *link.Template
|
||||
if link.Rel == "self" {
|
||||
subject = *link.Href
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if template == "" {
|
||||
return nil, fmt.Errorf("remote_account_lookup_failed")
|
||||
if x.IsEmpty(subject) {
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
|
||||
uri := url.QueryEscape(x.Format("%s/u/%s", x.PublicUrl(), username))
|
||||
template = strings.Replace(template, "{uri}", uri, -1)
|
||||
identities := x.FilterIdentities(func(identity IIdentity) bool {
|
||||
return identity.Username() == username
|
||||
})
|
||||
|
||||
return x.NewFollowActorResult(template), nil
|
||||
x.Assert(identities.HasExactlyOneItem()).Or(ERROR_USER_NOT_FOUND)
|
||||
identity := identities.First()
|
||||
|
||||
follower := x.GetActorId()
|
||||
|
||||
followee := &activitypub.Actor{}
|
||||
if err := x.GetActivityStreamSigned(subject, nil, followee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uniqueIdentifier := x.GenerateUUID()
|
||||
follow := activitypub.NewFollow(follower, followee.ID, uniqueIdentifier)
|
||||
|
||||
x.Atomic(func() error {
|
||||
activity := x.MarshalJson(follow)
|
||||
|
||||
x.AddActivityPubOutgoingActivity(
|
||||
identity.Id(),
|
||||
uniqueIdentifier,
|
||||
x.UnixNano(),
|
||||
follower,
|
||||
followee.ID,
|
||||
activitypub.TypeFollow,
|
||||
activity,
|
||||
)
|
||||
|
||||
x.AddActivityPubFollower(
|
||||
follower,
|
||||
followee.Inbox,
|
||||
followee.ID,
|
||||
activity,
|
||||
false,
|
||||
)
|
||||
|
||||
if err := x.PostActivityStreamSigned(followee.Inbox, follow, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return x.NewFollowActorResult(follow.Id), nil
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/reiver/greatape/app/activitypub"
|
||||
. "github.com/reiver/greatape/components/constants"
|
||||
. "github.com/reiver/greatape/components/contracts"
|
||||
|
@ -18,54 +15,72 @@ func PostToInbox(x IDispatcher, username string, body []byte) (IPostToInboxResul
|
|||
identity := identities.First()
|
||||
|
||||
object := &activitypub.Object{}
|
||||
if err := json.Unmarshal(body, object); err != nil {
|
||||
return nil, ERROR_UNKNOWN_ACTIVITY_PUB_OBJECT
|
||||
}
|
||||
|
||||
keyId := x.Format("%s/u/%s#main-key", x.PublicUrl(), username)
|
||||
x.UnmarshalJson(body, object)
|
||||
|
||||
switch object.Type {
|
||||
case activitypub.TypeFollow:
|
||||
case activitypub.TypeAccept:
|
||||
{
|
||||
activity := &activitypub.Activity{}
|
||||
if err := json.Unmarshal(body, activity); err != nil {
|
||||
return nil, ERROR_UNKNOWN_ACTIVITY_PUB_ACTIVITY
|
||||
x.UnmarshalJson(body, activity)
|
||||
|
||||
switch activity.Object.(map[string]interface{})["type"] {
|
||||
case activitypub.TypeFollow:
|
||||
follow := &activitypub.Follow{}
|
||||
x.DecodeMapStructure(activity.Object, follow)
|
||||
|
||||
x.Atomic(func() error {
|
||||
x.ForEachActivityPubFollower(func(record IActivityPubFollower) {
|
||||
if record.Handle() == follow.Actor && record.Subject() == follow.Object {
|
||||
record.UpdateAcceptedAtomic(x.Transaction(), true, x.Identity())
|
||||
}
|
||||
})
|
||||
|
||||
x.AddActivityPubIncomingActivity(
|
||||
identity.Id(),
|
||||
x.GenerateUUID(),
|
||||
x.UnixNano(),
|
||||
follow.Object,
|
||||
follow.Actor,
|
||||
activitypub.TypeAccept,
|
||||
string(body),
|
||||
)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
default:
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
}
|
||||
case activitypub.TypeFollow:
|
||||
{
|
||||
follow := &activitypub.Follow{}
|
||||
x.UnmarshalJson(body, follow)
|
||||
|
||||
url := activity.Actor
|
||||
var inbox string
|
||||
url := follow.Actor
|
||||
|
||||
{
|
||||
actor := &activitypub.Actor{}
|
||||
if err := x.GetActivityStreamSigned(url, keyId, identity.PrivateKey(), nil, actor); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inbox = actor.Inbox
|
||||
}
|
||||
|
||||
data, err := json.Marshal(activity)
|
||||
if err != nil {
|
||||
actor := &activitypub.Actor{}
|
||||
if err := x.GetActivityStreamSigned(url, nil, actor); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
follower := x.AddActivityPubFollower(
|
||||
activity.Actor,
|
||||
inbox,
|
||||
follow.Actor,
|
||||
actor.Inbox,
|
||||
x.Format("%s/u/%s", x.PublicUrl(), username),
|
||||
string(data),
|
||||
x.MarshalJson(follow),
|
||||
false,
|
||||
)
|
||||
|
||||
data, _ = json.Marshal(&activitypub.Activity{
|
||||
activity := &activitypub.Activity{
|
||||
Context: activitypub.ActivityStreams,
|
||||
ID: x.Format("%s/%s", x.PublicUrl(), x.GenerateUUID()),
|
||||
Type: activitypub.TypeAccept,
|
||||
Actor: x.Format("%s/u/%s", x.PublicUrl(), username),
|
||||
Object: activity,
|
||||
})
|
||||
Object: follow,
|
||||
}
|
||||
|
||||
if err := x.PostActivityStreamSigned(inbox, keyId, identity.PrivateKey(), data, nil); err != nil {
|
||||
if err := x.PostActivityStreamSigned(actor.Inbox, activity, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -74,18 +89,12 @@ func PostToInbox(x IDispatcher, username string, body []byte) (IPostToInboxResul
|
|||
case activitypub.TypeCreate:
|
||||
{
|
||||
activity := &activitypub.Activity{}
|
||||
if err := json.Unmarshal(body, activity); err != nil {
|
||||
return nil, ERROR_UNKNOWN_ACTIVITY_PUB_ACTIVITY
|
||||
}
|
||||
x.UnmarshalJson(body, activity)
|
||||
|
||||
switch activity.Object.(map[string]interface{})["type"] {
|
||||
case activitypub.TypeNote:
|
||||
note := &activitypub.Note{}
|
||||
if err := mapstructure.Decode(activity.Object, note); err != nil {
|
||||
return nil, ERROR_UNKNOWN_ACTIVITY_PUB_ACTIVITY
|
||||
}
|
||||
|
||||
raw, _ := json.Marshal(note)
|
||||
x.DecodeMapStructure(activity.Object, note)
|
||||
|
||||
x.AddActivityPubIncomingActivity(
|
||||
identity.Id(),
|
||||
|
@ -94,16 +103,14 @@ func PostToInbox(x IDispatcher, username string, body []byte) (IPostToInboxResul
|
|||
note.AttributedTo,
|
||||
note.To[0],
|
||||
note.Content,
|
||||
string(raw),
|
||||
string(body),
|
||||
)
|
||||
default:
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
|
||||
return x.NewPostToInboxResult(body), nil
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
ap "github.com/go-ap/activitypub"
|
||||
"github.com/reiver/greatape/app/activitypub"
|
||||
. "github.com/reiver/greatape/components/constants"
|
||||
. "github.com/reiver/greatape/components/contracts"
|
||||
|
@ -21,21 +19,21 @@ func PostToOutbox(x IDispatcher, username string, body []byte) (IPostToOutboxRes
|
|||
|
||||
item := x.UnmarshalActivityPubObjectOrLink(body)
|
||||
|
||||
id := x.Format("%s/u/%s", x.PublicUrl(), identity.Username())
|
||||
|
||||
publicKeyId := x.Format("%s#main-key", id)
|
||||
privateKey := identity.PrivateKey()
|
||||
actorId := x.GetActorId()
|
||||
|
||||
switch item.GetType() {
|
||||
case ap.NoteType:
|
||||
case activitypub.TypeNote:
|
||||
{
|
||||
note := x.UnmarshalActivityPubNote(body)
|
||||
note, err := activitypub.UnmarshalNote(body)
|
||||
if err != nil {
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
|
||||
content := note.Content.First().Value.String()
|
||||
to := note.To.First().GetID().String()
|
||||
from := note.AttributedTo.GetID().String()
|
||||
content := note.Content
|
||||
to := note.To[0]
|
||||
from := note.AttributedTo
|
||||
|
||||
if from != id {
|
||||
if from != actorId {
|
||||
return nil, ERROR_INVALID_PARAMETERS
|
||||
}
|
||||
|
||||
|
@ -51,23 +49,19 @@ func PostToOutbox(x IDispatcher, username string, body []byte) (IPostToOutboxRes
|
|||
Object: note,
|
||||
}
|
||||
|
||||
if to != activitypub.Public {
|
||||
if to != ACTIVITY_PUB_PUBLIC {
|
||||
recipient := &activitypub.Actor{}
|
||||
if err := x.GetActivityStreamSigned(to, publicKeyId, privateKey, nil, recipient); err != nil {
|
||||
if err := x.GetActivityStreamSigned(to, nil, recipient); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
to = recipient.ID
|
||||
|
||||
data, _ := json.Marshal(activity)
|
||||
output := &struct{}{}
|
||||
if err := x.PostActivityStreamSigned(recipient.Inbox, publicKeyId, privateKey, data, output); err != nil {
|
||||
if err := x.PostActivityStreamSigned(recipient.Inbox, activity, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
raw, _ := json.Marshal(note)
|
||||
|
||||
x.LogActivityPubOutgoingActivity(
|
||||
identity.Id(),
|
||||
uniqueIdentifier,
|
||||
|
@ -75,7 +69,7 @@ func PostToOutbox(x IDispatcher, username string, body []byte) (IPostToOutboxRes
|
|||
from,
|
||||
to,
|
||||
content,
|
||||
string(raw),
|
||||
string(body),
|
||||
"PostToOutbox",
|
||||
EMPTY_JSON,
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue