diff options
Diffstat (limited to 'internal/message/fromclientapiprocess.go')
-rw-r--r-- | internal/message/fromclientapiprocess.go | 217 |
1 files changed, 180 insertions, 37 deletions
diff --git a/internal/message/fromclientapiprocess.go b/internal/message/fromclientapiprocess.go index 1a12216e7..e91bd6ce4 100644 --- a/internal/message/fromclientapiprocess.go +++ b/internal/message/fromclientapiprocess.go @@ -19,55 +19,198 @@ package message import ( + "context" "errors" "fmt" + "net/url" + "github.com/go-fed/activity/streams" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error { - switch clientMsg.APObjectType { - case gtsmodel.ActivityStreamsNote: - status, ok := clientMsg.GTSModel.(*gtsmodel.Status) - if !ok { - return errors.New("note was not parseable as *gtsmodel.Status") - } + switch clientMsg.APActivityType { + case gtsmodel.ActivityStreamsCreate: + // CREATE + switch clientMsg.APObjectType { + case gtsmodel.ActivityStreamsNote: + // CREATE NOTE + status, ok := clientMsg.GTSModel.(*gtsmodel.Status) + if !ok { + return errors.New("note was not parseable as *gtsmodel.Status") + } - if err := p.notifyStatus(status); err != nil { - return err - } + if err := p.notifyStatus(status); err != nil { + return err + } + + if status.VisibilityAdvanced.Federated { + return p.federateStatus(status) + } + return nil + case gtsmodel.ActivityStreamsFollow: + // CREATE FOLLOW (request) + follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) + if !ok { + return errors.New("follow was not parseable as *gtsmodel.Follow") + } + + if err := p.notifyFollow(follow); err != nil { + return err + } - if status.VisibilityAdvanced.Federated { - return p.federateStatus(status) + return p.federateFollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) + } + case gtsmodel.ActivityStreamsUpdate: + // UPDATE + case gtsmodel.ActivityStreamsAccept: + // ACCEPT + switch clientMsg.APObjectType { + case gtsmodel.ActivityStreamsFollow: + // ACCEPT FOLLOW + follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) + if !ok { + return errors.New("accept was not parseable as *gtsmodel.Follow") + } + return p.federateAcceptFollowRequest(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) + } + case gtsmodel.ActivityStreamsUndo: + // UNDO + switch clientMsg.APObjectType { + case gtsmodel.ActivityStreamsFollow: + // UNDO FOLLOW + follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow) + if !ok { + return errors.New("undo was not parseable as *gtsmodel.Follow") + } + return p.federateUnfollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) } - return nil } - return fmt.Errorf("message type unprocessable: %+v", clientMsg) + return nil } func (p *processor) federateStatus(status *gtsmodel.Status) error { - // // derive the sending account -- it might be attached to the status already - // sendingAcct := >smodel.Account{} - // if status.GTSAccount != nil { - // sendingAcct = status.GTSAccount - // } else { - // // it wasn't attached so get it from the db instead - // if err := p.db.GetByID(status.AccountID, sendingAcct); err != nil { - // return err - // } - // } - - // outboxURI, err := url.Parse(sendingAcct.OutboxURI) - // if err != nil { - // return err - // } - - // // convert the status to AS format Note - // note, err := p.tc.StatusToAS(status) - // if err != nil { - // return err - // } - - // _, err = p.federator.FederatingActor().Send(context.Background(), outboxURI, note) - return nil + asStatus, err := p.tc.StatusToAS(status) + if err != nil { + return fmt.Errorf("federateStatus: error converting status to as format: %s", err) + } + + outboxIRI, err := url.Parse(status.GTSAccount.OutboxURI) + if err != nil { + return fmt.Errorf("federateStatus: error parsing outboxURI %s: %s", status.GTSAccount.OutboxURI, err) + } + + _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asStatus) + return err +} + +func (p *processor) federateFollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { + // if both accounts are local there's nothing to do here + if originAccount.Domain == "" && targetAccount.Domain == "" { + return nil + } + + asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + if err != nil { + return fmt.Errorf("federateFollow: error converting follow to as format: %s", err) + } + + outboxIRI, err := url.Parse(originAccount.OutboxURI) + if err != nil { + return fmt.Errorf("federateFollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) + } + + _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asFollow) + return err +} + +func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { + // if both accounts are local there's nothing to do here + if originAccount.Domain == "" && targetAccount.Domain == "" { + return nil + } + + // recreate the follow + asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + if err != nil { + return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) + } + + targetAccountURI, err := url.Parse(targetAccount.URI) + if err != nil { + return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) + } + + // create an Undo and set the appropriate actor on it + undo := streams.NewActivityStreamsUndo() + undo.SetActivityStreamsActor(asFollow.GetActivityStreamsActor()) + + // Set the recreated follow as the 'object' property. + undoObject := streams.NewActivityStreamsObjectProperty() + undoObject.AppendActivityStreamsFollow(asFollow) + undo.SetActivityStreamsObject(undoObject) + + // Set the To of the undo as the target of the recreated follow + undoTo := streams.NewActivityStreamsToProperty() + undoTo.AppendIRI(targetAccountURI) + undo.SetActivityStreamsTo(undoTo) + + outboxIRI, err := url.Parse(originAccount.OutboxURI) + if err != nil { + return fmt.Errorf("federateUnfollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) + } + + // send off the Undo + _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) + return err +} + +func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { + // if both accounts are local there's nothing to do here + if originAccount.Domain == "" && targetAccount.Domain == "" { + return nil + } + + // recreate the AS follow + asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + if err != nil { + return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) + } + + acceptingAccountURI, err := url.Parse(targetAccount.URI) + if err != nil { + return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) + } + + requestingAccountURI, err := url.Parse(originAccount.URI) + if err != nil { + return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err) + } + + // create an Accept + accept := streams.NewActivityStreamsAccept() + + // set the accepting actor on it + acceptActorProp := streams.NewActivityStreamsActorProperty() + acceptActorProp.AppendIRI(acceptingAccountURI) + accept.SetActivityStreamsActor(acceptActorProp) + + // Set the recreated follow as the 'object' property. + acceptObject := streams.NewActivityStreamsObjectProperty() + acceptObject.AppendActivityStreamsFollow(asFollow) + accept.SetActivityStreamsObject(acceptObject) + + // Set the To of the accept as the originator of the follow + acceptTo := streams.NewActivityStreamsToProperty() + acceptTo.AppendIRI(requestingAccountURI) + accept.SetActivityStreamsTo(acceptTo) + + outboxIRI, err := url.Parse(targetAccount.OutboxURI) + if err != nil { + return fmt.Errorf("federateAcceptFollowRequest: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) + } + + // send off the accept using the accepter's outbox + _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, accept) + return err } |