Skip to main content

QbtCompatSettings

Struct QbtCompatSettings 

Source
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: bool

Master 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: String

Username required for qBt v2 login. Default: "admin" (qBt factory default). Must be non-empty when enabled.

§password_hash: String

Argon2id 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: String

Legacy 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: String

Version string returned by GET /api/v2/app/version. Must match the regex ^v\d+\.\d+(\.\d+)?(-\w+)?$. Default: "v5.1.4".

§spoof_webapi_version: String

Version 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: u64

Session cookie TTL in seconds. Bounds: [60, 604_800] (1 minute to 1 week). Default: 86_400 (24 hours).

§max_sessions: usize

Maximum 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: u16

v0.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: String

v0.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: bool

M172a 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: bool

M172a 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: bool

M172a 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: u32

Maximum 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: u64

Ban 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: bool

When 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

Source§

fn clone(&self) -> QbtCompatSettings

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for QbtCompatSettings

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for QbtCompatSettings

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for QbtCompatSettings

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for QbtCompatSettings

Source§

fn eq(&self, other: &QbtCompatSettings) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for QbtCompatSettings

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Eq for QbtCompatSettings

Source§

impl StructuralPartialEq for QbtCompatSettings

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,