Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bugfix] Don't try to update suspended accounts #2348

Merged
merged 2 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions internal/federation/dereferencing/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ import (
// accountUpToDate returns whether the given account model is both updateable (i.e.
// non-instance remote account) and whether it needs an update based on `fetched_at`.
func accountUpToDate(account *gtsmodel.Account) bool {
if !account.SuspendedAt.IsZero() {
// Can't update suspended accounts.
return true
}

if account.IsLocal() {
// Can't update local accounts.
return true
Expand Down Expand Up @@ -331,6 +336,11 @@ func (d *Dereferencer) enrichAccountSafely(
account *gtsmodel.Account,
apubAcc ap.Accountable,
) (*gtsmodel.Account, ap.Accountable, error) {
// Noop if account has been suspended.
if !account.SuspendedAt.IsZero() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to check this here as accountIsUpToDate() is always called before entering enrichSafely() :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that, but the accountUpToDate call can still be overridden if refresh is true, so this makes extra sure. Checking IsZero is very cheap.

return account, nil, nil
}

// By default use account.URI
// as the per-URI deref lock.
uriStr := account.URI
Expand Down
7 changes: 7 additions & 0 deletions internal/federation/federatingprotocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@ func (f *Federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
return nil, false, err
}

if !requestingAccount.SuspendedAt.IsZero() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was going to say we should probably move this to AuthenticateFederatedRequest() to make sure we do this check in all applicable locations, but then saw that function doesn't guarantee to always have the account model by that point ... what if we updated AuthenticateFederatedRequest() to handle the instance model creation if necessary, and fetching updated account model? that way we can just move this check in there, and it won't need to be added anywhere else.

just this current way of doing it makes me worry we're going to miss out locations where it's needed as it needs to add them in all the locations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do a refactor of that in a subsequent PR 👍

// Account was marked as suspended by a
// local admin action. Stop request early.
w.WriteHeader(http.StatusForbidden)
return ctx, false, nil
}

// We have everything we need now, set the requesting
// and receiving accounts on the context for later use.
ctx = gtscontext.SetRequestingAccount(ctx, requestingAccount)
Expand Down
9 changes: 8 additions & 1 deletion internal/processing/fedi/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ func (p *Processor) authenticate(ctx context.Context, requestedUsername string)
return nil, nil, gtserror.NewErrorUnauthorized(err)
}

if !requestingAccount.SuspendedAt.IsZero() {
// Account was marked as suspended by a
// local admin action. Stop request early.
err = fmt.Errorf("account %s marked as suspended", requestingAccount.ID)
return nil, nil, gtserror.NewErrorForbidden(err)
}

// Ensure no block exists between requester + requested.
blocked, err := p.state.DB.IsEitherBlocked(ctx, requestedAccount.ID, requestingAccount.ID)
if err != nil {
Expand All @@ -72,7 +79,7 @@ func (p *Processor) authenticate(ctx context.Context, requestedUsername string)

if blocked {
err = fmt.Errorf("block exists between accounts %s and %s", requestedAccount.ID, requestingAccount.ID)
return nil, nil, gtserror.NewErrorUnauthorized(err)
return nil, nil, gtserror.NewErrorForbidden(err)
}

return requestedAccount, requestingAccount, nil
Expand Down
9 changes: 8 additions & 1 deletion internal/processing/fedi/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque
return nil, gtserror.NewErrorUnauthorized(err)
}

if !requestingAccount.SuspendedAt.IsZero() {
// Account was marked as suspended by a
// local admin action. Stop request early.
err = fmt.Errorf("account %s marked as suspended", requestingAccount.ID)
return nil, gtserror.NewErrorForbidden(err)
}

blocked, err := p.state.DB.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID)
if err != nil {
err := gtserror.Newf("error checking block from account %s to account %s: %w", requestedAccount.ID, requestingAccount.ID, err)
Expand All @@ -114,7 +121,7 @@ func (p *Processor) UserGet(ctx context.Context, requestedUsername string, reque

if blocked {
err := fmt.Errorf("account %s blocks account %s", requestedAccount.ID, requestingAccount.ID)
return nil, gtserror.NewErrorUnauthorized(err)
return nil, gtserror.NewErrorForbidden(err)
}

return data(person)
Expand Down