From 1bfc1aa7d178ccbb19cb70c52141831b9b07e810 Mon Sep 17 00:00:00 2001 From: tobi Date: Sun, 6 Apr 2025 12:02:26 +0200 Subject: [PATCH] fiddle with it! (that's what she said) --- internal/db/bundb/account.go | 263 +++++++----------- internal/federation/authenticate.go | 2 + internal/federation/dereferencing/account.go | 46 ++- .../federation/dereferencing/account_test.go | 15 +- internal/federation/dereferencing/status.go | 69 +++-- internal/processing/account/alias.go | 5 + internal/processing/account/get.go | 3 + internal/processing/account/move.go | 6 +- internal/processing/search/get.go | 5 + .../processing/workers/fromfediapi_move.go | 3 + 10 files changed, 218 insertions(+), 199 deletions(-) diff --git a/internal/db/bundb/account.go b/internal/db/bundb/account.go index 3029dba0f..88a923ecf 100644 --- a/internal/db/bundb/account.go +++ b/internal/db/bundb/account.go @@ -46,22 +46,48 @@ type accountDB struct { state *state.State } -func (a *accountDB) getAccountsBy( - ctx context.Context, - index string, - keys []string, - load func([]string) ([]*gtsmodel.Account, error), - getKey func(*gtsmodel.Account) string, -) ([]*gtsmodel.Account, error) { - // Load all input account keys via cache loader callback. - accounts, err := a.state.Caches.DB.Account.LoadIDs(index, keys, load) +func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, error) { + return a.getAccount( + ctx, + "ID", + func(account *gtsmodel.Account) error { + return a.db.NewSelect(). + Model(account). + Where("? = ?", bun.Ident("account.id"), id). + Scan(ctx) + }, + id, + ) +} + +func (a *accountDB) GetAccountsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Account, error) { + // Load all input account IDs via cache loader callback. + accounts, err := a.state.Caches.DB.Account.LoadIDs("ID", + ids, + func(uncached []string) ([]*gtsmodel.Account, error) { + // Preallocate expected length of uncached accounts. + accounts := make([]*gtsmodel.Account, 0, len(uncached)) + + // Perform database query scanning + // the remaining (uncached) account IDs. + if err := a.db.NewSelect(). + Model(&accounts). + Where("? IN (?)", bun.Ident("id"), bun.In(uncached)). + Scan(ctx); err != nil { + return nil, err + } + + return accounts, nil + }, + ) if err != nil { return nil, err } // Reorder the statuses by their - // keys to ensure in correct order. - xslices.OrderBy(accounts, keys, getKey) + // IDs to ensure in correct order. + getID := func(a *gtsmodel.Account) string { return a.ID } + xslices.OrderBy(accounts, ids, getID) if gtscontext.Barebones(ctx) { // no need to fully populate. @@ -81,75 +107,6 @@ func (a *accountDB) getAccountsBy( return accounts, nil } -func (a *accountDB) getOneAccountBy( - ctx context.Context, - index string, - key string, - load func([]string) ([]*gtsmodel.Account, error), -) (*gtsmodel.Account, error) { - // Get all accounts with the given key. - accounts, err := a.getAccountsBy( - ctx, - index, - []string{key}, - load, - func(a *gtsmodel.Account) string { return key }, - ) - if err != nil { - return nil, err - } - - // Ensure we have one - // and only one account. - l := len(accounts) - if l == 0 { - return nil, db.ErrNoEntries - } - if l > 1 { - return nil, db.ErrMultipleEntries - } - - return accounts[0], nil -} - -func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, error) { - return a.getAccount( - ctx, - "ID", - func(account *gtsmodel.Account) error { - return a.db.NewSelect(). - Model(account). - Where("? = ?", bun.Ident("account.id"), id). - Scan(ctx) - }, - id, - ) -} - -func (a *accountDB) GetAccountsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Account, error) { - return a.getAccountsBy( - ctx, - "ID", - ids, - func(uncached []string) ([]*gtsmodel.Account, error) { - // Preallocate expected length of uncached accounts. - accounts := make([]*gtsmodel.Account, 0, len(uncached)) - - // Perform database query scanning - // the remaining (uncached) accounts. - if err := a.db.NewSelect(). - Model(&accounts). - Where("? IN (?)", bun.Ident("account.id"), bun.In(uncached)). - Scan(ctx); err != nil { - return nil, err - } - - return accounts, nil - }, - func(a *gtsmodel.Account) string { return a.ID }, - ) -} - func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.Account, error) { return a.getAccount( ctx, @@ -165,51 +122,45 @@ func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel. } func (a *accountDB) GetOneAccountByURL(ctx context.Context, url string) (*gtsmodel.Account, error) { - return a.getOneAccountBy( - ctx, - "URL", - url, - func(uncached []string) ([]*gtsmodel.Account, error) { - // Preallocate expected length of uncached accounts. - accounts := make([]*gtsmodel.Account, 0, len(uncached)) + // Select IDs of all + // accounts with this url. + var ids []string + if err := a.db.NewSelect(). + TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")). + Column("account.id"). + Where("? = ?", bun.Ident("account.url"), url). + Scan(ctx, &ids); err != nil { + return nil, err + } - // Perform database query scanning - // the remaining (uncached) accounts. - if err := a.db.NewSelect(). - Model(&accounts). - Where("? IN (?)", bun.Ident("account.url"), bun.In(uncached)). - Scan(ctx); err != nil { - return nil, err - } + // Ensure exactly one account. + if len(ids) == 0 { + return nil, db.ErrNoEntries + } + if len(ids) > 1 { + return nil, db.ErrMultipleEntries + } - return accounts, nil - }, - ) + return a.GetAccountByID(ctx, ids[0]) } func (a *accountDB) GetAccountsByURL(ctx context.Context, url string) ([]*gtsmodel.Account, error) { - // Get all accounts with the given URL. - return a.getAccountsBy( - ctx, - "ID", - []string{url}, - func(uncached []string) ([]*gtsmodel.Account, error) { - // Preallocate expected length of uncached accounts. - accounts := make([]*gtsmodel.Account, 0, len(uncached)) + // Select IDs of all + // accounts with this url. + var ids []string + if err := a.db.NewSelect(). + TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")). + Column("account.id"). + Where("? = ?", bun.Ident("account.url"), url). + Scan(ctx, &ids); err != nil { + return nil, err + } - // Perform database query scanning - // the remaining (uncached) accounts. - if err := a.db.NewSelect(). - Model(&accounts). - Where("? IN (?)", bun.Ident("account.url"), bun.In(uncached)). - Scan(ctx); err != nil { - return nil, err - } + if len(ids) == 0 { + return nil, db.ErrNoEntries + } - return accounts, nil - }, - func(a *gtsmodel.Account) string { return a.URL }, - ) + return a.GetAccountsByIDs(ctx, ids) } func (a *accountDB) GetAccountByUsernameDomain(ctx context.Context, username string, domain string) (*gtsmodel.Account, error) { @@ -261,50 +212,50 @@ func (a *accountDB) GetAccountByPubkeyID(ctx context.Context, id string) (*gtsmo ) } -func (a *accountDB) GetOneAccountByInboxURI(ctx context.Context, uri string) (*gtsmodel.Account, error) { - return a.getOneAccountBy( - ctx, - "InboxURI", - uri, - func(uncached []string) ([]*gtsmodel.Account, error) { - // Preallocate expected length of uncached accounts. - accounts := make([]*gtsmodel.Account, 0, len(uncached)) +func (a *accountDB) GetOneAccountByInboxURI(ctx context.Context, inboxURI string) (*gtsmodel.Account, error) { + // Select IDs of all accounts + // with this inbox_uri. + var ids []string + if err := a.db.NewSelect(). + TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")). + Column("account.id"). + Where("? = ?", bun.Ident("account.inbox_uri"), inboxURI). + Scan(ctx, &ids); err != nil { + return nil, err + } - // Perform database query scanning - // the remaining (uncached) accounts. - if err := a.db.NewSelect(). - Model(&accounts). - Where("? IN (?)", bun.Ident("account.inbox_uri"), bun.In(uncached)). - Scan(ctx); err != nil { - return nil, err - } + // Ensure exactly one account. + if len(ids) == 0 { + return nil, db.ErrNoEntries + } + if len(ids) > 1 { + return nil, db.ErrMultipleEntries + } - return accounts, nil - }, - ) + return a.GetAccountByID(ctx, ids[0]) } -func (a *accountDB) GetOneAccountByOutboxURI(ctx context.Context, uri string) (*gtsmodel.Account, error) { - return a.getOneAccountBy( - ctx, - "OutboxURI", - uri, - func(uncached []string) ([]*gtsmodel.Account, error) { - // Preallocate expected length of uncached accounts. - accounts := make([]*gtsmodel.Account, 0, len(uncached)) +func (a *accountDB) GetOneAccountByOutboxURI(ctx context.Context, outboxURI string) (*gtsmodel.Account, error) { + // Select IDs of all accounts + // with this outbox_uri. + var ids []string + if err := a.db.NewSelect(). + TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")). + Column("account.id"). + Where("? = ?", bun.Ident("account.outbox_uri"), outboxURI). + Scan(ctx, &ids); err != nil { + return nil, err + } - // Perform database query scanning - // the remaining (uncached) accounts. - if err := a.db.NewSelect(). - Model(&accounts). - Where("? IN (?)", bun.Ident("account.outbox_uri"), bun.In(uncached)). - Scan(ctx); err != nil { - return nil, err - } + // Ensure exactly one account. + if len(ids) == 0 { + return nil, db.ErrNoEntries + } + if len(ids) > 1 { + return nil, db.ErrMultipleEntries + } - return accounts, nil - }, - ) + return a.GetAccountByID(ctx, ids[0]) } func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, error) { diff --git a/internal/federation/authenticate.go b/internal/federation/authenticate.go index 7d84774fd..363568f8b 100644 --- a/internal/federation/authenticate.go +++ b/internal/federation/authenticate.go @@ -199,9 +199,11 @@ func (f *Federator) AuthenticateFederatedRequest(ctx context.Context, requestedU } // Dereference the account located at owner URI. + // Use exact URI match, not URL match. pubKeyAuth.Owner, _, err = f.GetAccountByURI(ctx, requestedUsername, pubKeyAuth.OwnerURI, + false, ) if err != nil { if gtserror.StatusCode(err) == http.StatusGone { diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go index ca4fb16a5..f882eb7c3 100644 --- a/internal/federation/dereferencing/account.go +++ b/internal/federation/dereferencing/account.go @@ -89,14 +89,30 @@ func accountFresh( return !time.Now().After(staleAt) } -// GetAccountByURI will attempt to fetch an accounts by its URI, first checking the database. In the case of a newly-met remote model, or a remote model -// whose last_fetched date is beyond a certain interval, the account will be dereferenced. In the case of dereferencing, some low-priority account information -// may be enqueued for asynchronous fetching, e.g. featured account statuses (pins). An ActivityPub object indicates the account was dereferenced. -func (d *Dereferencer) GetAccountByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Account, ap.Accountable, error) { +// GetAccountByURI will attempt to fetch an accounts by its +// URI, first checking the database. In the case of a newly-met +// remote model, or a remote model whose last_fetched date is +// beyond a certain interval, the account will be dereferenced. +// In the case of dereferencing, some low-priority account info +// may be enqueued for asynchronous fetching, e.g. pinned statuses. +// An ActivityPub object indicates the account was dereferenced. +// +// if tryURL is true, then the database will also check for a *single* +// account where uri == account.url, not just uri == account.uri. +// Because url does not guarantee uniqueness, you should only set +// tryURL to true when doing searches set in motion by a user, +// ie., when it's not important that an exact account is returned. +func (d *Dereferencer) GetAccountByURI( + ctx context.Context, + requestUser string, + uri *url.URL, + tryURL bool, +) (*gtsmodel.Account, ap.Accountable, error) { // Fetch and dereference account if necessary. account, accountable, err := d.getAccountByURI(ctx, requestUser, uri, + tryURL, ) if err != nil { return nil, nil, err @@ -118,8 +134,15 @@ func (d *Dereferencer) GetAccountByURI(ctx context.Context, requestUser string, return account, accountable, nil } -// getAccountByURI is a package internal form of .GetAccountByURI() that doesn't bother dereferencing featured posts on update. -func (d *Dereferencer) getAccountByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Account, ap.Accountable, error) { +// getAccountByURI is a package internal form of +// .GetAccountByURI() that doesn't bother dereferencing +// featured posts on update. +func (d *Dereferencer) getAccountByURI( + ctx context.Context, + requestUser string, + uri *url.URL, + tryURL bool, +) (*gtsmodel.Account, ap.Accountable, error) { var ( account *gtsmodel.Account uriStr = uri.String() @@ -127,9 +150,8 @@ func (d *Dereferencer) getAccountByURI(ctx context.Context, requestUser string, ) // Search the database for existing account with URI. + // URI is unique so if we get a hit it's that account for sure. account, err = d.state.DB.GetAccountByURI( - // request a barebones object, it may be in the - // db but with related models not yet dereferenced. gtscontext.SetBarebones(ctx), uriStr, ) @@ -137,9 +159,11 @@ func (d *Dereferencer) getAccountByURI(ctx context.Context, requestUser string, return nil, nil, gtserror.Newf("error checking database for account %s by uri: %w", uriStr, err) } - if account == nil { - // Else, search the database for one account with URL. - // Can return multiple hits so check for ErrMultipleEntries. + if account == nil && tryURL { + // Else if we're permitted, search the database for *ONE* + // account with this URL. This can return multiple hits + // so check for ErrMultipleEntries. If we get exactly one + // hit it's *probably* the account we're looking for. account, err = d.state.DB.GetOneAccountByURL( gtscontext.SetBarebones(ctx), uriStr, diff --git a/internal/federation/dereferencing/account_test.go b/internal/federation/dereferencing/account_test.go index 14796c074..4af885468 100644 --- a/internal/federation/dereferencing/account_test.go +++ b/internal/federation/dereferencing/account_test.go @@ -54,6 +54,7 @@ func (suite *AccountTestSuite) TestDereferenceGroup() { context.Background(), fetchingAccount.Username, groupURL, + false, ) suite.NoError(err) suite.NotNil(group) @@ -78,6 +79,7 @@ func (suite *AccountTestSuite) TestDereferenceService() { context.Background(), fetchingAccount.Username, serviceURL, + false, ) suite.NoError(err) suite.NotNil(service) @@ -110,6 +112,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsRemoteURL() { context.Background(), fetchingAccount.Username, testrig.URLMustParse(targetAccount.URI), + false, ) suite.NoError(err) suite.NotNil(fetchedAccount) @@ -129,6 +132,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsRemoteURLNoSharedInb context.Background(), fetchingAccount.Username, testrig.URLMustParse(targetAccount.URI), + false, ) suite.NoError(err) suite.NotNil(fetchedAccount) @@ -143,6 +147,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsUsername() { context.Background(), fetchingAccount.Username, testrig.URLMustParse(targetAccount.URI), + false, ) suite.NoError(err) suite.NotNil(fetchedAccount) @@ -157,6 +162,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsUsernameDomain() { context.Background(), fetchingAccount.Username, testrig.URLMustParse(targetAccount.URI), + false, ) suite.NoError(err) suite.NotNil(fetchedAccount) @@ -213,6 +219,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountWithUnknownUserURI() { context.Background(), fetchingAccount.Username, testrig.URLMustParse("http://localhost:8080/users/thisaccountdoesnotexist"), + false, ) suite.True(gtserror.IsUnretrievable(err)) suite.EqualError(err, db.ErrNoEntries.Error()) @@ -265,7 +272,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountByRedirect() { uri := testrig.URLMustParse("https://this-will-be-redirected.butts/") // Try dereference the test URI, since it correctly redirects to us it should return our account. - account, accountable, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAccount.Username, uri) + account, accountable, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAccount.Username, uri, false) suite.NoError(err) suite.Nil(accountable) suite.NotNil(account) @@ -318,7 +325,7 @@ func (suite *AccountTestSuite) TestDereferenceMasqueradingLocalAccount() { ) // Try dereference the test URI, since it correctly redirects to us it should return our account. - account, accountable, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAccount.Username, uri) + account, accountable, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAccount.Username, uri, false) suite.NotNil(err) suite.Nil(account) suite.Nil(accountable) @@ -341,6 +348,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithNonMatchingURI() context.Background(), fetchingAccount.Username, testrig.URLMustParse(remoteAltURI), + false, ) suite.Equal(err.Error(), fmt.Sprintf("enrichAccount: account uri %s does not match %s", remoteURI, remoteAltURI)) suite.Nil(fetchedAccount) @@ -357,6 +365,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithUnexpectedKeyChan remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAcc.Username, testrig.URLMustParse(remoteURI), + false, ) suite.NoError(err) suite.NotNil(remoteAcc) @@ -395,6 +404,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithExpectedKeyChange remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAcc.Username, testrig.URLMustParse(remoteURI), + false, ) suite.NoError(err) suite.NotNil(remoteAcc) @@ -436,6 +446,7 @@ func (suite *AccountTestSuite) TestRefreshFederatedRemoteAccountWithKeyChange() remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx, fetchingAcc.Username, testrig.URLMustParse(remoteURI), + false, ) suite.NoError(err) suite.NotNil(remoteAcc) diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go index 2718187cf..cfb6b7f86 100644 --- a/internal/federation/dereferencing/status.go +++ b/internal/federation/dereferencing/status.go @@ -454,7 +454,8 @@ func (d *Dereferencer) enrichStatus( // Ensure we have the author account of the status dereferenced (+ up-to-date). If this is a new status // (i.e. status.AccountID == "") then any error here is irrecoverable. status.AccountID must ALWAYS be set. - if _, _, err := d.getAccountByURI(ctx, requestUser, attributedTo); err != nil && status.AccountID == "" { + // We want the exact URI match here as well, not the imprecise URL match. + if _, _, err := d.getAccountByURI(ctx, requestUser, attributedTo, false); err != nil && status.AccountID == "" { // Note that we specifically DO NOT wrap the error, instead collapsing it as string. // Errors fetching an account do not necessarily relate to dereferencing the status. @@ -1312,35 +1313,17 @@ func (d *Dereferencer) getPopulatedMention( bool, // True if mention already exists in the DB. error, ) { - // Mentions can be created using Name or Href. - // Prefer Href (TargetAccountURI), fall back to Name. - if mention.TargetAccountURI != "" { + // Mentions can be created using `name` or `href`, + // and when mention was extracted, we ensured that + // one of either `name` or `href` was set. + // + // Prefer to deref the mention target using `name`, + // which should always be exact. and fall back to `href`, + // which *should* be the target's URI, but may be the URL + // depending on implementation. + if mention.NameString != "" { - // Look for existing mention with target account's URI, if so use this. - existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI) - if ok && existingMention.ID != "" { - return existingMention, true, nil - } - - // Ensure that mention account URI is parseable. - accountURI, err := url.Parse(mention.TargetAccountURI) - if err != nil { - err := gtserror.Newf("invalid account uri %q: %w", mention.TargetAccountURI, err) - return nil, false, err - } - - // Ensure we have account of the mention target dereferenced. - mention.TargetAccount, _, err = d.getAccountByURI(ctx, - requestUser, - accountURI, - ) - if err != nil { - err := gtserror.Newf("failed to dereference account %s: %w", accountURI, err) - return nil, false, err - } - } else { - - // Href wasn't set, extract the username and domain parts from namestring. + // Extract the username and domain parts from namestring. username, domain, err := util.ExtractNamestringParts(mention.NameString) if err != nil { err := gtserror.Newf("failed to parse namestring %s: %w", mention.NameString, err) @@ -1369,6 +1352,34 @@ func (d *Dereferencer) getPopulatedMention( if ok && existingMention.ID != "" { return existingMention, true, nil } + } else { + + // Name wasn't set. + // + // Look for existing mention with target account's URI, if so use this. + existingMention, ok := existing.GetMentionByTargetURI(mention.TargetAccountURI) + if ok && existingMention.ID != "" { + return existingMention, true, nil + } + + // Ensure that mention account URI is parseable. + accountURI, err := url.Parse(mention.TargetAccountURI) + if err != nil { + err := gtserror.Newf("invalid account uri %q: %w", mention.TargetAccountURI, err) + return nil, false, err + } + + // Ensure we have account of the mention target dereferenced. + // Don't allow imprecise URL here, we want the exact acct. + mention.TargetAccount, _, err = d.getAccountByURI(ctx, + requestUser, + accountURI, + false, + ) + if err != nil { + err := gtserror.Newf("failed to dereference account %s: %w", accountURI, err) + return nil, false, err + } } // At this point, mention.TargetAccountURI diff --git a/internal/processing/account/alias.go b/internal/processing/account/alias.go index d7d4cf547..ca27a518c 100644 --- a/internal/processing/account/alias.go +++ b/internal/processing/account/alias.go @@ -107,9 +107,14 @@ func (p *Processor) Alias( } // Ensure we have account dereferenced. + // + // As this comes from user input, allow checking + // by URL to make things easier, not just to an + // exact AP URI (which a user might not even know). targetAccount, _, err := p.federator.GetAccountByURI(ctx, account.Username, newAKA.uri, + true, ) if err != nil { err := fmt.Errorf( diff --git a/internal/processing/account/get.go b/internal/processing/account/get.go index eac0f0c3f..33eb4c101 100644 --- a/internal/processing/account/get.go +++ b/internal/processing/account/get.go @@ -66,10 +66,13 @@ func (p *Processor) Get(ctx context.Context, requestingAccount *gtsmodel.Account // Perform a last-minute fetch of target account to // ensure remote account header / avatar is cached. + // + // Match by URI only. latest, _, err := p.federator.GetAccountByURI( gtscontext.SetFastFail(ctx), requestingAccount.Username, targetAccountURI, + false, ) if err != nil { log.Errorf(ctx, "error fetching latest target account: %v", err) diff --git a/internal/processing/account/move.go b/internal/processing/account/move.go index 1c5209e70..c8665cf04 100644 --- a/internal/processing/account/move.go +++ b/internal/processing/account/move.go @@ -119,11 +119,15 @@ func (p *Processor) MoveSelf( unlock := p.state.ProcessingLocks.Lock(lockKey) defer unlock() - // Ensure we have a valid, up-to-date representation of the target account. + // Ensure we have a valid, up-to-date + // representation of the target account. + // + // Match by uri only. targetAcct, targetAcctable, err = p.federator.GetAccountByURI( ctx, originAcct.Username, targetAcctURI, + false, ) if err != nil { const text = "error dereferencing moved_to_uri" diff --git a/internal/processing/search/get.go b/internal/processing/search/get.go index 0aeea5092..7a65bed1d 100644 --- a/internal/processing/search/get.go +++ b/internal/processing/search/get.go @@ -564,10 +564,15 @@ func (p *Processor) accountsByURI( if resolve { // We're allowed to resolve, leave the // rest up to the dereferencer functions. + // + // Allow dereferencing by URL and not just URI; + // there are many cases where someone might + // paste a URL into the search bar. account, _, err := p.federator.GetAccountByURI( gtscontext.SetFastFail(ctx), requestingAccount.Username, uri, + true, ) return []*gtsmodel.Account{account}, err diff --git a/internal/processing/workers/fromfediapi_move.go b/internal/processing/workers/fromfediapi_move.go index d1e43c0c7..d2f06de5d 100644 --- a/internal/processing/workers/fromfediapi_move.go +++ b/internal/processing/workers/fromfediapi_move.go @@ -303,10 +303,13 @@ func (p *fediAPI) MoveAccount(ctx context.Context, fMsg *messages.FromFediAPI) e } // Account to which the Move is taking place. + // + // Match by uri only. targetAcct, targetAcctable, err := p.federate.GetAccountByURI( ctx, fMsg.Receiving.Username, targetAcctURI, + false, ) if err != nil { return gtserror.Newf(