diff options
Diffstat (limited to 'internal/processing')
-rw-r--r-- | internal/processing/account/create.go | 99 | ||||
-rw-r--r-- | internal/processing/account/delete.go | 10 | ||||
-rw-r--r-- | internal/processing/account/delete_test.go | 5 | ||||
-rw-r--r-- | internal/processing/timeline/notification.go | 70 | ||||
-rw-r--r-- | internal/processing/user/email.go | 65 | ||||
-rw-r--r-- | internal/processing/user/email_test.go | 2 | ||||
-rw-r--r-- | internal/processing/workers/fromclientapi.go | 23 | ||||
-rw-r--r-- | internal/processing/workers/fromfediapi.go | 2 | ||||
-rw-r--r-- | internal/processing/workers/surfaceemail.go | 118 | ||||
-rw-r--r-- | internal/processing/workers/surfacenotify.go | 41 |
10 files changed, 307 insertions, 128 deletions
diff --git a/internal/processing/account/create.go b/internal/processing/account/create.go index 1925feb63..12b2d5e57 100644 --- a/internal/processing/account/create.go +++ b/internal/processing/account/create.go @@ -20,6 +20,7 @@ package account import ( "context" "fmt" + "time" "github.com/superseriousbusiness/gotosocial/internal/ap" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -32,15 +33,48 @@ import ( ) // Create processes the given form for creating a new account, -// returning an oauth token for that account if successful. +// returning a new user (with attached account) if successful. // -// Precondition: the form's fields should have already been validated and normalized by the caller. +// App should be the app used to create the account. +// If nil, the instance app will be used. +// +// Precondition: the form's fields should have already been +// validated and normalized by the caller. func (p *Processor) Create( ctx context.Context, - appToken oauth2.TokenInfo, app *gtsmodel.Application, form *apimodel.AccountCreateRequest, -) (*apimodel.Token, gtserror.WithCode) { +) (*gtsmodel.User, gtserror.WithCode) { + const ( + usersPerDay = 10 + regBacklog = 20 + ) + + // Ensure no more than usersPerDay + // have registered in the last 24h. + newUsersCount, err := p.state.DB.CountApprovedSignupsSince(ctx, time.Now().Add(-24*time.Hour)) + if err != nil { + err := fmt.Errorf("db error counting new users: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + if newUsersCount >= usersPerDay { + err := fmt.Errorf("this instance has hit its limit of new sign-ups for today; you can try again tomorrow") + return nil, gtserror.NewErrorUnprocessableEntity(err, err.Error()) + } + + // Ensure the new users backlog isn't full. + backlogLen, err := p.state.DB.CountUnhandledSignups(ctx) + if err != nil { + err := fmt.Errorf("db error counting registration backlog length: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + if backlogLen >= regBacklog { + err := fmt.Errorf("this instance's sign-up backlog is currently full; you must wait until pending sign-ups are handled by the admin(s)") + return nil, gtserror.NewErrorUnprocessableEntity(err, err.Error()) + } + emailAvailable, err := p.state.DB.IsEmailAvailable(ctx, form.Email) if err != nil { err := fmt.Errorf("db error checking email availability: %w", err) @@ -67,38 +101,61 @@ func (p *Processor) Create( reason = form.Reason } + // Use instance app if no app provided. + if app == nil { + app, err = p.state.DB.GetInstanceApplication(ctx) + if err != nil { + err := fmt.Errorf("db error getting instance app: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + } + user, err := p.state.DB.NewSignup(ctx, gtsmodel.NewSignup{ - Username: form.Username, - Email: form.Email, - Password: form.Password, - Reason: text.SanitizeToPlaintext(reason), - PreApproved: !config.GetAccountsApprovalRequired(), // Mark as approved if no approval required. - SignUpIP: form.IP, - Locale: form.Locale, - AppID: app.ID, + Username: form.Username, + Email: form.Email, + Password: form.Password, + Reason: text.SanitizeToPlaintext(reason), + SignUpIP: form.IP, + Locale: form.Locale, + AppID: app.ID, }) if err != nil { err := fmt.Errorf("db error creating new signup: %w", err) return nil, gtserror.NewErrorInternalError(err) } - // Generate access token *before* doing side effects; we - // don't want to process side effects if something borks. - accessToken, err := p.oauthServer.GenerateUserAccessToken(ctx, appToken, app.ClientSecret, user.ID) - if err != nil { - err := fmt.Errorf("error creating new access token for user %s: %w", user.ID, err) - return nil, gtserror.NewErrorInternalError(err) - } - // There are side effects for creating a new account // (confirmation emails etc), perform these async. p.state.Workers.EnqueueClientAPI(ctx, messages.FromClientAPI{ APObjectType: ap.ObjectProfile, APActivityType: ap.ActivityCreate, - GTSModel: user.Account, + GTSModel: user, OriginAccount: user.Account, }) + return user, nil +} + +// TokenForNewUser generates an OAuth Bearer token +// for a new user (with account) created by Create(). +func (p *Processor) TokenForNewUser( + ctx context.Context, + appToken oauth2.TokenInfo, + app *gtsmodel.Application, + user *gtsmodel.User, +) (*apimodel.Token, gtserror.WithCode) { + // Generate access token. + accessToken, err := p.oauthServer.GenerateUserAccessToken( + ctx, + appToken, + app.ClientSecret, + user.ID, + ) + if err != nil { + err := fmt.Errorf("error creating new access token for user %s: %w", user.ID, err) + return nil, gtserror.NewErrorInternalError(err) + } + return &apimodel.Token{ AccessToken: accessToken.GetAccess(), TokenType: "Bearer", diff --git a/internal/processing/account/delete.go b/internal/processing/account/delete.go index 2ae00194e..858e42d36 100644 --- a/internal/processing/account/delete.go +++ b/internal/processing/account/delete.go @@ -569,11 +569,6 @@ func stubbifyUser(user *gtsmodel.User) ([]string, error) { user.EncryptedPassword = string(dummyPassword) user.SignUpIP = net.IPv4zero - user.CurrentSignInAt = never - user.CurrentSignInIP = net.IPv4zero - user.LastSignInAt = never - user.LastSignInIP = net.IPv4zero - user.SignInCount = 1 user.Locale = "" user.CreatedByApplicationID = "" user.LastEmailedAt = never @@ -585,11 +580,6 @@ func stubbifyUser(user *gtsmodel.User) ([]string, error) { return []string{ "encrypted_password", "sign_up_ip", - "current_sign_in_at", - "current_sign_in_ip", - "last_sign_in_at", - "last_sign_in_ip", - "sign_in_count", "locale", "created_by_application_id", "last_emailed_at", diff --git a/internal/processing/account/delete_test.go b/internal/processing/account/delete_test.go index de7c8e08c..ee6fe1dfc 100644 --- a/internal/processing/account/delete_test.go +++ b/internal/processing/account/delete_test.go @@ -78,11 +78,6 @@ func (suite *AccountDeleteTestSuite) TestAccountDeleteLocal() { suite.WithinDuration(time.Now(), updatedUser.UpdatedAt, 1*time.Minute) suite.NotEqual(updatedUser.EncryptedPassword, ogUser.EncryptedPassword) suite.Equal(net.IPv4zero, updatedUser.SignUpIP) - suite.Zero(updatedUser.CurrentSignInAt) - suite.Equal(net.IPv4zero, updatedUser.CurrentSignInIP) - suite.Zero(updatedUser.LastSignInAt) - suite.Equal(net.IPv4zero, updatedUser.LastSignInIP) - suite.Equal(1, updatedUser.SignInCount) suite.Zero(updatedUser.Locale) suite.Zero(updatedUser.CreatedByApplicationID) suite.Zero(updatedUser.LastEmailedAt) diff --git a/internal/processing/timeline/notification.go b/internal/processing/timeline/notification.go index 09febdb46..42f708999 100644 --- a/internal/processing/timeline/notification.go +++ b/internal/processing/timeline/notification.go @@ -60,31 +60,14 @@ func (p *Processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, ma prevMinIDValue = n.ID } - // Ensure this notification should be shown to requester. - if n.OriginAccount != nil { - // Account is set, ensure it's visible to notif target. - visible, err := p.filter.AccountVisible(ctx, authed.Account, n.OriginAccount) - if err != nil { - log.Debugf(ctx, "skipping notification %s because of an error checking notification visibility: %s", n.ID, err) - continue - } - - if !visible { - continue - } + visible, err := p.notifVisible(ctx, n, authed.Account) + if err != nil { + log.Debugf(ctx, "skipping notification %s because of an error checking notification visibility: %v", n.ID, err) + continue } - if n.Status != nil { - // Status is set, ensure it's visible to notif target. - visible, err := p.filter.StatusVisible(ctx, authed.Account, n.Status) - if err != nil { - log.Debugf(ctx, "skipping notification %s because of an error checking notification visibility: %s", n.ID, err) - continue - } - - if !visible { - continue - } + if !visible { + continue } item, err := p.converter.NotificationToAPINotification(ctx, n) @@ -142,3 +125,44 @@ func (p *Processor) NotificationsClear(ctx context.Context, authed *oauth.Auth) return nil } + +func (p *Processor) notifVisible( + ctx context.Context, + n *gtsmodel.Notification, + acct *gtsmodel.Account, +) (bool, error) { + // If account is set, ensure it's + // visible to notif target. + if n.OriginAccount != nil { + // If this is a new local account sign-up, + // skip normal visibility checking because + // origin account won't be confirmed yet. + if n.NotificationType == gtsmodel.NotificationSignup { + return true, nil + } + + visible, err := p.filter.AccountVisible(ctx, acct, n.OriginAccount) + if err != nil { + return false, err + } + + if !visible { + return false, nil + } + } + + // If status is set, ensure it's + // visible to notif target. + if n.Status != nil { + visible, err := p.filter.StatusVisible(ctx, acct, n.Status) + if err != nil { + return false, err + } + + if !visible { + return false, nil + } + } + + return true, nil +} diff --git a/internal/processing/user/email.go b/internal/processing/user/email.go index dd2a96ae3..2b27c6c92 100644 --- a/internal/processing/user/email.go +++ b/internal/processing/user/email.go @@ -28,53 +28,78 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -var oneWeek = 168 * time.Hour - -// EmailConfirm processes an email confirmation request, usually initiated as a result of clicking on a link -// in a 'confirm your email address' type email. -func (p *Processor) EmailConfirm(ctx context.Context, token string) (*gtsmodel.User, gtserror.WithCode) { +// EmailGetUserForConfirmToken retrieves the user (with account) from +// the database for the given "confirm your email" token string. +func (p *Processor) EmailGetUserForConfirmToken(ctx context.Context, token string) (*gtsmodel.User, gtserror.WithCode) { if token == "" { - return nil, gtserror.NewErrorNotFound(errors.New("no token provided")) + err := errors.New("no token provided") + return nil, gtserror.NewErrorNotFound(err) } user, err := p.state.DB.GetUserByConfirmationToken(ctx, token) if err != nil { - if err == db.ErrNoEntries { - return nil, gtserror.NewErrorNotFound(err) + if !errors.Is(err, db.ErrNoEntries) { + // Real error. + return nil, gtserror.NewErrorInternalError(err) } - return nil, gtserror.NewErrorInternalError(err) + + // No user found for this token. + return nil, gtserror.NewErrorNotFound(err) } if user.Account == nil { - a, err := p.state.DB.GetAccountByID(ctx, user.AccountID) + user.Account, err = p.state.DB.GetAccountByID(ctx, user.AccountID) if err != nil { - return nil, gtserror.NewErrorNotFound(err) + // We need the account for a local user. + return nil, gtserror.NewErrorInternalError(err) } - user.Account = a } if !user.Account.SuspendedAt.IsZero() { - return nil, gtserror.NewErrorForbidden(fmt.Errorf("ConfirmEmail: account %s is suspended", user.AccountID)) + err := fmt.Errorf("account %s is suspended", user.AccountID) + return nil, gtserror.NewErrorForbidden(err, err.Error()) + } + + return user, nil +} + +// EmailConfirm processes an email confirmation request, +// usually initiated as a result of clicking on a link +// in a 'confirm your email address' type email. +func (p *Processor) EmailConfirm(ctx context.Context, token string) (*gtsmodel.User, gtserror.WithCode) { + user, errWithCode := p.EmailGetUserForConfirmToken(ctx, token) + if errWithCode != nil { + return nil, errWithCode } - if user.UnconfirmedEmail == "" || user.UnconfirmedEmail == user.Email { - // no pending email confirmations so just return OK + if user.UnconfirmedEmail == "" || + user.UnconfirmedEmail == user.Email { + // Confirmed already, just return. return user, nil } + // Ensure token not expired. + const oneWeek = 168 * time.Hour if user.ConfirmationSentAt.Before(time.Now().Add(-oneWeek)) { - return nil, gtserror.NewErrorForbidden(errors.New("ConfirmEmail: confirmation token expired")) + err := errors.New("confirmation token expired (older than one week)") + return nil, gtserror.NewErrorForbidden(err, err.Error()) } - // mark the user's email address as confirmed + remove the unconfirmed address and the token - updatingColumns := []string{"email", "unconfirmed_email", "confirmed_at", "confirmation_token", "updated_at"} + // Mark the user's email address as confirmed, + // and remove the unconfirmed address and the token. user.Email = user.UnconfirmedEmail user.UnconfirmedEmail = "" user.ConfirmedAt = time.Now() user.ConfirmationToken = "" - user.UpdatedAt = time.Now() - if err := p.state.DB.UpdateByID(ctx, user, user.ID, updatingColumns...); err != nil { + if err := p.state.DB.UpdateUser( + ctx, + user, + "email", + "unconfirmed_email", + "confirmed_at", + "confirmation_token", + ); err != nil { return nil, gtserror.NewErrorInternalError(err) } diff --git a/internal/processing/user/email_test.go b/internal/processing/user/email_test.go index b42446991..23d448a84 100644 --- a/internal/processing/user/email_test.go +++ b/internal/processing/user/email_test.go @@ -76,7 +76,7 @@ func (suite *EmailConfirmTestSuite) TestConfirmEmailOldToken() { // confirm with the token set above updatedUser, errWithCode := suite.user.EmailConfirm(ctx, "1d1aa44b-afa4-49c8-ac4b-eceb61715cc6") suite.Nil(updatedUser) - suite.EqualError(errWithCode, "ConfirmEmail: confirmation token expired") + suite.EqualError(errWithCode, "confirmation token expired (older than one week)") } func TestEmailConfirmTestSuite(t *testing.T) { diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go index c7e78fee2..ed513c331 100644 --- a/internal/processing/workers/fromclientapi.go +++ b/internal/processing/workers/fromclientapi.go @@ -209,18 +209,23 @@ func (p *Processor) ProcessFromClientAPI(ctx context.Context, cMsg messages.From } func (p *clientAPI) CreateAccount(ctx context.Context, cMsg messages.FromClientAPI) error { - account, ok := cMsg.GTSModel.(*gtsmodel.Account) + newUser, ok := cMsg.GTSModel.(*gtsmodel.User) if !ok { - return gtserror.Newf("%T not parseable as *gtsmodel.Account", cMsg.GTSModel) + return gtserror.Newf("%T not parseable as *gtsmodel.User", cMsg.GTSModel) + } + + // Notify mods of the new signup. + if err := p.surface.notifySignup(ctx, newUser); err != nil { + log.Errorf(ctx, "error notifying mods of new sign-up: %v", err) } - // Send a confirmation email to the newly created account. - user, err := p.state.DB.GetUserByAccountID(ctx, account.ID) - if err != nil { - return gtserror.Newf("db error getting user for account id %s: %w", account.ID, err) + // Send "new sign up" email to mods. + if err := p.surface.emailAdminNewSignup(ctx, newUser); err != nil { + log.Errorf(ctx, "error emailing new signup: %v", err) } - if err := p.surface.emailPleaseConfirm(ctx, user, account.Username); err != nil { + // Send "please confirm your address" email to the new user. + if err := p.surface.emailUserPleaseConfirm(ctx, newUser); err != nil { log.Errorf(ctx, "error emailing confirm: %v", err) } @@ -458,7 +463,7 @@ func (p *clientAPI) UpdateReport(ctx context.Context, cMsg messages.FromClientAP return nil } - if err := p.surface.emailReportClosed(ctx, report); err != nil { + if err := p.surface.emailUserReportClosed(ctx, report); err != nil { log.Errorf(ctx, "error emailing report closed: %v", err) } @@ -644,7 +649,7 @@ func (p *clientAPI) ReportAccount(ctx context.Context, cMsg messages.FromClientA } } - if err := p.surface.emailReportOpened(ctx, report); err != nil { + if err := p.surface.emailAdminReportOpened(ctx, report); err != nil { log.Errorf(ctx, "error emailing report opened: %v", err) } diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go index 2fc3b4b26..7b0e72490 100644 --- a/internal/processing/workers/fromfediapi.go +++ b/internal/processing/workers/fromfediapi.go @@ -473,7 +473,7 @@ func (p *fediAPI) CreateFlag(ctx context.Context, fMsg messages.FromFediAPI) err // TODO: handle additional side effects of flag creation: // - notify admins by dm / notification - if err := p.surface.emailReportOpened(ctx, incomingReport); err != nil { + if err := p.surface.emailAdminReportOpened(ctx, incomingReport); err != nil { log.Errorf(ctx, "error emailing report opened: %v", err) } diff --git a/internal/processing/workers/surfaceemail.go b/internal/processing/workers/surfaceemail.go index a6c97f48f..c00b22c86 100644 --- a/internal/processing/workers/surfaceemail.go +++ b/internal/processing/workers/surfaceemail.go @@ -31,41 +31,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/uris" ) -func (s *surface) emailReportOpened(ctx context.Context, report *gtsmodel.Report) error { - instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) - if err != nil { - return gtserror.Newf("error getting instance: %w", err) - } - - toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) - if err != nil { - if errors.Is(err, db.ErrNoEntries) { - // No registered moderator addresses. - return nil - } - return gtserror.Newf("error getting instance moderator addresses: %w", err) - } - - if err := s.state.DB.PopulateReport(ctx, report); err != nil { - return gtserror.Newf("error populating report: %w", err) - } - - reportData := email.NewReportData{ - InstanceURL: instance.URI, - InstanceName: instance.Title, - ReportURL: instance.URI + "/settings/admin/reports/" + report.ID, - ReportDomain: report.Account.Domain, - ReportTargetDomain: report.TargetAccount.Domain, - } - - if err := s.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { - return gtserror.Newf("error emailing instance moderators: %w", err) - } - - return nil -} - -func (s *surface) emailReportClosed(ctx context.Context, report *gtsmodel.Report) error { +// emailUserReportClosed emails the user who created the +// given report, to inform them the report has been closed. +func (s *surface) emailUserReportClosed(ctx context.Context, report *gtsmodel.Report) error { user, err := s.state.DB.GetUserByAccountID(ctx, report.Account.ID) if err != nil { return gtserror.Newf("db error getting user: %w", err) @@ -104,7 +72,9 @@ func (s *surface) emailReportClosed(ctx context.Context, report *gtsmodel.Report return s.emailSender.SendReportClosedEmail(user.Email, reportClosedData) } -func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, username string) error { +// emailUserPleaseConfirm emails the given user +// to ask them to confirm their email address. +func (s *surface) emailUserPleaseConfirm(ctx context.Context, user *gtsmodel.User) error { if user.UnconfirmedEmail == "" || user.UnconfirmedEmail == user.Email { // User has already confirmed this @@ -130,7 +100,7 @@ func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, u if err := s.emailSender.SendConfirmEmail( user.UnconfirmedEmail, email.ConfirmData{ - Username: username, + Username: user.Account.Username, InstanceURL: instance.URI, InstanceName: instance.Title, ConfirmLink: confirmLink, @@ -158,3 +128,77 @@ func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, u return nil } + +// emailAdminReportOpened emails all active moderators/admins +// of this instance that a new report has been created. +func (s *surface) emailAdminReportOpened(ctx context.Context, report *gtsmodel.Report) error { + instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) + if err != nil { + return gtserror.Newf("error getting instance: %w", err) + } + + toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered moderator addresses. + return nil + } + return gtserror.Newf("error getting instance moderator addresses: %w", err) + } + + if err := s.state.DB.PopulateReport(ctx, report); err != nil { + return gtserror.Newf("error populating report: %w", err) + } + + reportData := email.NewReportData{ + InstanceURL: instance.URI, + InstanceName: instance.Title, + ReportURL: instance.URI + "/settings/admin/reports/" + report.ID, + ReportDomain: report.Account.Domain, + ReportTargetDomain: report.TargetAccount.Domain, + } + + if err := s.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { + return gtserror.Newf("error emailing instance moderators: %w", err) + } + + return nil +} + +// emailAdminNewSignup emails all active moderators/admins of this +// instance that a new account sign-up has been submitted to the instance. +func (s *surface) emailAdminNewSignup(ctx context.Context, newUser *gtsmodel.User) error { + instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) + if err != nil { + return gtserror.Newf("error getting instance: %w", err) + } + + toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered moderator addresses. + return nil + } + return gtserror.Newf("error getting instance moderator addresses: %w", err) + } + + // Ensure user populated. + if err := s.state.DB.PopulateUser(ctx, newUser); err != nil { + return gtserror.Newf("error populating user: %w", err) + } + + newSignupData := email.NewSignupData{ + InstanceURL: instance.URI, + InstanceName: instance.Title, + SignupEmail: newUser.UnconfirmedEmail, + SignupUsername: newUser.Account.Username, + SignupReason: newUser.Reason, + SignupURL: "TODO", + } + + if err := s.emailSender.SendNewSignupEmail(toAddresses, newSignupData); err != nil { + return gtserror.Newf("error emailing instance moderators: %w", err) + } + + return nil +} diff --git a/internal/processing/workers/surfacenotify.go b/internal/processing/workers/surfacenotify.go index a8c36248c..9c82712f2 100644 --- a/internal/processing/workers/surfacenotify.go +++ b/internal/processing/workers/surfacenotify.go @@ -333,6 +333,45 @@ func (s *surface) notifyPollClose(ctx context.Context, status *gtsmodel.Status) return errs.Combine() } +func (s *surface) notifySignup(ctx context.Context, newUser *gtsmodel.User) error { + modAccounts, err := s.state.DB.GetInstanceModerators(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered + // mod accounts. + return nil + } + + // Real error. + return gtserror.Newf("error getting instance moderator accounts: %w", err) + } + + // Ensure user + account populated. + if err := s.state.DB.PopulateUser(ctx, newUser); err != nil { + return gtserror.Newf("db error populating new user: %w", err) + } + + if err := s.state.DB.PopulateAccount(ctx, newUser.Account); err != nil { + return gtserror.Newf("db error populating new user's account: %w", err) + } + + // Notify each moderator. + var errs gtserror.MultiError + for _, mod := range modAccounts { + if err := s.notify(ctx, + gtsmodel.NotificationSignup, + mod, + newUser.Account, + "", + ); err != nil { + errs.Appendf("error notifying moderator %s: %w", mod.ID, err) + continue + } + } + + return errs.Combine() +} + // notify creates, inserts, and streams a new // notification to the target account if it // doesn't yet exist with the given parameters. @@ -342,7 +381,7 @@ func (s *surface) notifyPollClose(ctx context.Context, status *gtsmodel.Status) // targets into this function without filtering // for non-local first. // -// targetAccountID and originAccountID must be +// targetAccount and originAccount must be // set, but statusID can be an empty string. func (s *surface) notify( ctx context.Context, |