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>,
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 ==.Source§impl Serialize for QbtCompatSettings
impl Serialize for QbtCompatSettings
impl Eq for QbtCompatSettings
impl StructuralPartialEq for QbtCompatSettings
Auto Trait Implementations§
impl Freeze for QbtCompatSettings
impl RefUnwindSafe for QbtCompatSettings
impl Send for QbtCompatSettings
impl Sync for QbtCompatSettings
impl Unpin for QbtCompatSettings
impl UnsafeUnpin for QbtCompatSettings
impl UnwindSafe for QbtCompatSettings
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.