| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // GoToSocial | 
					
						
							|  |  |  | // Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | // GNU Affero General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-30 13:12:00 +02:00
										 |  |  | package processing | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2022-01-24 13:12:17 +01:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"codeberg.org/gruf/go-kv" | 
					
						
							|  |  |  | 	"codeberg.org/gruf/go-logger/v2/level" | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/id" | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/messages" | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | // ProcessFromFederator reads the APActivityType and APObjectType of an incoming message from the federator, | 
					
						
							|  |  |  | // and directs the message into the appropriate side effect handler function, or simply does nothing if there's | 
					
						
							|  |  |  | // no handler function defined for the combination of Activity and Object. | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) ProcessFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	// Allocate new log fields slice | 
					
						
							|  |  |  | 	fields := make([]kv.Field, 3, 5) | 
					
						
							|  |  |  | 	fields[0] = kv.Field{"activityType", federatorMsg.APActivityType} | 
					
						
							|  |  |  | 	fields[1] = kv.Field{"objectType", federatorMsg.APObjectType} | 
					
						
							|  |  |  | 	fields[2] = kv.Field{"toAccount", federatorMsg.ReceivingAccount.Username} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if federatorMsg.APIri != nil { | 
					
						
							|  |  |  | 		// An IRI was supplied, append to log | 
					
						
							|  |  |  | 		fields = append(fields, kv.Field{ | 
					
						
							|  |  |  | 			"iri", federatorMsg.APIri, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if federatorMsg.GTSModel != nil && | 
					
						
							|  |  |  | 		log.Level() >= level.DEBUG { | 
					
						
							|  |  |  | 		// Append converted model to log | 
					
						
							|  |  |  | 		fields = append(fields, kv.Field{ | 
					
						
							|  |  |  | 			"model", federatorMsg.GTSModel, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Log this federated message | 
					
						
							| 
									
										
										
										
											2023-02-17 12:02:29 +01:00
										 |  |  | 	l := log.WithContext(ctx).WithFields(fields...) | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	l.Info("processing from federator") | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 	switch federatorMsg.APActivityType { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityCreate: | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		// CREATE SOMETHING | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 		switch federatorMsg.APObjectType { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ObjectNote: | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 			// CREATE A STATUS | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processCreateStatusFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ActivityLike: | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 			// CREATE A FAVE | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processCreateFaveFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ActivityFollow: | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 			// CREATE A FOLLOW REQUEST | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processCreateFollowRequestFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ActivityAnnounce: | 
					
						
							| 
									
										
										
										
											2021-05-28 19:57:04 +02:00
										 |  |  | 			// CREATE AN ANNOUNCE | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processCreateAnnounceFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ActivityBlock: | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 			// CREATE A BLOCK | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processCreateBlockFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2023-01-25 11:12:27 +01:00
										 |  |  | 		case ap.ActivityFlag: | 
					
						
							|  |  |  | 			// CREATE A FLAG / REPORT | 
					
						
							|  |  |  | 			return p.processCreateFlagFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityUpdate: | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		// UPDATE SOMETHING | 
					
						
							| 
									
										
										
										
											2021-11-22 08:46:19 +01:00
										 |  |  | 		if federatorMsg.APObjectType == ap.ObjectProfile { | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 			// UPDATE AN ACCOUNT | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processUpdateAccountFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityDelete: | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		// DELETE SOMETHING | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 		switch federatorMsg.APObjectType { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ObjectNote: | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 			// DELETE A STATUS | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processDeleteStatusFromFederator(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		case ap.ObjectProfile: | 
					
						
							| 
									
										
										
										
											2021-05-23 18:07:04 +02:00
										 |  |  | 			// DELETE A PROFILE/ACCOUNT | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 			return p.processDeleteAccountFromFederator(ctx, federatorMsg) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-30 10:56:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	// not a combination we can/need to process | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | // processCreateStatusFromFederator handles Activity Create and Object Note. | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateStatusFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		status *gtsmodel.Status | 
					
						
							|  |  |  | 		err    error | 
					
						
							| 
									
										
										
										
											2023-08-08 12:26:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Check the federatorMsg for either an already dereferenced | 
					
						
							|  |  |  | 		// and converted status pinned to the message, or a forwarded | 
					
						
							|  |  |  | 		// AP IRI that we still need to deref. | 
					
						
							|  |  |  | 		forwarded = (federatorMsg.GTSModel == nil) | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-08 12:26:34 +01:00
										 |  |  | 	if forwarded { | 
					
						
							|  |  |  | 		// Model was not set, deref with IRI. | 
					
						
							|  |  |  | 		// This will also cause the status to be inserted into the db. | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 		status, err = p.statusFromAPIRI(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2023-08-08 12:26:34 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		// Model is set, ensure we have the most up-to-date model. | 
					
						
							|  |  |  | 		status, err = p.statusFromGTSModel(ctx, federatorMsg) | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error extracting status from federatorMsg: %w", err) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	if status.Account == nil || status.Account.IsRemote() { | 
					
						
							|  |  |  | 		// Either no account attached yet, or a remote account. | 
					
						
							|  |  |  | 		// Both situations we need to parse account URI to fetch it. | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 		accountURI, err := url.Parse(status.AccountURI) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		// Ensure that account for this status has been deref'd. | 
					
						
							|  |  |  | 		status.Account, _, err = p.federator.GetAccountByURI(ctx, | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 			federatorMsg.ReceivingAccount.Username, | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 			accountURI, | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 	// Ensure status ancestors dereferenced. We need at least the | 
					
						
							|  |  |  | 	// immediate parent (if present) to ascertain timelineability. | 
					
						
							|  |  |  | 	if err := p.federator.DereferenceStatusAncestors(ctx, | 
					
						
							|  |  |  | 		federatorMsg.ReceivingAccount.Username, | 
					
						
							|  |  |  | 		status, | 
					
						
							|  |  |  | 	); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if status.InReplyToID != "" { | 
					
						
							|  |  |  | 		// Interaction counts changed on the replied status; | 
					
						
							|  |  |  | 		// uncache the prepared version from all timelines. | 
					
						
							|  |  |  | 		p.invalidateStatusFromTimelines(ctx, status.InReplyToID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := p.timelineAndNotifyStatus(ctx, status); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error timelining status: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | func (p *Processor) statusFromGTSModel(ctx context.Context, federatorMsg messages.FromFederator) (*gtsmodel.Status, error) { | 
					
						
							|  |  |  | 	// There should be a status pinned to the federatorMsg | 
					
						
							|  |  |  | 	// (we've already checked to ensure this is not nil). | 
					
						
							|  |  |  | 	status, ok := federatorMsg.GTSModel.(*gtsmodel.Status) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		err := gtserror.New("Note was not parseable as *gtsmodel.Status") | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// AP statusable representation may have also | 
					
						
							|  |  |  | 	// been set on message (no problem if not). | 
					
						
							|  |  |  | 	statusable, _ := federatorMsg.APObjectModel.(ap.Statusable) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Call refresh on status to update | 
					
						
							|  |  |  | 	// it (deref remote) if necessary. | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	status, _, err = p.federator.RefreshStatus( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							|  |  |  | 		federatorMsg.ReceivingAccount.Username, | 
					
						
							|  |  |  | 		status, | 
					
						
							|  |  |  | 		statusable, | 
					
						
							|  |  |  | 		false, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, gtserror.Newf("%w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return status, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Processor) statusFromAPIRI(ctx context.Context, federatorMsg messages.FromFederator) (*gtsmodel.Status, error) { | 
					
						
							|  |  |  | 	// There should be a status IRI pinned to | 
					
						
							|  |  |  | 	// the federatorMsg for us to dereference. | 
					
						
							|  |  |  | 	if federatorMsg.APIri == nil { | 
					
						
							|  |  |  | 		err := gtserror.New("status was not pinned to federatorMsg, and neither was an IRI for us to dereference") | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get the status + ensure we have | 
					
						
							|  |  |  | 	// the most up-to-date version. | 
					
						
							|  |  |  | 	status, _, err := p.federator.GetStatusByURI( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							|  |  |  | 		federatorMsg.ReceivingAccount.Username, | 
					
						
							|  |  |  | 		federatorMsg.APIri, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, gtserror.Newf("%w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return status, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | // processCreateFaveFromFederator handles Activity Create with Object Like. | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateFaveFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	statusFave, ok := federatorMsg.GTSModel.(*gtsmodel.StatusFave) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 		return gtserror.New("Like was not parseable as *gtsmodel.StatusFave") | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if err := p.notifyFave(ctx, statusFave); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error notifying status fave: %w", err) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Interaction counts changed on the faved status; | 
					
						
							|  |  |  | 	// uncache the prepared version from all timelines. | 
					
						
							|  |  |  | 	p.invalidateStatusFromTimelines(ctx, statusFave.StatusID) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // processCreateFollowRequestFromFederator handles Activity Create and Object Follow | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateFollowRequestFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	followRequest, ok := federatorMsg.GTSModel.(*gtsmodel.FollowRequest) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return errors.New("incomingFollowRequest was not parseable as *gtsmodel.FollowRequest") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	// make sure the account is pinned | 
					
						
							|  |  |  | 	if followRequest.Account == nil { | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 		a, err := p.state.DB.GetAccountByID(ctx, followRequest.AccountID) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		followRequest.Account = a | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 	// Get the remote account to make sure the avi and header are cached. | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	if followRequest.Account.Domain != "" { | 
					
						
							|  |  |  | 		remoteAccountID, err := url.Parse(followRequest.Account.URI) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		a, _, err := p.federator.GetAccountByURI(ctx, | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 			federatorMsg.ReceivingAccount.Username, | 
					
						
							|  |  |  | 			remoteAccountID, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		followRequest.Account = a | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if followRequest.TargetAccount == nil { | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 		a, err := p.state.DB.GetAccountByID(ctx, followRequest.TargetAccountID) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		followRequest.TargetAccount = a | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 12:35:05 +02:00
										 |  |  | 	if *followRequest.TargetAccount.Locked { | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		// if the account is locked just notify the follow request and nothing else | 
					
						
							|  |  |  | 		return p.notifyFollowRequest(ctx, followRequest) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if the target account isn't locked, we should already accept the follow and notify about the new follower instead | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 	follow, err := p.state.DB.AcceptFollowRequest(ctx, followRequest.AccountID, followRequest.TargetAccountID) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-16 13:27:43 +02:00
										 |  |  | 	if err := p.federateAcceptFollowRequest(ctx, follow); err != nil { | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	return p.notifyFollow(ctx, follow, followRequest.TargetAccount) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | // processCreateAnnounceFromFederator handles Activity Create with Object Announce. | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateAnnounceFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	status, ok := federatorMsg.GTSModel.(*gtsmodel.Status) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 		return gtserror.New("Announce was not parseable as *gtsmodel.Status") | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Dereference status that this status boosts. | 
					
						
							|  |  |  | 	if err := p.federator.DereferenceAnnounce(ctx, status, federatorMsg.ReceivingAccount.Username); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error dereferencing announce: %w", err) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Generate an ID for the boost wrapper status. | 
					
						
							|  |  |  | 	statusID, err := id.NewULIDFromTime(status.CreatedAt) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error generating id: %w", err) | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	status.ID = statusID | 
					
						
							| 
									
										
										
										
											2022-01-25 13:48:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 	// Store the boost wrapper status. | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if err := p.state.DB.PutStatus(ctx, status); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("db error inserting status: %w", err) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-24 09:32:10 +02:00
										 |  |  | 	// Ensure boosted status ancestors dereferenced. We need at least | 
					
						
							|  |  |  | 	// the immediate parent (if present) to ascertain timelineability. | 
					
						
							|  |  |  | 	if err := p.federator.DereferenceStatusAncestors(ctx, | 
					
						
							|  |  |  | 		federatorMsg.ReceivingAccount.Username, | 
					
						
							|  |  |  | 		status.BoostOf, | 
					
						
							|  |  |  | 	); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Timeline and notify the announce. | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if err := p.timelineAndNotifyStatus(ctx, status); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error timelining status: %w", err) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if err := p.notifyAnnounce(ctx, status); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error notifying status: %w", err) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Interaction counts changed on the boosted status; | 
					
						
							|  |  |  | 	// uncache the prepared version from all timelines. | 
					
						
							|  |  |  | 	p.invalidateStatusFromTimelines(ctx, status.ID) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // processCreateBlockFromFederator handles Activity Create and Object Block | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateBlockFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	block, ok := federatorMsg.GTSModel.(*gtsmodel.Block) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 		return gtserror.New("block was not parseable as *gtsmodel.Block") | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 	// Remove each account's posts from the other's timelines. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// First home timelines. | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 		return gtserror.Newf("%w", err) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 10:37:38 +02:00
										 |  |  | 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 		return gtserror.Newf("%w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now list timelines. | 
					
						
							|  |  |  | 	if err := p.state.Timelines.List.WipeItemsFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("%w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := p.state.Timelines.List.WipeItemsFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("%w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove any follows that existed between blocker + blockee. | 
					
						
							| 
									
										
										
										
											2023-07-08 23:12:06 +02:00
										 |  |  | 	if err := p.state.DB.DeleteFollow(ctx, block.AccountID, block.TargetAccountID); err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 		return gtserror.Newf( | 
					
						
							|  |  |  | 			"db error deleting follow from %s targeting %s: %w", | 
					
						
							|  |  |  | 			block.AccountID, block.TargetAccountID, err, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-08 23:12:06 +02:00
										 |  |  | 	if err := p.state.DB.DeleteFollow(ctx, block.TargetAccountID, block.AccountID); err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-08 16:43:12 +02:00
										 |  |  | 		return gtserror.Newf( | 
					
						
							|  |  |  | 			"db error deleting follow from %s targeting %s: %w", | 
					
						
							|  |  |  | 			block.TargetAccountID, block.AccountID, err, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove any follow requests that existed between blocker + blockee. | 
					
						
							|  |  |  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.AccountID, block.TargetAccountID); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf( | 
					
						
							|  |  |  | 			"db error deleting follow request from %s targeting %s: %w", | 
					
						
							|  |  |  | 			block.AccountID, block.TargetAccountID, err, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.TargetAccountID, block.AccountID); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf( | 
					
						
							|  |  |  | 			"db error deleting follow request from %s targeting %s: %w", | 
					
						
							|  |  |  | 			block.TargetAccountID, block.AccountID, err, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processCreateFlagFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-03-19 13:11:46 +01:00
										 |  |  | 	incomingReport, ok := federatorMsg.GTSModel.(*gtsmodel.Report) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return errors.New("flag was not parseable as *gtsmodel.Report") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: handle additional side effects of flag creation: | 
					
						
							|  |  |  | 	// - notify admins by dm / notification | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | 	return p.emailReport(ctx, incomingReport) | 
					
						
							| 
									
										
										
										
											2023-01-25 11:12:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | // processUpdateAccountFromFederator handles Activity Update and Object Profile | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processUpdateAccountFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 	// Parse the old/existing account model. | 
					
						
							|  |  |  | 	account, ok := federatorMsg.GTSModel.(*gtsmodel.Account) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 		return gtserror.New("account was not parseable as *gtsmodel.Account") | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 	// Because this was an Update, the new Accountable should be set on the message. | 
					
						
							|  |  |  | 	apubAcc, ok := federatorMsg.APObjectModel.(ap.Accountable) | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 		return gtserror.New("Accountable was not parseable on update account message") | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 	// Fetch up-to-date bio, avatar, header, etc. | 
					
						
							|  |  |  | 	_, _, err := p.federator.RefreshAccount( | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		federatorMsg.ReceivingAccount.Username, | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 		account, | 
					
						
							|  |  |  | 		apubAcc, | 
					
						
							|  |  |  | 		true, // Force refresh. | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-12 13:20:15 +02:00
										 |  |  | 		return gtserror.Newf("error refreshing updated account: %w", err) | 
					
						
							| 
									
										
										
										
											2023-05-09 12:16:10 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // processDeleteStatusFromFederator handles Activity Delete and Object Note | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processDeleteStatusFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	status, ok := federatorMsg.GTSModel.(*gtsmodel.Status) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 		return errors.New("Note was not parseable as *gtsmodel.Status") | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// Delete attachments from this status, since this request | 
					
						
							| 
									
										
										
										
											2022-06-24 17:17:40 +02:00
										 |  |  | 	// comes from the federating API, and there's no way the | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	// poster can do a delete + redraft for it on our instance. | 
					
						
							| 
									
										
										
										
											2022-06-24 17:17:40 +02:00
										 |  |  | 	deleteAttachments := true | 
					
						
							| 
									
										
										
										
											2023-06-11 11:18:44 +02:00
										 |  |  | 	if err := p.wipeStatus(ctx, status, deleteAttachments); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error wiping status: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if status.InReplyToID != "" { | 
					
						
							|  |  |  | 		// Interaction counts changed on the replied status; | 
					
						
							|  |  |  | 		// uncache the prepared version from all timelines. | 
					
						
							|  |  |  | 		p.invalidateStatusFromTimelines(ctx, status.InReplyToID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // processDeleteAccountFromFederator handles Activity Delete and Object Profile | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) processDeleteAccountFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | 	account, ok := federatorMsg.GTSModel.(*gtsmodel.Account) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return errors.New("account delete was not parseable as *gtsmodel.Account") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | 	return p.account.Delete(ctx, account, account.ID) | 
					
						
							| 
									
										
										
										
											2021-10-10 12:39:25 +02:00
										 |  |  | } |