mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-30 08:43:32 -06:00
fiddle with it! (that's what she said)
This commit is contained in:
parent
39339dc832
commit
1bfc1aa7d1
10 changed files with 218 additions and 199 deletions
|
|
@ -46,22 +46,48 @@ type accountDB struct {
|
||||||
state *state.State
|
state *state.State
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *accountDB) getAccountsBy(
|
func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, error) {
|
||||||
ctx context.Context,
|
return a.getAccount(
|
||||||
index string,
|
ctx,
|
||||||
keys []string,
|
"ID",
|
||||||
load func([]string) ([]*gtsmodel.Account, error),
|
func(account *gtsmodel.Account) error {
|
||||||
getKey func(*gtsmodel.Account) string,
|
return a.db.NewSelect().
|
||||||
) ([]*gtsmodel.Account, error) {
|
Model(account).
|
||||||
// Load all input account keys via cache loader callback.
|
Where("? = ?", bun.Ident("account.id"), id).
|
||||||
accounts, err := a.state.Caches.DB.Account.LoadIDs(index, keys, load)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorder the statuses by their
|
// Reorder the statuses by their
|
||||||
// keys to ensure in correct order.
|
// IDs to ensure in correct order.
|
||||||
xslices.OrderBy(accounts, keys, getKey)
|
getID := func(a *gtsmodel.Account) string { return a.ID }
|
||||||
|
xslices.OrderBy(accounts, ids, getID)
|
||||||
|
|
||||||
if gtscontext.Barebones(ctx) {
|
if gtscontext.Barebones(ctx) {
|
||||||
// no need to fully populate.
|
// no need to fully populate.
|
||||||
|
|
@ -81,75 +107,6 @@ func (a *accountDB) getAccountsBy(
|
||||||
return accounts, nil
|
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) {
|
func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.Account, error) {
|
||||||
return a.getAccount(
|
return a.getAccount(
|
||||||
ctx,
|
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) {
|
func (a *accountDB) GetOneAccountByURL(ctx context.Context, url string) (*gtsmodel.Account, error) {
|
||||||
return a.getOneAccountBy(
|
// Select IDs of all
|
||||||
ctx,
|
// accounts with this url.
|
||||||
"URL",
|
var ids []string
|
||||||
url,
|
|
||||||
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().
|
if err := a.db.NewSelect().
|
||||||
Model(&accounts).
|
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||||
Where("? IN (?)", bun.Ident("account.url"), bun.In(uncached)).
|
Column("account.id").
|
||||||
Scan(ctx); err != nil {
|
Where("? = ?", bun.Ident("account.url"), url).
|
||||||
|
Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts, nil
|
// Ensure exactly one account.
|
||||||
},
|
if len(ids) == 0 {
|
||||||
)
|
return nil, db.ErrNoEntries
|
||||||
|
}
|
||||||
|
if len(ids) > 1 {
|
||||||
|
return nil, db.ErrMultipleEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.GetAccountByID(ctx, ids[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *accountDB) GetAccountsByURL(ctx context.Context, url string) ([]*gtsmodel.Account, error) {
|
func (a *accountDB) GetAccountsByURL(ctx context.Context, url string) ([]*gtsmodel.Account, error) {
|
||||||
// Get all accounts with the given URL.
|
// Select IDs of all
|
||||||
return a.getAccountsBy(
|
// accounts with this url.
|
||||||
ctx,
|
var ids []string
|
||||||
"ID",
|
|
||||||
[]string{url},
|
|
||||||
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().
|
if err := a.db.NewSelect().
|
||||||
Model(&accounts).
|
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||||
Where("? IN (?)", bun.Ident("account.url"), bun.In(uncached)).
|
Column("account.id").
|
||||||
Scan(ctx); err != nil {
|
Where("? = ?", bun.Ident("account.url"), url).
|
||||||
|
Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts, nil
|
if len(ids) == 0 {
|
||||||
},
|
return nil, db.ErrNoEntries
|
||||||
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) {
|
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) {
|
func (a *accountDB) GetOneAccountByInboxURI(ctx context.Context, inboxURI string) (*gtsmodel.Account, error) {
|
||||||
return a.getOneAccountBy(
|
// Select IDs of all accounts
|
||||||
ctx,
|
// with this inbox_uri.
|
||||||
"InboxURI",
|
var ids []string
|
||||||
uri,
|
|
||||||
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().
|
if err := a.db.NewSelect().
|
||||||
Model(&accounts).
|
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||||
Where("? IN (?)", bun.Ident("account.inbox_uri"), bun.In(uncached)).
|
Column("account.id").
|
||||||
Scan(ctx); err != nil {
|
Where("? = ?", bun.Ident("account.inbox_uri"), inboxURI).
|
||||||
|
Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts, nil
|
// Ensure exactly one account.
|
||||||
},
|
if len(ids) == 0 {
|
||||||
)
|
return nil, db.ErrNoEntries
|
||||||
|
}
|
||||||
|
if len(ids) > 1 {
|
||||||
|
return nil, db.ErrMultipleEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.GetAccountByID(ctx, ids[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *accountDB) GetOneAccountByOutboxURI(ctx context.Context, uri string) (*gtsmodel.Account, error) {
|
func (a *accountDB) GetOneAccountByOutboxURI(ctx context.Context, outboxURI string) (*gtsmodel.Account, error) {
|
||||||
return a.getOneAccountBy(
|
// Select IDs of all accounts
|
||||||
ctx,
|
// with this outbox_uri.
|
||||||
"OutboxURI",
|
var ids []string
|
||||||
uri,
|
|
||||||
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().
|
if err := a.db.NewSelect().
|
||||||
Model(&accounts).
|
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||||
Where("? IN (?)", bun.Ident("account.outbox_uri"), bun.In(uncached)).
|
Column("account.id").
|
||||||
Scan(ctx); err != nil {
|
Where("? = ?", bun.Ident("account.outbox_uri"), outboxURI).
|
||||||
|
Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts, nil
|
// Ensure exactly one account.
|
||||||
},
|
if len(ids) == 0 {
|
||||||
)
|
return nil, db.ErrNoEntries
|
||||||
|
}
|
||||||
|
if len(ids) > 1 {
|
||||||
|
return nil, db.ErrMultipleEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.GetAccountByID(ctx, ids[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, error) {
|
func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, error) {
|
||||||
|
|
|
||||||
|
|
@ -199,9 +199,11 @@ func (f *Federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dereference the account located at owner URI.
|
// Dereference the account located at owner URI.
|
||||||
|
// Use exact URI match, not URL match.
|
||||||
pubKeyAuth.Owner, _, err = f.GetAccountByURI(ctx,
|
pubKeyAuth.Owner, _, err = f.GetAccountByURI(ctx,
|
||||||
requestedUsername,
|
requestedUsername,
|
||||||
pubKeyAuth.OwnerURI,
|
pubKeyAuth.OwnerURI,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if gtserror.StatusCode(err) == http.StatusGone {
|
if gtserror.StatusCode(err) == http.StatusGone {
|
||||||
|
|
|
||||||
|
|
@ -89,14 +89,30 @@ func accountFresh(
|
||||||
return !time.Now().After(staleAt)
|
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
|
// GetAccountByURI will attempt to fetch an accounts by its
|
||||||
// whose last_fetched date is beyond a certain interval, the account will be dereferenced. In the case of dereferencing, some low-priority account information
|
// URI, first checking the database. In the case of a newly-met
|
||||||
// may be enqueued for asynchronous fetching, e.g. featured account statuses (pins). An ActivityPub object indicates the account was dereferenced.
|
// remote model, or a remote model whose last_fetched date is
|
||||||
func (d *Dereferencer) GetAccountByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Account, ap.Accountable, error) {
|
// 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.
|
// Fetch and dereference account if necessary.
|
||||||
account, accountable, err := d.getAccountByURI(ctx,
|
account, accountable, err := d.getAccountByURI(ctx,
|
||||||
requestUser,
|
requestUser,
|
||||||
uri,
|
uri,
|
||||||
|
tryURL,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -118,8 +134,15 @@ func (d *Dereferencer) GetAccountByURI(ctx context.Context, requestUser string,
|
||||||
return account, accountable, nil
|
return account, accountable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAccountByURI is a package internal form of .GetAccountByURI() that doesn't bother dereferencing featured posts on update.
|
// getAccountByURI is a package internal form of
|
||||||
func (d *Dereferencer) getAccountByURI(ctx context.Context, requestUser string, uri *url.URL) (*gtsmodel.Account, ap.Accountable, error) {
|
// .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 (
|
var (
|
||||||
account *gtsmodel.Account
|
account *gtsmodel.Account
|
||||||
uriStr = uri.String()
|
uriStr = uri.String()
|
||||||
|
|
@ -127,9 +150,8 @@ func (d *Dereferencer) getAccountByURI(ctx context.Context, requestUser string,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Search the database for existing account with URI.
|
// 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(
|
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),
|
gtscontext.SetBarebones(ctx),
|
||||||
uriStr,
|
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)
|
return nil, nil, gtserror.Newf("error checking database for account %s by uri: %w", uriStr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if account == nil {
|
if account == nil && tryURL {
|
||||||
// Else, search the database for one account with URL.
|
// Else if we're permitted, search the database for *ONE*
|
||||||
// Can return multiple hits so check for ErrMultipleEntries.
|
// 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(
|
account, err = d.state.DB.GetOneAccountByURL(
|
||||||
gtscontext.SetBarebones(ctx),
|
gtscontext.SetBarebones(ctx),
|
||||||
uriStr,
|
uriStr,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ func (suite *AccountTestSuite) TestDereferenceGroup() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
groupURL,
|
groupURL,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(group)
|
suite.NotNil(group)
|
||||||
|
|
@ -78,6 +79,7 @@ func (suite *AccountTestSuite) TestDereferenceService() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
serviceURL,
|
serviceURL,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(service)
|
suite.NotNil(service)
|
||||||
|
|
@ -110,6 +112,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsRemoteURL() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse(targetAccount.URI),
|
testrig.URLMustParse(targetAccount.URI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(fetchedAccount)
|
suite.NotNil(fetchedAccount)
|
||||||
|
|
@ -129,6 +132,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsRemoteURLNoSharedInb
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse(targetAccount.URI),
|
testrig.URLMustParse(targetAccount.URI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(fetchedAccount)
|
suite.NotNil(fetchedAccount)
|
||||||
|
|
@ -143,6 +147,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsUsername() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse(targetAccount.URI),
|
testrig.URLMustParse(targetAccount.URI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(fetchedAccount)
|
suite.NotNil(fetchedAccount)
|
||||||
|
|
@ -157,6 +162,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountAsUsernameDomain() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse(targetAccount.URI),
|
testrig.URLMustParse(targetAccount.URI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(fetchedAccount)
|
suite.NotNil(fetchedAccount)
|
||||||
|
|
@ -213,6 +219,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountWithUnknownUserURI() {
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse("http://localhost:8080/users/thisaccountdoesnotexist"),
|
testrig.URLMustParse("http://localhost:8080/users/thisaccountdoesnotexist"),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.True(gtserror.IsUnretrievable(err))
|
suite.True(gtserror.IsUnretrievable(err))
|
||||||
suite.EqualError(err, db.ErrNoEntries.Error())
|
suite.EqualError(err, db.ErrNoEntries.Error())
|
||||||
|
|
@ -265,7 +272,7 @@ func (suite *AccountTestSuite) TestDereferenceLocalAccountByRedirect() {
|
||||||
uri := testrig.URLMustParse("https://this-will-be-redirected.butts/")
|
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.
|
// 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.NoError(err)
|
||||||
suite.Nil(accountable)
|
suite.Nil(accountable)
|
||||||
suite.NotNil(account)
|
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.
|
// 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.NotNil(err)
|
||||||
suite.Nil(account)
|
suite.Nil(account)
|
||||||
suite.Nil(accountable)
|
suite.Nil(accountable)
|
||||||
|
|
@ -341,6 +348,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithNonMatchingURI()
|
||||||
context.Background(),
|
context.Background(),
|
||||||
fetchingAccount.Username,
|
fetchingAccount.Username,
|
||||||
testrig.URLMustParse(remoteAltURI),
|
testrig.URLMustParse(remoteAltURI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.Equal(err.Error(), fmt.Sprintf("enrichAccount: account uri %s does not match %s", remoteURI, remoteAltURI))
|
suite.Equal(err.Error(), fmt.Sprintf("enrichAccount: account uri %s does not match %s", remoteURI, remoteAltURI))
|
||||||
suite.Nil(fetchedAccount)
|
suite.Nil(fetchedAccount)
|
||||||
|
|
@ -357,6 +365,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithUnexpectedKeyChan
|
||||||
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
||||||
fetchingAcc.Username,
|
fetchingAcc.Username,
|
||||||
testrig.URLMustParse(remoteURI),
|
testrig.URLMustParse(remoteURI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(remoteAcc)
|
suite.NotNil(remoteAcc)
|
||||||
|
|
@ -395,6 +404,7 @@ func (suite *AccountTestSuite) TestDereferenceRemoteAccountWithExpectedKeyChange
|
||||||
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
||||||
fetchingAcc.Username,
|
fetchingAcc.Username,
|
||||||
testrig.URLMustParse(remoteURI),
|
testrig.URLMustParse(remoteURI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(remoteAcc)
|
suite.NotNil(remoteAcc)
|
||||||
|
|
@ -436,6 +446,7 @@ func (suite *AccountTestSuite) TestRefreshFederatedRemoteAccountWithKeyChange()
|
||||||
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
remoteAcc, _, err := suite.dereferencer.GetAccountByURI(ctx,
|
||||||
fetchingAcc.Username,
|
fetchingAcc.Username,
|
||||||
testrig.URLMustParse(remoteURI),
|
testrig.URLMustParse(remoteURI),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.NotNil(remoteAcc)
|
suite.NotNil(remoteAcc)
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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.
|
// (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.
|
// 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.
|
// 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.
|
bool, // True if mention already exists in the DB.
|
||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
// Mentions can be created using Name or Href.
|
// Mentions can be created using `name` or `href`,
|
||||||
// Prefer Href (TargetAccountURI), fall back to Name.
|
// and when mention was extracted, we ensured that
|
||||||
if mention.TargetAccountURI != "" {
|
// 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.
|
// Extract the username and domain parts from namestring.
|
||||||
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.
|
|
||||||
username, domain, err := util.ExtractNamestringParts(mention.NameString)
|
username, domain, err := util.ExtractNamestringParts(mention.NameString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := gtserror.Newf("failed to parse namestring %s: %w", mention.NameString, err)
|
err := gtserror.Newf("failed to parse namestring %s: %w", mention.NameString, err)
|
||||||
|
|
@ -1369,6 +1352,34 @@ func (d *Dereferencer) getPopulatedMention(
|
||||||
if ok && existingMention.ID != "" {
|
if ok && existingMention.ID != "" {
|
||||||
return existingMention, true, nil
|
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
|
// At this point, mention.TargetAccountURI
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,14 @@ func (p *Processor) Alias(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have account dereferenced.
|
// 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,
|
targetAccount, _, err := p.federator.GetAccountByURI(ctx,
|
||||||
account.Username,
|
account.Username,
|
||||||
newAKA.uri,
|
newAKA.uri,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf(
|
err := fmt.Errorf(
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,13 @@ func (p *Processor) Get(ctx context.Context, requestingAccount *gtsmodel.Account
|
||||||
|
|
||||||
// Perform a last-minute fetch of target account to
|
// Perform a last-minute fetch of target account to
|
||||||
// ensure remote account header / avatar is cached.
|
// ensure remote account header / avatar is cached.
|
||||||
|
//
|
||||||
|
// Match by URI only.
|
||||||
latest, _, err := p.federator.GetAccountByURI(
|
latest, _, err := p.federator.GetAccountByURI(
|
||||||
gtscontext.SetFastFail(ctx),
|
gtscontext.SetFastFail(ctx),
|
||||||
requestingAccount.Username,
|
requestingAccount.Username,
|
||||||
targetAccountURI,
|
targetAccountURI,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "error fetching latest target account: %v", err)
|
log.Errorf(ctx, "error fetching latest target account: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -119,11 +119,15 @@ func (p *Processor) MoveSelf(
|
||||||
unlock := p.state.ProcessingLocks.Lock(lockKey)
|
unlock := p.state.ProcessingLocks.Lock(lockKey)
|
||||||
defer unlock()
|
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(
|
targetAcct, targetAcctable, err = p.federator.GetAccountByURI(
|
||||||
ctx,
|
ctx,
|
||||||
originAcct.Username,
|
originAcct.Username,
|
||||||
targetAcctURI,
|
targetAcctURI,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
const text = "error dereferencing moved_to_uri"
|
const text = "error dereferencing moved_to_uri"
|
||||||
|
|
|
||||||
|
|
@ -564,10 +564,15 @@ func (p *Processor) accountsByURI(
|
||||||
if resolve {
|
if resolve {
|
||||||
// We're allowed to resolve, leave the
|
// We're allowed to resolve, leave the
|
||||||
// rest up to the dereferencer functions.
|
// 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(
|
account, _, err := p.federator.GetAccountByURI(
|
||||||
gtscontext.SetFastFail(ctx),
|
gtscontext.SetFastFail(ctx),
|
||||||
requestingAccount.Username,
|
requestingAccount.Username,
|
||||||
uri,
|
uri,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
|
|
||||||
return []*gtsmodel.Account{account}, err
|
return []*gtsmodel.Account{account}, err
|
||||||
|
|
|
||||||
|
|
@ -303,10 +303,13 @@ func (p *fediAPI) MoveAccount(ctx context.Context, fMsg *messages.FromFediAPI) e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account to which the Move is taking place.
|
// Account to which the Move is taking place.
|
||||||
|
//
|
||||||
|
// Match by uri only.
|
||||||
targetAcct, targetAcctable, err := p.federate.GetAccountByURI(
|
targetAcct, targetAcctable, err := p.federate.GetAccountByURI(
|
||||||
ctx,
|
ctx,
|
||||||
fMsg.Receiving.Username,
|
fMsg.Receiving.Username,
|
||||||
targetAcctURI,
|
targetAcctURI,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gtserror.Newf(
|
return gtserror.Newf(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue