From b605b1ba7ca740046d80b7e41339455907b95928 Mon Sep 17 00:00:00 2001 From: Konstantin Pichugin Date: Wed, 6 May 2026 19:17:06 +0300 Subject: [PATCH] docs(access): document user_source_deny usage and API path Add config examples and behavior notes for access.user_source_deny, and clarify that it is configured through config.toml rather than dedicated user API request fields. --- docs/Architecture/API/API.md | 15 +++++++++++++++ docs/Config_params/CONFIG_PARAMS.en.md | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/docs/Architecture/API/API.md b/docs/Architecture/API/API.md index 7177200..502453f 100644 --- a/docs/Architecture/API/API.md +++ b/docs/Architecture/API/API.md @@ -178,6 +178,21 @@ Notes: | `data_quota_bytes` | `u64` | no | Per-user traffic quota. | | `max_unique_ips` | `usize` | no | Per-user unique source IP limit. | +### `access.user_source_deny` via API +- In current API surface, per-user deny-list is **not** exposed as a dedicated field in `CreateUserRequest` / `PatchUserRequest`. +- Configure it in `config.toml` under `[access.user_source_deny]` and apply via normal config reload path. +- Runtime behavior after apply: + - auth succeeds for username/secret + - source IP is checked against `access.user_source_deny[username]` + - on match, handshake is rejected with the same fail-closed outcome as invalid auth + +Example config: +```toml +[access.user_source_deny] +alice = ["203.0.113.0/24", "2001:db8:abcd::/48"] +bob = ["198.51.100.42/32"] +``` + ### `RotateSecretRequest` | Field | Type | Required | Description | | --- | --- | --- | --- | diff --git a/docs/Config_params/CONFIG_PARAMS.en.md b/docs/Config_params/CONFIG_PARAMS.en.md index d222e1f..8cd193e 100644 --- a/docs/Config_params/CONFIG_PARAMS.en.md +++ b/docs/Config_params/CONFIG_PARAMS.en.md @@ -2886,6 +2886,7 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p | [`user_max_unique_ips_global_each`](#user_max_unique_ips_global_each) | `usize` | `0` | | [`user_max_unique_ips_mode`](#user_max_unique_ips_mode) | `"active_window"`, `"time_window"`, or `"combined"` | `"active_window"` | | [`user_max_unique_ips_window_secs`](#user_max_unique_ips_window_secs) | `u64` | `30` | +| [`user_source_deny`](#user_source_deny) | `Map` | `{}` | | [`replay_check_len`](#replay_check_len) | `usize` | `65536` | | [`replay_window_secs`](#replay_window_secs) | `u64` | `120` | | [`ignore_time_skew`](#ignore_time_skew) | `bool` | `false` | @@ -2990,6 +2991,20 @@ If your backend or network is very bandwidth-constrained, reduce cap first. If p [access] user_max_unique_ips_window_secs = 30 ``` +## user_source_deny + - **Constraints / validation**: Table `username -> IpNetwork[]`. Each network must parse as CIDR (for example `203.0.113.0/24` or `2001:db8::/32`). + - **Description**: Per-user source IP/CIDR deny-list applied **after successful auth** in TLS and MTProto handshake paths. A matched source IP is rejected via the same fail-closed path as invalid auth. + - **Example**: + + ```toml + [access.user_source_deny] + alice = ["203.0.113.0/24", "2001:db8:abcd::/48"] + bob = ["198.51.100.42/32"] + ``` + + - **How it works (quick check)**: + - connection from user `alice` and source `203.0.113.55` -> rejected (matches `203.0.113.0/24`) + - connection from user `alice` and source `198.51.100.10` -> allowed by this rule set (no match) ## replay_check_len - **Constraints / validation**: `usize`. - **Description**: Replay-protection storage length (number of entries tracked for duplicate detection).