mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 15:42:24 -05:00
[feature] Forward-compatibility with Approval objects (#3807)
* vendor * [feature] Forward-compatibility with Approval objects * vendor the thing * fix leetle bug * lil syntax tweak for beloved kimb
This commit is contained in:
parent
e220c6a894
commit
96716e4f43
125 changed files with 20960 additions and 2964 deletions
|
|
@ -20,6 +20,7 @@ package federatingdb
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
|
|
@ -62,8 +63,8 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
|
|||
return nil
|
||||
}
|
||||
|
||||
activityID := ap.GetJSONLDId(accept)
|
||||
if activityID == nil {
|
||||
acceptID := ap.GetJSONLDId(accept)
|
||||
if acceptID == nil {
|
||||
// We need an ID.
|
||||
const text = "Accept had no id property"
|
||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
|
|
@ -87,12 +88,11 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
|
|||
// handling the ones we know how to handle.
|
||||
for _, object := range ap.ExtractObjects(accept) {
|
||||
if asType := object.GetType(); asType != nil {
|
||||
|
||||
// Check and handle any vocab.Type objects.
|
||||
switch name := asType.GetTypeName(); name {
|
||||
switch name := asType.GetTypeName(); {
|
||||
|
||||
// ACCEPT FOLLOW
|
||||
case ap.ActivityFollow:
|
||||
case name == ap.ActivityFollow:
|
||||
if err := f.acceptFollowType(
|
||||
ctx,
|
||||
asType,
|
||||
|
|
@ -102,6 +102,50 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
|
|||
return err
|
||||
}
|
||||
|
||||
// ACCEPT TYPE-HINTED LIKE
|
||||
//
|
||||
// ie., a Like with just `id`
|
||||
// and `type` properties set.
|
||||
case name == ap.ActivityLike:
|
||||
objIRI := ap.GetJSONLDId(asType)
|
||||
if objIRI == nil {
|
||||
log.Debugf(ctx, "could not retrieve id of inlined Accept object %s", name)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := f.acceptLikeIRI(
|
||||
ctx,
|
||||
acceptID,
|
||||
accept,
|
||||
objIRI.String(),
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ACCEPT TYPE-HINTED REPLY OR ANNOUNCE.
|
||||
//
|
||||
// ie., a statusable or Announce with
|
||||
// just `id` and `type` properties set.
|
||||
case name == ap.ActivityAnnounce || ap.IsStatusable(name):
|
||||
objIRI := ap.GetJSONLDId(asType)
|
||||
if objIRI == nil {
|
||||
log.Debugf(ctx, "could not retrieve id of inlined Accept object %s", name)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := f.acceptOtherIRI(
|
||||
ctx,
|
||||
acceptID,
|
||||
accept,
|
||||
objIRI,
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// UNHANDLED
|
||||
default:
|
||||
log.Debugf(ctx, "unhandled object type: %s", name)
|
||||
|
|
@ -127,7 +171,8 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
|
|||
case uris.IsLikePath(objIRI):
|
||||
if err := f.acceptLikeIRI(
|
||||
ctx,
|
||||
activityID.String(),
|
||||
acceptID,
|
||||
accept,
|
||||
objIRI.String(),
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
|
|
@ -135,14 +180,15 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
|
|||
return err
|
||||
}
|
||||
|
||||
// ACCEPT OTHER (reply? boost?)
|
||||
// ACCEPT OTHER (reply? announce?)
|
||||
//
|
||||
// Don't check on IsStatusesPath
|
||||
// as this may be a remote status.
|
||||
default:
|
||||
if err := f.acceptOtherIRI(
|
||||
ctx,
|
||||
activityID,
|
||||
acceptID,
|
||||
accept,
|
||||
objIRI,
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
|
|
@ -292,7 +338,8 @@ func (f *federatingDB) acceptFollowIRI(
|
|||
|
||||
func (f *federatingDB) acceptOtherIRI(
|
||||
ctx context.Context,
|
||||
activityID *url.URL,
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
objectIRI *url.URL,
|
||||
receivingAcct *gtsmodel.Account,
|
||||
requestingAcct *gtsmodel.Account,
|
||||
|
|
@ -309,7 +356,8 @@ func (f *federatingDB) acceptOtherIRI(
|
|||
// objectIRI, proceed to accept it.
|
||||
return f.acceptStoredStatus(
|
||||
ctx,
|
||||
activityID,
|
||||
acceptID,
|
||||
accept,
|
||||
status,
|
||||
receivingAcct,
|
||||
requestingAcct,
|
||||
|
|
@ -348,13 +396,21 @@ func (f *federatingDB) acceptOtherIRI(
|
|||
// This may be a reply, or it may be a boost,
|
||||
// we can't know yet without dereferencing it,
|
||||
// but let the processor worry about that.
|
||||
//
|
||||
// TODO: do something with type hinting here.
|
||||
apObjectType := ap.ObjectUnknown
|
||||
|
||||
// Extract appropriate approvedByURI from the Accept.
|
||||
approvedByURI, err := approvedByURI(acceptID, accept)
|
||||
if err != nil {
|
||||
return gtserror.NewErrorForbidden(err, err.Error())
|
||||
}
|
||||
|
||||
// Pass to the processor and let them handle side effects.
|
||||
f.state.Workers.Federator.Queue.Push(&messages.FromFediAPI{
|
||||
APObjectType: apObjectType,
|
||||
APActivityType: ap.ActivityAccept,
|
||||
APIRI: activityID,
|
||||
APIRI: approvedByURI,
|
||||
APObject: objectIRI,
|
||||
Receiving: receivingAcct,
|
||||
Requesting: requestingAcct,
|
||||
|
|
@ -365,7 +421,8 @@ func (f *federatingDB) acceptOtherIRI(
|
|||
|
||||
func (f *federatingDB) acceptStoredStatus(
|
||||
ctx context.Context,
|
||||
activityID *url.URL,
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
status *gtsmodel.Status,
|
||||
receivingAcct *gtsmodel.Account,
|
||||
requestingAcct *gtsmodel.Account,
|
||||
|
|
@ -391,9 +448,15 @@ func (f *federatingDB) acceptStoredStatus(
|
|||
return gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// Mark the status as approved by this Accept URI.
|
||||
// Extract appropriate approvedByURI from the Accept.
|
||||
approvedByURI, err := approvedByURI(acceptID, accept)
|
||||
if err != nil {
|
||||
return gtserror.NewErrorForbidden(err, err.Error())
|
||||
}
|
||||
|
||||
// Mark the status as approved by this URI.
|
||||
status.PendingApproval = util.Ptr(false)
|
||||
status.ApprovedByURI = activityID.String()
|
||||
status.ApprovedByURI = approvedByURI.String()
|
||||
if err := f.state.DB.UpdateStatus(
|
||||
ctx,
|
||||
status,
|
||||
|
|
@ -428,7 +491,8 @@ func (f *federatingDB) acceptStoredStatus(
|
|||
|
||||
func (f *federatingDB) acceptLikeIRI(
|
||||
ctx context.Context,
|
||||
activityID string,
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
objectIRI string,
|
||||
receivingAcct *gtsmodel.Account,
|
||||
requestingAcct *gtsmodel.Account,
|
||||
|
|
@ -482,9 +546,15 @@ func (f *federatingDB) acceptLikeIRI(
|
|||
return gtserror.NewErrorForbidden(errors.New(text), text)
|
||||
}
|
||||
|
||||
// Mark the fave as approved by this Accept URI.
|
||||
// Extract appropriate approvedByURI from the Accept.
|
||||
approvedByURI, err := approvedByURI(acceptID, accept)
|
||||
if err != nil {
|
||||
return gtserror.NewErrorForbidden(err, err.Error())
|
||||
}
|
||||
|
||||
// Mark the fave as approved by this URI.
|
||||
fave.PendingApproval = util.Ptr(false)
|
||||
fave.ApprovedByURI = activityID
|
||||
fave.ApprovedByURI = approvedByURI.String()
|
||||
if err := f.state.DB.UpdateStatusFave(
|
||||
ctx,
|
||||
fave,
|
||||
|
|
@ -507,3 +577,72 @@ func (f *federatingDB) acceptLikeIRI(
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// approvedByURI extracts the appropriate *url.URL
|
||||
// to use as an interaction's approvedBy value by
|
||||
// checking to see if the Accept has a result URL set.
|
||||
// If that result URL exists, is an IRI (not a type),
|
||||
// and is on the same host as the Accept ID, then the
|
||||
// result URI will be returned. In all other cases,
|
||||
// the Accept ID is returned unchanged.
|
||||
//
|
||||
// Error is only returned if the result URI is set
|
||||
// but the host differs from the Accept ID host.
|
||||
//
|
||||
// TODO: This function should be updated at some point
|
||||
// to check for inlined result type, and see if type is
|
||||
// a LikeApproval, ReplyApproval, or AnnounceApproval,
|
||||
// and check the attributedTo, object, and target of
|
||||
// the approval as well. But this'll do for now.
|
||||
func approvedByURI(
|
||||
acceptID *url.URL,
|
||||
accept vocab.ActivityStreamsAccept,
|
||||
) (*url.URL, error) {
|
||||
// Check if the Accept has a `result` property
|
||||
// set on it (which should be an approval).
|
||||
resultProp := accept.GetActivityStreamsResult()
|
||||
if resultProp == nil {
|
||||
// No result,
|
||||
// use AcceptID.
|
||||
return acceptID, nil
|
||||
}
|
||||
|
||||
if resultProp.Len() != 1 {
|
||||
// Result was unexpected
|
||||
// length, can't use this.
|
||||
return acceptID, nil
|
||||
}
|
||||
|
||||
result := resultProp.At(0)
|
||||
if result == nil {
|
||||
// Result entry
|
||||
// was nil, huh!
|
||||
return acceptID, nil
|
||||
}
|
||||
|
||||
if !result.IsIRI() {
|
||||
// Can't handle
|
||||
// inlined yet.
|
||||
return acceptID, nil
|
||||
}
|
||||
|
||||
resultIRI := result.GetIRI()
|
||||
if resultIRI == nil {
|
||||
// Result entry
|
||||
// was nil, huh!
|
||||
return acceptID, nil
|
||||
}
|
||||
|
||||
if resultIRI.Host != acceptID.Host {
|
||||
// What the boobs is this?
|
||||
err := fmt.Errorf(
|
||||
"host of result %s differed from host of Accept %s",
|
||||
resultIRI, accept,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use the result IRI we've been
|
||||
// given instead of the acceptID.
|
||||
return resultIRI, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue