mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-11-01 01:06:49 +02:00
Add configurable Fill Assist rules URL (#7791)
This commit is contained in:
6 files changed
+94
-5
No files matched your search
@@ -386,6 +386,11 @@
|
|||||||
# HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS=true
|
# HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS=true
|
||||||
|
|
||||||
## Client Settings
|
## Client Settings
|
||||||
|
## Server-wide Fill Assist rules feed base directory URL, not a JSON file.
|
||||||
|
## Defaults to https://fillassist.bitwarden.com.
|
||||||
|
## Must be a valid HTTPS URL without credentials, query parameters, fragments, or surrounding whitespace.
|
||||||
|
# FILL_ASSIST_RULES_URL=https://fillassist.bitwarden.com
|
||||||
|
|
||||||
## Enable experimental feature flags for clients.
|
## Enable experimental feature flags for clients.
|
||||||
## This is a comma-separated list of flags, e.g. "flag1,flag2,flag3".
|
## This is a comma-separated list of flags, e.g. "flag1,flag2,flag3".
|
||||||
## Note that clients cache the /api/config endpoint for about 1 hour and it could take some time before they are enabled or disabled!
|
## Note that clients cache the /api/config endpoint for about 1 hour and it could take some time before they are enabled or disabled!
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ fn config() -> Json<Value> {
|
|||||||
"notifications": format!("{domain}/notifications"),
|
"notifications": format!("{domain}/notifications"),
|
||||||
"sso": "",
|
"sso": "",
|
||||||
"cloudRegion": null,
|
"cloudRegion": null,
|
||||||
|
"fillAssistRules": CONFIG.fill_assist_rules_url(),
|
||||||
},
|
},
|
||||||
// Bitwarden uses this for the self-hosted servers to indicate the default push technology
|
// Bitwarden uses this for the self-hosted servers to indicate the default push technology
|
||||||
"push": {
|
"push": {
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ use crate::{
|
|||||||
DbConn,
|
DbConn,
|
||||||
models::{
|
models::{
|
||||||
Cipher, CipherId, Collection, CollectionCipher, CollectionGroup, CollectionId, CollectionUser, Device,
|
Cipher, CipherId, Collection, CollectionCipher, CollectionGroup, CollectionId, CollectionUser, Device,
|
||||||
EventType, Group, GroupId, GroupUser, Invitation, Membership, MembershipId, MembershipStatus,
|
EventType, FillAssistPolicyData, Group, GroupId, GroupUser, Invitation, Membership, MembershipId,
|
||||||
MembershipType, OrgPolicy, OrgPolicyType, Organization, OrganizationApiKey, OrganizationId, TwoFactor,
|
MembershipStatus, MembershipType, OrgPolicy, OrgPolicyType, Organization, OrganizationApiKey,
|
||||||
TwoFactorType, User, UserId,
|
OrganizationId, TwoFactor, TwoFactorType, User, UserId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mail,
|
mail,
|
||||||
@@ -2048,6 +2048,29 @@ async fn put_policy(
|
|||||||
err!("Invalid or unsupported policy type")
|
err!("Invalid or unsupported policy type")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let current_policy = OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await;
|
||||||
|
let is_currently_enabled = current_policy.as_ref().is_some_and(|policy| policy.enabled);
|
||||||
|
|
||||||
|
// Fill Assist depends on Single Organization. Match Bitwarden's dependency checks by only checking when the
|
||||||
|
// policy changes state.
|
||||||
|
if pol_type_enum == OrgPolicyType::FillAssist && data.enabled && !is_currently_enabled {
|
||||||
|
let single_org_policy_enabled =
|
||||||
|
OrgPolicy::find_by_org_and_type(&org_id, OrgPolicyType::SingleOrg, &conn).await.is_some_and(|p| p.enabled);
|
||||||
|
|
||||||
|
if !single_org_policy_enabled {
|
||||||
|
err!("Turn on the Single organization policy because it is required for the Activate fill assist policy.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pol_type_enum == OrgPolicyType::SingleOrg && !data.enabled && is_currently_enabled {
|
||||||
|
let fill_assist_policy_enabled =
|
||||||
|
OrgPolicy::find_by_org_and_type(&org_id, OrgPolicyType::FillAssist, &conn).await.is_some_and(|p| p.enabled);
|
||||||
|
|
||||||
|
if fill_assist_policy_enabled {
|
||||||
|
err!("Turn off the Activate fill assist policy because it requires the Single organization policy.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bitwarden only allows the Reset Password policy when Single Org policy is enabled
|
// Bitwarden only allows the Reset Password policy when Single Org policy is enabled
|
||||||
// Vaultwarden encouraged to use multiple orgs instead of groups because groups were not available in the past
|
// Vaultwarden encouraged to use multiple orgs instead of groups because groups were not available in the past
|
||||||
// Now that groups are available we can enforce this option when wanted.
|
// Now that groups are available we can enforce this option when wanted.
|
||||||
@@ -2080,6 +2103,37 @@ async fn put_policy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pol_type_enum == OrgPolicyType::FillAssist {
|
||||||
|
let fill_assist_data = match data.data.as_ref() {
|
||||||
|
None | Some(Value::Null) => FillAssistPolicyData {
|
||||||
|
rules_url: None,
|
||||||
|
},
|
||||||
|
Some(data) => {
|
||||||
|
let Ok(data) = serde_json::from_value::<FillAssistPolicyData>(data.clone()) else {
|
||||||
|
err!("Invalid data for FillAssist policy: rulesUrl has an invalid value.")
|
||||||
|
};
|
||||||
|
data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if data.enabled {
|
||||||
|
let Some(rules_url) = fill_assist_data.rules_url.filter(|url| !url.trim().is_empty()) else {
|
||||||
|
err!("The RulesUrl field is required.")
|
||||||
|
};
|
||||||
|
let Ok(rules_url) = url::Url::parse(&rules_url) else {
|
||||||
|
err!("The RulesUrl field is not a valid fully-qualified http, https, or ftp URL.")
|
||||||
|
};
|
||||||
|
|
||||||
|
if !rules_url.has_host() || !matches!(rules_url.scheme(), "http" | "https" | "ftp") {
|
||||||
|
err!("The RulesUrl field is not a valid fully-qualified http, https, or ftp URL.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rules_url.scheme() != "https" {
|
||||||
|
err!("RulesUrl must use HTTPS.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// When enabling the TwoFactorAuthentication policy, revoke all members that do not have 2FA
|
// When enabling the TwoFactorAuthentication policy, revoke all members that do not have 2FA
|
||||||
if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled {
|
if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled {
|
||||||
two_factor::enforce_2fa_policy_for_org(
|
two_factor::enforce_2fa_policy_for_org(
|
||||||
@@ -2127,7 +2181,7 @@ async fn put_policy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await {
|
let mut policy = match current_policy {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => OrgPolicy::new(org_id.clone(), pol_type_enum, false, "{}".to_owned()),
|
None => OrgPolicy::new(org_id.clone(), pol_type_enum, false, "{}".to_owned()),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -603,6 +603,9 @@ make_config! {
|
|||||||
/// This setting applies globally to all users. To control this on a per-org basis instead, use the "Disable Send" org policy.
|
/// This setting applies globally to all users. To control this on a per-org basis instead, use the "Disable Send" org policy.
|
||||||
sends_allowed: bool, true, def, true;
|
sends_allowed: bool, true, def, true;
|
||||||
|
|
||||||
|
/// Fill Assist Rules URL |> HTTPS URL for the server-wide Fill Assist rules feed base directory.
|
||||||
|
fill_assist_rules_url: String, true, def, "https://fillassist.bitwarden.com".to_owned();
|
||||||
|
|
||||||
/// HIBP Api Key |> HaveIBeenPwned API Key, request it here: https://haveibeenpwned.com/API/Key
|
/// HIBP Api Key |> HaveIBeenPwned API Key, request it here: https://haveibeenpwned.com/API/Key
|
||||||
hibp_api_key: Pass, true, option;
|
hibp_api_key: Pass, true, option;
|
||||||
|
|
||||||
@@ -1023,6 +1026,21 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let valid_fill_assist_rules_url = Url::parse(&cfg.fill_assist_rules_url).is_ok_and(|url| {
|
||||||
|
url.scheme() == "https"
|
||||||
|
&& url.has_host()
|
||||||
|
&& url.username().is_empty()
|
||||||
|
&& url.password().is_none()
|
||||||
|
&& url.query().is_none()
|
||||||
|
&& url.fragment().is_none()
|
||||||
|
&& cfg.fill_assist_rules_url.trim() == cfg.fill_assist_rules_url
|
||||||
|
});
|
||||||
|
if !valid_fill_assist_rules_url {
|
||||||
|
err!(
|
||||||
|
"`FILL_ASSIST_RULES_URL` must be a valid HTTPS URL without credentials, query parameters, fragments, or surrounding whitespace."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let connect_src = cfg.allowed_connect_src.to_lowercase();
|
let connect_src = cfg.allowed_connect_src.to_lowercase();
|
||||||
for url in connect_src.split_whitespace() {
|
for url in connect_src.split_whitespace() {
|
||||||
if !url.starts_with("https://") || Url::parse(url).is_err() {
|
if !url.starts_with("https://") || Url::parse(url).is_err() {
|
||||||
@@ -1477,6 +1495,7 @@ pub const SUPPORTED_FEATURE_FLAGS: &[&str] = &[
|
|||||||
// Autofill Team
|
// Autofill Team
|
||||||
"undetermined-cipher-scenario-logic",
|
"undetermined-cipher-scenario-logic",
|
||||||
"enable-basic-auth-response",
|
"enable-basic-auth-response",
|
||||||
|
"fill-assist-targeting-rules",
|
||||||
"ssh-agent-v2",
|
"ssh-agent-v2",
|
||||||
"windows-desktop-autotype",
|
"windows-desktop-autotype",
|
||||||
"windows-desktop-autotype-ga",
|
"windows-desktop-autotype-ga",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub use self::event::{Event, EventType};
|
|||||||
pub use self::favorite::Favorite;
|
pub use self::favorite::Favorite;
|
||||||
pub use self::folder::{Folder, FolderCipher, FolderId};
|
pub use self::folder::{Folder, FolderCipher, FolderId};
|
||||||
pub use self::group::{CollectionGroup, Group, GroupId, GroupUser};
|
pub use self::group::{CollectionGroup, Group, GroupId, GroupUser};
|
||||||
pub use self::org_policy::{OrgPolicy, OrgPolicyId, OrgPolicyType};
|
pub use self::org_policy::{FillAssistPolicyData, OrgPolicy, OrgPolicyId, OrgPolicyType};
|
||||||
pub use self::organization::{
|
pub use self::organization::{
|
||||||
Membership, MembershipId, MembershipStatus, MembershipType, OrgApiKeyId, Organization, OrganizationApiKey,
|
Membership, MembershipId, MembershipStatus, MembershipType, OrgApiKeyId, Organization, OrganizationApiKey,
|
||||||
OrganizationId,
|
OrganizationId,
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub enum OrgPolicyType {
|
|||||||
// AutoConfirm = 18, // Not supported (not implemented yet)
|
// AutoConfirm = 18, // Not supported (not implemented yet)
|
||||||
// BlockClaimedDomainAccountCreation = 19, // Not supported (Not AGPLv3 Licensed)
|
// BlockClaimedDomainAccountCreation = 19, // Not supported (Not AGPLv3 Licensed)
|
||||||
OrganizationUserNotification = 20,
|
OrganizationUserNotification = 20,
|
||||||
|
// SendControls = 21, // Not supported yet
|
||||||
|
FillAssist = 22,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
||||||
@@ -71,6 +73,14 @@ pub struct ResetPasswordDataModel {
|
|||||||
pub auto_enroll_enabled: bool,
|
pub auto_enroll_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/bitwarden/server/blob/13bc813de8e715a71d3410f1e584e87ccdf76025/src/Core/AdminConsole/Models/Data/Organizations/Policies/FillAssistPolicyData.cs
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FillAssistPolicyData {
|
||||||
|
#[serde(alias = "RulesUrl")]
|
||||||
|
pub rules_url: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Local methods
|
/// Local methods
|
||||||
impl OrgPolicy {
|
impl OrgPolicy {
|
||||||
pub fn new(org_uuid: OrganizationId, atype: OrgPolicyType, enabled: bool, data: String) -> Self {
|
pub fn new(org_uuid: OrganizationId, atype: OrgPolicyType, enabled: bool, data: String) -> Self {
|
||||||
|
|||||||
Reference in new issue
Block a user