pub struct QbtCompatSettings {Show 20 fields
pub enabled: bool,
pub username: String,
pub password_hash: String,
pub password: String,
pub spoof_app_version: String,
pub spoof_webapi_version: String,
pub session_ttl_secs: u64,
pub max_sessions: usize,
pub max_concurrent_argon2_ops: Option<u32>,
pub port: u16,
pub bind_address: String,
pub csrf_protection_enabled: bool,
pub host_header_validation_enabled: bool,
pub web_ui_reverse_proxy_enabled: bool,
pub web_ui_reverse_proxies_list: Vec<String>,
pub max_failed_auth_count: u32,
pub ban_duration_secs: u64,
pub bypass_local_auth: bool,
pub bypass_auth_subnet_whitelist: Vec<String>,
pub brute_force_registry_capacity: Option<usize>,
}Expand description
qBittorrent WebUI v2 compatibility layer configuration.
§Security note (M172a)
As of M172a passwords are stored in PHC-format argon2id hashes in
Self::password_hash. The legacy Self::password field is retained
as a one-shot upgrade path — on daemon startup, if password_hash is
empty and password is non-empty, the daemon hashes the plaintext,
writes it back to Self::password_hash (zeroing the plaintext), and
atomically rewrites the config file via
crate::migrate_qbt_credentials. Fresh installs ship with
password = "" and a pre-hashed password_hash so no migration WARN
ever fires on a clean daemon.
File permissions (0o600) are still enforced by
[irontide-config’s save_config_atomic] as defence-in-depth — the PHC
hash is not directly reversible, but password-cracking dictionaries
remain feasible for weak passwords.
Fields§
§enabled: boolMaster enable flag. When false, all /api/v2/* routes return 404
(not 403) — the route must appear non-existent. Default: true
(v0.172.1 flip, inverted from v0.168.0’s security-through-invisibility
default). Set enabled = false in config.toml under [qbt_compat]
to opt out — the argon2id hash + brute-force ban + CSRF middleware
(M172a) remain the primary defences; 404-on-disabled is defence-in-
depth, not primary security.
username: StringUsername required for qBt v2 login. Default: "admin" (qBt factory
default). Must be non-empty when enabled.
password_hash: StringArgon2id PHC-format password hash (M172a). Example:
"$argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>". OWASP-recommended
parameters (m=19456 KiB, t=2, p=1).
Fresh installs ship a non-empty default pre-hashing the factory “adminadmin” password so no migration WARN ever fires. The daemon rejects a malformed hash at validate-time.
password: StringLegacy plaintext password — deprecated, migration-only. Populated
on config files written before M172a; the daemon rehashes and
zeroizes this on next startup, leaving it permanently empty
afterwards. New configs must ship with password = "" and a
non-empty password_hash. Default: "".
spoof_app_version: StringVersion string returned by GET /api/v2/app/version. Must match the
regex ^v\d+\.\d+(\.\d+)?(-\w+)?$. Default: "v5.1.4".
spoof_webapi_version: StringVersion string returned by GET /api/v2/app/webapiVersion. Must match
the regex ^\d+\.\d+(\.\d+)?$ (no leading v). Default: "2.11.4".
session_ttl_secs: u64Session cookie TTL in seconds. Bounds: [60, 604_800] (1 minute to
1 week). Default: 86_400 (24 hours).
max_sessions: usizeMaximum concurrent sessions. Prevents unbounded growth on login
storms. Must be > 0. Default: 1024.
max_concurrent_argon2_ops: Option<u32>Optional override for the global argon2 verification semaphore size
(M172a G2). None means use the computed default
num_cpus::get() * 2, clamped to [2, 16]. Rejects Some(0). Peak
memory under flood is bounded by permits * 19 MiB.
port: u16v0.187.3 / 2A: TCP port the Web UI listens on. Single source of truth
for the listen port; the legacy [api].port field is deprecated and
auto-migrates to this value on config load with a one-time warning.
Default: 9080. Validated > 0 when enabled is true.
bind_address: Stringv0.187.3 / 2A: bind address the Web UI listens on. Single source of
truth; the legacy [api].bind field is deprecated and auto-migrates.
Default: "127.0.0.1". Use "0.0.0.0" to expose on all interfaces
(behind a reverse proxy strongly recommended).
csrf_protection_enabled: boolM172a Lane B: enable Origin/Referer CSRF checks on mutating requests
(POST/PATCH/PUT/DELETE) against /webui/* and /api/v2/*. When both
headers are absent the request is allowed (server-to-server case;
matches qBt and is what *arr clients need). Default: true.
host_header_validation_enabled: boolM172a Lane B: enable Host-header validation against Origin/Referer.
When csrf_protection_enabled is true but this flag is false, the
middleware short-circuits to allow. Useful for reverse-proxy setups
whose proxy strips/rewrites the Host header in a non-trivial way.
Default: true.
web_ui_reverse_proxy_enabled: boolM172a Lane B: when true, the CSRF middleware resolves the real client
IP via the XFF trust-hop algorithm and validates Host against
X-Forwarded-Host + X-Forwarded-Proto only when the peer matches
one of the CIDRs in Self::web_ui_reverse_proxies_list. Untrusted
peers fall back to direct Host validation — defence-in-depth against
an attacker spoofing XFH from outside the proxy layer. Default:
false.
web_ui_reverse_proxies_list: Vec<String>M172a Lane B: list of CIDRs trusted to supply X-Forwarded-For and
X-Forwarded-Host headers. Each entry must parse as
ipnet::IpNet (validated in Settings::validate). Empty list
is valid but degrades reverse-proxy mode to “trust nobody” — the
middleware falls back to direct Host validation in that case.
Narrow is safer. Prefer single-host CIDRs like 172.20.0.5/32
over block-wide 172.16.0.0/12. A too-wide mask means any client
inside a trusted subnet can spoof X-Forwarded-Host and defeat
CSRF protection; a /32 binds trust to the exact proxy IP.
max_failed_auth_count: u32Maximum number of failed auth/login attempts from a single source
IP before the IP is banned. Must be > 0 unless
Self::bypass_local_auth is true. Default: 5.
The counter resets on a successful login and on ban expiry.
ban_duration_secs: u64Ban duration (seconds) after hitting Self::max_failed_auth_count.
Bounds: [60, 86_400] (1 minute to 1 day). Default: 3_600 (1 hour).
bypass_local_auth: boolWhen true, any request whose resolved client IP is loopback
(127.0.0.0/8, ::1) bypasses authentication entirely and
receives a valid SID cookie. Default: false.
Combined with Self::bypass_auth_subnet_whitelist these provide
the qBt-parity “local auth off” and “whitelisted subnets” escape
hatches that *arr clients rely on.
bypass_auth_subnet_whitelist: Vec<String>CIDR strings whose resolved client IP bypasses authentication
entirely. Each string must parse as an ipnet::IpNet. Default:
vec![].
Interpreted at router construction time and re-parsed on
setPreferences apply so runtime reconfiguration flows through the
shared QbtState::bypass_auth_subnet_whitelist RwLock.
brute_force_registry_capacity: Option<usize>Optional override for the brute-force-ban registry’s LRU capacity.
None means use the internal default of 10_000. Rejects values
< 100. Default: None.
The registry retains its initial capacity until daemon restart —
runtime changes only affect NEW entries admitted afterwards (see
FIXME in the classify_immediate handler).
Trait Implementations§
Source§impl Clone for QbtCompatSettings
impl Clone for QbtCompatSettings
Source§fn clone(&self) -> QbtCompatSettings
fn clone(&self) -> QbtCompatSettings
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for QbtCompatSettings
impl Debug for QbtCompatSettings
Source§impl Default for QbtCompatSettings
impl Default for QbtCompatSettings
Source§impl<'de> Deserialize<'de> for QbtCompatSettingswhere
QbtCompatSettings: Default,
impl<'de> Deserialize<'de> for QbtCompatSettingswhere
QbtCompatSettings: Default,
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for QbtCompatSettings
Source§impl PartialEq for QbtCompatSettings
impl PartialEq for QbtCompatSettings
Source§fn eq(&self, other: &QbtCompatSettings) -> bool
fn eq(&self, other: &QbtCompatSettings) -> bool
self and other values to be equal, and is used by ==.