diff options
author | 2024-02-27 13:22:05 +0100 | |
---|---|---|
committer | 2024-02-27 12:22:05 +0000 | |
commit | 9cadc764b389df970c767608e7a061f3bd777dfa (patch) | |
tree | e49218fff3af5800b5305720a04a4f74e7b5c2cb /internal/federation/federatingdb/create.go | |
parent | [chore]: Bump github.com/tdewolff/minify/v2 from 2.20.17 to 2.20.18 (#2689) (diff) | |
download | gotosocial-9cadc764b389df970c767608e7a061f3bd777dfa.tar.xz |
[feature] Add experimental `instance-federation-spam-filter` option (#2685)
* [chore] Move `visibility` to `filter/visibility`
* [feature] Add experimental instance-federation-spam-filter option
Diffstat (limited to 'internal/federation/federatingdb/create.go')
-rw-r--r-- | internal/federation/federatingdb/create.go | 94 |
1 files changed, 32 insertions, 62 deletions
diff --git a/internal/federation/federatingdb/create.go b/internal/federation/federatingdb/create.go index e2540b739..cfb0f319b 100644 --- a/internal/federation/federatingdb/create.go +++ b/internal/federation/federatingdb/create.go @@ -21,13 +21,11 @@ import ( "context" "errors" "fmt" - "strings" "codeberg.org/gruf/go-logger/v2/level" "github.com/miekg/dns" "github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/gotosocial/internal/ap" - "github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtscontext" "github.com/superseriousbusiness/gotosocial/internal/gtserror" @@ -35,7 +33,6 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/id" "github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/messages" - "github.com/superseriousbusiness/gotosocial/internal/util" ) // Create adds a new entry to the database which must be able to be @@ -321,26 +318,45 @@ func (f *federatingDB) createStatusable( statusable ap.Statusable, forwarded bool, ) error { - - // Check whether we should accept this new status, - // we do this BEFORE even handling forwards to us. - accept, err := f.shouldAcceptStatusable(ctx, + // Check whether this status is both + // relevant, and doesn't look like spam. + err := f.spamFilter.StatusableOK(ctx, receiver, requester, statusable, ) - if err != nil { - return gtserror.Newf("error checking status acceptibility: %w", err) - } - if !accept { - // This is a status sent with no relation to receiver, i.e. - // - receiving account does not follow requesting account - // - received status does not mention receiving account + switch { + case err == nil: + // No problem! + + case gtserror.IsNotRelevant(err): + // This case is quite common if a remote (Mastodon) + // instance forwards a message to us which is a reply + // from someone else to a status we've also replied to. // - // We just pretend that all is fine (dog with cuppa, flames everywhere) - log.Trace(ctx, "status failed acceptability check") + // It does this to try to ensure thread completion, but + // we have our own thread fetching mechanism anyway. + log.Debugf(ctx, + "status %s is not relevant to receiver (%v); dropping it", + ap.GetJSONLDId(statusable), err, + ) return nil + + case gtserror.IsSpam(err): + // Log this at a higher level so admins can + // gauge how much spam is being sent to them. + // + // TODO: add Prometheus metrics for this. + log.Infof(ctx, + "status %s looked like spam (%v); dropping it", + ap.GetJSONLDId(statusable), err, + ) + return nil + + default: + // A real error has occurred. + return gtserror.Newf("error checking relevancy/spam: %w", err) } // If we do have a forward, we should ignore the content @@ -378,52 +394,6 @@ func (f *federatingDB) createStatusable( return nil } -func (f *federatingDB) shouldAcceptStatusable(ctx context.Context, receiver *gtsmodel.Account, requester *gtsmodel.Account, statusable ap.Statusable) (bool, error) { - host := config.GetHost() - accountDomain := config.GetAccountDomain() - - // Check whether status mentions the receiver, - // this is the quickest check so perform it first. - mentions, _ := ap.ExtractMentions(statusable) - for _, mention := range mentions { - - // Extract placeholder mention vars. - accURI := mention.TargetAccountURI - name := mention.NameString - - switch { - case accURI != "" && - accURI == receiver.URI || accURI == receiver.URL: - // Mention target is receiver, - // they are mentioned in status. - return true, nil - - case accURI == "" && name != "": - // Only a name was provided, extract the user@domain parts. - user, domain, err := util.ExtractNamestringParts(name) - if err != nil { - return false, gtserror.Newf("error extracting mention name parts: %w", err) - } - - // Check if the name points to our receiving local user. - isLocal := (domain == host || domain == accountDomain) - if isLocal && strings.EqualFold(user, receiver.Username) { - return true, nil - } - } - } - - // Check whether receiving account follows the requesting account. - follows, err := f.state.DB.IsFollowing(ctx, receiver.ID, requester.ID) - if err != nil { - return false, gtserror.Newf("error checking follow status: %w", err) - } - - // Status will only be acceptable - // if receiver follows requester. - return follows, nil -} - /* FOLLOW HANDLERS */ |