Skip to content

New Filters System Specifications #1530

@mbaruh

Description

@mbaruh

This issue documents the planned changes to the filters extension. This needs to be done alongside python-discord/site#479.
Minor details may still change. This issue specifies the full extent of the desired changes, but this can be split into several issues and made into a project.

The changes allow for granular control over the behavior of individual filters, and increase the scope of it. All aspects of the extension, including automatic rules, will be controlled from a single entry-point.

Filter Settings

Each added filter has settings which dictate what happens if a given message matches it. The settings are:

  • Does it ping?
    • Which roles? everyone/here/mods/something else
  • Does it delete?
  • Does it filter reactions?
  • Does it filter usernames and nicknames?
  • Does it catch DM's?
  • Does it ping for DM's?
  • Does it DM the user about the rule? (similarly to what happens for invite links / everyone pings)
    • A secondary configuration for the message sent
  • Do the filters apply only in specific channels / categories
  • Which roles can bypass the filter?
  • Does it apply an infraction? warn / mute / ban
  • For domains: be able to choose whether it should be exact, or apply for subdomains as well (this should close Filtering - New blacklist type that catch all subdomains of domain #1276)

Each filter additionally has a description, as they already do.

Each list type has default settings, while each individual filter can override any setting.

Filter Types

The current filters are split between four types: guild_invite, file_format, domain_name, filter_token. Each of those is split into a blacklist and a whitelist.

Renaming

The names should be simpler and more memorable: invites, formats, domains, tokens.

Whitelisting and Blacklisting

Not every filter type needs to have both a whitelist and a blacklist. Each filter type has its own method of deciding whether action should be taken, taking the whitelist, the blacklist, or both into account.

A blacklist or a whitelist should be created before anything can be added to it.

Invites

The filters should save the invite which was used to add a guild to the list, unlike the current state in which only the ID is saved.

Domains

Domains should support path patterns, e.g *.pythondiscord.com/*/ric*rolls.

New Type: Custom Functions

Each filter type has its own method of checking whether a specific filter should be applied. There should be a list which specifies special filters, each with their own way of deciding whether they apply to a given message. Examples of such filters: the token remover, webhook remover, and any of the antispam rules. When an item can and should be added to this list will be clearer in the Implementation Details section.

UI And Utilities

Search

There should be an option to present all filters in a specific list which match a given input.
For example, if we have the tokens a\db and 123, and we call !bl search tokens a4b, we will be presented with a list which contains the filter a\db. The listed filters should show each filter's ID (explained below).

Aliasing

There should alternative ways to phrase the same command:
!bl add tokens <token> -> !tokens deny <token>
!al add invites <invite> -> !invites allow <invite>
!bl list domains -> !domains list bl

find should be an alias of search

Reaction Menus

There should be reaction menus to go from !bl / !al, to one of the option: list, search, add, remove, which in turn should allow choosing one the possible filter lists (if there is no tokens whitelist it shouldn't be given as an option).

Similarly, following the aliasing section, specifying one of the list types as a top-level command should allow choosing one of list, search, allow, deny (if there is no whitelist, allow isn't an option).

Editing

As mentioned in the Settings section, each individual filter should have a way to override the default settings, including the pattern or the name of the filter which is used to dictate when it applies to a message. The only non-modifiable field of a filter is its ID (explained below).

Identification

Each filter should have its own ID, which is unique for a specific list. There should be a way to edit and remove a filter via that ID.

Additionally, it should be possible to bring up an embed with a particular filter's ID, pattern or name, and the values of all of its settings, via either the ID or the pattern / name.

Alerting

As different filters can have different affects on a message, it should be explored whether it's possible to present in the alert all tokens which triggered unique filters (meaning, we don't have to show all tokens that triggered a specific filter).

User Ignore List

There should be a command which makes a specific filter temporarily not apply to a specified user. This is the same feature as in #551, except a redis cache might be enough.

Implementation Details

OOP-Based Approach

  • There should be a Settings dataclass that implements a binary operation to join settings together. This will allow us to decide all the actions that should be taken for a specific message. For example, if one filter that is matched says the message should be deleted, and another says the moderators should be pinged, they should be joined together, and then actioned after going over all filters. There should also be a method to apply overrides to a Settings object, returning a new Settings object.

  • There should be a base Filter class with a settings attribute, that is then subclassed for each filter type to code a predicate to decide whether the filter should be applied (along the lines of async def matches(message: Message) -> bool). This will also allow the custom filters to be subclasses of Filter.

  • Lastly, there should be a base FilterList class, that is then subclassed to specify which Filters class it uses, how it loads and initializes its filters, and what it does with its blacklist and/or whitelist. Each list loads its filters from the database, transforms each into an object of a Filter subclass, and stores it in the list corresponding to the blacklist or whitelist.

Extensibility and Modularity

I don't claim to foresee every future need or use case. For that reason, during development special attention should be made to extensibility (this also applies to the site issue). Most parts should be modular, with several dispatching methods. A good indication of a hard-to-extend implementation would be if a fragmented diff, scattered across a file, is necessary to say add an additional type of filter, or an additional effect a filter can have.

Furthermore, a module, a file, or a class should have a clear documentation on what parts need to be looked at and added / changed in order to add or remove an additional filter setting or filter type.

Each FilterList class should be specified in its own file, within a dedicated module, and all of them should be dynamically loaded in the cog from said module.

Similarly, each custom filter should be in its own file, within a dedicated module. The filter within the custom filters list will then store the name of the class (similarly to how tokens store a regex), which will then be dynamically loaded from said module (as a reminder, each FilterList subclass can override how it loads its filters).

Related Issues

Additionally to #1276 and #551 mentioned above, this specification should allow to gracefully handle #1018, #1421.

#665, #998, #1379, #1522 are additional issues related to the functionality of one or more filters that can be handled as a part of this rewrite, but technically speaking are out of scope for this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: filtersRelated to message filters: (antimalware, antispam, filtering, token_remover)a: frontendRelated to output and formattinga: moderationRelated to community moderation functionality: (moderation, defcon, verification)t: enhancementChanges or improvements to existing featurest: featureNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions