fix the annoying infinite handshake bug (tested) (#69)

This commit is contained in:
Tobi Smethurst
2021-06-27 11:46:07 +02:00
committed by GitHub
parent b71bbc86a7
commit 3e6aef00b2
4 changed files with 125 additions and 29 deletions

View File

@ -21,6 +21,7 @@ package federation
import (
"net/http"
"net/url"
"sync"
"github.com/go-fed/activity/pub"
"github.com/sirupsen/logrus"
@ -54,6 +55,8 @@ type Federator interface {
//
// If username is an empty string, our instance user's credentials will be used instead.
GetTransportForUser(username string) (transport.Transport, error)
// Handshaking returns true if the given username is currently in the process of dereferencing the remoteAccountID.
Handshaking(username string, remoteAccountID *url.URL) bool
pub.CommonBehavior
pub.FederatingProtocol
}
@ -67,6 +70,8 @@ type federator struct {
transportController transport.Controller
actor pub.FederatingActor
log *logrus.Logger
handshakes map[string][]*url.URL
handshakeSync *sync.Mutex // mutex to lock/unlock when checking or updating the handshakes map
}
// NewFederator returns a new federator
@ -81,6 +86,7 @@ func NewFederator(db db.DB, federatingDB federatingdb.DB, transportController tr
typeConverter: typeConverter,
transportController: transportController,
log: log,
handshakeSync: &sync.Mutex{},
}
actor := newFederatingActor(f, f, federatingDB, clock)
f.actor = actor

View File

@ -0,0 +1,80 @@
package federation
import "net/url"
func (f *federator) Handshaking(username string, remoteAccountID *url.URL) bool {
f.handshakeSync.Lock()
defer f.handshakeSync.Unlock()
if f.handshakes == nil {
// handshakes isn't even initialized yet so we can't be handshaking with anyone
return false
}
remoteIDs, ok := f.handshakes[username];
if !ok {
// user isn't handshaking with anyone, bail
return false
}
for _, id := range remoteIDs {
if id.String() == remoteAccountID.String() {
// we are currently handshaking with the remote account, yep
return true
}
}
// didn't find it which means we're not handshaking
return false
}
func (f *federator) startHandshake(username string, remoteAccountID *url.URL) {
f.handshakeSync.Lock()
defer f.handshakeSync.Unlock()
// lazily initialize handshakes
if f.handshakes == nil {
f.handshakes = make(map[string][]*url.URL)
}
remoteIDs, ok := f.handshakes[username]
if !ok {
// there was nothing in there yet, so just add this entry and return
f.handshakes[username] = []*url.URL{remoteAccountID}
return
}
// add the remote ID to the slice
remoteIDs = append(remoteIDs, remoteAccountID)
f.handshakes[username] = remoteIDs
}
func (f *federator) stopHandshake(username string, remoteAccountID *url.URL) {
f.handshakeSync.Lock()
defer f.handshakeSync.Unlock()
if f.handshakes == nil {
return
}
remoteIDs, ok := f.handshakes[username]
if !ok {
// there was nothing in there yet anyway so just bail
return
}
newRemoteIDs := []*url.URL{}
for _, id := range remoteIDs {
if id.String() != remoteAccountID.String() {
newRemoteIDs = append(newRemoteIDs, id)
}
}
if len(newRemoteIDs) == 0 {
// there are no handshakes so just remove this user entry from the map and save a few bytes
delete(f.handshakes, username)
} else {
// there are still other handshakes ongoing
f.handshakes[username] = newRemoteIDs
}
}

View File

@ -213,6 +213,8 @@ func (f *federator) AuthenticateFederatedRequest(username string, r *http.Reques
}
func (f *federator) DereferenceRemoteAccount(username string, remoteAccountID *url.URL) (typeutils.Accountable, error) {
f.startHandshake(username, remoteAccountID)
defer f.stopHandshake(username, remoteAccountID)
transport, err := f.GetTransportForUser(username)
if err != nil {