summaryrefslogtreecommitdiff
path: root/internal/federation
diff options
context:
space:
mode:
Diffstat (limited to 'internal/federation')
-rw-r--r--internal/federation/federating_db.go205
-rw-r--r--internal/federation/federatingprotocol.go2
-rw-r--r--internal/federation/util.go16
3 files changed, 180 insertions, 43 deletions
diff --git a/internal/federation/federating_db.go b/internal/federation/federating_db.go
index 8f203e132..af685904a 100644
--- a/internal/federation/federating_db.go
+++ b/internal/federation/federating_db.go
@@ -241,6 +241,40 @@ func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) {
return true, nil
}
+ if util.IsFollowersPath(id) {
+ username, err := util.ParseFollowersPath(id)
+ if err != nil {
+ return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
+ }
+ if err := f.db.GetLocalAccountByUsername(username, &gtsmodel.Account{}); err != nil {
+ if _, ok := err.(db.ErrNoEntries); ok {
+ // there are no entries for this username
+ return false, nil
+ }
+ // an actual error happened
+ return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
+ }
+ l.Debug("we DO own this")
+ return true, nil
+ }
+
+ if util.IsFollowingPath(id) {
+ username, err := util.ParseFollowingPath(id)
+ if err != nil {
+ return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
+ }
+ if err := f.db.GetLocalAccountByUsername(username, &gtsmodel.Account{}); err != nil {
+ if _, ok := err.(db.ErrNoEntries); ok {
+ // there are no entries for this username
+ return false, nil
+ }
+ // an actual error happened
+ return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
+ }
+ l.Debug("we DO own this")
+ return true, nil
+ }
+
return false, fmt.Errorf("could not match activityID: %s", id.String())
}
@@ -502,6 +536,15 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l.Error("receiving account was set on context but couldn't be parsed")
}
+ requestingAcctI := ctx.Value(util.APRequestingAccount)
+ if receivingAcctI == nil {
+ l.Error("requesting account wasn't set on context")
+ }
+ requestingAcct, ok := requestingAcctI.(*gtsmodel.Account)
+ if !ok {
+ l.Error("requesting account was set on context but couldn't be parsed")
+ }
+
fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
if fromFederatorChanI == nil {
l.Error("from federator channel wasn't set on context")
@@ -511,51 +554,76 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l.Error("from federator channel was set on context but couldn't be parsed")
}
- switch asType.GetTypeName() {
- case gtsmodel.ActivityStreamsUpdate:
- update, ok := asType.(vocab.ActivityStreamsCreate)
- if !ok {
- return errors.New("could not convert type to create")
+ typeName := asType.GetTypeName()
+ if typeName == gtsmodel.ActivityStreamsApplication ||
+ typeName == gtsmodel.ActivityStreamsGroup ||
+ typeName == gtsmodel.ActivityStreamsOrganization ||
+ typeName == gtsmodel.ActivityStreamsPerson ||
+ typeName == gtsmodel.ActivityStreamsService {
+ // it's an UPDATE to some kind of account
+ var accountable typeutils.Accountable
+
+ switch asType.GetTypeName() {
+ case gtsmodel.ActivityStreamsApplication:
+ l.Debug("got update for APPLICATION")
+ i, ok := asType.(vocab.ActivityStreamsApplication)
+ if !ok {
+ return errors.New("could not convert type to application")
+ }
+ accountable = i
+ case gtsmodel.ActivityStreamsGroup:
+ l.Debug("got update for GROUP")
+ i, ok := asType.(vocab.ActivityStreamsGroup)
+ if !ok {
+ return errors.New("could not convert type to group")
+ }
+ accountable = i
+ case gtsmodel.ActivityStreamsOrganization:
+ l.Debug("got update for ORGANIZATION")
+ i, ok := asType.(vocab.ActivityStreamsOrganization)
+ if !ok {
+ return errors.New("could not convert type to organization")
+ }
+ accountable = i
+ case gtsmodel.ActivityStreamsPerson:
+ l.Debug("got update for PERSON")
+ i, ok := asType.(vocab.ActivityStreamsPerson)
+ if !ok {
+ return errors.New("could not convert type to person")
+ }
+ accountable = i
+ case gtsmodel.ActivityStreamsService:
+ l.Debug("got update for SERVICE")
+ i, ok := asType.(vocab.ActivityStreamsService)
+ if !ok {
+ return errors.New("could not convert type to service")
+ }
+ accountable = i
}
- object := update.GetActivityStreamsObject()
- for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {
- switch objectIter.GetType().GetTypeName() {
- case string(gtsmodel.ActivityStreamsPerson):
- person := objectIter.GetActivityStreamsPerson()
- updatedAcct, err := f.typeConverter.ASRepresentationToAccount(person)
- if err != nil {
- return fmt.Errorf("error converting person to account: %s", err)
- }
- if err := f.db.Put(updatedAcct); err != nil {
- return fmt.Errorf("database error inserting updated account: %s", err)
- }
- fromFederatorChan <- gtsmodel.FromFederator{
- APObjectType: gtsmodel.ActivityStreamsProfile,
- APActivityType: gtsmodel.ActivityStreamsUpdate,
- GTSModel: updatedAcct,
- ReceivingAccount: receivingAcct,
- }
+ updatedAcct, err := f.typeConverter.ASRepresentationToAccount(accountable, true)
+ if err != nil {
+ return fmt.Errorf("error converting to account: %s", err)
+ }
- case string(gtsmodel.ActivityStreamsApplication):
- application := objectIter.GetActivityStreamsApplication()
- updatedAcct, err := f.typeConverter.ASRepresentationToAccount(application)
- if err != nil {
- return fmt.Errorf("error converting person to account: %s", err)
- }
- if err := f.db.Put(updatedAcct); err != nil {
- return fmt.Errorf("database error inserting updated account: %s", err)
- }
+ 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)
+ }
- fromFederatorChan <- gtsmodel.FromFederator{
- APObjectType: gtsmodel.ActivityStreamsProfile,
- APActivityType: gtsmodel.ActivityStreamsUpdate,
- GTSModel: updatedAcct,
- ReceivingAccount: receivingAcct,
- }
- }
+ updatedAcct.ID = requestingAcct.ID // set this here so the db will update properly instead of trying to PUT this and getting constraint issues
+ if err := f.db.UpdateByID(requestingAcct.ID, updatedAcct); err != nil {
+ return fmt.Errorf("database error inserting updated account: %s", err)
+ }
+
+ fromFederatorChan <- gtsmodel.FromFederator{
+ APObjectType: gtsmodel.ActivityStreamsProfile,
+ APActivityType: gtsmodel.ActivityStreamsUpdate,
+ GTSModel: updatedAcct,
+ ReceivingAccount: receivingAcct,
}
+
}
+
return nil
}
@@ -565,7 +633,7 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
// Protocol instead call Update to create a Tombstone.
//
// The library makes this call only after acquiring a lock first.
-func (f *federatingDB) Delete(c context.Context, id *url.URL) error {
+func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
l := f.log.WithFields(
logrus.Fields{
"func": "Delete",
@@ -573,6 +641,63 @@ func (f *federatingDB) Delete(c context.Context, id *url.URL) error {
},
)
l.Debugf("received DELETE id %s", id.String())
+
+ inboxAcctI := ctx.Value(util.APAccount)
+ if inboxAcctI == nil {
+ l.Error("inbox account wasn't set on context")
+ return nil
+ }
+ inboxAcct, ok := inboxAcctI.(*gtsmodel.Account)
+ if !ok {
+ l.Error("inbox account was set on context but couldn't be parsed")
+ return nil
+ }
+
+ fromFederatorChanI := ctx.Value(util.APFromFederatorChanKey)
+ if fromFederatorChanI == nil {
+ l.Error("from federator channel wasn't set on context")
+ return nil
+ }
+ fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator)
+ if !ok {
+ l.Error("from federator channel was set on context but couldn't be parsed")
+ return nil
+ }
+
+ // in a delete we only get the URI, we can't know if we have a status or a profile or something else,
+ // so we have to try a few different things...
+ where := []db.Where{{Key: "uri", Value: id.String()}}
+
+ s := &gtsmodel.Status{}
+ if err := f.db.GetWhere(where, s); err == nil {
+ // it's a status
+ l.Debugf("uri is for status with id: %s", s.ID)
+ if err := f.db.DeleteByID(s.ID, &gtsmodel.Status{}); err != nil {
+ return fmt.Errorf("Delete: err deleting status: %s", err)
+ }
+ fromFederatorChan <- gtsmodel.FromFederator{
+ APObjectType: gtsmodel.ActivityStreamsNote,
+ APActivityType: gtsmodel.ActivityStreamsDelete,
+ GTSModel: s,
+ ReceivingAccount: inboxAcct,
+ }
+ }
+
+ a := &gtsmodel.Account{}
+ if err := f.db.GetWhere(where, a); err == nil {
+ // it's an account
+ l.Debugf("uri is for an account with id: %s", s.ID)
+ if err := f.db.DeleteByID(a.ID, &gtsmodel.Account{}); err != nil {
+ return fmt.Errorf("Delete: err deleting account: %s", err)
+ }
+ fromFederatorChan <- gtsmodel.FromFederator{
+ APObjectType: gtsmodel.ActivityStreamsProfile,
+ APActivityType: gtsmodel.ActivityStreamsDelete,
+ GTSModel: a,
+ ReceivingAccount: inboxAcct,
+ }
+ }
+
return nil
}
diff --git a/internal/federation/federatingprotocol.go b/internal/federation/federatingprotocol.go
index 61fecb11a..ab4b5ccbc 100644
--- a/internal/federation/federatingprotocol.go
+++ b/internal/federation/federatingprotocol.go
@@ -136,7 +136,7 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
return ctx, false, fmt.Errorf("error dereferencing account with public key id %s: %s", publicKeyOwnerURI.String(), err)
}
- a, err := f.typeConverter.ASRepresentationToAccount(person)
+ a, err := f.typeConverter.ASRepresentationToAccount(person, false)
if err != nil {
return ctx, false, fmt.Errorf("error converting person with public key id %s to account: %s", publicKeyOwnerURI.String(), err)
}
diff --git a/internal/federation/util.go b/internal/federation/util.go
index 3f53ed6a7..6ae0152df 100644
--- a/internal/federation/util.go
+++ b/internal/federation/util.go
@@ -132,9 +132,11 @@ func (f *federator) AuthenticateFederatedRequest(username string, r *http.Reques
var publicKey interface{}
var pkOwnerURI *url.URL
+ requestingRemoteAccount := &gtsmodel.Account{}
+ requestingLocalAccount := &gtsmodel.Account{}
if strings.EqualFold(requestingPublicKeyID.Host, f.config.Host) {
+ // LOCAL ACCOUNT REQUEST
// the request is coming from INSIDE THE HOUSE so skip the remote dereferencing
- requestingLocalAccount := &gtsmodel.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)
}
@@ -143,8 +145,18 @@ func (f *federator) AuthenticateFederatedRequest(username string, r *http.Reques
if err != nil {
return nil, fmt.Errorf("error parsing url %s: %s", requestingLocalAccount.URI, err)
}
+ } else if err := f.db.GetWhere([]db.Where{{Key: "public_key_uri", Value: requestingPublicKeyID.String()}}, requestingRemoteAccount); err == nil {
+ // REMOTE ACCOUNT REQUEST WITH KEY CACHED LOCALLY
+ // this is a remote account and we already have the public key for it so use that
+ publicKey = requestingRemoteAccount.PublicKey
+ pkOwnerURI, err = url.Parse(requestingRemoteAccount.URI)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing url %s: %s", requestingRemoteAccount.URI, err)
+ }
} else {
- // the request is remote, so we need to authenticate the request properly by dereferencing the remote key
+ // REMOTE ACCOUNT REQUEST WITHOUT KEY CACHED LOCALLY
+ // the request is remote and we don't have the public key yet,
+ // 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)