{"id":22714503,"url":"https://github.com/theawiteb/forgejo-guardian","last_synced_at":"2025-03-29T22:44:22.544Z","repository":{"id":263140355,"uuid":"889484981","full_name":"TheAwiteb/forgejo-guardian","owner":"TheAwiteb","description":"[Mirror] Simple Forgejo instance guardian, banning users and alerting admins based on certain regular expressions","archived":false,"fork":false,"pushed_at":"2025-03-01T22:00:52.000Z","size":532,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T01:16:05.178Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://git.4rs.nl/awiteb/forgejo-guardian","language":"Rust","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheAwiteb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-16T13:05:16.000Z","updated_at":"2025-03-01T22:00:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"a86e1aaa-b8f3-4b70-84f0-745ba5ff900e","html_url":"https://github.com/TheAwiteb/forgejo-guardian","commit_stats":null,"previous_names":["theawiteb/forgejo-guardian"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheAwiteb%2Fforgejo-guardian","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheAwiteb%2Fforgejo-guardian/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheAwiteb%2Fforgejo-guardian/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheAwiteb%2Fforgejo-guardian/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheAwiteb","download_url":"https://codeload.github.com/TheAwiteb/forgejo-guardian/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246254099,"owners_count":20747948,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-10T14:10:19.027Z","updated_at":"2025-03-29T22:44:22.531Z","avatar_url":"https://github.com/TheAwiteb.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Forgejo Guardian\n\nSimple Forgejo instance guardian, banning users and alerting admins based on certain regular expressions (regex)\n\n[![Forgejo CI Status](https://git.4rs.nl/awiteb/forgejo-guardian/badges/workflows/ci.yml/badge.svg)](https://git.4rs.nl/awiteb/forgejo-guardian)\n[![Forgejo CD Status](https://git.4rs.nl/awiteb/forgejo-guardian/badges/workflows/cd.yml/badge.svg)](https://git.4rs.nl/awiteb/forgejo-guardian)\n[![Minimum Forgejo version v10.0.0](https://img.shields.io/badge/Minimum_Forgejo_version-v10.0.0-brightgreen?style=flat\u0026color=ff7f24\u0026logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMTIgMjEyIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiPjxzdHlsZT5jaXJjbGUscGF0aHtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjE1fXBhdGh7c3Ryb2tlLXdpZHRoOjI1fS5vcmFuZ2V7c3Ryb2tlOiNmNjB9LnJlZHtzdHJva2U6I2Q0MDAwMH08L3N0eWxlPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYgNikiPjxwYXRoIGQ9Ik01OCAxNjhWNzBhNTAgNTAgMCAwIDEgNTAtNTBoMjAiIGNsYXNzPSJvcmFuZ2UiLz48cGF0aCBkPSJNNTggMTY4di0zMGE1MCA1MCAwIDAgMSA1MC01MGgyMCIgY2xhc3M9InJlZCIvPjxjaXJjbGUgY3g9IjE0MiIgY3k9IjIwIiByPSIxOCIgY2xhc3M9Im9yYW5nZSIvPjxjaXJjbGUgY3g9IjE0MiIgY3k9Ijg4IiByPSIxOCIgY2xhc3M9InJlZCIvPjxjaXJjbGUgY3g9IjU4IiBjeT0iMTgwIiByPSIxOCIgY2xhc3M9InJlZCIvPjwvZz48L3N2Zz4=)](https://codeberg.org/forgejo/forgejo/milestone/8377)\n\n[![agplv3-or-later](https://www.gnu.org/graphics/agplv3-88x31.png)](https://www.gnu.org/licenses/agpl-3.0.html)\n\n\u003c/div\u003e\n\n\u003e [!NOTE]\n\u003e The minimum Forgejo version required is `v10.0.0`, because of this [PR](https://codeberg.org/forgejo/forgejo/pulls/6228).\n\n## About\n\n`forgejo-guardian` is a simple guardian for your Forgejo instance, it will ban\nusers based on certain regular expressions (regex) and alert the admins about\nthem. The alert will send to the admin via a Telegram/Matrix bot.\n\n### The expressions\n\nSee the [Configuration](#configuration) section for more information about the\nexpressions. The different between `ban` and `sus` is that the `ban` will ban\nthe user, and the `sus` will only alert the admins about the user and the admin\ncan decide to ban the user or not. You can also\nset `expressions.ban_alert` to `true` to send a notification when a user is banned.\n\n#### Lazy purge\n\nIf you enable `lazy_purge.enabled` in the configuration file, the guardian will\nnot purge the user immediately. Instead, the purge will be delayed for the\nduration specified in `lazy_purge.purge_after`, allowing the moderation team to\nundo the action if needed. When lazy purge is enabled, the guardian will add an\n`undo` button to any ban action (suspension, ban request in safe mode, and\nbanning using the `ban` command).\n\n### Bots\n\nThe guardian can send suspicious users, banned users, and ban request to the\nmoderation team via a Telegram/Matrix bot. The bot will send the messages in the\nlanguage specified in the configuration file.\n\n#### Telegram\n\nThe Telegram bot will send the messages to the chat ID specified in the\nconfiguration file. You can use a group, a channel, or a user chat ID. If the\nmessage is a suspicious user alert or ban request, the bot will attach two\nbuttons to the message, one for banning the user and the other for ignoring\nthe request.\n\n#### Matrix\n\nThe Matrix bot will send the messages to the room ID specified in the\nconfiguration file. You can use a room ID. If the message is a suspicious user\nalert or ban request, the bot will add two reactions to the message, one for\nbanning the user and the other for ignoring the request, and the bot will listen\nto the reactions and act accordingly.\n\n\u003e [!NOTE]\n\u003e You have to invite the bot to the room before running the guardian\n\n#### Commands\n\nThe telegram prefix for the commands is `/`, and the matrix prefix is `!`. The\ncommands are:\n\n-   `ping`: To check if the bot is alive, the bot will reply with `Pong!`\n-   `ban \u003cusername\u003e`: To send a ban request for a user, the bot will send a\n    message to the admins with the user information and two buttons, one for\n    banning the user and the other for ignoring the request\n\n### Database\n\nThe guardian uses a database to store the ignored users and Matrix events, the\ndefault path is `/app/db.redb`, but you can specify a different one in the\nconfiguration file. The database file extension should be `.redb`.\n\n### Ban action\n\nThe ban action can be `purge` or `suspend`, the default is `purge`. The `purge`\nwill delete the user and all their data, and the `suspend` will only suspend the\nuser, the suspended user can be unsuspended later by the admin from the\ndashboard.\n\n### Clean up instance of inactive users\n\nThe guardian can also clean up inactive users by setting `inactive.enabled` to\n`true` in the configuration file and specifying the number of days in\n`inactive.days` to consider a user inactive. The guardian will ban users who\nhave had no activity since they registered.\n\nInactivity feature need `read:user` and `read:admin` scopes.\n\n## Docker\n\nIf you want to run the guardian in a docker container, you can find the\n`Dockerfile` and `docker-compose.toml` in the\n[docker](https://git.4rs.nl/awiteb/forgejo-guardian/src/branch/master/docker)\ndirectory. Copy them or clone the repository, make sure to have `Dockerfile`,\n`docker-compose.toml` and your configuration file `forgejo-guardian.toml` (see\n[Configuration](#Configuration) section) in the same directory, then you can run\nthe following command:\n\n```sh\ndocker-compose up -d # To run the guardian in the background (remove `-d` first time to see the logs and make sure everything is working)\n```\n\n## Without building the image\n\nIf you don't want to build the image yourself, you can use this docker-compose file:\n\n```yaml\nservices:\n    forgejo-guardian:\n        image: git.4rs.nl/awiteb/forgejo-guardian:0.7\n        volumes:\n            - ./forgejo-guardian.toml:/app/forgejo-guardian.toml:ro\n            - ./db.redb:/app/db.redb\n```\n\nMake sure to have the `forgejo-guardian.toml` file in the same directory as the `docker-compose.yml` file, then you can run the following command:\n\n```sh\ndocker-compose up -d\n```\n\n### Without docker-compose\n\n#### Build the image\n\n```sh\ndocker build -t forgejo-guardian .\ndocker run --rm -d -v $PWD/forgejo-guardian.toml:/app/forgejo-guardian.toml:ro forgejo-guardian\n```\n\n#### Without building the image\n\n```sh\ndocker run --rm -d -v $PWD/forgejo-guardian.toml:/app/forgejo-guardian.toml:ro git.4rs.nl/awiteb/forgejo-guardian:0.7\n```\n\n## Installation\n\nYou can let [cargo](https://doc.rust-lang.org/cargo/) build the binary for you, or build it yourself. You can also download the pre-built binaries from the [releases](https://git.4rs.nl/awiteb/forgejo-guardian/releases) page.\n\n### Build it\n\n#### `cargo-install`\n\n\u003e [!TIP]\n\u003e This will install the binary in `~/.cargo/bin/forgejo-guardian`. Make sure to add this directory to your `PATH`.\n\u003e If you want to update it, rerun the command.\n\n```sh\ncargo install --git https://git.4rs.nl/awiteb/forgejo-guardian\n```\n\n#### `cargo-install` (from source)\n\n\u003e [!TIP]\n\u003e Then when you want to update it, pull the changes and run `cargo install --path .` again.\n\n```sh\ngit clone https://git.4rs.nl/awiteb/forgejo-guardian\ncd forgejo-guardian\ncargo install --path .\n```\n\n#### Build (from source)\n\n\u003e [!TIP]\n\u003e The binary will be in `./target/release/forgejo-guardian`.\n\n```sh\ngit clone https://git.4rs.nl/awiteb/forgejo-guardian\ncd forgejo-guardian\ncargo build --release\n```\n\n## Configuration\n\nWe use `TOML` format for configuration, the default configuration file is `/app/forgejo-guardian.toml`, but you can specify a different one with `FORGEJO_GUARDIAN_CONFIG` environment variable.\n\n### Structure\n\n\u003e [!NOTE]\n\u003e The field may start with a version, this version is the required Forgejo\n\u003e version, so you can use this version or later\n\nIn our configuration file you can have the following sections and the global section:\n\n-   `lazy_purge`: Lazy purge configuration, to delay the purge action\n-   `inactive`: Configuration for cleaning up inactive users\n-   `forgejo`: Forgejo instance configuration\n-   `expressions`: Regular expressions to match against\n-   `telegram`: Telegram bot configuration\n-   `matrix`: Matrix bot configuration\n\n#### Global section\n\nThe global section is the one that doesn't have a name, and it's in the top of the configuration file, with the following fields:\n\n-   `dry_run`: If set to `true`, the guardian will not ban the users, but will only alert the admins (default: `false`)\n-   `database`: Database path to store ignored users and Matrix events, if you\n    are using docker, the path should be inside the container, for example\n    `/app/db.redb`, and you can mount it to the host machine, for example `-v\n/path/to/db.redb:/app/db.redb`. The db file extension should be `.redb`\n    (default: `/app/db.redb`)\n-   `hide_user_email`: If set to `true`, the guardian will hide the user email\n    in the alerts (default: `false`)\n-   **v10.0.1** `check_tokens`: Check if the user has tokens, to consider them\n    in safe mode or as inactive (default: `true`)\n-   **v10.0.1** `check_oauth2`: Check if the user has OAuth2 applications, to\n    consider them in safe mode or as inactive (default: `true`)\n\n```toml\ndry_run  = true\ndatabase = \"./db.redb\"\n```\n\n#### `forgejo`\n\nForgejo configuration section, with the following fields:\n\n-   `instance_url`: Forgejo instance URL (must be HTTPS or HTTP) **required**\n-   `token`: Token to use to get the new users and ban them, requires\n    `read:admin`, `write:admin` and `read:user` scopes. The token can be\n    retrieved from an environment variable by prefixing the variable name with\n    `\"env.\"`. For example, use `\"env.FORGEJO_TOKEN\"` to get the token from the\n    `FORGEJO_TOKEN` environment variable. **required**\n\n```toml\n[forgejo]\ninstance_url = \"https://forgejo.example\"\ntoken = \"your-token\"\n```\n\n#### `inactive`\n\nWhen enabled, users that never did anything on the instance will be deleted.\n\nInactive users configuration section, with the following fields:\n\n-   `enabled`: Enable the cleanup of inactive users, inactive feature need `read:user` scope (default: `false`)\n-   `exclude`: List of usernames to exclude from the cleanup (default: `[]`)\n-   `source_id`: List of source IDs to only consider users from (default: `[]`)\n-   `source_id_exclude`: List of source IDs to exclude users from (default: `[]`)\n-   `days`: The number of days that a new user is given to become active. (default: `30`)\n-   `req_limit`: Maximum number of requests to send to the Forgejo instance within each interval (default: `200`) (Minimum: `4`)\n-   `req_interval`: Time interval to pause after reaching the `req_limit` (default: `10m`)\n-   `interval`: Time Interval to check for inactive users (default: `7d`)\n\nThe `inactive.req_interval` and `inactive.interval` have the following suffixes:\n\n-   `s`: Seconds\n-   `m`: Minutes\n-   `h`: Hours\n-   `d`: Days\n\n```toml\n[inactive]\nenabled = true\ndays = 30\nexclude = [\"some-user\", \"another-user\"]\nsource_id = [1, 2] # Only consider users from source IDs 1 and 2\n# source_id_exclude = [3, 4] # Exclude users from source IDs 3 and 4\nreq_limit = 200\nreq_interval = \"10m\"\ninterval = \"7d\"\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e Forgejo itself has no rate limiting, but the reverse proxy may have rate\n\u003e limiting.\n\n#### `expressions`\n\nExpressions configuration section, with the following fields:\n\n-   `check_existing_users`: If set to `true`, the guardian will check the existing users bisides the new users (default: `false`)\n-   `check_sus_existing_users`: If set to `true`, the guardian will check the existing users for the `sus` expressions (default: `false`)\n-   `active_sus_notice`: If set to `true`, the guardian will add a notice to the\n    `sus` alerts if the user is active (default: `false`)\n-   `check_updated_users`: If set to `true`, the guardian will check the updated users (default: `false`)\n-   `safe_mode`: Prevents purge active users immediately. If a user matches the\n    ban expressions but is active, a ban request is sent to the moderation team\n    for review instead of purge the user directly\n-   `interval`: Interval to check for new users in seconds (default: `300s`)\n-   `limit`: Limit of users to fetch in each interval (default: `100`)\n-   `req_limit`: Maximum number of requests to send to the Forgejo instance within each interval (default: `200`) (Minimum: `1`)\n-   `req_interval`: Time interval to pause after reaching the `req_limit` (default: `10m`)\n-   `ban_alert`: Send a notification when a user is banned (default: `false`)\n-   `ban_action`: The action to take when a user is banned, can be one of the following:\n    -   `purge` (default): Forcibly delete user and any repositories, organizations, and\n        packages owned by the user. All comments and issues posted by this user\n        will also be deleted. (unduoable, the user will be permanently deleted)\n    -   `suspend`: Block the user from interacting with the service through their\n        account and prohibit signing in. The admins can later decide to\n        reactivate the user, from the dashboard.\n-   `ban`: Regular expressions to match against to ban the user\n-   `sus`: Regular expressions to match against to alert the admins\n\nThe `expressions.interval` and `expressions.req_interval` have the following suffixes:\n\n-   `s`: Seconds\n-   `m`: Minutes\n-   `h`: Hours\n-   `d`: Days\n\n`ban` and `sus` are tables, and each one have the following fields:\n\n-   `enabled`: Enable the expressions (default: enabled if the section is present,\n    otherwise disabled. You can disable manually by setting it to `false`)\n-   `usernames`: Regular expressions to match against the usernames\n-   `full_names`: Regular expressions to match against the full names\n-   `biographies`: Regular expressions to match against the biographies\n-   `emails`: Regular expressions to match against the emails\n-   `websites`: Regular expressions to match against the websites\n-   `locations`: Regular expressions to match against the locations\n\nEach field is an array of regular expressions, the regular expression can be one of the following:\n\n-   String: The regular expression itself\n-   Table: The regular expression and the reason, with the following fields:\n    -   `re` (string, array of string): The regular expression (if it's an array of strings, all regex in that array should match to ban/sus the user)\n    -   `reason` (optional string): The reason to ban/sus the user. This will be used in the notification message.\n\n```toml\n[expressions]\ncheck_existing_users = true\ncheck_sus_existing_users = true\ninterval = 40\nlimit = 50\nban_alert = false\nban_action = \"suspend\"\n\n[expressions.ban]\nusernames = ['^admin.*$']\nwebsites = ['^https://example\\.com$', { re = '^https://example2\\.com$', reason = \"Example 2 is not allowed\" }, '^https://example3\\.com$']\n\n[expressions.sus]\nusernames = ['^mod.*$']\n```\n\n\u003e [!TIP]\n\u003e You can start your regular expression with `(?i)` to make it case-insensitive.\n\u003e For example, `(?i)^.*admin.*$` will match `Admin`, `ADMIN`, `admin`, etc.\n\n\u003e [!TIP]\n\u003e Make sure to set `interval` and `limit` to a reasonable values based on your\n\u003e instance size and the number of new users. If your instance is small, you can\n\u003e set `interval` to a higher value (something like `600`) and `limit` to a lower\n\u003e value (something like `50`), so the guardian will fetch latest 50 users every\n\u003e 10 minutes, which should be enough for small instances.\n\n#### `lazy_purge`\n\nLazy purge configuration section, with the following fields:\n\n-   `enabled`: Enable the lazy purge (default: `false`)\n-   `purge_after`: The duration to wait before purging the user (default: `2h`)\n-   `req_limit`: Maximum number of requests to send to the Forgejo instance within each interval (default: `200`) (Minimum: `1`)\n-   `req_interval`: Time interval to pause after reaching the `req_limit` (default: `2m`)\n-   `interval`: Time Interval to check to start purge purged users (default: `1h`)\n\n#### `telegram`\n\nTelegram bot configuration section, with the following fields:\n\n-   `enabled`: Enable the Telegram bot (default: If the section is present, it's\n    required, otherwise disabled)\n-   `token`: Telegram bot token **required, if the section is enabled**\n-   `chat`: Chat ID to send the alerts to (Can be a group or a channel or a\n    user) **required, if the section is enabled**\n-   `lang`: Language to use for the alerts (Currently only `ar-sa`, `en-us`,\n    `ru-ru` and `de-de` are supported) **required, if the section is enabled**\n\n```toml\n[telegram]\ntoken = \"your-token\"\nchat = 00000000000\nlang = \"en-us\"\n```\n\n#### `matrix`\n\nMatrix bot configuration section, with the following fields:\n\n-   `enabled`: Enable the Matrix bot (default: If the section is present, it's\n    required, otherwise disabled)\n-   `homeserver`: Matrix homeserver URL **required, if the section is enabled**\n-   `username`: Bot username **required, if the section is enabled**\n-   `password`: Bot password **required, if the section is enabled**\n-   `room`: Room ID to send the alerts to **required, if the section is enabled**\n-   `lang`: Language to use for the alerts (Currently only `ar-sa`, `en-us`,\n    `ru-ru` and `de-de` are supported) **required, if the section is enabled**\n\n```toml\n[matrix]\nenabled    = true\nhomeserver = \"https://matrix.example.com\"\nusername   = \"bot-username\"\npassword   = \"bot-password\"\nroom       = \"!egffmeGtArQzgmcuUb:example.com\"\nlang       = \"en-us\"\n```\n\n## Running the guardian\n\nAfter you have the configuration file ready, you can run the guardian with the following command:\n\n```sh\nFORGEJO_GUARDIAN_CONFIG=/path/to/your/config.toml forgejo-guardian\n```\n\nYou can remove the `FORGEJO_GUARDIAN_CONFIG` environment variable from the command if it's already set, or the file in the default location `/app/forgejo-guardian.toml`.\n\n### Adding a new language\n\nIf you would like to contribute by adding a new language, you can do that by adding your language file in the `locales` directory, and then add it to `Lang` enum in `src/bots/mod.rs` file. Then you can use it in the configuration file.\n\n## Mirrors\n\n-   [Codeberg](https://codeberg.org/awiteb/forgejo-guardian)\n-   [GitHub](https://github.com/theawiteb/forgejo-guardian)\n\n## License\n\nThis project is licensed under the [AGPL-3.0-or-later](https://www.gnu.org/licenses/agpl-3.0.html) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheawiteb%2Fforgejo-guardian","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheawiteb%2Fforgejo-guardian","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheawiteb%2Fforgejo-guardian/lists"}