diff options
Diffstat (limited to 'internal/federation')
| -rw-r--r-- | internal/federation/dereferencing/account.go | 30 | ||||
| -rw-r--r-- | internal/federation/dereferencing/error.go | 14 | ||||
| -rw-r--r-- | internal/federation/dereferencing/status.go | 75 | ||||
| -rw-r--r-- | internal/federation/federatingactor.go | 271 | ||||
| -rw-r--r-- | internal/federation/federatingprotocol.go | 89 | ||||
| -rw-r--r-- | internal/federation/handshake.go | 18 | 
6 files changed, 229 insertions, 268 deletions
diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go index 0ce35b0e4..4795db733 100644 --- a/internal/federation/dereferencing/account.go +++ b/internal/federation/dereferencing/account.go @@ -357,39 +357,13 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.  // dereferenceAccountable calls remoteAccountID with a GET request, and tries to parse whatever  // it finds as something that an account model can be constructed out of. -// -// Will work for Person, Application, or Service models.  func (d *deref) dereferenceAccountable(ctx context.Context, transport transport.Transport, remoteAccountID *url.URL) (ap.Accountable, error) {  	b, err := transport.Dereference(ctx, remoteAccountID)  	if err != nil { -		return nil, fmt.Errorf("DereferenceAccountable: error deferencing %s: %w", remoteAccountID.String(), err) -	} - -	m := make(map[string]interface{}) -	if err := json.Unmarshal(b, &m); err != nil { -		return nil, fmt.Errorf("DereferenceAccountable: error unmarshalling bytes into json: %w", err) -	} - -	t, err := streams.ToType(ctx, m) -	if err != nil { -		return nil, fmt.Errorf("DereferenceAccountable: error resolving json into ap vocab type: %w", err) -	} - -	//nolint:forcetypeassert -	switch t.GetTypeName() { -	case ap.ActorApplication: -		return t.(vocab.ActivityStreamsApplication), nil -	case ap.ActorGroup: -		return t.(vocab.ActivityStreamsGroup), nil -	case ap.ActorOrganization: -		return t.(vocab.ActivityStreamsOrganization), nil -	case ap.ActorPerson: -		return t.(vocab.ActivityStreamsPerson), nil -	case ap.ActorService: -		return t.(vocab.ActivityStreamsService), nil +		return nil, fmt.Errorf("dereferenceAccountable: error deferencing %s: %w", remoteAccountID.String(), err)  	} -	return nil, newErrWrongType(fmt.Errorf("DereferenceAccountable: type name %s not supported as Accountable", t.GetTypeName())) +	return ap.ResolveAccountable(ctx, b)  }  func (d *deref) fetchRemoteAccountAvatar(ctx context.Context, tsport transport.Transport, avatarURL string, accountID string) (string, error) { diff --git a/internal/federation/dereferencing/error.go b/internal/federation/dereferencing/error.go index f2fae63ac..769150cef 100644 --- a/internal/federation/dereferencing/error.go +++ b/internal/federation/dereferencing/error.go @@ -66,20 +66,6 @@ func newErrTransportError(err error) error {  	return &ErrTransportError{wrapped: err}  } -// ErrWrongType indicates that an unexpected type was returned from a remote call; -// for example, we were served a Person when we were looking for a statusable. -type ErrWrongType struct { -	wrapped error -} - -func (err *ErrWrongType) Error() string { -	return fmt.Sprintf("wrong received type: %v", err.wrapped) -} - -func newErrWrongType(err error) error { -	return &ErrWrongType{wrapped: err} -} -  // ErrOther denotes some other kind of weird error, perhaps from a malformed json  // or some other weird crapola.  type ErrOther struct { diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go index 8e202d585..fe07be23a 100644 --- a/internal/federation/dereferencing/status.go +++ b/internal/federation/dereferencing/status.go @@ -19,14 +19,11 @@ package dereferencing  import (  	"context" -	"encoding/json"  	"errors"  	"fmt"  	"net/url"  	"strings" -	"github.com/superseriousbusiness/activity/streams" -	"github.com/superseriousbusiness/activity/streams/vocab"  	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/config"  	"github.com/superseriousbusiness/gotosocial/internal/db" @@ -161,78 +158,10 @@ func (d *deref) dereferenceStatusable(ctx context.Context, tsport transport.Tran  	b, err := tsport.Dereference(ctx, remoteStatusID)  	if err != nil { -		return nil, fmt.Errorf("DereferenceStatusable: error deferencing %s: %s", remoteStatusID.String(), err) +		return nil, fmt.Errorf("dereferenceStatusable: error deferencing %s: %w", remoteStatusID.String(), err)  	} -	m := make(map[string]interface{}) -	if err := json.Unmarshal(b, &m); err != nil { -		return nil, fmt.Errorf("DereferenceStatusable: error unmarshalling bytes into json: %s", err) -	} - -	t, err := streams.ToType(ctx, m) -	if err != nil { -		return nil, fmt.Errorf("DereferenceStatusable: error resolving json into ap vocab type: %s", err) -	} - -	// Article, Document, Image, Video, Note, Page, Event, Place, Mention, Profile -	switch t.GetTypeName() { -	case ap.ObjectArticle: -		p, ok := t.(vocab.ActivityStreamsArticle) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsArticle") -		} -		return p, nil -	case ap.ObjectDocument: -		p, ok := t.(vocab.ActivityStreamsDocument) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsDocument") -		} -		return p, nil -	case ap.ObjectImage: -		p, ok := t.(vocab.ActivityStreamsImage) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsImage") -		} -		return p, nil -	case ap.ObjectVideo: -		p, ok := t.(vocab.ActivityStreamsVideo) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsVideo") -		} -		return p, nil -	case ap.ObjectNote: -		p, ok := t.(vocab.ActivityStreamsNote) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsNote") -		} -		return p, nil -	case ap.ObjectPage: -		p, ok := t.(vocab.ActivityStreamsPage) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsPage") -		} -		return p, nil -	case ap.ObjectEvent: -		p, ok := t.(vocab.ActivityStreamsEvent) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsEvent") -		} -		return p, nil -	case ap.ObjectPlace: -		p, ok := t.(vocab.ActivityStreamsPlace) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsPlace") -		} -		return p, nil -	case ap.ObjectProfile: -		p, ok := t.(vocab.ActivityStreamsProfile) -		if !ok { -			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsProfile") -		} -		return p, nil -	} - -	return nil, newErrWrongType(fmt.Errorf("DereferenceStatusable: type name %s not supported as Statusable", t.GetTypeName())) +	return ap.ResolveStatusable(ctx, b)  }  // populateStatusFields fetches all the information we temporarily pinned to an incoming diff --git a/internal/federation/federatingactor.go b/internal/federation/federatingactor.go index eec45d0ba..18cdf2106 100644 --- a/internal/federation/federatingactor.go +++ b/internal/federation/federatingactor.go @@ -19,133 +19,218 @@ package federation  import (  	"context" +	"encoding/json" +	"fmt" +	"io"  	"net/http"  	"net/url" +	"strings" +	"codeberg.org/gruf/go-kv"  	"github.com/superseriousbusiness/activity/pub" +	"github.com/superseriousbusiness/activity/streams"  	"github.com/superseriousbusiness/activity/streams/vocab" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/log"  ) -// federatingActor implements the go-fed federating protocol interface +// Potential incoming Content-Type header values; be +// lenient with whitespace and quotation mark placement. +var activityStreamsMediaTypes = []string{ +	"application/activity+json", +	"application/ld+json;profile=https://www.w3.org/ns/activitystreams", +	"application/ld+json;profile=\"https://www.w3.org/ns/activitystreams\"", +	"application/ld+json ;profile=https://www.w3.org/ns/activitystreams", +	"application/ld+json ;profile=\"https://www.w3.org/ns/activitystreams\"", +	"application/ld+json ; profile=https://www.w3.org/ns/activitystreams", +	"application/ld+json ; profile=\"https://www.w3.org/ns/activitystreams\"", +	"application/ld+json; profile=https://www.w3.org/ns/activitystreams", +	"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", +} + +// federatingActor wraps the pub.FederatingActor interface +// with some custom GoToSocial-specific logic.  type federatingActor struct { -	actor pub.FederatingActor +	sideEffectActor pub.DelegateActor +	wrapped         pub.FederatingActor  } -// newFederatingProtocol returns the gotosocial implementation of the GTSFederatingProtocol interface +// newFederatingProtocol returns a new federatingActor, which +// implements the pub.FederatingActor interface.  func newFederatingActor(c pub.CommonBehavior, s2s pub.FederatingProtocol, db pub.Database, clock pub.Clock) pub.FederatingActor { -	actor := pub.NewFederatingActor(c, s2s, db, clock) +	sideEffectActor := pub.NewSideEffectActor(c, s2s, nil, db, clock) +	customActor := pub.NewCustomActor(sideEffectActor, false, true, clock)  	return &federatingActor{ -		actor: actor, +		sideEffectActor: sideEffectActor, +		wrapped:         customActor,  	}  } -// Send a federated activity. -// -// The provided url must be the outbox of the sender. All processing of -// the activity occurs similarly to the C2S flow: -//   - If t is not an Activity, it is wrapped in a Create activity. -//   - A new ID is generated for the activity. -//   - The activity is added to the specified outbox. -//   - The activity is prepared and delivered to recipients. -// -// Note that this function will only behave as expected if the -// implementation has been constructed to support federation. This -// method will guaranteed work for non-custom Actors. For custom actors, -// care should be used to not call this method if only C2S is supported.  func (f *federatingActor) Send(c context.Context, outbox *url.URL, t vocab.Type) (pub.Activity, error) {  	log.Infof(c, "send activity %s via outbox %s", t.GetTypeName(), outbox) -	return f.actor.Send(c, outbox, t) +	return f.wrapped.Send(c, outbox, t)  } -// PostInbox returns true if the request was handled as an ActivityPub -// POST to an actor's inbox. If false, the request was not an -// ActivityPub request and may still be handled by the caller in -// another way, such as serving a web page. -// -// If the error is nil, then the ResponseWriter's headers and response -// has already been written. If a non-nil error is returned, then no -// response has been written. -// -// If the Actor was constructed with the Federated Protocol enabled, -// side effects will occur. -// -// If the Federated Protocol is not enabled, writes the -// http.StatusMethodNotAllowed status code in the response. No side -// effects occur.  func (f *federatingActor) PostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) { -	return f.actor.PostInbox(c, w, r) +	return f.PostInboxScheme(c, w, r, "https")  } -// PostInboxScheme is similar to PostInbox, except clients are able to -// specify which protocol scheme to handle the incoming request and the -// data stored within the application (HTTP, HTTPS, etc). -func (f *federatingActor) PostInboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) { -	return f.actor.PostInboxScheme(c, w, r, scheme) +// PostInboxScheme is a reimplementation of the default baseActor +// implementation of PostInboxScheme in pub/base_actor.go. +// +// Key differences from that implementation: +//   - More explicit debug logging when a request is not processed. +//   - Normalize content of activity object. +//   - Return code 202 instead of 200 on successful POST, to reflect +//     that we process most side effects asynchronously. +func (f *federatingActor) PostInboxScheme(ctx context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) { +	l := log. +		WithContext(ctx). +		WithFields([]kv.Field{ +			{"userAgent", r.UserAgent()}, +			{"path", r.URL.Path}, +		}...) + +	// Do nothing if this is not an ActivityPub POST request. +	if !func() bool { +		if r.Method != http.MethodPost { +			l.Debugf("inbox request was %s rather than required POST", r.Method) +			return false +		} + +		contentType := r.Header.Get("Content-Type") +		for _, mediaType := range activityStreamsMediaTypes { +			if strings.Contains(contentType, mediaType) { +				return true +			} +		} + +		l.Debugf("inbox POST request content-type %s was not recognized", contentType) +		return false +	}() { +		return false, nil +	} + +	// Check the peer request is authentic. +	ctx, authenticated, err := f.sideEffectActor.AuthenticatePostInbox(ctx, w, r) +	if err != nil { +		return true, err +	} else if !authenticated { +		return true, nil +	} + +	// Begin processing the request, but note that we have +	// not yet applied authorization (ex: blocks). +	// +	// Obtain the activity and reject unknown activities. +	b, err := io.ReadAll(r.Body) +	if err != nil { +		err = fmt.Errorf("PostInboxScheme: error reading request body: %w", err) +		return true, err +	} + +	var rawActivity map[string]interface{} +	if err := json.Unmarshal(b, &rawActivity); err != nil { +		err = fmt.Errorf("PostInboxScheme: error unmarshalling request body: %w", err) +		return true, err +	} + +	t, err := streams.ToType(ctx, rawActivity) +	if err != nil { +		if !streams.IsUnmatchedErr(err) { +			// Real error. +			err = fmt.Errorf("PostInboxScheme: error matching json to type: %w", err) +			return true, err +		} +		// Respond with bad request; we just couldn't +		// match the type to one that we know about. +		l.Debug("json could not be resolved to ActivityStreams value") +		w.WriteHeader(http.StatusBadRequest) +		return true, nil +	} + +	activity, ok := t.(pub.Activity) +	if !ok { +		err = fmt.Errorf("ActivityStreams value with type %T is not a pub.Activity", t) +		return true, err +	} + +	if activity.GetJSONLDId() == nil { +		l.Debugf("incoming Activity %s did not have required id property set", activity.GetTypeName()) +		w.WriteHeader(http.StatusBadRequest) +		return true, nil +	} + +	// If activity Object is a Statusable, we'll want to replace the +	// parsed `content` value with the value from the raw JSON instead. +	// See https://github.com/superseriousbusiness/gotosocial/issues/1661 +	ap.NormalizeActivityObject(activity, rawActivity) + +	// Allow server implementations to set context data with a hook. +	ctx, err = f.sideEffectActor.PostInboxRequestBodyHook(ctx, r, activity) +	if err != nil { +		return true, err +	} + +	// Check authorization of the activity. +	authorized, err := f.sideEffectActor.AuthorizePostInbox(ctx, w, activity) +	if err != nil { +		return true, err +	} else if !authorized { +		return true, nil +	} + +	// Copy existing URL + add request host and scheme. +	inboxID := func() *url.URL { +		id := &url.URL{} +		*id = *r.URL +		id.Host = r.Host +		id.Scheme = scheme +		return id +	}() + +	// Post the activity to the actor's inbox and trigger side effects for +	// that particular Activity type. It is up to the delegate to resolve +	// the given map. +	if err := f.sideEffectActor.PostInbox(ctx, inboxID, activity); err != nil { +		// Special case: We know it is a bad request if the object or +		// target properties needed to be populated, but weren't. +		// +		// Send the rejection to the peer. +		if err == pub.ErrObjectRequired || err == pub.ErrTargetRequired { +			l.Debugf("malformed incoming Activity: %s", err) +			w.WriteHeader(http.StatusBadRequest) +			return true, nil +		} +		err = fmt.Errorf("PostInboxScheme: error calling sideEffectActor.PostInbox: %w", err) +		return true, err +	} + +	// Our side effects are complete, now delegate determining whether to do inbox forwarding, as well as the action to do it. +	if err := f.sideEffectActor.InboxForwarding(ctx, inboxID, activity); err != nil { +		err = fmt.Errorf("PostInboxScheme: error calling sideEffectActor.InboxForwarding: %w", err) +		return true, err +	} + +	// Request is now undergoing processing. +	// Respond with an Accepted status. +	w.WriteHeader(http.StatusAccepted) +	return true, nil  } -// GetInbox returns true if the request was handled as an ActivityPub -// GET to an actor's inbox. If false, the request was not an ActivityPub -// request and may still be handled by the caller in another way, such -// as serving a web page. -// -// If the error is nil, then the ResponseWriter's headers and response -// has already been written. If a non-nil error is returned, then no -// response has been written. -// -// If the request is an ActivityPub request, the Actor will defer to the -// application to determine the correct authorization of the request and -// the resulting OrderedCollection to respond with. The Actor handles -// serializing this OrderedCollection and responding with the correct -// headers and http.StatusOK.  func (f *federatingActor) GetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) { -	return f.actor.GetInbox(c, w, r) +	return f.wrapped.GetInbox(c, w, r)  } -// PostOutbox returns true if the request was handled as an ActivityPub -// POST to an actor's outbox. If false, the request was not an -// ActivityPub request and may still be handled by the caller in another -// way, such as serving a web page. -// -// If the error is nil, then the ResponseWriter's headers and response -// has already been written. If a non-nil error is returned, then no -// response has been written. -// -// If the Actor was constructed with the Social Protocol enabled, side -// effects will occur. -// -// If the Social Protocol is not enabled, writes the -// http.StatusMethodNotAllowed status code in the response. No side -// effects occur. -// -// If the Social and Federated Protocol are both enabled, it will handle -// the side effects of receiving an ActivityStream Activity, and then -// federate the Activity to peers.  func (f *federatingActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) { -	return f.actor.PostOutbox(c, w, r) +	return f.wrapped.PostOutbox(c, w, r)  } -// PostOutboxScheme is similar to PostOutbox, except clients are able to -// specify which protocol scheme to handle the incoming request and the -// data stored within the application (HTTP, HTTPS, etc).  func (f *federatingActor) PostOutboxScheme(c context.Context, w http.ResponseWriter, r *http.Request, scheme string) (bool, error) { -	return f.actor.PostOutboxScheme(c, w, r, scheme) +	return f.wrapped.PostOutboxScheme(c, w, r, scheme)  } -// GetOutbox returns true if the request was handled as an ActivityPub -// GET to an actor's outbox. If false, the request was not an -// ActivityPub request. -// -// If the error is nil, then the ResponseWriter's headers and response -// has already been written. If a non-nil error is returned, then no -// response has been written. -// -// If the request is an ActivityPub request, the Actor will defer to the -// application to determine the correct authorization of the request and -// the resulting OrderedCollection to respond with. The Actor handles -// serializing this OrderedCollection and responding with the correct -// headers and http.StatusOK.  func (f *federatingActor) GetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error) { -	return f.actor.GetOutbox(c, w, r) +	return f.wrapped.GetOutbox(c, w, r)  } diff --git a/internal/federation/federatingprotocol.go b/internal/federation/federatingprotocol.go index ed0a216fe..52f46586d 100644 --- a/internal/federation/federatingprotocol.go +++ b/internal/federation/federatingprotocol.go @@ -24,7 +24,6 @@ import (  	"net/http"  	"net/url" -	"codeberg.org/gruf/go-kv"  	"github.com/superseriousbusiness/activity/pub"  	"github.com/superseriousbusiness/activity/streams"  	"github.com/superseriousbusiness/activity/streams/vocab" @@ -138,74 +137,80 @@ func (f *federator) PostInboxRequestBodyHook(ctx context.Context, r *http.Reques  // authenticated must be true and error nil. The request will continue  // to be processed.  func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { -	l := log.WithContext(ctx). -		WithFields(kv.Fields{ -			{"useragent", r.UserAgent()}, -			{"url", r.URL.String()}, -		}...) -	l.Trace("received request to authenticate") - -	if !uris.IsInboxPath(r.URL) { -		return nil, false, fmt.Errorf("path %s was not an inbox path", r.URL.String()) -	} +	log.Tracef(ctx, "received request to authenticate inbox %s", r.URL.String()) +	// Ensure this is an inbox path, and fetch the inbox owner +	// account by parsing username from `/users/{username}/inbox`.  	username, err := uris.ParseInboxPath(r.URL)  	if err != nil { -		return nil, false, fmt.Errorf("could not parse path %s: %s", r.URL.String(), err) +		err = fmt.Errorf("AuthenticatePostInbox: could not parse %s as inbox path: %w", r.URL.String(), err) +		return nil, false, err  	}  	if username == "" { -		return nil, false, errors.New("username was empty") +		err = errors.New("AuthenticatePostInbox: inbox username was empty") +		return nil, false, err  	}  	receivingAccount, err := f.db.GetAccountByUsernameDomain(ctx, username, "")  	if err != nil { -		return nil, false, fmt.Errorf("could not fetch receiving account with username %s: %s", username, err) +		err = fmt.Errorf("AuthenticatePostInbox: could not fetch receiving account %s: %w", username, err) +		return nil, false, err  	} +	// Check who's delivering by inspecting the http signature.  	publicKeyOwnerURI, errWithCode := f.AuthenticateFederatedRequest(ctx, receivingAccount.Username)  	if errWithCode != nil {  		switch errWithCode.Code() {  		case http.StatusUnauthorized, http.StatusForbidden, http.StatusBadRequest: -			// if 400, 401, or 403, obey the interface by writing the header and bailing +			// If codes 400, 401, or 403, obey the go-fed +			// interface by writing the header and bailing.  			w.WriteHeader(errWithCode.Code())  			return ctx, false, nil  		case http.StatusGone: -			// if the requesting account has gone (http 410) then likely -			// inbox post was a delete, we can just write 202 and leave, -			// since we didn't know about the account anyway, so we can't -			// do any further processing +			// If the requesting account's key has gone +			// (410) then likely inbox post was a delete. +			// +			// We can just write 202 and leave: we didn't +			// know about the account anyway, so we can't +			// do any further processing.  			w.WriteHeader(http.StatusAccepted)  			return ctx, false, nil  		default: -			// if not, there's been a proper error +			// Proper error.  			return ctx, false, err  		}  	} -	// authentication has passed, so add an instance entry for this instance if it hasn't been done already -	i := >smodel.Instance{} -	if err := f.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: publicKeyOwnerURI.Host}}, i); err != nil { -		if err != db.ErrNoEntries { -			// there's been an actual error -			return ctx, false, fmt.Errorf("error getting requesting account with public key id %s: %s", publicKeyOwnerURI.String(), err) +	// Authentication has passed, check if we need to create a +	// new instance entry for the Host of the requesting account. +	if _, err := f.db.GetInstance(ctx, publicKeyOwnerURI.Host); err != nil { +		if !errors.Is(err, db.ErrNoEntries) { +			// There's been an actual error. +			err = fmt.Errorf("AuthenticatePostInbox: error getting instance %s: %w", publicKeyOwnerURI.Host, err) +			return ctx, false, err  		} -		// we don't have an entry for this instance yet so dereference it -		i, err = f.GetRemoteInstance(transport.WithFastfail(ctx), username, &url.URL{ +		// We don't yet have an entry for +		// the instance, go dereference it. +		instance, err := f.GetRemoteInstance(transport.WithFastfail(ctx), username, &url.URL{  			Scheme: publicKeyOwnerURI.Scheme,  			Host:   publicKeyOwnerURI.Host,  		})  		if err != nil { -			return nil, false, fmt.Errorf("could not dereference new remote instance %s during AuthenticatePostInbox: %s", publicKeyOwnerURI.Host, err) +			err = fmt.Errorf("AuthenticatePostInbox: error dereferencing instance %s: %w", publicKeyOwnerURI.Host, err) +			return nil, false, err  		} -		// and put it in the db -		if err := f.db.Put(ctx, i); err != nil { -			return nil, false, fmt.Errorf("error inserting newly dereferenced instance %s: %s", publicKeyOwnerURI.Host, err) +		if err := f.db.Put(ctx, instance); err != nil { +			err = fmt.Errorf("AuthenticatePostInbox: error inserting instance entry for %s: %w", publicKeyOwnerURI.Host, err) +			return nil, false, err  		}  	} +	// We know the public key owner URI now, so we can +	// dereference the remote account (or just get it +	// from the db if we already have it).  	requestingAccount, err := f.GetAccountByURI(  		transport.WithFastfail(ctx), username, publicKeyOwnerURI, false,  	) @@ -220,9 +225,12 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr  			w.WriteHeader(http.StatusAccepted)  			return ctx, false, nil  		} -		return nil, false, fmt.Errorf("couldn't get requesting account %s: %s", publicKeyOwnerURI, err) +		err = fmt.Errorf("AuthenticatePostInbox: couldn't get requesting account %s: %w", publicKeyOwnerURI, err) +		return nil, false, err  	} +	// We have everything we need now, set the requesting +	// and receiving accounts on the context for later use.  	withRequesting := context.WithValue(ctx, ap.ContextRequestingAccount, requestingAccount)  	withReceiving := context.WithValue(withRequesting, ap.ContextReceivingAccount, receivingAccount)  	return withReceiving, true, nil @@ -351,14 +359,15 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er  // type and extension. The unhandled ones are passed to DefaultCallback.  func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.FederatingWrappedCallbacks, other []interface{}, err error) {  	wrapped = pub.FederatingWrappedCallbacks{ -		// OnFollow determines what action to take for this particular callback -		// if a Follow Activity is handled. +		// OnFollow determines what action to take for this +		// particular callback if a Follow Activity is handled.  		// -		// For our implementation, we always want to do nothing because we have internal logic for handling follows. +		// For our implementation, we always want to do nothing +		// because we have internal logic for handling follows.  		OnFollow: pub.OnFollowDoNothing,  	} -	// override some default behaviors and trigger our own side effects +	// Override some default behaviors to trigger our own side effects.  	other = []interface{}{  		func(ctx context.Context, undo vocab.ActivityStreamsUndo) error {  			return f.FederatingDB().Undo(ctx, undo) @@ -385,11 +394,7 @@ func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.Federa  // type and extension, so the unhandled ones are passed to  // DefaultCallback.  func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) error { -	l := log.WithContext(ctx). -		WithFields(kv.Fields{ -			{"aptype", activity.GetTypeName()}, -		}...) -	l.Debug("received unhandle-able activity type so ignoring it") +	log.Debugf(ctx, "received unhandle-able activity type (%s) so ignoring it", activity.GetTypeName())  	return nil  } diff --git a/internal/federation/handshake.go b/internal/federation/handshake.go deleted file mode 100644 index b83d2b6c4..000000000 --- a/internal/federation/handshake.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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/>. - -package federation  | 
