mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:32:25 -05:00 
			
		
		
		
	federate account updates
This commit is contained in:
		
					parent
					
						
							
								87177d840b
							
						
					
				
			
			
				commit
				
					
						cb54324430
					
				
			
		
					 7 changed files with 135 additions and 3 deletions
				
			
		|  | @ -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 { | ||||
|  | @ -281,3 +291,23 @@ func (p *processor) federateAnnounce(boostWrapperStatus *gtsmodel.Status, boosti | |||
| 	_, 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. | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue