Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package forgejo-guardian for
openSUSE:Factory checked in at 2025-01-29 16:18:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/forgejo-guardian (Old)
and /work/SRC/openSUSE:Factory/.forgejo-guardian.new.2316 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "forgejo-guardian"
Wed Jan 29 16:18:23 2025 rev:2 rq:1241173 version:0.5.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/forgejo-guardian/forgejo-guardian.changes
2025-01-23 18:03:03.458301207 +0100
+++
/work/SRC/openSUSE:Factory/.forgejo-guardian.new.2316/forgejo-guardian.changes
2025-01-29 16:19:02.665032992 +0100
@@ -1,0 +2,11 @@
+Tue Jan 28 20:15:49 UTC 2025 - Richard Rahl <[email protected]>
+
+- update to 0.5.0:
+ * Ability to check user tokens and oauth2 apps
+ * The minimum value for inactive.req_limit changed to 4
+ * Ability to enter seconds in the interval without s suffix
+ * Make expressions.interval suffixably
+ * Guardian checks all instance users when expressions.only_new_users is false
+ * Prevent async deadlock when Telegram is disabled
+
+-------------------------------------------------------------------
Old:
----
forgejo-guardian-0.4.1.obscpio
New:
----
forgejo-guardian-0.5.0.obscpio
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ forgejo-guardian.spec ++++++
--- /var/tmp/diff_new_pack.L9FkpA/_old 2025-01-29 16:19:03.897084084 +0100
+++ /var/tmp/diff_new_pack.L9FkpA/_new 2025-01-29 16:19:03.897084084 +0100
@@ -17,7 +17,7 @@
Name: forgejo-guardian
-Version: 0.4.1
+Version: 0.5.0
Release: 0
Summary: Simple Forgejo instance guardian
License: AGPL-3.0-or-later
++++++ _service ++++++
--- /var/tmp/diff_new_pack.L9FkpA/_old 2025-01-29 16:19:03.921085079 +0100
+++ /var/tmp/diff_new_pack.L9FkpA/_new 2025-01-29 16:19:03.925085245 +0100
@@ -3,7 +3,7 @@
<service name="obs_scm" mode="manual">
<param name="scm">git</param>
<param name="url">https://git.4rs.nl/awiteb/forgejo-guardian</param>
- <param name="revision">refs/tags/v0.4.1</param>
+ <param name="revision">refs/tags/v0.5.0</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">v(.*)</param>
</service>
++++++ forgejo-guardian-0.4.1.obscpio -> forgejo-guardian-0.5.0.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/CHANGELOG.md
new/forgejo-guardian-0.5.0/CHANGELOG.md
--- old/forgejo-guardian-0.4.1/CHANGELOG.md 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/CHANGELOG.md 2025-01-28 20:22:43.000000000
+0100
@@ -6,6 +6,16 @@
## unreleased
### Added
+- Ability to check user tokens and oauth2 apps
([**#25**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/25))
([`1e90760`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/1e907609cd9fae24e58cbe9eab99cc4b88459cb3))
+ - **BC**: The minimum value for `inactive.req_limit` changed to 4
+- Ability to enter seconds in the interval without `s` suffix
([**#28**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/28))
([`c9dfc6e`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/c9dfc6e57acdfbdbc2485d729ce24edcab292224))
+- Make `expressions.interval` suffixably
([**#29**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/29))
([`e32aca7`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/e32aca7164669532ca08ee356fc01aaf6185aa67))
+### Fixed
+- Guardian checks all instance users when `expressions.only_new_users` is
`false` ([**#27**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/27))
([`cf05a68`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/cf05a68c22f1eeffc3308856c7117ff6d82855da))
+- Prevent async deadlock when Telegram is disabled
([**#31**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/31))
([`2ee7849`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/2ee784916305d32705d6a667ce1979c47f67874f))
+
+## [0.4.1](https://git.4rs.nl/awiteb/forgejo-guardian/compare/v0.4.0..v0.4.1)
- 2025-01-22
+### Added
- Add support for including and excluding users
([**#22**](https://git.4rs.nl/awiteb/forgejo-guardian/issues/22))
([`f07fdab`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/f07fdaba7e9a37b87848e6d0bbb6b639c84cfd95))
### Fixed
- Check for the user activities for more than last 365 days
([`e41b9b3`](https://git.4rs.nl/awiteb/forgejo-guardian/commit/e41b9b36f67ff465731a20c1baaca9a9e6440bd0))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/Cargo.lock
new/forgejo-guardian-0.5.0/Cargo.lock
--- old/forgejo-guardian-0.4.1/Cargo.lock 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/Cargo.lock 2025-01-28 20:22:43.000000000
+0100
@@ -332,7 +332,7 @@
[[package]]
name = "forgejo-guardian"
-version = "0.4.1"
+version = "0.5.0"
dependencies = [
"chrono",
"regex",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/Cargo.toml
new/forgejo-guardian-0.5.0/Cargo.toml
--- old/forgejo-guardian-0.4.1/Cargo.toml 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/Cargo.toml 2025-01-28 20:22:43.000000000
+0100
@@ -1,7 +1,7 @@
[package]
name = "forgejo-guardian"
description = "Simple Forgejo instance guardian, banning users and alerting
admins based on certain regular expressions"
-version = "0.4.1"
+version = "0.5.0"
edition = "2021"
authors = ["Awiteb <[email protected]>"]
repository = "https://git.4rs.nl/awiteb/forgejo-guardian"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/README.md
new/forgejo-guardian-0.5.0/README.md
--- old/forgejo-guardian-0.4.1/README.md 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/README.md 2025-01-28 20:22:43.000000000
+0100
@@ -66,7 +66,7 @@
```yaml
services:
forgejo-guardian:
- image: git.4rs.nl/awiteb/forgejo-guardian:0.4
+ image: git.4rs.nl/awiteb/forgejo-guardian:0.5
volumes:
- ./forgejo-guardian.toml:/app/forgejo-guardian.toml:ro
```
@@ -89,7 +89,7 @@
#### Without building the image
```sh
-docker run --rm -d -v $PWD/forgejo-guardian.toml:/app/forgejo-guardian.toml:ro
git.4rs.nl/awiteb/forgejo-guardian:0.4
+docker run --rm -d -v $PWD/forgejo-guardian.toml:/app/forgejo-guardian.toml:ro
git.4rs.nl/awiteb/forgejo-guardian:0.5
```
## Installation
@@ -176,12 +176,20 @@
Inactive users configuration section, with the following fields:
+> [!NOTE]
+> The field may start with a version, this version is the required Forgejo
+> version, so you can use this version or later
+
- `enabled`: Enable the cleanup of inactive users, inactive feature need
`read:user` scope (default: `false`)
- `exclude`: List of usernames to exclude from the cleanup (default: `[]`)
- `source_id`: List of source IDs to only consider users from (default: `[]`)
- `source_id_exclude`: List of source IDs to exclude users from (default:
`[]`)
+- **v10.0.1** `check_tokens`: Check if the user has tokens, if true the user
+ will not be considered (default: `true`)
+- **v10.0.1** `check_oauth2`: Check if the user has OAuth2 applications, if
+ true the user will not be considered (default: `true`)
- `days`: The number of days that a new user is given to become active.
(default: `30`)
-- `req_limit`: Maximum number of requests to send to the Forgejo instance
within each interval (default: `200`) (Minimum: `2`)
+- `req_limit`: Maximum number of requests to send to the Forgejo instance
within each interval (default: `200`) (Minimum: `4`)
- `req_interval`: Time interval to pause after reaching the `req_limit`
(default: `10m`)
- `interval`: Time Interval to check for inactive users (default: `7d`)
@@ -214,8 +222,10 @@
Expressions configuration section, with the following fields:
- `only_new_users`: If set to `true`, the guardian will only check the new
users, and not the existing ones (default: `false`)
-- `interval`: Interval to check for new users in seconds (default: `300`)
+- `interval`: Interval to check for new users in seconds (default: `300s`)
- `limit`: Limit of users to fetch in each interval (default: `100`)
+- `req_limit`: Maximum number of requests to send to the Forgejo instance
within each interval (default: `200`) (Minimum: `1`) *
+- `req_interval`: Time interval to pause after reaching the `req_limit`
(default: `10m`) *
- `ban_alert`: Send a notification when a user is banned (default: `false`)
- `ban_action`: The action to take when a user is banned, can be one of the
following:
- `purge` (default): Forcibly delete user and any repositories,
organizations, and
@@ -227,6 +237,15 @@
- `ban`: Regular expressions to match against to ban the user
- `sus`: Regular expressions to match against to alert the admins
+The `expressions.interval` and `expressions.req_interval` have the following
suffixes:
+
+- `s`: Seconds
+- `m`: Minutes
+- `h`: Hours
+- `d`: Days
+
+*: Only for checking old users, if `only_new_users` is set to `true`, the
guardian will not use these values.
+
`ban` and `sus` are tables, and each one have the following fields:
- `enabled`: Enable the expressions (default: enabled if the section is
present,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/docker/Dockerfile
new/forgejo-guardian-0.5.0/docker/Dockerfile
--- old/forgejo-guardian-0.4.1/docker/Dockerfile 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/docker/Dockerfile 2025-01-28
20:22:43.000000000 +0100
@@ -3,7 +3,7 @@
WORKDIR /app
RUN apk add --no-cache curl
-RUN curl
https://git.4rs.nl/awiteb/forgejo-guardian/releases/download/v0.4.1/forgejo-guardian-v0.4.1-x86_64-linux-musl
--output forgejo-guardian
+RUN curl
https://git.4rs.nl/awiteb/forgejo-guardian/releases/download/v0.5.0/forgejo-guardian-v0.5.0-x86_64-linux-musl
--output forgejo-guardian
RUN chmod +x forgejo-guardian
ENTRYPOINT ["./forgejo-guardian"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/config/defaults.rs
new/forgejo-guardian-0.5.0/src/config/defaults.rs
--- old/forgejo-guardian-0.4.1/src/config/defaults.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/config/defaults.rs 2025-01-28
20:22:43.000000000 +0100
@@ -23,6 +23,14 @@
pub const fn ban_action() -> BanAction {
BanAction::Purge
}
+
+ pub const fn req_limit() -> u32 {
+ 200
+ }
+
+ pub const fn req_interval() -> u32 {
+ 10 * 60
+ }
}
/// Default configuration for inactive section.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/config/deserializers.rs
new/forgejo-guardian-0.5.0/src/config/deserializers.rs
--- old/forgejo-guardian-0.4.1/src/config/deserializers.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/config/deserializers.rs 2025-01-28
20:22:43.000000000 +0100
@@ -121,8 +121,19 @@
where
D: de::Deserializer<'de>,
{
- let interval = String::deserialize(des)
- .map_err(|_| de::Error::custom("Expected a suffixed interval, e.g. 1s,
2m"))?;
+ let toml_value = Value::deserialize(des)?;
+
+ if let Value::Integer(interval) = toml_value {
+ return u32::try_from(interval)
+ .map_err(|_| de::Error::custom("It is a negative number, it must
be positive"));
+ }
+
+ let Value::String(interval) = toml_value else {
+ return Err(de::Error::custom(
+ "Expected a suffixed interval, e.g. 1s, 2m",
+ ));
+ };
+
if interval.chars().count() < 2 {
return Err(de::Error::custom(format!(
"Expected a suffixed interval, e.g. 1s, 2m. found {interval}"
@@ -142,10 +153,10 @@
})?;
let suffix = interval.chars().last().expect("the length more than 2");
let interval = match suffix {
- 's' => number,
- 'm' => number * 60,
- 'h' => number * 60 * 60,
- 'd' => number * 24 * 60 * 60,
+ 's' => Some(number),
+ 'm' => number.checked_mul(60),
+ 'h' => number.checked_mul(60 * 60),
+ 'd' => number.checked_mul(24 * 60 * 60),
_ => {
return Err(de::Error::custom(format!(
"Unknown suffix `{suffix}`, expected s, m, h, d"
@@ -153,7 +164,9 @@
}
};
- Ok(interval)
+ interval.ok_or_else(|| {
+ de::Error::custom("The interval is too large, the maximum value is
49710 days.")
+ })
}
/// Deserialize the deserializer into `T` then check if the value is greater
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/config/mod.rs
new/forgejo-guardian-0.5.0/src/config/mod.rs
--- old/forgejo-guardian-0.4.1/src/config/mod.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/config/mod.rs 2025-01-28
20:22:43.000000000 +0100
@@ -48,12 +48,19 @@
/// Source ID to exclude
#[serde(default)]
pub source_id_exclude: Vec<u32>,
+ /// Check if the user has tokens, if true the user will not be considered
+ #[serde(default = "defaults::bool_true")]
+ pub check_tokens: bool,
+ /// Check if the user has OAuth2 applications, if true the user will not be
+ /// considered
+ #[serde(default = "defaults::bool_true")]
+ pub check_oauth2: bool,
/// Number of inactive days to consider
#[serde(default = "defaults::inactive::days")]
pub days: u64,
/// Number of requests to send
#[serde(default = "defaults::inactive::req_limit")]
- #[serde(deserialize_with = "deserializers::unsigned_minimum::<_, _, 2>")]
+ #[serde(deserialize_with = "deserializers::unsigned_minimum::<_, _, 4>")]
pub req_limit: u16,
/// Time interval in seconds for the request limit
#[serde(
@@ -171,11 +178,26 @@
#[serde(default)]
pub only_new_users: bool,
/// Interval to check for new users in seconds
- #[serde(default = "defaults::expressions::interval")]
+ #[serde(
+ default = "defaults::expressions::interval",
+ deserialize_with = "deserializers::suffix_interval"
+ )]
pub interval: u32,
/// Limit of users to fetch in each interval
#[serde(default = "defaults::expressions::limit")]
pub limit: u32,
+ /// Maximum number of requests to send
+ #[serde(
+ default = "defaults::expressions::req_limit",
+ deserialize_with = "deserializers::unsigned_minimum::<_, _, 1>"
+ )]
+ pub req_limit: u32,
+ /// Interval when hitting the request limit
+ #[serde(
+ default = "defaults::expressions::req_interval",
+ deserialize_with = "deserializers::suffix_interval"
+ )]
+ pub req_interval: u32,
/// Action to take when banning a user
#[serde(default = "defaults::expressions::ban_action")]
pub ban_action: BanAction,
@@ -267,6 +289,8 @@
exclude: Vec::new(),
source_id: Vec::new(),
source_id_exclude: Vec::new(),
+ check_tokens: true,
+ check_oauth2: true,
days: defaults::inactive::days(),
req_limit: defaults::inactive::req_limit(),
req_interval: defaults::inactive::req_interval(),
@@ -282,6 +306,8 @@
ban_alert: false,
interval: defaults::expressions::interval(),
limit: defaults::expressions::limit(),
+ req_limit: defaults::expressions::req_limit(),
+ req_interval: defaults::expressions::req_interval(),
ban_action: defaults::expressions::ban_action(),
ban: Expr::default(),
sus: Expr::default(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/forgejo-guardian-0.4.1/src/forgejo_api/activity_feed.rs
new/forgejo-guardian-0.5.0/src/forgejo_api/activity_feed.rs
--- old/forgejo-guardian-0.4.1/src/forgejo_api/activity_feed.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/forgejo_api/activity_feed.rs 2025-01-28
20:22:43.000000000 +0100
@@ -1,3 +1,6 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// Copyright (C) 2024-2025 Awiteb <[email protected]>
+
use reqwest::{Client, Method};
use url::Url;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/forgejo_api/mod.rs
new/forgejo-guardian-0.5.0/src/forgejo_api/mod.rs
--- old/forgejo-guardian-0.4.1/src/forgejo_api/mod.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/forgejo_api/mod.rs 2025-01-28
20:22:43.000000000 +0100
@@ -6,12 +6,14 @@
mod activity_feed;
mod ban_user;
mod get_users;
+mod tokens;
mod user;
pub use activity_feed::*;
pub use ban_user::*;
pub use get_users::*;
use reqwest::{Method, Request};
+pub use tokens::*;
pub use user::*;
/// Build a request with the given method, instance, token and endpoint.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/forgejo_api/tokens.rs
new/forgejo-guardian-0.5.0/src/forgejo_api/tokens.rs
--- old/forgejo-guardian-0.4.1/src/forgejo_api/tokens.rs 1970-01-01
01:00:00.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/forgejo_api/tokens.rs 2025-01-28
20:22:43.000000000 +0100
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// Copyright (C) 2024-2025 Awiteb <[email protected]>
+
+use reqwest::{Client, Method};
+use url::Url;
+
+use crate::{
+ error::{GuardError, GuardResult},
+ forgejo_api,
+};
+
+/// Returns whether the tokens is empty.
+pub async fn is_empty_tokens(
+ client: &Client,
+ instance: &Url,
+ token: &str,
+ username: &str,
+) -> GuardResult<bool> {
+ let req = forgejo_api::build_request(
+ Method::GET,
+ instance,
+ token,
+ &format!("/api/v1/users/{username}/tokens"),
+ );
+ let url = req.url().clone();
+ let res = client.execute(req).await?;
+
+ if !res.status().is_success() {
+ return Err(GuardError::InvalidForgejoResponse(
+ format!("Status code: {status}", status = res.status()),
+ url,
+ ));
+ }
+
+ tracing::debug!("Get tokens response: {res:?}");
+
+ Ok(res.text().await.unwrap_or_default().trim() == "[]")
+}
+
+/// Returns whether the apps is empty
+pub async fn is_empty_apps(
+ client: &Client,
+ instance: &Url,
+ token: &str,
+ username: &str,
+) -> GuardResult<bool> {
+ let req = forgejo_api::build_request(
+ Method::GET,
+ instance,
+ token,
+ &format!("/api/v1/user/applications/oauth2?sudo={username}"),
+ );
+ let url = req.url().clone();
+ let res = client.execute(req).await?;
+
+ if !res.status().is_success() {
+ return Err(GuardError::InvalidForgejoResponse(
+ format!("Status code: {status}", status = res.status()),
+ url,
+ ));
+ }
+
+ tracing::debug!("Get apps response: {res:?}");
+
+ Ok(res.text().await.unwrap_or_default().trim() == "[]")
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/inactive_users.rs
new/forgejo-guardian-0.5.0/src/inactive_users.rs
--- old/forgejo-guardian-0.4.1/src/inactive_users.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/inactive_users.rs 2025-01-28
20:22:43.000000000 +0100
@@ -8,6 +8,7 @@
use reqwest::Client;
use tokio_util::sync::CancellationToken;
+use url::Url;
use crate::{
config::{BanAction, Config},
@@ -16,6 +17,65 @@
const LIMIT: u32 = 30;
+/// Returns true if the user has no tokens or `is_enabled` is false.
+///
+/// If there is an error while fetching the tokens, it will return false.
+async fn is_empty_tokens(
+ client: &Client,
+ instance: &Url,
+ token: &str,
+ username: &str,
+ is_enabled: bool,
+) -> bool {
+ if !is_enabled {
+ return true;
+ }
+
+ match forgejo_api::is_empty_tokens(client, instance, token,
username).await {
+ Ok(value) => value,
+ Err(err) => {
+ tracing::error!("Error while get user `@{}` tokens: {err}",
username);
+ false
+ }
+ }
+}
+
+/// Returns true if the user has no apps or `is_enabled` is false.
+///
+/// If there is an error while fetching the apps, it will return false.
+async fn is_empty_apps(
+ client: &Client,
+ instance: &Url,
+ token: &str,
+ username: &str,
+ is_enabled: bool,
+) -> bool {
+ if !is_enabled {
+ return true;
+ }
+
+ match forgejo_api::is_empty_apps(client, instance, token, username).await {
+ Ok(value) => value,
+ Err(err) => {
+ tracing::error!("Error while get user `@{}` tokens: {err}",
username);
+ false
+ }
+ }
+}
+
+/// Returns true if the tokens and apps are empty
+async fn is_empty_tokens_and_apps(
+ client: &Client,
+ instance: &Url,
+ token: &str,
+ username: &str,
+ tokens_enabled: bool,
+ apps_enabled: bool,
+) -> bool {
+ is_empty_tokens(client, instance, token, username, tokens_enabled).await
+ && is_empty_apps(client, instance, token, username, apps_enabled).await
+}
+
/// Check if the user is inactive.
async fn check_user(req_client: &Client, config: &Config, user: ForgejoUser)
-> usize {
if user.is_admin
@@ -33,15 +93,25 @@
return 0;
}
- match forgejo_api::is_empty_feeds(
- req_client,
- &config.forgejo.instance,
- &config.forgejo.token,
- &user.username,
- )
- .await
- {
- Ok(true) => {
+ match (
+ forgejo_api::is_empty_feeds(
+ req_client,
+ &config.forgejo.instance,
+ &config.forgejo.token,
+ &user.username,
+ )
+ .await,
+ is_empty_tokens_and_apps(
+ req_client,
+ &config.forgejo.instance,
+ &config.forgejo.token,
+ &user.username,
+ config.inactive.check_tokens,
+ config.inactive.check_oauth2,
+ )
+ .await,
+ ) {
+ (Ok(true), true) => {
tracing::info!("User `@{}` is inactive.", user.username);
if !config.dry_run {
if let Err(err) = forgejo_api::ban_user(
@@ -55,16 +125,19 @@
{
tracing::error!("Error while ban inactive user `@{}`:
{err}", user.username);
}
- return 2; // heatmap and purge request}
+ // activity feed, purge request and tokens (if sended)
+ return 2
+ + usize::from(config.inactive.check_tokens)
+ + usize::from(config.inactive.check_oauth2);
}
}
- Err(err) => {
+ (Err(err), ..) => {
tracing::error!("{err}");
}
_ => {}
}
- 1 // only heatmap request
+ 1 // only activity feed request
}
/// Check all the instance users and delete the inactive ones.
@@ -131,8 +204,7 @@
}
};
for user in users {
- // +2 Because the next check need 1~2 requests
- if (reqs + 2) > config.inactive.req_limit.into() {
+ if (reqs + 4) > config.inactive.req_limit.into() {
if wait_interval().await {
tracing::warn!("Inactive users checker stopped while
checking users.");
break 'main_loop;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/main.rs
new/forgejo-guardian-0.5.0/src/main.rs
--- old/forgejo-guardian-0.4.1/src/main.rs 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/src/main.rs 2025-01-28 20:22:43.000000000
+0100
@@ -116,6 +116,13 @@
sus_sender,
ban_sender,
));
+
+ if !config.expressions.only_new_users {
+ tokio::spawn(users_fetcher::old_users(
+ Arc::clone(&config),
+ cancellation_token.clone(),
+ ));
+ }
}
if let Some(telegram) = config.telegram.is_enabled() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/traits.rs
new/forgejo-guardian-0.5.0/src/traits.rs
--- old/forgejo-guardian-0.4.1/src/traits.rs 2025-01-22 07:46:25.000000000
+0100
+++ new/forgejo-guardian-0.5.0/src/traits.rs 2025-01-28 20:22:43.000000000
+0100
@@ -14,6 +14,10 @@
impl ExprChecker for Expr {
fn is_match<'a>(&'a self, user: &ForgejoUser) -> Option<RegexReason> {
+ if !self.enabled {
+ return None;
+ }
+
let one_of = |hay: &str, exprs: &'a Vec<RegexReason>| {
// Join the user bio into a single line
// ref: https://git.4rs.nl/awiteb/forgejo-guardian/issues/2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/forgejo-guardian-0.4.1/src/users_fetcher.rs
new/forgejo-guardian-0.5.0/src/users_fetcher.rs
--- old/forgejo-guardian-0.4.1/src/users_fetcher.rs 2025-01-22
07:46:25.000000000 +0100
+++ new/forgejo-guardian-0.5.0/src/users_fetcher.rs 2025-01-28
20:22:43.000000000 +0100
@@ -43,22 +43,22 @@
.collect())
}
-/// Check if ban or suspect a new user
+/// Check if ban or suspect a new user, returns `true` if the ban request
sended
async fn check_new_user(
user: ForgejoUser,
request_client: &reqwest::Client,
config: &Config,
- sus_sender: &Sender<(ForgejoUser, RegexReason)>,
- ban_sender: &Sender<(ForgejoUser, RegexReason)>,
-) {
+ sus_sender: Option<&Sender<(ForgejoUser, RegexReason)>>,
+ ban_sender: Option<&Sender<(ForgejoUser, RegexReason)>>,
+) -> bool {
if let Some(re) = config.expressions.ban.is_match(&user) {
tracing::info!("@{} has been banned because `{re}`", user.username);
if config.dry_run {
// If it's a dry run, we don't need to ban the user
- if config.expressions.ban_alert {
- ban_sender.send((user, re)).await.ok();
+ if config.expressions.ban_alert && ban_sender.is_some() {
+ ban_sender.unwrap().send((user, re)).await.ok();
}
- return;
+ return false;
}
if let Err(err) = forgejo_api::ban_user(
@@ -71,13 +71,15 @@
.await
{
tracing::error!("Error while banning a user: {err}");
- } else if config.expressions.ban_alert {
- ban_sender.send((user, re)).await.ok();
+ } else if config.expressions.ban_alert && ban_sender.is_some() {
+ ban_sender.unwrap().send((user, re)).await.ok();
}
- } else if let Some(re) = config.expressions.sus.is_match(&user) {
+ return true;
+ } else if let Some(re) =
sus_sender.and(config.expressions.sus.is_match(&user)) {
tracing::info!("@{} has been suspected because `{re}`", user.username);
- sus_sender.send((user, re)).await.ok();
+ sus_sender.unwrap().send((user, re)).await.ok();
}
+ false
}
/// Check for new users and send the suspected users to the channel and ban the
@@ -107,12 +109,27 @@
last_user_id.store(uid, Ordering::Relaxed);
}
- if config.expressions.only_new_users && is_first_fetch {
+ if is_first_fetch {
return;
}
for user in new_users {
- check_new_user(user, &request_client, &config, &sus_sender,
&ban_sender).await;
+ check_new_user(
+ user,
+ &request_client,
+ &config,
+ config
+ .telegram
+ .is_enabled()
+ .is_some()
+ .then_some(&sus_sender),
+ config
+ .telegram
+ .is_enabled()
+ .is_some()
+ .then_some(&ban_sender),
+ )
+ .await;
}
}
Err(err) => {
@@ -151,3 +168,71 @@
};
}
}
+
+/// Check for old users and ban them if they match the ban expressions. This
+/// will not sned any alerts
+pub async fn old_users(config: Arc<Config>, cancellation_token:
CancellationToken) {
+ tracing::info!("Starting old users fetcher");
+
+ let wait_interval = || {
+ async {
+ tracing::debug!(
+ "Reached the request limit for old users checker. Waiting for
{} seconds.",
+ config.expressions.req_interval
+ );
+ tokio::select! {
+ _ =
tokio::time::sleep(Duration::from_secs(config.expressions.req_interval.into()))
=> false,
+ _ = cancellation_token.cancelled() => true,
+ }
+ }
+ };
+
+ let client = reqwest::Client::new();
+ let mut reqs = 0;
+ let mut page = 1;
+
+ 'main_loop: loop {
+ // Enter the block if we cancelled, so will break
+ if reqs >= config.expressions.req_limit ||
cancellation_token.is_cancelled() {
+ if wait_interval().await {
+ break;
+ }
+ reqs = 0
+ }
+ reqs += 1;
+
+ let Ok(users) = forgejo_api::get_users(
+ &client,
+ &config.forgejo.instance,
+ &config.forgejo.token,
+ config.expressions.limit,
+ page,
+ "oldest",
+ )
+ .await
+ else {
+ tracing::error!("Falid to fetch old users");
+ continue;
+ };
+
+ if users.is_empty() {
+ tracing::info!("No more old users to check, all instance users are
checked.");
+ break;
+ }
+
+ for user in users {
+ if reqs >= config.expressions.req_limit ||
cancellation_token.is_cancelled() {
+ if wait_interval().await {
+ break 'main_loop;
+ }
+ reqs = 0;
+ }
+
+ if check_new_user(user, &client, &config, None, None).await {
+ reqs += 1;
+ }
+ }
+
+ page += 1;
+ }
+}
++++++ forgejo-guardian.obsinfo ++++++
--- /var/tmp/diff_new_pack.L9FkpA/_old 2025-01-29 16:19:04.037089890 +0100
+++ /var/tmp/diff_new_pack.L9FkpA/_new 2025-01-29 16:19:04.041090056 +0100
@@ -1,5 +1,5 @@
name: forgejo-guardian
-version: 0.4.1
-mtime: 1737528385
-commit: 1e76bd0a05771dfe53d0e4d15f68e7657a705334
+version: 0.5.0
+mtime: 1738092163
+commit: e82f4a1e1f195f0778eb52ee6a87181f4bbc60e4
++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/forgejo-guardian/vendor.tar.zst
/work/SRC/openSUSE:Factory/.forgejo-guardian.new.2316/vendor.tar.zst differ:
char 7, line 1