mirror of
				https://github.com/superseriousbusiness/gotosocial
				synced 2025-06-05 21:59:39 +02:00 
			
		
		
		
	federate account updates
This commit is contained in:
		@@ -120,6 +120,12 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
 | 
			
		||||
			return fmt.Errorf("error converting to account: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if updatedAcct.Domain == f.config.Host {
 | 
			
		||||
			// no need to update local accounts
 | 
			
		||||
			// in fact, if we do this will break the shit out of things so do NOT
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if requestingAcct.URI != updatedAcct.URI {
 | 
			
		||||
			return fmt.Errorf("update for account %s was requested by account %s, this is not valid", updatedAcct.URI, requestingAcct.URI)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -143,6 +143,19 @@ func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err
 | 
			
		||||
				return idProp.GetIRI(), nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case gtsmodel.ActivityStreamsUpdate:
 | 
			
		||||
		// UPDATE
 | 
			
		||||
		// ID might already be set on an update we've created, so check it here and return it if it is
 | 
			
		||||
		update, ok := t.(vocab.ActivityStreamsUpdate)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, errors.New("newid: fave couldn't be parsed into vocab.ActivityStreamsUpdate")
 | 
			
		||||
		}
 | 
			
		||||
		idProp := update.GetJSONLDId()
 | 
			
		||||
		if idProp != nil {
 | 
			
		||||
			if idProp.IsIRI() {
 | 
			
		||||
				return idProp.GetIRI(), nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// fallback default behavior: just return a random UUID after our protocol and host
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +188,13 @@ func (p *processor) AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCrede
 | 
			
		||||
		return nil, fmt.Errorf("could not fetch updated account %s: %s", authed.Account.ID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.fromClientAPI <- gtsmodel.FromClientAPI{
 | 
			
		||||
		APObjectType:   gtsmodel.ActivityStreamsProfile,
 | 
			
		||||
		APActivityType: gtsmodel.ActivityStreamsUpdate,
 | 
			
		||||
		GTSModel:       updatedAccount,
 | 
			
		||||
		OriginAccount:  updatedAccount,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	acctSensitive, err := p.tc.AccountToMastoSensitive(updatedAccount)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("could not convert account into mastosensitive account: %s", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -88,6 +88,16 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
 | 
			
		||||
		}
 | 
			
		||||
	case gtsmodel.ActivityStreamsUpdate:
 | 
			
		||||
		// UPDATE
 | 
			
		||||
		switch clientMsg.APObjectType {
 | 
			
		||||
		case gtsmodel.ActivityStreamsProfile, gtsmodel.ActivityStreamsPerson:
 | 
			
		||||
			// UPDATE ACCOUNT/PROFILE
 | 
			
		||||
			account, ok := clientMsg.GTSModel.(*gtsmodel.Account)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return errors.New("account was not parseable as *gtsmodel.Account")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return p.federateAccountUpdate(account, clientMsg.OriginAccount)
 | 
			
		||||
		}
 | 
			
		||||
	case gtsmodel.ActivityStreamsAccept:
 | 
			
		||||
		// ACCEPT
 | 
			
		||||
		switch clientMsg.APObjectType {
 | 
			
		||||
@@ -277,7 +287,27 @@ func (p *processor) federateAnnounce(boostWrapperStatus *gtsmodel.Status, boosti
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("federateAnnounce: error parsing outboxURI %s: %s", boostingAccount.OutboxURI, err)
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, announce)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *processor) federateAccountUpdate(updatedAccount *gtsmodel.Account, originAccount *gtsmodel.Account) error {
 | 
			
		||||
	person, err := p.tc.AccountToAS(updatedAccount)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("federateAccountUpdate: error converting account to person: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	update, err := p.tc.WrapPersonInUpdate(person, originAccount)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("federateAccountUpdate: error wrapping person in update: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	outboxIRI, err := url.Parse(originAccount.OutboxURI)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("federateAnnounce: error parsing outboxURI %s: %s", originAccount.OutboxURI, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, update)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -141,6 +141,13 @@ type TypeConverter interface {
 | 
			
		||||
	FollowRequestToFollow(f *gtsmodel.FollowRequest) *gtsmodel.Follow
 | 
			
		||||
	// StatusToBoost wraps the given status into a boosting status.
 | 
			
		||||
	StatusToBoost(s *gtsmodel.Status, boostingAccount *gtsmodel.Account) (*gtsmodel.Status, error)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		WRAPPER CONVENIENCE FUNCTIONS
 | 
			
		||||
	*/
 | 
			
		||||
	
 | 
			
		||||
	// WrapPersonInUpdate
 | 
			
		||||
	WrapPersonInUpdate(person vocab.ActivityStreamsPerson, originAccount *gtsmodel.Account) (vocab.ActivityStreamsUpdate, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type converter struct {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								internal/typeutils/wrap.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								internal/typeutils/wrap.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
package typeutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-fed/activity/streams"
 | 
			
		||||
	"github.com/go-fed/activity/streams/vocab"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
 | 
			
		||||
	"github.com/superseriousbusiness/gotosocial/internal/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c *converter) WrapPersonInUpdate(person vocab.ActivityStreamsPerson, originAccount *gtsmodel.Account) (vocab.ActivityStreamsUpdate, error) {
 | 
			
		||||
 | 
			
		||||
	update := streams.NewActivityStreamsUpdate()
 | 
			
		||||
 | 
			
		||||
	// set the actor
 | 
			
		||||
	actorURI, err := url.Parse(originAccount.URI)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("WrapPersonInUpdate: error parsing url %s: %s", originAccount.URI, err)
 | 
			
		||||
	}
 | 
			
		||||
	actorProp := streams.NewActivityStreamsActorProperty()
 | 
			
		||||
	actorProp.AppendIRI(actorURI)
 | 
			
		||||
	update.SetActivityStreamsActor(actorProp)
 | 
			
		||||
 | 
			
		||||
	// set the ID
 | 
			
		||||
	idString := util.GenerateURIForUpdate(originAccount.Username, c.config.Protocol, c.config.Host, uuid.NewString())
 | 
			
		||||
	idURI, err := url.Parse(idString)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("WrapPersonInUpdate: error parsing url %s: %s", idString, err)
 | 
			
		||||
	}
 | 
			
		||||
	idProp := streams.NewJSONLDIdProperty()
 | 
			
		||||
	idProp.SetIRI(idURI)
 | 
			
		||||
	update.SetJSONLDId(idProp)
 | 
			
		||||
 | 
			
		||||
	// set the person as the object here
 | 
			
		||||
	objectProp := streams.NewActivityStreamsObjectProperty()
 | 
			
		||||
	objectProp.AppendActivityStreamsPerson(person)
 | 
			
		||||
	update.SetActivityStreamsObject(objectProp)
 | 
			
		||||
 | 
			
		||||
	// to should be public
 | 
			
		||||
	toURI, err := url.Parse(asPublicURI)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("WrapPersonInUpdate: error parsing url %s: %s", asPublicURI, err)
 | 
			
		||||
	}
 | 
			
		||||
	toProp := streams.NewActivityStreamsToProperty()
 | 
			
		||||
	toProp.AppendIRI(toURI)
 | 
			
		||||
	update.SetActivityStreamsTo(toProp)
 | 
			
		||||
 | 
			
		||||
	// bcc followers
 | 
			
		||||
	followersURI, err := url.Parse(originAccount.FollowersURI)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("WrapPersonInUpdate: error parsing url %s: %s", originAccount.FollowersURI, err)
 | 
			
		||||
	}
 | 
			
		||||
	bccProp := streams.NewActivityStreamsBccProperty()
 | 
			
		||||
	bccProp.AppendIRI(followersURI)
 | 
			
		||||
	update.SetActivityStreamsBcc(bccProp)
 | 
			
		||||
 | 
			
		||||
	return update, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -49,6 +49,8 @@ const (
 | 
			
		||||
	PublicKeyPath = "main-key"
 | 
			
		||||
	// FollowPath used to generate the URI for an individual follow or follow request
 | 
			
		||||
	FollowPath = "follow"
 | 
			
		||||
	// UpdatePath is used to generate the URI for an account update
 | 
			
		||||
	UpdatePath = "updates"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// APContextKey is a type used specifically for settings values on contexts within go-fed AP request chains
 | 
			
		||||
@@ -108,13 +110,19 @@ type UserURIs struct {
 | 
			
		||||
// GenerateURIForFollow returns the AP URI for a new follow -- something like:
 | 
			
		||||
// https://example.org/users/whatever_user/follow/41c7f33f-1060-48d9-84df-38dcb13cf0d8
 | 
			
		||||
func GenerateURIForFollow(username string, protocol string, host string, thisFollowID string) string {
 | 
			
		||||
	return fmt.Sprintf("%s://%s/%s/%s/%s", protocol, host, UsersPath, FollowPath, thisFollowID)
 | 
			
		||||
	return fmt.Sprintf("%s://%s/%s/%s/%s/%s", protocol, host, UsersPath, username, FollowPath, thisFollowID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenerateURIForFollow returns the AP URI for a new like/fave -- something like:
 | 
			
		||||
// https://example.org/users/whatever_user/liked/41c7f33f-1060-48d9-84df-38dcb13cf0d8
 | 
			
		||||
func GenerateURIForLike(username string, protocol string, host string, thisFavedID string) string {
 | 
			
		||||
	return fmt.Sprintf("%s://%s/%s/%s/%s", protocol, host, UsersPath, LikedPath, thisFavedID)
 | 
			
		||||
	return fmt.Sprintf("%s://%s/%s/%s/%s/%s", protocol, host, UsersPath, username, LikedPath, thisFavedID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenerateURIForUpdate returns the AP URI for a new update activity -- something like:
 | 
			
		||||
// https://example.org/users/whatever_user#updates/41c7f33f-1060-48d9-84df-38dcb13cf0d8
 | 
			
		||||
func GenerateURIForUpdate(username string, protocol string, host string, thisUpdateID string) string {
 | 
			
		||||
	return fmt.Sprintf("%s://%s/%s/%s#%s/%s", protocol, host, UsersPath, username, UpdatePath, thisUpdateID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenerateURIsForAccount throws together a bunch of URIs for the given username, with the given protocol and host.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user