diff options
Diffstat (limited to 'internal/db/federating_db.go')
-rw-r--r-- | internal/db/federating_db.go | 119 |
1 files changed, 109 insertions, 10 deletions
diff --git a/internal/db/federating_db.go b/internal/db/federating_db.go index 16e3262ae..ab66b19de 100644 --- a/internal/db/federating_db.go +++ b/internal/db/federating_db.go @@ -21,12 +21,16 @@ package db import ( "context" "errors" + "fmt" "net/url" "sync" "github.com/go-fed/activity/pub" "github.com/go-fed/activity/streams/vocab" + "github.com/sirupsen/logrus" "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/util" ) // FederatingDB uses the underlying DB interface to implement the go-fed pub.Database interface. @@ -35,13 +39,15 @@ type federatingDB struct { locks *sync.Map db DB config *config.Config + log *logrus.Logger } -func newFederatingDB(db DB, config *config.Config) pub.Database { +func NewFederatingDB(db DB, config *config.Config, log *logrus.Logger) pub.Database { return &federatingDB{ locks: new(sync.Map), db: db, config: config, + log: log, } } @@ -98,7 +104,30 @@ func (f *federatingDB) Unlock(c context.Context, id *url.URL) error { // // The library makes this call only after acquiring a lock first. func (f *federatingDB) InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error) { - return false, nil + + if !util.IsInboxPath(inbox) { + return false, fmt.Errorf("%s is not an inbox URI", inbox.String()) + } + + if !util.IsStatusesPath(id) { + return false, fmt.Errorf("%s is not a status URI", id.String()) + } + _, statusID, err := util.ParseStatusesPath(inbox) + if err != nil { + return false, fmt.Errorf("status URI %s was not parseable: %s", id.String(), err) + } + + if err := f.db.GetByID(statusID, >smodel.Status{}); err != nil { + if _, ok := err.(ErrNoEntries); ok { + // we don't have it + return false, nil + } + // actual error + return false, fmt.Errorf("error getting status from db: %s", err) + } + + // we must have it + return true, nil } // GetInbox returns the first ordered collection page of the outbox at @@ -118,26 +147,86 @@ func (f *federatingDB) SetInbox(c context.Context, inbox vocab.ActivityStreamsOr return nil } -// Owns returns true if the database has an entry for the IRI and it -// exists in the database. -// +// Owns returns true if the IRI belongs to this instance, and if +// the database has an entry for the IRI. // The library makes this call only after acquiring a lock first. -func (f *federatingDB) Owns(c context.Context, id *url.URL) (owns bool, err error) { - return false, nil +func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) { + // if the id host isn't this instance host, we don't own this IRI + if id.Host != f.config.Host { + return false, nil + } + + // apparently we own it, so what *is* it? + + // check if it's a status, eg /users/example_username/statuses/SOME_UUID_OF_A_STATUS + if util.IsStatusesPath(id) { + _, uid, err := util.ParseStatusesPath(id) + if err != nil { + return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err) + } + if err := f.db.GetWhere("uri", uid, >smodel.Status{}); err != nil { + if _, ok := err.(ErrNoEntries); ok { + // there are no entries for this status + return false, nil + } + // an actual error happened + return false, fmt.Errorf("database error fetching status with id %s: %s", uid, err) + } + return true, nil + } + + // check if it's a user, eg /users/example_username + if util.IsUserPath(id) { + username, err := util.ParseUserPath(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, >smodel.Account{}); err != nil { + if _, ok := err.(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) + } + return true, nil + } + + return false, fmt.Errorf("could not match activityID: %s", id.String()) } // ActorForOutbox fetches the actor's IRI for the given outbox IRI. // // The library makes this call only after acquiring a lock first. func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { - return nil, nil + if !util.IsOutboxPath(outboxIRI) { + return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String()) + } + acct := >smodel.Account{} + if err := f.db.GetWhere("outbox_uri", outboxIRI.String(), acct); err != nil { + if _, ok := err.(ErrNoEntries); ok { + return nil, fmt.Errorf("no actor found that corresponds to outbox %s", outboxIRI.String()) + } + return nil, fmt.Errorf("db error searching for actor with outbox %s", outboxIRI.String()) + } + return url.Parse(acct.URI) } // ActorForInbox fetches the actor's IRI for the given outbox IRI. // // The library makes this call only after acquiring a lock first. func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { - return nil, nil + if !util.IsInboxPath(inboxIRI) { + return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) + } + acct := >smodel.Account{} + if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil { + if _, ok := err.(ErrNoEntries); ok { + return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String()) + } + return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String()) + } + return url.Parse(acct.URI) } // OutboxForInbox fetches the corresponding actor's outbox IRI for the @@ -145,7 +234,17 @@ func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (acto // // The library makes this call only after acquiring a lock first. func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { - return nil, nil + if !util.IsInboxPath(inboxIRI) { + return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String()) + } + acct := >smodel.Account{} + if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil { + if _, ok := err.(ErrNoEntries); ok { + return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String()) + } + return nil, fmt.Errorf("db error searching for actor with inbox %s", inboxIRI.String()) + } + return url.Parse(acct.OutboxURI) } // Exists returns true if the database has an entry for the specified |