diff options
author | 2021-05-21 15:48:26 +0200 | |
---|---|---|
committer | 2021-05-21 15:48:26 +0200 | |
commit | d839f27c306eedebdc7cc0311f35b8856cc2bb24 (patch) | |
tree | 7a11a3a641f902991d26771c4d3f8e836a2bce7e /internal/federation/util.go | |
parent | update progress (diff) | |
download | gotosocial-d839f27c306eedebdc7cc0311f35b8856cc2bb24.tar.xz |
Follows and relationships (#27)
* Follows -- create and undo, both remote and local
* Statuses -- federate new posts, including media, attachments, CWs and image descriptions.
Diffstat (limited to 'internal/federation/util.go')
-rw-r--r-- | internal/federation/util.go | 118 |
1 files changed, 81 insertions, 37 deletions
diff --git a/internal/federation/util.go b/internal/federation/util.go index 14ceaeb1d..3f53ed6a7 100644 --- a/internal/federation/util.go +++ b/internal/federation/util.go @@ -27,11 +27,13 @@ import ( "fmt" "net/http" "net/url" + "strings" "github.com/go-fed/activity/pub" "github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams/vocab" "github.com/go-fed/httpsig" + "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/transport" "github.com/superseriousbusiness/gotosocial/internal/typeutils" @@ -128,57 +130,73 @@ func (f *federator) AuthenticateFederatedRequest(username string, r *http.Reques return nil, fmt.Errorf("could not parse key id into a url: %s", err) } - transport, err := f.GetTransportForUser(username) - if err != nil { - return nil, fmt.Errorf("transport err: %s", err) - } + var publicKey interface{} + var pkOwnerURI *url.URL + if strings.EqualFold(requestingPublicKeyID.Host, f.config.Host) { + // the request is coming from INSIDE THE HOUSE so skip the remote dereferencing + requestingLocalAccount := >smodel.Account{} + if err := f.db.GetWhere([]db.Where{{Key: "public_key_uri", Value: requestingPublicKeyID.String()}}, requestingLocalAccount); err != nil { + return nil, fmt.Errorf("couldn't get local account with public key uri %s from the database: %s", requestingPublicKeyID.String(), err) + } + publicKey = requestingLocalAccount.PublicKey + pkOwnerURI, err = url.Parse(requestingLocalAccount.URI) + if err != nil { + return nil, fmt.Errorf("error parsing url %s: %s", requestingLocalAccount.URI, err) + } + } else { + // the request is remote, so we need to authenticate the request properly by dereferencing the remote key + transport, err := f.GetTransportForUser(username) + if err != nil { + return nil, fmt.Errorf("transport err: %s", err) + } - // The actual http call to the remote server is made right here in the Dereference function. - b, err := transport.Dereference(context.Background(), requestingPublicKeyID) - if err != nil { - return nil, fmt.Errorf("error deferencing key %s: %s", requestingPublicKeyID.String(), err) - } + // The actual http call to the remote server is made right here in the Dereference function. + b, err := transport.Dereference(context.Background(), requestingPublicKeyID) + if err != nil { + return nil, fmt.Errorf("error deferencing key %s: %s", requestingPublicKeyID.String(), err) + } - // if the key isn't in the response, we can't authenticate the request - requestingPublicKey, err := getPublicKeyFromResponse(context.Background(), b, requestingPublicKeyID) - if err != nil { - return nil, fmt.Errorf("error getting key %s from response %s: %s", requestingPublicKeyID.String(), string(b), err) - } + // if the key isn't in the response, we can't authenticate the request + requestingPublicKey, err := getPublicKeyFromResponse(context.Background(), b, requestingPublicKeyID) + if err != nil { + return nil, fmt.Errorf("error getting key %s from response %s: %s", requestingPublicKeyID.String(), string(b), err) + } - // we should be able to get the actual key embedded in the vocab.W3IDSecurityV1PublicKey - pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem() - if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() { - return nil, errors.New("publicKeyPem property is not provided or it is not embedded as a value") - } + // we should be able to get the actual key embedded in the vocab.W3IDSecurityV1PublicKey + pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem() + if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() { + return nil, errors.New("publicKeyPem property is not provided or it is not embedded as a value") + } - // and decode the PEM so that we can parse it as a golang public key - pubKeyPem := pkPemProp.Get() - block, _ := pem.Decode([]byte(pubKeyPem)) - if block == nil || block.Type != "PUBLIC KEY" { - return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type") - } + // and decode the PEM so that we can parse it as a golang public key + pubKeyPem := pkPemProp.Get() + block, _ := pem.Decode([]byte(pubKeyPem)) + if block == nil || block.Type != "PUBLIC KEY" { + return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type") + } - p, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return nil, fmt.Errorf("could not parse public key from block bytes: %s", err) + publicKey, err = x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("could not parse public key from block bytes: %s", err) + } + + // all good! we just need the URI of the key owner to return + pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner() + if pkOwnerProp == nil || !pkOwnerProp.IsIRI() { + return nil, errors.New("publicKeyOwner property is not provided or it is not embedded as a value") + } + pkOwnerURI = pkOwnerProp.GetIRI() } - if p == nil { + if publicKey == nil { return nil, errors.New("returned public key was empty") } // do the actual authentication here! algo := httpsig.RSA_SHA256 // TODO: make this more robust - if err := verifier.Verify(p, algo); err != nil { + if err := verifier.Verify(publicKey, algo); err != nil { return nil, fmt.Errorf("error verifying key %s: %s", requestingPublicKeyID.String(), err) } - // all good! we just need the URI of the key owner to return - pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner() - if pkOwnerProp == nil || !pkOwnerProp.IsIRI() { - return nil, errors.New("publicKeyOwner property is not provided or it is not embedded as a value") - } - pkOwnerURI := pkOwnerProp.GetIRI() - return pkOwnerURI, nil } @@ -217,6 +235,12 @@ func (f *federator) DereferenceRemoteAccount(username string, remoteAccountID *u return nil, errors.New("error resolving type as activitystreams application") } return p, nil + case string(gtsmodel.ActivityStreamsService): + p, ok := t.(vocab.ActivityStreamsService) + if !ok { + return nil, errors.New("error resolving type as activitystreams service") + } + return p, nil } return nil, fmt.Errorf("type name %s not supported", t.GetTypeName()) @@ -243,3 +267,23 @@ func (f *federator) GetTransportForUser(username string) (transport.Transport, e } return transport, nil } + +func sameActor(activityActor vocab.ActivityStreamsActorProperty, followActor vocab.ActivityStreamsActorProperty) bool { + if activityActor == nil || followActor == nil { + return false + } + for aIter := activityActor.Begin(); aIter != activityActor.End(); aIter = aIter.Next() { + for fIter := followActor.Begin(); fIter != followActor.End(); fIter = fIter.Next() { + if aIter.GetIRI() == nil { + return false + } + if fIter.GetIRI() == nil { + return false + } + if aIter.GetIRI().String() == fIter.GetIRI().String() { + return true + } + } + } + return false +} |