From 0d990e1dc00569e1a240a05425a9df08cb6cfd19 Mon Sep 17 00:00:00 2001 From: Hagen Tasche Date: Wed, 17 Aug 2022 08:00:46 +0200 Subject: [PATCH 01/11] Open Externallink in new Tab The link to the backup documentation was opened in the active tab. With this change it will open in a new tab and prevent tabnabbing --- src/static/templates/admin/settings.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/templates/admin/settings.hbs b/src/static/templates/admin/settings.hbs index 04142785..fb9668ad 100644 --- a/src/static/templates/admin/settings.hbs +++ b/src/static/templates/admin/settings.hbs @@ -122,7 +122,7 @@ This does not include any configuration or file attachment data that may also be needed to fully restore a vaultwarden instance. For details on how to perform complete backups, refer to the wiki page on - backups. + backups. From d9c0eb3cfcd63c361c436615f1302e5211cd03e9 Mon Sep 17 00:00:00 2001 From: Hagen Tasche Date: Wed, 17 Aug 2022 08:14:19 +0200 Subject: [PATCH 02/11] Update two external Links to prevent tabnabbing Added noopener to prevent tabnabbing --- src/static/templates/admin/diagnostics.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs index 6fd08f4a..99f27193 100644 --- a/src/static/templates/admin/diagnostics.hbs +++ b/src/static/templates/admin/diagnostics.hbs @@ -168,8 +168,8 @@
If you need support please check the following links first before you create a new issue: - Vaultwarden Forum - | Github Discussions + Vaultwarden Forum + | Github Discussions
From 1722742ab3637cbe46d3527f1c63533a23719fa7 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Sat, 20 Aug 2022 16:42:36 +0200 Subject: [PATCH 03/11] Add Org user revoke feature This PR adds a the new v2022.8.x revoke feature which allows an organization owner or admin to revoke access for one or more users. This PR also fixes several permissions and policy checks which were faulty. - Modified some functions to use DB Count features instead of iter/count aftwards. - Rearanged some if statements (faster matching or just one if instead of nested if's) - Added and fixed several policy checks where needed - Some small updates on some response models - Made some functions require an enum instead of an i32 --- src/api/admin.rs | 21 +- src/api/core/ciphers.rs | 2 +- src/api/core/emergency_access.rs | 6 +- src/api/core/organizations.rs | 318 +++++++++++++++++++++++-------- src/api/core/sends.rs | 5 +- src/db/models/mod.rs | 2 +- src/db/models/org_policy.rs | 150 ++++++++++++--- src/db/models/organization.rs | 122 +++++++++--- src/db/models/user.rs | 10 +- 9 files changed, 487 insertions(+), 149 deletions(-) diff --git a/src/api/admin.rs b/src/api/admin.rs index 2f946fc5..867c8ca1 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -418,15 +418,26 @@ async fn update_user_org_type(data: Json, _token: AdminToken, c }; if user_to_edit.atype == UserOrgType::Owner && new_type != UserOrgType::Owner { - // Removing owner permmission, check that there are at least another owner - let num_owners = - UserOrganization::find_by_org_and_type(&data.org_uuid, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { + // Removing owner permmission, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(&data.org_uuid, UserOrgType::Owner, &conn).await <= 1 { err!("Can't change the type of the last owner") } } + // This check is also done at api::organizations::{accept_invite(), _confirm_invite, _activate_user(), edit_user()}, update_user_org_type + // It returns different error messages per function. + if new_type < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_edit.user_uuid, &user_to_edit.org_uuid, true, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot modify this user to this type because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot modify this user to this type because it is a member of an organization which forbids it"); + } + } + } + user_to_edit.atype = new_type; user_to_edit.save(&conn).await } diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index b491424e..5256c28a 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -328,7 +328,7 @@ async fn enforce_personal_ownership_policy(data: Option<&CipherData>, headers: & if data.is_none() || data.unwrap().OrganizationId.is_none() { let user_uuid = &headers.user.uuid; let policy_type = OrgPolicyType::PersonalOwnership; - if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn).await { + if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, None, conn).await { err!("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.") } } diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index d01b599b..5ca86910 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -258,7 +258,7 @@ async fn send_invite(data: JsonUpcase, headers: Heade match User::find_by_mail(&email, &conn).await { Some(user) => { match accept_invite_process(user.uuid, new_emergency_access.uuid, Some(email), conn.borrow()).await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } } @@ -317,7 +317,7 @@ async fn resend_invite(emer_id: String, headers: Headers, conn: DbConn) -> Empty match accept_invite_process(grantee_user.uuid, emergency_access.uuid, emergency_access.email, conn.borrow()) .await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } } @@ -363,7 +363,7 @@ async fn accept_invite(emer_id: String, data: JsonUpcase, conn: DbCo && (claims.grantor_email.is_some() && grantor_user.email == claims.grantor_email.unwrap()) { match accept_invite_process(grantee_user.uuid.clone(), emer_id, Some(grantee_user.email.clone()), &conn).await { - Ok(v) => (v), + Ok(v) => v, Err(e) => err!(e.to_string()), } diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index e968ffbd..9b7d264c 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -61,6 +61,10 @@ pub fn routes() -> Vec { import, post_org_keys, bulk_public_keys, + deactivate_organization_user, + bulk_deactivate_organization_user, + activate_organization_user, + bulk_activate_organization_user ] } @@ -107,7 +111,7 @@ async fn create_organization(headers: Headers, data: JsonUpcase, conn: if !CONFIG.is_org_creation_allowed(&headers.user.email) { err!("User not allowed to create organizations") } - if OrgPolicy::is_applicable_to_user(&headers.user.uuid, OrgPolicyType::SingleOrg, &conn).await { + if OrgPolicy::is_applicable_to_user(&headers.user.uuid, OrgPolicyType::SingleOrg, None, &conn).await { err!( "You may not create an organization. You belong to an organization which has a policy that prohibits you from being a member of any other organization." ) @@ -172,13 +176,10 @@ async fn leave_organization(org_id: String, headers: Headers, conn: DbConn) -> E match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn).await { None => err!("User not part of organization"), Some(user_org) => { - if user_org.atype == UserOrgType::Owner { - let num_owners = - UserOrganization::find_by_org_and_type(&org_id, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { - err!("The last owner can't leave") - } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &conn).await <= 1 + { + err!("The last owner can't leave") } user_org.delete(&conn).await @@ -749,17 +750,16 @@ struct AcceptData { Token: String, } -#[post("/organizations/<_org_id>/users/<_org_user_id>/accept", data = "")] +#[post("/organizations//users/<_org_user_id>/accept", data = "")] async fn accept_invite( - _org_id: String, + org_id: String, _org_user_id: String, data: JsonUpcase, conn: DbConn, ) -> EmptyResult { // The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead let data: AcceptData = data.into_inner().data; - let token = &data.Token; - let claims = decode_invite(token)?; + let claims = decode_invite(&data.Token)?; match User::find_by_mail(&claims.email, &conn).await { Some(_) => { @@ -775,46 +775,20 @@ async fn accept_invite( err!("User already accepted the invitation") } - let user_twofactor_disabled = TwoFactor::find_by_user(&user_org.user_uuid, &conn).await.is_empty(); - - let policy = OrgPolicyType::TwoFactorAuthentication as i32; - let org_twofactor_policy_enabled = - match OrgPolicy::find_by_org_and_type(&user_org.org_uuid, policy, &conn).await { - Some(p) => p.enabled, - None => false, - }; - - if org_twofactor_policy_enabled && user_twofactor_disabled { - err!("You cannot join this organization until you enable two-step login on your user account.") - } - - // Enforce Single Organization Policy of organization user is trying to join - let single_org_policy_enabled = - match OrgPolicy::find_by_org_and_type(&user_org.org_uuid, OrgPolicyType::SingleOrg as i32, &conn) - .await - { - Some(p) => p.enabled, - None => false, - }; - if single_org_policy_enabled && user_org.atype < UserOrgType::Admin { - let is_member_of_another_org = UserOrganization::find_any_state_by_user(&user_org.user_uuid, &conn) - .await - .into_iter() - .filter(|uo| uo.org_uuid != user_org.org_uuid) - .count() - > 1; - if is_member_of_another_org { - err!("You may not join this organization until you leave or remove all other organizations.") + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_org.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_org.user_uuid, &org_id, false, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot join this organization until you enable two-step login on your user account"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot join this organization because you are a member of an organization which forbids it"); + } } } - // Enforce Single Organization Policy of other organizations user is a member of - if OrgPolicy::is_applicable_to_user(&user_org.user_uuid, OrgPolicyType::SingleOrg, &conn).await { - err!( - "You cannot join this organization because you are a member of an organization which forbids it" - ) - } - user_org.status = UserOrgStatus::Accepted as i32; user_org.save(&conn).await?; } @@ -918,6 +892,20 @@ async fn _confirm_invite( err!("User in invalid state") } + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_to_confirm.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_confirm.user_uuid, org_id, true, conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot confirm this user because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot confirm this user because it is a member of an organization which forbids it"); + } + } + } + user_to_confirm.status = UserOrgStatus::Confirmed as i32; user_to_confirm.akey = key.to_string(); @@ -997,14 +985,26 @@ async fn edit_user( } if user_to_edit.atype == UserOrgType::Owner && new_type != UserOrgType::Owner { - // Removing owner permmission, check that there are at least another owner - let num_owners = UserOrganization::find_by_org_and_type(&org_id, UserOrgType::Owner as i32, &conn).await.len(); - - if num_owners <= 1 { + // Removing owner permmission, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(&org_id, UserOrgType::Owner, &conn).await <= 1 { err!("Can't delete the last owner") } } + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if new_type < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_to_edit.user_uuid, &org_id, true, &conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot modify this user to this type because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot modify this user to this type because it is a member of an organization which forbids it"); + } + } + } + user_to_edit.access_all = data.AccessAll; user_to_edit.atype = new_type as i32; @@ -1083,10 +1083,8 @@ async fn _delete_user(org_id: &str, org_user_id: &str, headers: &AdminHeaders, c } if user_to_delete.atype == UserOrgType::Owner { - // Removing owner, check that there are at least another owner - let num_owners = UserOrganization::find_by_org_and_type(org_id, UserOrgType::Owner as i32, conn).await.len(); - - if num_owners <= 1 { + // Removing owner, check that there is at least one other confirmed owner + if UserOrganization::count_confirmed_by_org_and_type(org_id, UserOrgType::Owner, conn).await <= 1 { err!("Can't delete the last owner") } } @@ -1255,7 +1253,7 @@ async fn get_policy(org_id: String, pol_type: i32, _headers: AdminHeaders, conn: None => err!("Invalid or unsupported policy type"), }; - let policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn).await { + let policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await { Some(p) => p, None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), }; @@ -1283,15 +1281,16 @@ async fn put_policy( let pol_type_enum = match OrgPolicyType::from_i32(pol_type) { Some(pt) => pt, - None => err!("Invalid policy type"), + None => err!("Invalid or unsupported policy type"), }; - // If enabling the TwoFactorAuthentication policy, remove this org's members that do have 2FA + // When enabling the TwoFactorAuthentication policy, remove this org's members that do have 2FA if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled { for member in UserOrganization::find_by_org(&org_id, &conn).await.into_iter() { let user_twofactor_disabled = TwoFactor::find_by_user(&member.user_uuid, &conn).await.is_empty(); // Policy only applies to non-Owner/non-Admin members who have accepted joining the org + // Invited users still need to accept the invite and will get an error when they try to accept the invite. if user_twofactor_disabled && member.atype < UserOrgType::Admin && member.status != UserOrgStatus::Invited as i32 @@ -1307,33 +1306,29 @@ async fn put_policy( } } - // If enabling the SingleOrg policy, remove this org's members that are members of other orgs + // When enabling the SingleOrg policy, remove this org's members that are members of other orgs if pol_type_enum == OrgPolicyType::SingleOrg && data.enabled { for member in UserOrganization::find_by_org(&org_id, &conn).await.into_iter() { // Policy only applies to non-Owner/non-Admin members who have accepted joining the org - if member.atype < UserOrgType::Admin && member.status != UserOrgStatus::Invited as i32 { - let is_member_of_another_org = UserOrganization::find_any_state_by_user(&member.user_uuid, &conn) - .await - .into_iter() - // Other UserOrganization's where they have accepted being a member of - .filter(|uo| uo.uuid != member.uuid && uo.status != UserOrgStatus::Invited as i32) - .count() - > 1; - - if is_member_of_another_org { - if CONFIG.mail_enabled() { - let org = Organization::find_by_uuid(&member.org_uuid, &conn).await.unwrap(); - let user = User::find_by_uuid(&member.user_uuid, &conn).await.unwrap(); - - mail::send_single_org_removed_from_org(&user.email, &org.name).await?; - } - member.delete(&conn).await?; + // Exclude invited and revoked users when checking for this policy. + // Those users will not be allowed to accept or be activated because of the policy checks done there. + // We check if the count is larger then 1, because it includes this organization also. + if member.atype < UserOrgType::Admin + && member.status != UserOrgStatus::Invited as i32 + && UserOrganization::count_accepted_and_confirmed_by_user(&member.user_uuid, &conn).await > 1 + { + if CONFIG.mail_enabled() { + let org = Organization::find_by_uuid(&member.org_uuid, &conn).await.unwrap(); + let user = User::find_by_uuid(&member.user_uuid, &conn).await.unwrap(); + + mail::send_single_org_removed_from_org(&user.email, &org.name).await?; } + member.delete(&conn).await?; } } } - let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn).await { + let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type_enum, &conn).await { Some(p) => p, None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), }; @@ -1473,7 +1468,7 @@ async fn import(org_id: String, data: JsonUpcase, headers: Header // If this flag is enabled, any user that isn't provided in the Users list will be removed (by default they will be kept unless they have Deleted == true) if data.OverwriteExisting { - for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User as i32, &conn).await { + for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User, &conn).await { if let Some(user_email) = User::find_by_uuid(&user_org.user_uuid, &conn).await.map(|u| u.email) { if !data.Users.iter().any(|u| u.Email == user_email) { user_org.delete(&conn).await?; @@ -1484,3 +1479,166 @@ async fn import(org_id: String, data: JsonUpcase, headers: Header Ok(()) } + +#[put("/organizations//users//deactivate")] +async fn deactivate_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _deactivate_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +#[put("/organizations//users/deactivate", data = "")] +async fn bulk_deactivate_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + let data = data.into_inner().data; + + let mut bulk_response = Vec::new(); + match data["Ids"].as_array() { + Some(org_users) => { + for org_user_id in org_users { + let org_user_id = org_user_id.as_str().unwrap_or_default(); + let err_msg = match _deactivate_organization_user(&org_id, org_user_id, &headers, &conn).await { + Ok(_) => String::from(""), + Err(e) => format!("{:?}", e), + }; + + bulk_response.push(json!( + { + "Object": "OrganizationUserBulkResponseModel", + "Id": org_user_id, + "Error": err_msg + } + )); + } + } + None => error!("No users to revoke"), + } + + Json(json!({ + "Data": bulk_response, + "Object": "list", + "ContinuationToken": null + })) +} + +async fn _deactivate_organization_user( + org_id: &str, + org_user_id: &str, + headers: &AdminHeaders, + conn: &DbConn, +) -> EmptyResult { + match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { + Some(mut user_org) if user_org.status > UserOrgStatus::Revoked as i32 => { + if user_org.user_uuid == headers.user.uuid { + err!("You cannot revoke yourself") + } + if user_org.atype == UserOrgType::Owner && headers.org_user_type != UserOrgType::Owner { + err!("Only owners can revoke other owners") + } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(org_id, UserOrgType::Owner, conn).await <= 1 + { + err!("Organization must have at least one confirmed owner") + } + + user_org.revoke(); + user_org.save(conn).await?; + } + Some(_) => err!("User is already revoked"), + None => err!("User not found in organization"), + } + Ok(()) +} + +#[put("/organizations//users//activate")] +async fn activate_organization_user( + org_id: String, + org_user_id: String, + headers: AdminHeaders, + conn: DbConn, +) -> EmptyResult { + _activate_organization_user(&org_id, &org_user_id, &headers, &conn).await +} + +#[put("/organizations//users/activate", data = "")] +async fn bulk_activate_organization_user( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + conn: DbConn, +) -> Json { + let data = data.into_inner().data; + + let mut bulk_response = Vec::new(); + match data["Ids"].as_array() { + Some(org_users) => { + for org_user_id in org_users { + let org_user_id = org_user_id.as_str().unwrap_or_default(); + let err_msg = match _activate_organization_user(&org_id, org_user_id, &headers, &conn).await { + Ok(_) => String::from(""), + Err(e) => format!("{:?}", e), + }; + + bulk_response.push(json!( + { + "Object": "OrganizationUserBulkResponseModel", + "Id": org_user_id, + "Error": err_msg + } + )); + } + } + None => error!("No users to restore"), + } + + Json(json!({ + "Data": bulk_response, + "Object": "list", + "ContinuationToken": null + })) +} + +async fn _activate_organization_user( + org_id: &str, + org_user_id: &str, + headers: &AdminHeaders, + conn: &DbConn, +) -> EmptyResult { + match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { + Some(mut user_org) if user_org.status < UserOrgStatus::Accepted as i32 => { + if user_org.user_uuid == headers.user.uuid { + err!("You cannot restore yourself") + } + if user_org.atype == UserOrgType::Owner && headers.org_user_type != UserOrgType::Owner { + err!("Only owners can restore other owners") + } + + // This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type + // It returns different error messages per function. + if user_org.atype < UserOrgType::Admin { + match OrgPolicy::is_user_allowed(&user_org.user_uuid, org_id, false, conn).await { + Ok(_) => {} + Err(OrgPolicyErr::TwoFactorMissing) => { + err!("You cannot restore this user because it has no two-step login method activated"); + } + Err(OrgPolicyErr::SingleOrgEnforced) => { + err!("You cannot restore this user because it is a member of an organization which forbids it"); + } + } + } + + user_org.activate(); + user_org.save(conn).await?; + } + Some(_) => err!("User is already active"), + None => err!("User not found in organization"), + } + Ok(()) +} diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs index 4f3291dc..3d150b31 100644 --- a/src/api/core/sends.rs +++ b/src/api/core/sends.rs @@ -70,8 +70,9 @@ struct SendData { /// controls this policy globally. async fn enforce_disable_send_policy(headers: &Headers, conn: &DbConn) -> EmptyResult { let user_uuid = &headers.user.uuid; - let policy_type = OrgPolicyType::DisableSend; - if !CONFIG.sends_allowed() || OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn).await { + if !CONFIG.sends_allowed() + || OrgPolicy::is_applicable_to_user(user_uuid, OrgPolicyType::DisableSend, None, conn).await + { err!("Due to an Enterprise Policy, you are only able to delete an existing Send.") } Ok(()) diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 251511da..eb425d1a 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -19,7 +19,7 @@ pub use self::device::Device; pub use self::emergency_access::{EmergencyAccess, EmergencyAccessStatus, EmergencyAccessType}; pub use self::favorite::Favorite; pub use self::folder::{Folder, FolderCipher}; -pub use self::org_policy::{OrgPolicy, OrgPolicyType}; +pub use self::org_policy::{OrgPolicy, OrgPolicyErr, OrgPolicyType}; pub use self::organization::{Organization, UserOrgStatus, UserOrgType, UserOrganization}; pub use self::send::{Send, SendType}; pub use self::two_factor::{TwoFactor, TwoFactorType}; diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs index 65ec0fd8..02ca8408 100644 --- a/src/db/models/org_policy.rs +++ b/src/db/models/org_policy.rs @@ -6,7 +6,7 @@ use crate::db::DbConn; use crate::error::MapResult; use crate::util::UpCase; -use super::{UserOrgStatus, UserOrgType, UserOrganization}; +use super::{TwoFactor, UserOrgStatus, UserOrgType, UserOrganization}; db_object! { #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -21,25 +21,37 @@ db_object! { } } +// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/PolicyType.cs #[derive(Copy, Clone, Eq, PartialEq, num_derive::FromPrimitive)] pub enum OrgPolicyType { TwoFactorAuthentication = 0, MasterPassword = 1, PasswordGenerator = 2, SingleOrg = 3, - // RequireSso = 4, // Not currently supported. + // RequireSso = 4, // Not supported PersonalOwnership = 5, DisableSend = 6, SendOptions = 7, + // ResetPassword = 8, // Not supported + // MaximumVaultTimeout = 9, // Not supported (Not AGPLv3 Licensed) + // DisablePersonalVaultExport = 10, // Not supported (Not AGPLv3 Licensed) } -// https://github.com/bitwarden/server/blob/master/src/Core/Models/Data/SendOptionsPolicyData.cs +// https://github.com/bitwarden/server/blob/5cbdee137921a19b1f722920f0fa3cd45af2ef0f/src/Core/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs #[derive(Deserialize)] #[allow(non_snake_case)] pub struct SendOptionsPolicyData { pub DisableHideEmail: bool, } +pub type OrgPolicyResult = Result<(), OrgPolicyErr>; + +#[derive(Debug)] +pub enum OrgPolicyErr { + TwoFactorMissing, + SingleOrgEnforced, +} + /// Local methods impl OrgPolicy { pub fn new(org_uuid: String, atype: OrgPolicyType, data: String) -> Self { @@ -160,11 +172,11 @@ impl OrgPolicy { }} } - pub async fn find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Option { + pub async fn find_by_org_and_type(org_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> Option { db_run! { conn: { org_policies::table .filter(org_policies::org_uuid.eq(org_uuid)) - .filter(org_policies::atype.eq(atype)) + .filter(org_policies::atype.eq(policy_type as i32)) .first::(conn) .ok() .from_db() @@ -179,40 +191,128 @@ impl OrgPolicy { }} } + pub async fn find_accepted_and_confirmed_by_user_and_active_policy( + user_uuid: &str, + policy_type: OrgPolicyType, + conn: &DbConn, + ) -> Vec { + db_run! { conn: { + org_policies::table + .inner_join( + users_organizations::table.on( + users_organizations::org_uuid.eq(org_policies::org_uuid) + .and(users_organizations::user_uuid.eq(user_uuid))) + ) + .filter( + users_organizations::status.eq(UserOrgStatus::Accepted as i32) + ) + .or_filter( + users_organizations::status.eq(UserOrgStatus::Confirmed as i32) + ) + .filter(org_policies::atype.eq(policy_type as i32)) + .filter(org_policies::enabled.eq(true)) + .select(org_policies::all_columns) + .load::(conn) + .expect("Error loading org_policy") + .from_db() + }} + } + + pub async fn find_confirmed_by_user_and_active_policy( + user_uuid: &str, + policy_type: OrgPolicyType, + conn: &DbConn, + ) -> Vec { + db_run! { conn: { + org_policies::table + .inner_join( + users_organizations::table.on( + users_organizations::org_uuid.eq(org_policies::org_uuid) + .and(users_organizations::user_uuid.eq(user_uuid))) + ) + .filter( + users_organizations::status.eq(UserOrgStatus::Confirmed as i32) + ) + .filter(org_policies::atype.eq(policy_type as i32)) + .filter(org_policies::enabled.eq(true)) + .select(org_policies::all_columns) + .load::(conn) + .expect("Error loading org_policy") + .from_db() + }} + } + /// Returns true if the user belongs to an org that has enabled the specified policy type, /// and the user is not an owner or admin of that org. This is only useful for checking /// applicability of policy types that have these particular semantics. - pub async fn is_applicable_to_user(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> bool { - // TODO: Should check confirmed and accepted users - for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn).await { - if policy.enabled && policy.has_type(policy_type) { - let org_uuid = &policy.org_uuid; - if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn).await { - if user.atype < UserOrgType::Admin { - return true; - } + pub async fn is_applicable_to_user( + user_uuid: &str, + policy_type: OrgPolicyType, + exclude_org_uuid: Option<&str>, + conn: &DbConn, + ) -> bool { + for policy in + OrgPolicy::find_accepted_and_confirmed_by_user_and_active_policy(user_uuid, policy_type, conn).await + { + // Check if we need to skip this organization. + if exclude_org_uuid.is_some() && exclude_org_uuid.unwrap() == policy.org_uuid { + continue; + } + + if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, &policy.org_uuid, conn).await { + if user.atype < UserOrgType::Admin { + return true; } } } false } + pub async fn is_user_allowed( + user_uuid: &str, + org_uuid: &str, + exclude_current_org: bool, + conn: &DbConn, + ) -> OrgPolicyResult { + // Enforce TwoFactor/TwoStep login + if TwoFactor::find_by_user(user_uuid, conn).await.is_empty() { + match Self::find_by_org_and_type(org_uuid, OrgPolicyType::TwoFactorAuthentication, conn).await { + Some(p) if p.enabled => { + return Err(OrgPolicyErr::TwoFactorMissing); + } + _ => {} + }; + } + + // Enforce Single Organization Policy of other organizations user is a member of + // This check here needs to exclude this current org-id, else an accepted user can not be confirmed. + let exclude_org = if exclude_current_org { + Some(org_uuid) + } else { + None + }; + if Self::is_applicable_to_user(user_uuid, OrgPolicyType::SingleOrg, exclude_org, conn).await { + return Err(OrgPolicyErr::SingleOrgEnforced); + } + + Ok(()) + } + /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` /// option of the `Send Options` policy, and the user is not an owner or admin of that org. pub async fn is_hide_email_disabled(user_uuid: &str, conn: &DbConn) -> bool { - for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn).await { - if policy.enabled && policy.has_type(OrgPolicyType::SendOptions) { - let org_uuid = &policy.org_uuid; - if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn).await { - if user.atype < UserOrgType::Admin { - match serde_json::from_str::>(&policy.data) { - Ok(opts) => { - if opts.data.DisableHideEmail { - return true; - } + for policy in + OrgPolicy::find_confirmed_by_user_and_active_policy(user_uuid, OrgPolicyType::SendOptions, conn).await + { + if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, &policy.org_uuid, conn).await { + if user.atype < UserOrgType::Admin { + match serde_json::from_str::>(&policy.data) { + Ok(opts) => { + if opts.data.DisableHideEmail { + return true; } - _ => error!("Failed to deserialize policy data: {}", policy.data), } + _ => error!("Failed to deserialize SendOptionsPolicyData: {}", policy.data), } } } diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index 3a02867c..eb2de71a 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -31,7 +31,9 @@ db_object! { } } +// https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs pub enum UserOrgStatus { + Revoked = -1, Invited = 0, Accepted = 1, Confirmed = 2, @@ -133,26 +135,29 @@ impl Organization { public_key, } } - + // https://github.com/bitwarden/server/blob/13d1e74d6960cf0d042620b72d85bf583a4236f7/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs pub fn to_json(&self) -> Value { json!({ "Id": self.uuid, "Identifier": null, // not supported by us "Name": self.name, "Seats": 10, // The value doesn't matter, we don't check server-side + // "MaxAutoscaleSeats": null, // The value doesn't matter, we don't check server-side "MaxCollections": 10, // The value doesn't matter, we don't check server-side "MaxStorageGb": 10, // The value doesn't matter, we don't check server-side "Use2fa": true, "UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet) - "UseEvents": false, // not supported by us - "UseGroups": false, // not supported by us + "UseEvents": false, // Not supported + "UseGroups": false, // Not supported "UseTotp": true, "UsePolicies": true, - "UseSso": false, // We do not support SSO + // "UseScim": false, // Not supported (Not AGPLv3 Licensed) + "UseSso": false, // Not supported + // "UseKeyConnector": false, // Not supported "SelfHost": true, - "UseApi": false, // not supported by us + "UseApi": false, // Not supported "HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(), - "ResetPasswordEnrolled": false, // not supported by us + "UseResetPassword": false, // Not supported "BusinessName": null, "BusinessAddress1": null, @@ -170,6 +175,12 @@ impl Organization { } } +// Used to either subtract or add to the current status +// The number 128 should be fine, it is well within the range of an i32 +// The same goes for the database where we only use INTEGER (the same as an i32) +// It should also provide enough room for 100+ types, which i doubt will ever happen. +static ACTIVATE_REVOKE_DIFF: i32 = 128; + impl UserOrganization { pub fn new(user_uuid: String, org_uuid: String) -> Self { Self { @@ -184,6 +195,18 @@ impl UserOrganization { atype: UserOrgType::User as i32, } } + + pub fn activate(&mut self) { + if self.status < UserOrgStatus::Accepted as i32 { + self.status += ACTIVATE_REVOKE_DIFF; + } + } + + pub fn revoke(&mut self) { + if self.status > UserOrgStatus::Revoked as i32 { + self.status -= ACTIVATE_REVOKE_DIFF; + } + } } use crate::db::DbConn; @@ -265,9 +288,10 @@ impl UserOrganization { pub async fn to_json(&self, conn: &DbConn) -> Value { let org = Organization::find_by_uuid(&self.org_uuid, conn).await.unwrap(); + // https://github.com/bitwarden/server/blob/13d1e74d6960cf0d042620b72d85bf583a4236f7/src/Api/Models/Response/ProfileOrganizationResponseModel.cs json!({ "Id": self.org_uuid, - "Identifier": null, // not supported by us + "Identifier": null, // Not supported "Name": org.name, "Seats": 10, // The value doesn't matter, we don't check server-side "MaxCollections": 10, // The value doesn't matter, we don't check server-side @@ -275,44 +299,48 @@ impl UserOrganization { "Use2fa": true, "UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet) - "UseEvents": false, // not supported by us - "UseGroups": false, // not supported by us + "UseEvents": false, // Not supported + "UseGroups": false, // Not supported "UseTotp": true, + // "UseScim": false, // Not supported (Not AGPLv3 Licensed) "UsePolicies": true, - "UseApi": false, // not supported by us + "UseApi": false, // Not supported "SelfHost": true, "HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(), - "ResetPasswordEnrolled": false, // not supported by us - "SsoBound": false, // We do not support SSO - "UseSso": false, // We do not support SSO - // TODO: Add support for Business Portal - // Upstream is moving Policies and SSO management outside of the web-vault to /portal - // For now they still have that code also in the web-vault, but they will remove it at some point. - // https://github.com/bitwarden/server/tree/master/bitwarden_license/src/ - "UseBusinessPortal": false, // Disable BusinessPortal Button + "ResetPasswordEnrolled": false, // Not supported + "SsoBound": false, // Not supported + "UseSso": false, // Not supported "ProviderId": null, "ProviderName": null, + // "KeyConnectorEnabled": false, + // "KeyConnectorUrl": null, // TODO: Add support for Custom User Roles // See: https://bitwarden.com/help/article/user-types-access-control/#custom-role // "Permissions": { - // "AccessBusinessPortal": false, - // "AccessEventLogs": false, + // "AccessEventLogs": false, // Not supported // "AccessImportExport": false, // "AccessReports": false, // "ManageAllCollections": false, + // "CreateNewCollections": false, + // "EditAnyCollection": false, + // "DeleteAnyCollection": false, // "ManageAssignedCollections": false, + // "editAssignedCollections": false, + // "deleteAssignedCollections": false, // "ManageCiphers": false, - // "ManageGroups": false, + // "ManageGroups": false, // Not supported // "ManagePolicies": false, - // "ManageResetPassword": false, - // "ManageSso": false, + // "ManageResetPassword": false, // Not supported + // "ManageSso": false, // Not supported // "ManageUsers": false, + // "ManageScim": false, // Not supported (Not AGPLv3 Licensed) // }, "MaxStorageGb": 10, // The value doesn't matter, we don't check server-side // These are per user + "UserId": self.user_uuid, "Key": self.akey, "Status": self.status, "Type": self.atype, @@ -325,13 +353,21 @@ impl UserOrganization { pub async fn to_json_user_details(&self, conn: &DbConn) -> Value { let user = User::find_by_uuid(&self.user_uuid, conn).await.unwrap(); + // Because BitWarden want the status to be -1 for revoked users we need to catch that here. + // We subtract/add a number so we can restore/activate the user to it's previouse state again. + let status = if self.status < UserOrgStatus::Revoked as i32 { + UserOrgStatus::Revoked as i32 + } else { + self.status + }; + json!({ "Id": self.uuid, "UserId": self.user_uuid, "Name": user.name, "Email": user.email, - "Status": self.status, + "Status": status, "Type": self.atype, "AccessAll": self.access_all, @@ -365,11 +401,19 @@ impl UserOrganization { .collect() }; + // Because BitWarden want the status to be -1 for revoked users we need to catch that here. + // We subtract/add a number so we can restore/activate the user to it's previouse state again. + let status = if self.status < UserOrgStatus::Revoked as i32 { + UserOrgStatus::Revoked as i32 + } else { + self.status + }; + json!({ "Id": self.uuid, "UserId": self.user_uuid, - "Status": self.status, + "Status": status, "Type": self.atype, "AccessAll": self.access_all, "Collections": coll_uuids, @@ -507,6 +551,18 @@ impl UserOrganization { }} } + pub async fn count_accepted_and_confirmed_by_user(user_uuid: &str, conn: &DbConn) -> i64 { + db_run! { conn: { + users_organizations::table + .filter(users_organizations::user_uuid.eq(user_uuid)) + .filter(users_organizations::status.eq(UserOrgStatus::Accepted as i32)) + .or_filter(users_organizations::status.eq(UserOrgStatus::Confirmed as i32)) + .count() + .first::(conn) + .unwrap_or(0) + }} + } + pub async fn find_by_org(org_uuid: &str, conn: &DbConn) -> Vec { db_run! { conn: { users_organizations::table @@ -527,16 +583,28 @@ impl UserOrganization { }} } - pub async fn find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Vec { + pub async fn find_by_org_and_type(org_uuid: &str, atype: UserOrgType, conn: &DbConn) -> Vec { db_run! { conn: { users_organizations::table .filter(users_organizations::org_uuid.eq(org_uuid)) - .filter(users_organizations::atype.eq(atype)) + .filter(users_organizations::atype.eq(atype as i32)) .load::(conn) .expect("Error loading user organizations").from_db() }} } + pub async fn count_confirmed_by_org_and_type(org_uuid: &str, atype: UserOrgType, conn: &DbConn) -> i64 { + db_run! { conn: { + users_organizations::table + .filter(users_organizations::org_uuid.eq(org_uuid)) + .filter(users_organizations::atype.eq(atype as i32)) + .filter(users_organizations::status.eq(UserOrgStatus::Confirmed as i32)) + .count() + .first::(conn) + .unwrap_or(0) + }} + } + pub async fn find_by_user_and_org(user_uuid: &str, org_uuid: &str, conn: &DbConn) -> Option { db_run! { conn: { users_organizations::table diff --git a/src/db/models/user.rs b/src/db/models/user.rs index a8d27060..9e692a3f 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -275,11 +275,11 @@ impl User { pub async fn delete(self, conn: &DbConn) -> EmptyResult { for user_org in UserOrganization::find_confirmed_by_user(&self.uuid, conn).await { - if user_org.atype == UserOrgType::Owner { - let owner_type = UserOrgType::Owner as i32; - if UserOrganization::find_by_org_and_type(&user_org.org_uuid, owner_type, conn).await.len() <= 1 { - err!("Can't delete last owner") - } + if user_org.atype == UserOrgType::Owner + && UserOrganization::count_confirmed_by_org_and_type(&user_org.org_uuid, UserOrgType::Owner, conn).await + <= 1 + { + err!("Can't delete last owner") } } From a62dc102fb7968d821af24028f30cab6935fff71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Sun, 4 Sep 2022 23:18:27 +0200 Subject: [PATCH 04/11] Update web vault to 2022.8.1 and cargo dependencies --- Cargo.lock | 255 ++++++++++++++------------ Cargo.toml | 24 +-- docker/Dockerfile.j2 | 4 +- docker/amd64/Dockerfile | 12 +- docker/amd64/Dockerfile.alpine | 12 +- docker/amd64/Dockerfile.buildx | 12 +- docker/amd64/Dockerfile.buildx.alpine | 12 +- docker/arm64/Dockerfile | 12 +- docker/arm64/Dockerfile.alpine | 12 +- docker/arm64/Dockerfile.buildx | 12 +- docker/arm64/Dockerfile.buildx.alpine | 12 +- docker/armv6/Dockerfile | 12 +- docker/armv6/Dockerfile.alpine | 12 +- docker/armv6/Dockerfile.buildx | 12 +- docker/armv6/Dockerfile.buildx.alpine | 12 +- docker/armv7/Dockerfile | 12 +- docker/armv7/Dockerfile.alpine | 12 +- docker/armv7/Dockerfile.buildx | 12 +- docker/armv7/Dockerfile.buildx.alpine | 12 +- 19 files changed, 246 insertions(+), 229 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2dfb8ce0..8c9f1122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] @@ -76,6 +76,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -228,9 +237,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byteorder" @@ -246,16 +255,16 @@ checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cached" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e6092f8c7ba6e65a46f6f26d7d7997201d3a6f0e69ff5d2440b930d7c0513a" +checksum = "f3e27085975166ffaacbd04527132e1cf5906fa612991f9b4fea08e787da2961" dependencies = [ "async-trait", "async_once", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown 0.12.3", + "hashbrown", "instant", "lazy_static", "once_cell", @@ -295,10 +304,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6127248204b9aba09a362f6c930ef6a78f2c1b2215f8a7b398c06e1083f17af0" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ + "iana-time-zone", "js-sys", "num-integer", "num-traits", @@ -353,7 +363,7 @@ dependencies = [ "rand", "sha2", "subtle", - "time 0.3.12", + "time 0.3.14", "version_check", ] @@ -369,7 +379,7 @@ dependencies = [ "publicsuffix", "serde", "serde_json", - "time 0.3.12", + "time 0.3.14", "url 2.2.2", ] @@ -391,9 +401,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -449,9 +459,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.2" +version = "3.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" +checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" dependencies = [ "nix", "winapi", @@ -494,13 +504,14 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.3.4" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown", "lock_api", + "once_cell", "parking_lot_core", ] @@ -632,9 +643,9 @@ dependencies = [ [[package]] name = "either" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "email-encoding" @@ -648,9 +659,9 @@ dependencies = [ [[package]] name = "email_address" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8684b7c9cb4857dfa1e5b9629ef584ba618c9b93bae60f58cb23f4f271d0468e" +checksum = "b1b32a7a2580c4473f10f66b512c34bdd7d33c5e3473227ca833abdb5afe4809" [[package]] name = "encoding_rs" @@ -758,9 +769,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -773,9 +784,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -783,15 +794,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -800,15 +811,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -817,15 +828,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-timer" @@ -835,9 +846,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-channel", "futures-core", @@ -926,9 +937,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" dependencies = [ "bytes", "fnv", @@ -964,12 +975,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - [[package]] name = "hashbrown" version = "0.12.3" @@ -1053,9 +1058,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1100,6 +1105,20 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "once_cell", + "wasm-bindgen", + "winapi", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1135,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", "serde", ] @@ -1254,9 +1273,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.127" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libmimalloc-sys" @@ -1286,9 +1305,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" dependencies = [ "autocfg", "scopeguard", @@ -1407,9 +1426,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] @@ -1475,10 +1494,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" dependencies = [ + "autocfg", "bitflags", "cfg-if", "libc", @@ -1577,9 +1597,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "opaque-debug" @@ -1676,9 +1696,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pear" @@ -1726,9 +1746,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" +checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" dependencies = [ "thiserror", "ucd-trie", @@ -1736,9 +1756,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13570633aff33c6d22ce47dd566b10a3b9122c2fe9d8e7501895905be532b91" +checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" dependencies = [ "pest", "pest_generator", @@ -1746,9 +1766,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c567e5702efdc79fb18859ea74c3eb36e14c43da7b8c1f098a4ed6514ec7a0" +checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" dependencies = [ "pest", "pest_meta", @@ -1759,9 +1779,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb32be5ee3bbdafa8c7a18b0a8a8d962b66cfa2ceee4037f49267a50ee821fe" +checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" dependencies = [ "once_cell", "pest", @@ -1770,18 +1790,18 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4724fa946c8d1e7cd881bd3dbee63ce32fc1e9e191e35786b3dc1320a3f68131" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ba0c43d7a1b6492b2924a62290cfd83987828af037b0743b38e6ab092aee58" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" dependencies = [ "phf_generator", "phf_shared", @@ -1789,9 +1809,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b450720b6f75cfbfabc195814bd3765f337a4f9a83186f8537297cac12f6705" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" dependencies = [ "phf_shared", "rand", @@ -1799,9 +1819,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd5609d4b2df87167f908a32e1b146ce309c16cf35df76bc11f440b756048e4" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", "uncased", @@ -1888,18 +1908,16 @@ dependencies = [ [[package]] name = "psl-types" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8eda7c62d9ecaafdf8b62374c006de0adf61666ae96a96ba74a37134aa4e470" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "publicsuffix" -version = "2.1.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292972edad6bbecc137ab84c5e36421a4a6c979ea31d3cc73540dd04315b33e1" +checksum = "aeeedb0b429dc462f30ad27ef3de97058b060016f47790c066757be38ef792b4" dependencies = [ - "byteorder", - "hashbrown 0.11.2", "idna 0.2.3", "psl-types", ] @@ -1984,9 +2002,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.4.0" +version = "10.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c49596760fce12ca21550ac21dc5a9617b2ea4b6e0aa7d8dab8ff2824fc2bba" +checksum = "6aa2540135b6a94f74c7bc90ad4b794f822026a894f3d7bcd185c100d13d4ad6" dependencies = [ "bitflags", ] @@ -2186,7 +2204,7 @@ dependencies = [ "serde_json", "state", "tempfile", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-stream", "tokio-util", @@ -2235,7 +2253,7 @@ dependencies = [ "smallvec", "stable-pattern", "state", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-rustls", "uncased", @@ -2332,9 +2350,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2355,9 +2373,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] @@ -2374,9 +2392,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.142" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -2385,9 +2403,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -2419,9 +2437,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" dependencies = [ "cfg-if", "cpufeatures", @@ -2430,9 +2448,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" dependencies = [ "cfg-if", "cpufeatures", @@ -2466,7 +2484,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.12", + "time 0.3.14", ] [[package]] @@ -2492,9 +2510,9 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -2563,7 +2581,7 @@ dependencies = [ "hostname", "libc", "log", - "time 0.3.12", + "time 0.3.14", ] [[package]] @@ -2582,18 +2600,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" dependencies = [ "proc-macro2", "quote", @@ -2630,12 +2648,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.12" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b7cc93fc23ba97fde84f7eea56c55d1ba183f495c6715defdfc7b9cb8c870f" +checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" dependencies = [ "itoa", - "js-sys", "libc", "num_threads", "time-macros", @@ -2664,9 +2681,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42" dependencies = [ "autocfg", "bytes", @@ -2932,18 +2949,18 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ubyte" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a58e29f263341a29bb79e14ad7fda5f63b1c7e48929bad4c685d7876b1d04e94" +checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" dependencies = [ "serde", ] [[package]] name = "ucd-trie" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uncased" @@ -3088,7 +3105,7 @@ dependencies = [ "serde", "serde_json", "syslog", - "time 0.3.12", + "time 0.3.14", "tokio", "tokio-tungstenite", "totp-lite", diff --git a/Cargo.toml b/Cargo.toml index 0ee42851..32838c72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,10 +42,10 @@ tracing = { version = "0.1.36", features = ["log"] } # Needed to have lettre and backtrace = "0.3.66" # Logging panics to logfile instead stderr only # A `dotenv` implementation for Rust -dotenvy = { version = "0.15.1", default-features = false } +dotenvy = { version = "=0.15.1", default-features = false } # Lazy initialization -once_cell = "1.13.0" +once_cell = "1.14.0" # Numerical libraries num-traits = "0.2.15" @@ -57,15 +57,15 @@ rocket = { version = "0.5.0-rc.2", features = ["tls", "json"], default-features # WebSockets libraries tokio-tungstenite = "0.17.2" rmpv = "1.0.0" # MessagePack library -dashmap = "5.3.4" # Concurrent hashmap implementation +dashmap = "5.4.0" # Async futures -futures = "0.3.21" -tokio = { version = "1.20.1", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] } +futures = "0.3.24" +tokio = { version = "1.21.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] } # A generic serialization/deserialization framework -serde = { version = "1.0.142", features = ["derive"] } -serde_json = "1.0.83" +serde = { version = "1.0.144", features = ["derive"] } +serde_json = "1.0.85" # A safe, extensible ORM and Query builder diesel = { version = "1.4.8", features = ["chrono", "r2d2"] } @@ -82,9 +82,9 @@ ring = "0.16.20" uuid = { version = "1.1.2", features = ["v4"] } # Date and time libraries -chrono = { version = "0.4.20", features = ["clock", "serde"], default-features = false } +chrono = { version = "0.4.22", features = ["clock", "serde"], default-features = false } chrono-tz = "0.6.3" -time = "0.3.12" +time = "0.3.14" # Job scheduler job_scheduler_ng = "2.0.1" @@ -122,7 +122,7 @@ html5gum = "0.5.2" regex = { version = "1.6.0", features = ["std", "perf", "unicode-perl"], default-features = false } data-url = "0.1.1" bytes = "1.2.1" -cached = "0.38.0" +cached = "0.39.0" # Used for custom short lived cookie jar during favicon extraction cookie = "0.16.0" @@ -135,11 +135,11 @@ openssl = "0.10.41" pico-args = "0.5.0" # Macro ident concatenation -paste = "1.0.8" +paste = "1.0.9" governor = "0.4.2" # Capture CTRL+C -ctrlc = { version = "3.2.2", features = ["termination"] } +ctrlc = { version = "3.2.3", features = ["termination"] } # Allow overriding the default memory allocator # Mainly used for the musl builds, since the default musl malloc is very slow diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 index ac42cee8..181d03ef 100644 --- a/docker/Dockerfile.j2 +++ b/docker/Dockerfile.j2 @@ -59,8 +59,8 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -{% set vault_version = "v2022.6.2" %} -{% set vault_image_digest = "sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70" %} +{% set vault_version = "v2022.8.1" %} +{% set vault_image_digest = "sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa" %} # The web-vault digest specifies a particular web-vault build on Docker Hub. # Using the digest instead of the tag name provides better security, # as the digest of an image is immutable, whereas a tag name can later diff --git a/docker/amd64/Dockerfile b/docker/amd64/Dockerfile index 5435cc8a..23b488fd 100644 --- a/docker/amd64/Dockerfile +++ b/docker/amd64/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/amd64/Dockerfile.alpine b/docker/amd64/Dockerfile.alpine index 5e092305..56e8ee13 100644 --- a/docker/amd64/Dockerfile.alpine +++ b/docker/amd64/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:x86_64-musl-stable-1.61.0 as build diff --git a/docker/amd64/Dockerfile.buildx b/docker/amd64/Dockerfile.buildx index 1bae9391..643d3edd 100644 --- a/docker/amd64/Dockerfile.buildx +++ b/docker/amd64/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/amd64/Dockerfile.buildx.alpine b/docker/amd64/Dockerfile.buildx.alpine index 15f979b5..91284a5f 100644 --- a/docker/amd64/Dockerfile.buildx.alpine +++ b/docker/amd64/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:x86_64-musl-stable-1.61.0 as build diff --git a/docker/arm64/Dockerfile b/docker/arm64/Dockerfile index 0ab21c5b..0db44ce4 100644 --- a/docker/arm64/Dockerfile +++ b/docker/arm64/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/arm64/Dockerfile.alpine b/docker/arm64/Dockerfile.alpine index cfe8b3b3..321cde5c 100644 --- a/docker/arm64/Dockerfile.alpine +++ b/docker/arm64/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:aarch64-musl-stable-1.61.0 as build diff --git a/docker/arm64/Dockerfile.buildx b/docker/arm64/Dockerfile.buildx index 4c5d0474..274647a5 100644 --- a/docker/arm64/Dockerfile.buildx +++ b/docker/arm64/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/arm64/Dockerfile.buildx.alpine b/docker/arm64/Dockerfile.buildx.alpine index 787280d4..f4db5327 100644 --- a/docker/arm64/Dockerfile.buildx.alpine +++ b/docker/arm64/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:aarch64-musl-stable-1.61.0 as build diff --git a/docker/armv6/Dockerfile b/docker/armv6/Dockerfile index b3bbbf92..d8a4d3bc 100644 --- a/docker/armv6/Dockerfile +++ b/docker/armv6/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv6/Dockerfile.alpine b/docker/armv6/Dockerfile.alpine index e544fea4..ca29c997 100644 --- a/docker/armv6/Dockerfile.alpine +++ b/docker/armv6/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:arm-musleabi-stable-1.61.0 as build diff --git a/docker/armv6/Dockerfile.buildx b/docker/armv6/Dockerfile.buildx index 4fd3aef4..7d34edcc 100644 --- a/docker/armv6/Dockerfile.buildx +++ b/docker/armv6/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv6/Dockerfile.buildx.alpine b/docker/armv6/Dockerfile.buildx.alpine index af4547c1..0218405e 100644 --- a/docker/armv6/Dockerfile.buildx.alpine +++ b/docker/armv6/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:arm-musleabi-stable-1.61.0 as build diff --git a/docker/armv7/Dockerfile b/docker/armv7/Dockerfile index 11a7a70e..a457b6b3 100644 --- a/docker/armv7/Dockerfile +++ b/docker/armv7/Dockerfile @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv7/Dockerfile.alpine b/docker/armv7/Dockerfile.alpine index a64dd871..aa255a35 100644 --- a/docker/armv7/Dockerfile.alpine +++ b/docker/armv7/Dockerfile.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:armv7-musleabihf-stable-1.61.0 as build diff --git a/docker/armv7/Dockerfile.buildx b/docker/armv7/Dockerfile.buildx index c3820a9d..a788d6ea 100644 --- a/docker/armv7/Dockerfile.buildx +++ b/docker/armv7/Dockerfile.buildx @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM rust:1.61-bullseye as build diff --git a/docker/armv7/Dockerfile.buildx.alpine b/docker/armv7/Dockerfile.buildx.alpine index 3be205aa..2f858d95 100644 --- a/docker/armv7/Dockerfile.buildx.alpine +++ b/docker/armv7/Dockerfile.buildx.alpine @@ -16,15 +16,15 @@ # - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # click the tag name to view the digest of the image it currently points to. # - From the command line: -# $ docker pull vaultwarden/web-vault:v2022.6.2 -# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.6.2 -# [vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70] +# $ docker pull vaultwarden/web-vault:v2022.8.1 +# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2022.8.1 +# [vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 -# [vaultwarden/web-vault:v2022.6.2] +# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa +# [vaultwarden/web-vault:v2022.8.1] # -FROM vaultwarden/web-vault@sha256:1dfda41cbddeac5bc59540261fff8defcac37170b5ba02d29c12fa1215498f70 as vault +FROM vaultwarden/web-vault@sha256:7268e7782d6a37f43a5d63614a9b1b14bd54e404e4a3886cc58a0d4d98a70aaa as vault ########################## BUILD IMAGE ########################## FROM blackdex/rust-musl:armv7-musleabihf-stable-1.61.0 as build From 5a05139efe484b37edbc2db6eb618676d26f3723 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Tue, 6 Sep 2022 17:14:16 +0200 Subject: [PATCH 05/11] Change the handling of login errors. Previously FlashMessage was used to provide an error message during login. This PR changes that flow to not use redirect for this, but renders the HTML and responds using the correct status code where needed. This should solve some issues which were reported in the past. Thanks to @RealOrangeOne, for initiating this with a PR. Fixes #2448 Fixes #2712 Closes #2715 Co-authored-by: Jake Howard --- src/api/admin.rs | 46 +- src/api/web.rs | 4 +- src/static/scripts/bootstrap.css | 1223 ++--------------- ...ery-3.6.0.slim.js => jquery-3.6.1.slim.js} | 190 +-- src/static/templates/admin/organizations.hbs | 2 +- src/static/templates/admin/users.hbs | 2 +- 6 files changed, 262 insertions(+), 1205 deletions(-) rename src/static/scripts/{jquery-3.6.0.slim.js => jquery-3.6.1.slim.js} (98%) diff --git a/src/api/admin.rs b/src/api/admin.rs index 867c8ca1..d77842e6 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -7,8 +7,8 @@ use rocket::serde::json::Json; use rocket::{ form::Form, http::{Cookie, CookieJar, SameSite, Status}, - request::{self, FlashMessage, FromRequest, Outcome, Request}, - response::{content::RawHtml as Html, Flash, Redirect}, + request::{self, FromRequest, Outcome, Request}, + response::{content::RawHtml as Html, Redirect}, Route, }; @@ -141,10 +141,24 @@ fn admin_url(referer: Referer) -> String { } } +#[derive(Responder)] +enum AdminResponse { + #[response(status = 200)] + Ok(ApiResult>), + #[response(status = 401)] + Unauthorized(ApiResult>), + #[response(status = 429)] + TooManyRequests(ApiResult>), +} + #[get("/", rank = 2)] -fn admin_login(flash: Option>) -> ApiResult> { +fn admin_login() -> ApiResult> { + render_admin_login(None) +} + +fn render_admin_login(msg: Option<&str>) -> ApiResult> { // If there is an error, show it - let msg = flash.map(|msg| format!("{}: {}", msg.kind(), msg.message())); + let msg = msg.map(|msg| format!("Error: {msg}")); let json = json!({ "page_content": "admin/login", "version": VERSION, @@ -163,22 +177,17 @@ struct LoginForm { } #[post("/", data = "")] -fn post_admin_login( - data: Form, - cookies: &CookieJar<'_>, - ip: ClientIp, - referer: Referer, -) -> Result> { +fn post_admin_login(data: Form, cookies: &CookieJar<'_>, ip: ClientIp) -> AdminResponse { let data = data.into_inner(); if crate::ratelimit::check_limit_admin(&ip.ip).is_err() { - return Err(Flash::error(Redirect::to(admin_url(referer)), "Too many requests, try again later.")); + return AdminResponse::TooManyRequests(render_admin_login(Some("Too many requests, try again later."))); } // If the token is invalid, redirect to login page if !_validate_token(&data.token) { error!("Invalid admin token. IP: {}", ip.ip); - Err(Flash::error(Redirect::to(admin_url(referer)), "Invalid admin token, please try again.")) + AdminResponse::Unauthorized(render_admin_login(Some("Invalid admin token, please try again."))) } else { // If the token received is valid, generate JWT and save it as a cookie let claims = generate_admin_claims(); @@ -192,7 +201,7 @@ fn post_admin_login( .finish(); cookies.add(cookie); - Ok(Redirect::to(admin_url(referer))) + AdminResponse::Ok(render_admin_page()) } } @@ -244,12 +253,16 @@ impl AdminTemplateData { } } -#[get("/", rank = 1)] -fn admin_page(_token: AdminToken) -> ApiResult> { +fn render_admin_page() -> ApiResult> { let text = AdminTemplateData::new().render()?; Ok(Html(text)) } +#[get("/", rank = 1)] +fn admin_page(_token: AdminToken) -> ApiResult> { + render_admin_page() +} + #[derive(Deserialize, Debug)] #[allow(non_snake_case)] struct InviteData { @@ -303,7 +316,7 @@ async fn test_smtp(data: Json, _token: AdminToken) -> EmptyResult { #[get("/logout")] fn logout(cookies: &CookieJar<'_>, referer: Referer) -> Redirect { cookies.remove(Cookie::build(COOKIE_NAME, "").path(admin_path()).finish()); - Redirect::to(admin_url(referer)) + Redirect::temporary(admin_url(referer)) } #[get("/users")] @@ -509,7 +522,6 @@ use cached::proc_macro::cached; async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> (String, String, String) { // If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway. if has_http_access { - info!("Running get_release_info!!"); ( match get_github_api::("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest") .await diff --git a/src/api/web.rs b/src/api/web.rs index c8ecdb84..c01e782a 100644 --- a/src/api/web.rs +++ b/src/api/web.rs @@ -88,8 +88,8 @@ fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Error> "identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))), "datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))), "datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))), - "jquery-3.6.0.slim.js" => { - Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.0.slim.js"))) + "jquery-3.6.1.slim.js" => { + Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.1.slim.js"))) } _ => err!(format!("Static file not found: {}", filename)), } diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css index ddf519cc..3e4ae582 100644 --- a/src/static/scripts/bootstrap.css +++ b/src/static/scripts/bootstrap.css @@ -1,6 +1,6 @@ @charset "UTF-8"; /*! - * Bootstrap v5.2.0-beta1 (https://getbootstrap.com/) + * Bootstrap v5.2.0 (https://getbootstrap.com/) * Copyright 2011-2022 The Bootstrap Authors * Copyright 2011-2022 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) @@ -68,7 +68,6 @@ --bs-border-radius-xl: 1rem; --bs-border-radius-2xl: 2rem; --bs-border-radius-pill: 50rem; - --bs-heading-color: ; --bs-link-color: #0d6efd; --bs-link-hover-color: #0a58ca; --bs-code-color: #d63384; @@ -113,7 +112,6 @@ h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; - color: var(--bs-heading-color); } h1, .h1 { @@ -313,7 +311,7 @@ table { caption { padding-top: 0.5rem; padding-bottom: 0.5rem; - color: rgba(var(--bs-body-color-rgb), 0.75); + color: #6c757d; text-align: left; } @@ -898,210 +896,166 @@ progress { .col-sm { flex: 1 0 0%; } - .row-cols-sm-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-sm-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-sm-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-sm-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-sm-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-sm-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-sm-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-sm-auto { flex: 0 0 auto; width: auto; } - .col-sm-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-sm-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-sm-3 { flex: 0 0 auto; width: 25%; } - .col-sm-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-sm-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-sm-6 { flex: 0 0 auto; width: 50%; } - .col-sm-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-sm-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-sm-9 { flex: 0 0 auto; width: 75%; } - .col-sm-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-sm-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-sm-12 { flex: 0 0 auto; width: 100%; } - .offset-sm-0 { margin-left: 0; } - .offset-sm-1 { margin-left: 8.33333333%; } - .offset-sm-2 { margin-left: 16.66666667%; } - .offset-sm-3 { margin-left: 25%; } - .offset-sm-4 { margin-left: 33.33333333%; } - .offset-sm-5 { margin-left: 41.66666667%; } - .offset-sm-6 { margin-left: 50%; } - .offset-sm-7 { margin-left: 58.33333333%; } - .offset-sm-8 { margin-left: 66.66666667%; } - .offset-sm-9 { margin-left: 75%; } - .offset-sm-10 { margin-left: 83.33333333%; } - .offset-sm-11 { margin-left: 91.66666667%; } - .g-sm-0, .gx-sm-0 { --bs-gutter-x: 0; } - .g-sm-0, .gy-sm-0 { --bs-gutter-y: 0; } - .g-sm-1, .gx-sm-1 { --bs-gutter-x: 0.25rem; } - .g-sm-1, .gy-sm-1 { --bs-gutter-y: 0.25rem; } - .g-sm-2, .gx-sm-2 { --bs-gutter-x: 0.5rem; } - .g-sm-2, .gy-sm-2 { --bs-gutter-y: 0.5rem; } - .g-sm-3, .gx-sm-3 { --bs-gutter-x: 1rem; } - .g-sm-3, .gy-sm-3 { --bs-gutter-y: 1rem; } - .g-sm-4, .gx-sm-4 { --bs-gutter-x: 1.5rem; } - .g-sm-4, .gy-sm-4 { --bs-gutter-y: 1.5rem; } - .g-sm-5, .gx-sm-5 { --bs-gutter-x: 3rem; } - .g-sm-5, .gy-sm-5 { --bs-gutter-y: 3rem; @@ -1111,210 +1065,166 @@ progress { .col-md { flex: 1 0 0%; } - .row-cols-md-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-md-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-md-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-md-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-md-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-md-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-md-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-md-auto { flex: 0 0 auto; width: auto; } - .col-md-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-md-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-md-3 { flex: 0 0 auto; width: 25%; } - .col-md-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-md-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-md-6 { flex: 0 0 auto; width: 50%; } - .col-md-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-md-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-md-9 { flex: 0 0 auto; width: 75%; } - .col-md-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-md-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-md-12 { flex: 0 0 auto; width: 100%; } - .offset-md-0 { margin-left: 0; } - .offset-md-1 { margin-left: 8.33333333%; } - .offset-md-2 { margin-left: 16.66666667%; } - .offset-md-3 { margin-left: 25%; } - .offset-md-4 { margin-left: 33.33333333%; } - .offset-md-5 { margin-left: 41.66666667%; } - .offset-md-6 { margin-left: 50%; } - .offset-md-7 { margin-left: 58.33333333%; } - .offset-md-8 { margin-left: 66.66666667%; } - .offset-md-9 { margin-left: 75%; } - .offset-md-10 { margin-left: 83.33333333%; } - .offset-md-11 { margin-left: 91.66666667%; } - .g-md-0, .gx-md-0 { --bs-gutter-x: 0; } - .g-md-0, .gy-md-0 { --bs-gutter-y: 0; } - .g-md-1, .gx-md-1 { --bs-gutter-x: 0.25rem; } - .g-md-1, .gy-md-1 { --bs-gutter-y: 0.25rem; } - .g-md-2, .gx-md-2 { --bs-gutter-x: 0.5rem; } - .g-md-2, .gy-md-2 { --bs-gutter-y: 0.5rem; } - .g-md-3, .gx-md-3 { --bs-gutter-x: 1rem; } - .g-md-3, .gy-md-3 { --bs-gutter-y: 1rem; } - .g-md-4, .gx-md-4 { --bs-gutter-x: 1.5rem; } - .g-md-4, .gy-md-4 { --bs-gutter-y: 1.5rem; } - .g-md-5, .gx-md-5 { --bs-gutter-x: 3rem; } - .g-md-5, .gy-md-5 { --bs-gutter-y: 3rem; @@ -1324,210 +1234,166 @@ progress { .col-lg { flex: 1 0 0%; } - .row-cols-lg-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-lg-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-lg-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-lg-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-lg-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-lg-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-lg-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-lg-auto { flex: 0 0 auto; width: auto; } - .col-lg-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-lg-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-lg-3 { flex: 0 0 auto; width: 25%; } - .col-lg-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-lg-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-lg-6 { flex: 0 0 auto; width: 50%; } - .col-lg-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-lg-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-lg-9 { flex: 0 0 auto; width: 75%; } - .col-lg-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-lg-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-lg-12 { flex: 0 0 auto; width: 100%; } - .offset-lg-0 { margin-left: 0; } - .offset-lg-1 { margin-left: 8.33333333%; } - .offset-lg-2 { margin-left: 16.66666667%; } - .offset-lg-3 { margin-left: 25%; } - .offset-lg-4 { margin-left: 33.33333333%; } - .offset-lg-5 { margin-left: 41.66666667%; } - .offset-lg-6 { margin-left: 50%; } - .offset-lg-7 { margin-left: 58.33333333%; } - .offset-lg-8 { margin-left: 66.66666667%; } - .offset-lg-9 { margin-left: 75%; } - .offset-lg-10 { margin-left: 83.33333333%; } - .offset-lg-11 { margin-left: 91.66666667%; } - .g-lg-0, .gx-lg-0 { --bs-gutter-x: 0; } - .g-lg-0, .gy-lg-0 { --bs-gutter-y: 0; } - .g-lg-1, .gx-lg-1 { --bs-gutter-x: 0.25rem; } - .g-lg-1, .gy-lg-1 { --bs-gutter-y: 0.25rem; } - .g-lg-2, .gx-lg-2 { --bs-gutter-x: 0.5rem; } - .g-lg-2, .gy-lg-2 { --bs-gutter-y: 0.5rem; } - .g-lg-3, .gx-lg-3 { --bs-gutter-x: 1rem; } - .g-lg-3, .gy-lg-3 { --bs-gutter-y: 1rem; } - .g-lg-4, .gx-lg-4 { --bs-gutter-x: 1.5rem; } - .g-lg-4, .gy-lg-4 { --bs-gutter-y: 1.5rem; } - .g-lg-5, .gx-lg-5 { --bs-gutter-x: 3rem; } - .g-lg-5, .gy-lg-5 { --bs-gutter-y: 3rem; @@ -1537,210 +1403,166 @@ progress { .col-xl { flex: 1 0 0%; } - .row-cols-xl-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-xl-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-xl-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-xl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-xl-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-xl-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-xl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-xl-auto { flex: 0 0 auto; width: auto; } - .col-xl-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-xl-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-xl-3 { flex: 0 0 auto; width: 25%; } - .col-xl-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-xl-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-xl-6 { flex: 0 0 auto; width: 50%; } - .col-xl-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-xl-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-xl-9 { flex: 0 0 auto; width: 75%; } - .col-xl-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-xl-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-xl-12 { flex: 0 0 auto; width: 100%; } - .offset-xl-0 { margin-left: 0; } - .offset-xl-1 { margin-left: 8.33333333%; } - .offset-xl-2 { margin-left: 16.66666667%; } - .offset-xl-3 { margin-left: 25%; } - .offset-xl-4 { margin-left: 33.33333333%; } - .offset-xl-5 { margin-left: 41.66666667%; } - .offset-xl-6 { margin-left: 50%; } - .offset-xl-7 { margin-left: 58.33333333%; } - .offset-xl-8 { margin-left: 66.66666667%; } - .offset-xl-9 { margin-left: 75%; } - .offset-xl-10 { margin-left: 83.33333333%; } - .offset-xl-11 { margin-left: 91.66666667%; } - .g-xl-0, .gx-xl-0 { --bs-gutter-x: 0; } - .g-xl-0, .gy-xl-0 { --bs-gutter-y: 0; } - .g-xl-1, .gx-xl-1 { --bs-gutter-x: 0.25rem; } - .g-xl-1, .gy-xl-1 { --bs-gutter-y: 0.25rem; } - .g-xl-2, .gx-xl-2 { --bs-gutter-x: 0.5rem; } - .g-xl-2, .gy-xl-2 { --bs-gutter-y: 0.5rem; } - .g-xl-3, .gx-xl-3 { --bs-gutter-x: 1rem; } - .g-xl-3, .gy-xl-3 { --bs-gutter-y: 1rem; } - .g-xl-4, .gx-xl-4 { --bs-gutter-x: 1.5rem; } - .g-xl-4, .gy-xl-4 { --bs-gutter-y: 1.5rem; } - .g-xl-5, .gx-xl-5 { --bs-gutter-x: 3rem; } - .g-xl-5, .gy-xl-5 { --bs-gutter-y: 3rem; @@ -1750,210 +1572,166 @@ progress { .col-xxl { flex: 1 0 0%; } - .row-cols-xxl-auto > * { flex: 0 0 auto; width: auto; } - .row-cols-xxl-1 > * { flex: 0 0 auto; width: 100%; } - .row-cols-xxl-2 > * { flex: 0 0 auto; width: 50%; } - .row-cols-xxl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } - .row-cols-xxl-4 > * { flex: 0 0 auto; width: 25%; } - .row-cols-xxl-5 > * { flex: 0 0 auto; width: 20%; } - .row-cols-xxl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } - .col-xxl-auto { flex: 0 0 auto; width: auto; } - .col-xxl-1 { flex: 0 0 auto; width: 8.33333333%; } - .col-xxl-2 { flex: 0 0 auto; width: 16.66666667%; } - .col-xxl-3 { flex: 0 0 auto; width: 25%; } - .col-xxl-4 { flex: 0 0 auto; width: 33.33333333%; } - .col-xxl-5 { flex: 0 0 auto; width: 41.66666667%; } - .col-xxl-6 { flex: 0 0 auto; width: 50%; } - .col-xxl-7 { flex: 0 0 auto; width: 58.33333333%; } - .col-xxl-8 { flex: 0 0 auto; width: 66.66666667%; } - .col-xxl-9 { flex: 0 0 auto; width: 75%; } - .col-xxl-10 { flex: 0 0 auto; width: 83.33333333%; } - .col-xxl-11 { flex: 0 0 auto; width: 91.66666667%; } - .col-xxl-12 { flex: 0 0 auto; width: 100%; } - .offset-xxl-0 { margin-left: 0; } - .offset-xxl-1 { margin-left: 8.33333333%; } - .offset-xxl-2 { margin-left: 16.66666667%; } - .offset-xxl-3 { margin-left: 25%; } - .offset-xxl-4 { margin-left: 33.33333333%; } - .offset-xxl-5 { margin-left: 41.66666667%; } - .offset-xxl-6 { margin-left: 50%; } - .offset-xxl-7 { margin-left: 58.33333333%; } - .offset-xxl-8 { margin-left: 66.66666667%; } - .offset-xxl-9 { margin-left: 75%; } - .offset-xxl-10 { margin-left: 83.33333333%; } - .offset-xxl-11 { margin-left: 91.66666667%; } - .g-xxl-0, .gx-xxl-0 { --bs-gutter-x: 0; } - .g-xxl-0, .gy-xxl-0 { --bs-gutter-y: 0; } - .g-xxl-1, .gx-xxl-1 { --bs-gutter-x: 0.25rem; } - .g-xxl-1, .gy-xxl-1 { --bs-gutter-y: 0.25rem; } - .g-xxl-2, .gx-xxl-2 { --bs-gutter-x: 0.5rem; } - .g-xxl-2, .gy-xxl-2 { --bs-gutter-y: 0.5rem; } - .g-xxl-3, .gx-xxl-3 { --bs-gutter-x: 1rem; } - .g-xxl-3, .gy-xxl-3 { --bs-gutter-y: 1rem; } - .g-xxl-4, .gx-xxl-4 { --bs-gutter-x: 1.5rem; } - .g-xxl-4, .gy-xxl-4 { --bs-gutter-y: 1.5rem; } - .g-xxl-5, .gx-xxl-5 { --bs-gutter-x: 3rem; } - .g-xxl-5, .gy-xxl-5 { --bs-gutter-y: 3rem; @@ -2209,7 +1987,7 @@ progress { .form-text { margin-top: 0.25rem; font-size: 0.875em; - color: rgba(var(--bs-body-color-rgb), 0.75); + color: #6c757d; } .form-control { @@ -2258,7 +2036,7 @@ progress { color: #6c757d; opacity: 1; } -.form-control:disabled, .form-control[readonly] { +.form-control:disabled { background-color: #e9ecef; opacity: 1; } @@ -2320,6 +2098,9 @@ progress { border: solid transparent; border-width: 1px 0; } +.form-control-plaintext:focus { + outline: 0; +} .form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { padding-right: 0; padding-left: 0; @@ -2375,20 +2156,25 @@ textarea.form-control-lg { .form-control-color { width: 3rem; - height: auto; + height: calc(1.5em + 0.75rem + 2px); padding: 0.375rem; } .form-control-color:not(:disabled):not([readonly]) { cursor: pointer; } .form-control-color::-moz-color-swatch { - height: 1.5em; + border: 0 !important; border-radius: 0.375rem; } .form-control-color::-webkit-color-swatch { - height: 1.5em; border-radius: 0.375rem; } +.form-control-color.form-control-sm { + height: calc(1.5em + 0.5rem + 2px); +} +.form-control-color.form-control-lg { + height: calc(1.5em + 1rem + 2px); +} .form-select { display: block; @@ -2678,8 +2464,12 @@ textarea.form-control-lg { position: absolute; top: 0; left: 0; + width: 100%; height: 100%; padding: 1rem 0.75rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; pointer-events: none; border: 1px solid transparent; transform-origin: 0 0; @@ -2747,14 +2537,16 @@ textarea.form-control-lg { width: 100%; } .input-group > .form-control, -.input-group > .form-select { +.input-group > .form-select, +.input-group > .form-floating { position: relative; flex: 1 1 auto; width: 1%; min-width: 0; } .input-group > .form-control:focus, -.input-group > .form-select:focus { +.input-group > .form-select:focus, +.input-group > .form-floating:focus-within { z-index: 3; } .input-group .btn { @@ -2803,17 +2595,23 @@ textarea.form-control-lg { padding-right: 3rem; } -.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), -.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) { +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select { border-top-right-radius: 0; border-bottom-right-radius: 0; } -.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu), -.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) { +.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select { border-top-right-radius: 0; border-bottom-right-radius: 0; } -.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { +.input-group > :not(:first-child):not(.dropdown-menu):not(.form-floating):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback), +.input-group > .form-floating:not(:first-child) > .form-control, +.input-group > .form-floating:not(:first-child) > .form-select { margin-left: -1px; border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -3179,12 +2977,12 @@ textarea.form-control-lg { --bs-btn-bg: #f8f9fa; --bs-btn-border-color: #f8f9fa; --bs-btn-hover-color: #000; - --bs-btn-hover-bg: #f9fafb; - --bs-btn-hover-border-color: #f9fafb; + --bs-btn-hover-bg: #d3d4d5; + --bs-btn-hover-border-color: #c6c7c8; --bs-btn-focus-shadow-rgb: 211, 212, 213; --bs-btn-active-color: #000; - --bs-btn-active-bg: #f9fafb; - --bs-btn-active-border-color: #f9fafb; + --bs-btn-active-bg: #c6c7c8; + --bs-btn-active-border-color: #babbbc; --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #000; --bs-btn-disabled-bg: #f8f9fa; @@ -3196,12 +2994,12 @@ textarea.form-control-lg { --bs-btn-bg: #212529; --bs-btn-border-color: #212529; --bs-btn-hover-color: #fff; - --bs-btn-hover-bg: #1c1f23; - --bs-btn-hover-border-color: #1a1e21; + --bs-btn-hover-bg: #424649; + --bs-btn-hover-border-color: #373b3e; --bs-btn-focus-shadow-rgb: 66, 70, 73; --bs-btn-active-color: #fff; - --bs-btn-active-bg: #1a1e21; - --bs-btn-active-border-color: #191c1f; + --bs-btn-active-bg: #4d5154; + --bs-btn-active-border-color: #373b3e; --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #fff; --bs-btn-disabled-bg: #212529; @@ -3221,6 +3019,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #0d6efd; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; --bs-gradient: none; } @@ -3237,6 +3036,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #6c757d; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6c757d; --bs-gradient: none; } @@ -3253,6 +3053,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #198754; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #198754; --bs-gradient: none; } @@ -3269,6 +3070,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #0dcaf0; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; --bs-gradient: none; } @@ -3285,6 +3087,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #ffc107; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #ffc107; --bs-gradient: none; } @@ -3301,6 +3104,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #dc3545; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; --bs-gradient: none; } @@ -3317,6 +3121,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #f8f9fa; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f8f9fa; --bs-gradient: none; } @@ -3333,6 +3138,7 @@ textarea.form-control-lg { --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); --bs-btn-disabled-color: #212529; --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212529; --bs-gradient: none; } @@ -3343,12 +3149,21 @@ textarea.form-control-lg { --bs-btn-border-color: transparent; --bs-btn-hover-color: var(--bs-link-hover-color); --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); --bs-btn-active-border-color: transparent; --bs-btn-disabled-color: #6c757d; --bs-btn-disabled-border-color: transparent; --bs-btn-box-shadow: none; + --bs-btn-focus-shadow-rgb: 49, 132, 253; text-decoration: underline; } +.btn-link:focus { + color: var(--bs-btn-color); +} +.btn-link:hover { + color: var(--bs-btn-hover-color); +} + .btn-lg, .btn-group-lg > .btn { --bs-btn-padding-y: 0.5rem; --bs-btn-padding-x: 1rem; @@ -3497,7 +3312,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-sm-end { --bs-position: end; } @@ -3514,7 +3328,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-md-end { --bs-position: end; } @@ -3531,7 +3344,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-lg-end { --bs-position: end; } @@ -3548,7 +3360,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-xl-end { --bs-position: end; } @@ -3565,7 +3376,6 @@ textarea.form-control-lg { right: auto; left: 0; } - .dropdown-menu-xxl-end { --bs-position: end; } @@ -3997,6 +3807,7 @@ textarea.form-control-lg { .navbar-nav { --bs-nav-link-padding-x: 0; --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; --bs-nav-link-color: var(--bs-navbar-color); --bs-nav-link-hover-color: var(--bs-navbar-hover-color); --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); @@ -4822,7 +4633,7 @@ textarea.form-control-lg { text-align: center; white-space: nowrap; vertical-align: baseline; - border-radius: var(--bs-badge-border-radius, 0); + border-radius: var(--bs-badge-border-radius); } .badge:empty { display: none; @@ -4848,7 +4659,7 @@ textarea.form-control-lg { color: var(--bs-alert-color); background-color: var(--bs-alert-bg); border: var(--bs-alert-border); - border-radius: var(--bs-alert-border-radius, 0); + border-radius: var(--bs-alert-border-radius); } .alert-heading { @@ -5607,13 +5418,11 @@ textarea.form-control-lg { --bs-modal-margin: 1.75rem; --bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } - .modal-dialog { max-width: var(--bs-modal-width); margin-right: auto; margin-left: auto; } - .modal-sm { --bs-modal-width: 300px; } @@ -5848,7 +5657,7 @@ textarea.form-control-lg { color: var(--bs-tooltip-color); text-align: center; background-color: var(--bs-tooltip-bg); - border-radius: var(--bs-tooltip-border-radius, 0); + border-radius: var(--bs-tooltip-border-radius); } .popover { @@ -6326,16 +6135,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 575.98px) { - .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 575.98px) { - .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { - visibility: visible; - } -} @media (max-width: 575.98px) { .offcanvas-sm.offcanvas-start { top: 0; @@ -6375,6 +6174,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { + visibility: visible; + } +} @media (min-width: 576px) { .offcanvas-sm { --bs-offcanvas-height: auto; @@ -6414,16 +6223,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 767.98px) { - .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 767.98px) { - .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { - visibility: visible; - } -} @media (max-width: 767.98px) { .offcanvas-md.offcanvas-start { top: 0; @@ -6463,6 +6262,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { + visibility: visible; + } +} @media (min-width: 768px) { .offcanvas-md { --bs-offcanvas-height: auto; @@ -6502,16 +6311,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 991.98px) { - .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 991.98px) { - .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { - visibility: visible; - } -} @media (max-width: 991.98px) { .offcanvas-lg.offcanvas-start { top: 0; @@ -6551,6 +6350,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { + visibility: visible; + } +} @media (min-width: 992px) { .offcanvas-lg { --bs-offcanvas-height: auto; @@ -6590,16 +6399,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 1199.98px) { - .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 1199.98px) { - .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { - visibility: visible; - } -} @media (max-width: 1199.98px) { .offcanvas-xl.offcanvas-start { top: 0; @@ -6639,6 +6438,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { + visibility: visible; + } +} @media (min-width: 1200px) { .offcanvas-xl { --bs-offcanvas-height: auto; @@ -6678,16 +6487,6 @@ textarea.form-control-lg { transition: none; } } -@media (max-width: 1399.98px) { - .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { - transform: none; - } -} -@media (max-width: 1399.98px) { - .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { - visibility: visible; - } -} @media (max-width: 1399.98px) { .offcanvas-xxl.offcanvas-start { top: 0; @@ -6727,6 +6526,16 @@ textarea.form-control-lg { transform: translateY(100%); } } +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1399.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { + visibility: visible; + } +} @media (min-width: 1400px) { .offcanvas-xxl { --bs-offcanvas-height: auto; @@ -6764,12 +6573,6 @@ textarea.form-control-lg { transition: none; } } -.offcanvas.showing, .offcanvas.show:not(.hiding) { - transform: none; -} -.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { - visibility: visible; -} .offcanvas.offcanvas-start { top: 0; left: 0; @@ -6801,6 +6604,12 @@ textarea.form-control-lg { border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); transform: translateY(100%); } +.offcanvas.showing, .offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { + visibility: visible; +} .offcanvas-backdrop { position: fixed; @@ -7077,7 +6886,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-sm-bottom { position: -webkit-sticky; position: sticky; @@ -7092,7 +6900,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-md-bottom { position: -webkit-sticky; position: sticky; @@ -7107,7 +6914,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-lg-bottom { position: -webkit-sticky; position: sticky; @@ -7122,7 +6928,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-xl-bottom { position: -webkit-sticky; position: sticky; @@ -7137,7 +6942,6 @@ textarea.form-control-lg { top: 0; z-index: 1020; } - .sticky-xxl-bottom { position: -webkit-sticky; position: sticky; @@ -8365,7 +8169,7 @@ textarea.form-control-lg { .text-muted { --bs-text-opacity: 1; - color: rgba(var(--bs-body-color-rgb), 0.75) !important; + color: #6c757d !important; } .text-black-50 { @@ -8577,649 +8381,494 @@ textarea.form-control-lg { .float-sm-start { float: left !important; } - .float-sm-end { float: right !important; } - .float-sm-none { float: none !important; } - .d-sm-inline { display: inline !important; } - .d-sm-inline-block { display: inline-block !important; } - .d-sm-block { display: block !important; } - .d-sm-grid { display: grid !important; } - .d-sm-table { display: table !important; } - .d-sm-table-row { display: table-row !important; } - .d-sm-table-cell { display: table-cell !important; } - .d-sm-flex { display: flex !important; } - .d-sm-inline-flex { display: inline-flex !important; } - .d-sm-none { display: none !important; } - .flex-sm-fill { flex: 1 1 auto !important; } - .flex-sm-row { flex-direction: row !important; } - .flex-sm-column { flex-direction: column !important; } - .flex-sm-row-reverse { flex-direction: row-reverse !important; } - .flex-sm-column-reverse { flex-direction: column-reverse !important; } - .flex-sm-grow-0 { flex-grow: 0 !important; } - .flex-sm-grow-1 { flex-grow: 1 !important; } - .flex-sm-shrink-0 { flex-shrink: 0 !important; } - .flex-sm-shrink-1 { flex-shrink: 1 !important; } - .flex-sm-wrap { flex-wrap: wrap !important; } - .flex-sm-nowrap { flex-wrap: nowrap !important; } - .flex-sm-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-sm-start { justify-content: flex-start !important; } - .justify-content-sm-end { justify-content: flex-end !important; } - .justify-content-sm-center { justify-content: center !important; } - .justify-content-sm-between { justify-content: space-between !important; } - .justify-content-sm-around { justify-content: space-around !important; } - .justify-content-sm-evenly { justify-content: space-evenly !important; } - .align-items-sm-start { align-items: flex-start !important; } - .align-items-sm-end { align-items: flex-end !important; } - .align-items-sm-center { align-items: center !important; } - .align-items-sm-baseline { align-items: baseline !important; } - .align-items-sm-stretch { align-items: stretch !important; } - .align-content-sm-start { align-content: flex-start !important; } - .align-content-sm-end { align-content: flex-end !important; } - .align-content-sm-center { align-content: center !important; } - .align-content-sm-between { align-content: space-between !important; } - .align-content-sm-around { align-content: space-around !important; } - .align-content-sm-stretch { align-content: stretch !important; } - .align-self-sm-auto { align-self: auto !important; } - .align-self-sm-start { align-self: flex-start !important; } - .align-self-sm-end { align-self: flex-end !important; } - .align-self-sm-center { align-self: center !important; } - .align-self-sm-baseline { align-self: baseline !important; } - .align-self-sm-stretch { align-self: stretch !important; } - .order-sm-first { order: -1 !important; } - .order-sm-0 { order: 0 !important; } - .order-sm-1 { order: 1 !important; } - .order-sm-2 { order: 2 !important; } - .order-sm-3 { order: 3 !important; } - .order-sm-4 { order: 4 !important; } - .order-sm-5 { order: 5 !important; } - .order-sm-last { order: 6 !important; } - .m-sm-0 { margin: 0 !important; } - .m-sm-1 { margin: 0.25rem !important; } - .m-sm-2 { margin: 0.5rem !important; } - .m-sm-3 { margin: 1rem !important; } - .m-sm-4 { margin: 1.5rem !important; } - .m-sm-5 { margin: 3rem !important; } - .m-sm-auto { margin: auto !important; } - .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-sm-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-sm-auto { margin-right: auto !important; margin-left: auto !important; } - .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-sm-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-sm-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-sm-0 { margin-top: 0 !important; } - .mt-sm-1 { margin-top: 0.25rem !important; } - .mt-sm-2 { margin-top: 0.5rem !important; } - .mt-sm-3 { margin-top: 1rem !important; } - .mt-sm-4 { margin-top: 1.5rem !important; } - .mt-sm-5 { margin-top: 3rem !important; } - .mt-sm-auto { margin-top: auto !important; } - .me-sm-0 { margin-right: 0 !important; } - .me-sm-1 { margin-right: 0.25rem !important; } - .me-sm-2 { margin-right: 0.5rem !important; } - .me-sm-3 { margin-right: 1rem !important; } - .me-sm-4 { margin-right: 1.5rem !important; } - .me-sm-5 { margin-right: 3rem !important; } - .me-sm-auto { margin-right: auto !important; } - .mb-sm-0 { margin-bottom: 0 !important; } - .mb-sm-1 { margin-bottom: 0.25rem !important; } - .mb-sm-2 { margin-bottom: 0.5rem !important; } - .mb-sm-3 { margin-bottom: 1rem !important; } - .mb-sm-4 { margin-bottom: 1.5rem !important; } - .mb-sm-5 { margin-bottom: 3rem !important; } - .mb-sm-auto { margin-bottom: auto !important; } - .ms-sm-0 { margin-left: 0 !important; } - .ms-sm-1 { margin-left: 0.25rem !important; } - .ms-sm-2 { margin-left: 0.5rem !important; } - .ms-sm-3 { margin-left: 1rem !important; } - .ms-sm-4 { margin-left: 1.5rem !important; } - .ms-sm-5 { margin-left: 3rem !important; } - .ms-sm-auto { margin-left: auto !important; } - .p-sm-0 { padding: 0 !important; } - .p-sm-1 { padding: 0.25rem !important; } - .p-sm-2 { padding: 0.5rem !important; } - .p-sm-3 { padding: 1rem !important; } - .p-sm-4 { padding: 1.5rem !important; } - .p-sm-5 { padding: 3rem !important; } - .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-sm-0 { padding-top: 0 !important; } - .pt-sm-1 { padding-top: 0.25rem !important; } - .pt-sm-2 { padding-top: 0.5rem !important; } - .pt-sm-3 { padding-top: 1rem !important; } - .pt-sm-4 { padding-top: 1.5rem !important; } - .pt-sm-5 { padding-top: 3rem !important; } - .pe-sm-0 { padding-right: 0 !important; } - .pe-sm-1 { padding-right: 0.25rem !important; } - .pe-sm-2 { padding-right: 0.5rem !important; } - .pe-sm-3 { padding-right: 1rem !important; } - .pe-sm-4 { padding-right: 1.5rem !important; } - .pe-sm-5 { padding-right: 3rem !important; } - .pb-sm-0 { padding-bottom: 0 !important; } - .pb-sm-1 { padding-bottom: 0.25rem !important; } - .pb-sm-2 { padding-bottom: 0.5rem !important; } - .pb-sm-3 { padding-bottom: 1rem !important; } - .pb-sm-4 { padding-bottom: 1.5rem !important; } - .pb-sm-5 { padding-bottom: 3rem !important; } - .ps-sm-0 { padding-left: 0 !important; } - .ps-sm-1 { padding-left: 0.25rem !important; } - .ps-sm-2 { padding-left: 0.5rem !important; } - .ps-sm-3 { padding-left: 1rem !important; } - .ps-sm-4 { padding-left: 1.5rem !important; } - .ps-sm-5 { padding-left: 3rem !important; } - .gap-sm-0 { gap: 0 !important; } - .gap-sm-1 { gap: 0.25rem !important; } - .gap-sm-2 { gap: 0.5rem !important; } - .gap-sm-3 { gap: 1rem !important; } - .gap-sm-4 { gap: 1.5rem !important; } - .gap-sm-5 { gap: 3rem !important; } - .text-sm-start { text-align: left !important; } - .text-sm-end { text-align: right !important; } - .text-sm-center { text-align: center !important; } @@ -9228,649 +8877,494 @@ textarea.form-control-lg { .float-md-start { float: left !important; } - .float-md-end { float: right !important; } - .float-md-none { float: none !important; } - .d-md-inline { display: inline !important; } - .d-md-inline-block { display: inline-block !important; } - .d-md-block { display: block !important; } - .d-md-grid { display: grid !important; } - .d-md-table { display: table !important; } - .d-md-table-row { display: table-row !important; } - .d-md-table-cell { display: table-cell !important; } - .d-md-flex { display: flex !important; } - .d-md-inline-flex { display: inline-flex !important; } - .d-md-none { display: none !important; } - .flex-md-fill { flex: 1 1 auto !important; } - .flex-md-row { flex-direction: row !important; } - .flex-md-column { flex-direction: column !important; } - .flex-md-row-reverse { flex-direction: row-reverse !important; } - .flex-md-column-reverse { flex-direction: column-reverse !important; } - .flex-md-grow-0 { flex-grow: 0 !important; } - .flex-md-grow-1 { flex-grow: 1 !important; } - .flex-md-shrink-0 { flex-shrink: 0 !important; } - .flex-md-shrink-1 { flex-shrink: 1 !important; } - .flex-md-wrap { flex-wrap: wrap !important; } - .flex-md-nowrap { flex-wrap: nowrap !important; } - .flex-md-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-md-start { justify-content: flex-start !important; } - .justify-content-md-end { justify-content: flex-end !important; } - .justify-content-md-center { justify-content: center !important; } - .justify-content-md-between { justify-content: space-between !important; } - .justify-content-md-around { justify-content: space-around !important; } - .justify-content-md-evenly { justify-content: space-evenly !important; } - .align-items-md-start { align-items: flex-start !important; } - .align-items-md-end { align-items: flex-end !important; } - .align-items-md-center { align-items: center !important; } - .align-items-md-baseline { align-items: baseline !important; } - .align-items-md-stretch { align-items: stretch !important; } - .align-content-md-start { align-content: flex-start !important; } - .align-content-md-end { align-content: flex-end !important; } - .align-content-md-center { align-content: center !important; } - .align-content-md-between { align-content: space-between !important; } - .align-content-md-around { align-content: space-around !important; } - .align-content-md-stretch { align-content: stretch !important; } - .align-self-md-auto { align-self: auto !important; } - .align-self-md-start { align-self: flex-start !important; } - .align-self-md-end { align-self: flex-end !important; } - .align-self-md-center { align-self: center !important; } - .align-self-md-baseline { align-self: baseline !important; } - .align-self-md-stretch { align-self: stretch !important; } - .order-md-first { order: -1 !important; } - .order-md-0 { order: 0 !important; } - .order-md-1 { order: 1 !important; } - .order-md-2 { order: 2 !important; } - .order-md-3 { order: 3 !important; } - .order-md-4 { order: 4 !important; } - .order-md-5 { order: 5 !important; } - .order-md-last { order: 6 !important; } - .m-md-0 { margin: 0 !important; } - .m-md-1 { margin: 0.25rem !important; } - .m-md-2 { margin: 0.5rem !important; } - .m-md-3 { margin: 1rem !important; } - .m-md-4 { margin: 1.5rem !important; } - .m-md-5 { margin: 3rem !important; } - .m-md-auto { margin: auto !important; } - .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-md-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-md-auto { margin-right: auto !important; margin-left: auto !important; } - .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-md-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-md-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-md-0 { margin-top: 0 !important; } - .mt-md-1 { margin-top: 0.25rem !important; } - .mt-md-2 { margin-top: 0.5rem !important; } - .mt-md-3 { margin-top: 1rem !important; } - .mt-md-4 { margin-top: 1.5rem !important; } - .mt-md-5 { margin-top: 3rem !important; } - .mt-md-auto { margin-top: auto !important; } - .me-md-0 { margin-right: 0 !important; } - .me-md-1 { margin-right: 0.25rem !important; } - .me-md-2 { margin-right: 0.5rem !important; } - .me-md-3 { margin-right: 1rem !important; } - .me-md-4 { margin-right: 1.5rem !important; } - .me-md-5 { margin-right: 3rem !important; } - .me-md-auto { margin-right: auto !important; } - .mb-md-0 { margin-bottom: 0 !important; } - .mb-md-1 { margin-bottom: 0.25rem !important; } - .mb-md-2 { margin-bottom: 0.5rem !important; } - .mb-md-3 { margin-bottom: 1rem !important; } - .mb-md-4 { margin-bottom: 1.5rem !important; } - .mb-md-5 { margin-bottom: 3rem !important; } - .mb-md-auto { margin-bottom: auto !important; } - .ms-md-0 { margin-left: 0 !important; } - .ms-md-1 { margin-left: 0.25rem !important; } - .ms-md-2 { margin-left: 0.5rem !important; } - .ms-md-3 { margin-left: 1rem !important; } - .ms-md-4 { margin-left: 1.5rem !important; } - .ms-md-5 { margin-left: 3rem !important; } - .ms-md-auto { margin-left: auto !important; } - .p-md-0 { padding: 0 !important; } - .p-md-1 { padding: 0.25rem !important; } - .p-md-2 { padding: 0.5rem !important; } - .p-md-3 { padding: 1rem !important; } - .p-md-4 { padding: 1.5rem !important; } - .p-md-5 { padding: 3rem !important; } - .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-md-0 { padding-top: 0 !important; } - .pt-md-1 { padding-top: 0.25rem !important; } - .pt-md-2 { padding-top: 0.5rem !important; } - .pt-md-3 { padding-top: 1rem !important; } - .pt-md-4 { padding-top: 1.5rem !important; } - .pt-md-5 { padding-top: 3rem !important; } - .pe-md-0 { padding-right: 0 !important; } - .pe-md-1 { padding-right: 0.25rem !important; } - .pe-md-2 { padding-right: 0.5rem !important; } - .pe-md-3 { padding-right: 1rem !important; } - .pe-md-4 { padding-right: 1.5rem !important; } - .pe-md-5 { padding-right: 3rem !important; } - .pb-md-0 { padding-bottom: 0 !important; } - .pb-md-1 { padding-bottom: 0.25rem !important; } - .pb-md-2 { padding-bottom: 0.5rem !important; } - .pb-md-3 { padding-bottom: 1rem !important; } - .pb-md-4 { padding-bottom: 1.5rem !important; } - .pb-md-5 { padding-bottom: 3rem !important; } - .ps-md-0 { padding-left: 0 !important; } - .ps-md-1 { padding-left: 0.25rem !important; } - .ps-md-2 { padding-left: 0.5rem !important; } - .ps-md-3 { padding-left: 1rem !important; } - .ps-md-4 { padding-left: 1.5rem !important; } - .ps-md-5 { padding-left: 3rem !important; } - .gap-md-0 { gap: 0 !important; } - .gap-md-1 { gap: 0.25rem !important; } - .gap-md-2 { gap: 0.5rem !important; } - .gap-md-3 { gap: 1rem !important; } - .gap-md-4 { gap: 1.5rem !important; } - .gap-md-5 { gap: 3rem !important; } - .text-md-start { text-align: left !important; } - .text-md-end { text-align: right !important; } - .text-md-center { text-align: center !important; } @@ -9879,649 +9373,494 @@ textarea.form-control-lg { .float-lg-start { float: left !important; } - .float-lg-end { float: right !important; } - .float-lg-none { float: none !important; } - .d-lg-inline { display: inline !important; } - .d-lg-inline-block { display: inline-block !important; } - .d-lg-block { display: block !important; } - .d-lg-grid { display: grid !important; } - .d-lg-table { display: table !important; } - .d-lg-table-row { display: table-row !important; } - .d-lg-table-cell { display: table-cell !important; } - .d-lg-flex { display: flex !important; } - .d-lg-inline-flex { display: inline-flex !important; } - .d-lg-none { display: none !important; } - .flex-lg-fill { flex: 1 1 auto !important; } - .flex-lg-row { flex-direction: row !important; } - .flex-lg-column { flex-direction: column !important; } - .flex-lg-row-reverse { flex-direction: row-reverse !important; } - .flex-lg-column-reverse { flex-direction: column-reverse !important; } - .flex-lg-grow-0 { flex-grow: 0 !important; } - .flex-lg-grow-1 { flex-grow: 1 !important; } - .flex-lg-shrink-0 { flex-shrink: 0 !important; } - .flex-lg-shrink-1 { flex-shrink: 1 !important; } - .flex-lg-wrap { flex-wrap: wrap !important; } - .flex-lg-nowrap { flex-wrap: nowrap !important; } - .flex-lg-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-lg-start { justify-content: flex-start !important; } - .justify-content-lg-end { justify-content: flex-end !important; } - .justify-content-lg-center { justify-content: center !important; } - .justify-content-lg-between { justify-content: space-between !important; } - .justify-content-lg-around { justify-content: space-around !important; } - .justify-content-lg-evenly { justify-content: space-evenly !important; } - .align-items-lg-start { align-items: flex-start !important; } - .align-items-lg-end { align-items: flex-end !important; } - .align-items-lg-center { align-items: center !important; } - .align-items-lg-baseline { align-items: baseline !important; } - .align-items-lg-stretch { align-items: stretch !important; } - .align-content-lg-start { align-content: flex-start !important; } - .align-content-lg-end { align-content: flex-end !important; } - .align-content-lg-center { align-content: center !important; } - .align-content-lg-between { align-content: space-between !important; } - .align-content-lg-around { align-content: space-around !important; } - .align-content-lg-stretch { align-content: stretch !important; } - .align-self-lg-auto { align-self: auto !important; } - .align-self-lg-start { align-self: flex-start !important; } - .align-self-lg-end { align-self: flex-end !important; } - .align-self-lg-center { align-self: center !important; } - .align-self-lg-baseline { align-self: baseline !important; } - .align-self-lg-stretch { align-self: stretch !important; } - .order-lg-first { order: -1 !important; } - .order-lg-0 { order: 0 !important; } - .order-lg-1 { order: 1 !important; } - .order-lg-2 { order: 2 !important; } - .order-lg-3 { order: 3 !important; } - .order-lg-4 { order: 4 !important; } - .order-lg-5 { order: 5 !important; } - .order-lg-last { order: 6 !important; } - .m-lg-0 { margin: 0 !important; } - .m-lg-1 { margin: 0.25rem !important; } - .m-lg-2 { margin: 0.5rem !important; } - .m-lg-3 { margin: 1rem !important; } - .m-lg-4 { margin: 1.5rem !important; } - .m-lg-5 { margin: 3rem !important; } - .m-lg-auto { margin: auto !important; } - .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-lg-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-lg-auto { margin-right: auto !important; margin-left: auto !important; } - .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-lg-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-lg-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-lg-0 { margin-top: 0 !important; } - .mt-lg-1 { margin-top: 0.25rem !important; } - .mt-lg-2 { margin-top: 0.5rem !important; } - .mt-lg-3 { margin-top: 1rem !important; } - .mt-lg-4 { margin-top: 1.5rem !important; } - .mt-lg-5 { margin-top: 3rem !important; } - .mt-lg-auto { margin-top: auto !important; } - .me-lg-0 { margin-right: 0 !important; } - .me-lg-1 { margin-right: 0.25rem !important; } - .me-lg-2 { margin-right: 0.5rem !important; } - .me-lg-3 { margin-right: 1rem !important; } - .me-lg-4 { margin-right: 1.5rem !important; } - .me-lg-5 { margin-right: 3rem !important; } - .me-lg-auto { margin-right: auto !important; } - .mb-lg-0 { margin-bottom: 0 !important; } - .mb-lg-1 { margin-bottom: 0.25rem !important; } - .mb-lg-2 { margin-bottom: 0.5rem !important; } - .mb-lg-3 { margin-bottom: 1rem !important; } - .mb-lg-4 { margin-bottom: 1.5rem !important; } - .mb-lg-5 { margin-bottom: 3rem !important; } - .mb-lg-auto { margin-bottom: auto !important; } - .ms-lg-0 { margin-left: 0 !important; } - .ms-lg-1 { margin-left: 0.25rem !important; } - .ms-lg-2 { margin-left: 0.5rem !important; } - .ms-lg-3 { margin-left: 1rem !important; } - .ms-lg-4 { margin-left: 1.5rem !important; } - .ms-lg-5 { margin-left: 3rem !important; } - .ms-lg-auto { margin-left: auto !important; } - .p-lg-0 { padding: 0 !important; } - .p-lg-1 { padding: 0.25rem !important; } - .p-lg-2 { padding: 0.5rem !important; } - .p-lg-3 { padding: 1rem !important; } - .p-lg-4 { padding: 1.5rem !important; } - .p-lg-5 { padding: 3rem !important; } - .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-lg-0 { padding-top: 0 !important; } - .pt-lg-1 { padding-top: 0.25rem !important; } - .pt-lg-2 { padding-top: 0.5rem !important; } - .pt-lg-3 { padding-top: 1rem !important; } - .pt-lg-4 { padding-top: 1.5rem !important; } - .pt-lg-5 { padding-top: 3rem !important; } - .pe-lg-0 { padding-right: 0 !important; } - .pe-lg-1 { padding-right: 0.25rem !important; } - .pe-lg-2 { padding-right: 0.5rem !important; } - .pe-lg-3 { padding-right: 1rem !important; } - .pe-lg-4 { padding-right: 1.5rem !important; } - .pe-lg-5 { padding-right: 3rem !important; } - .pb-lg-0 { padding-bottom: 0 !important; } - .pb-lg-1 { padding-bottom: 0.25rem !important; } - .pb-lg-2 { padding-bottom: 0.5rem !important; } - .pb-lg-3 { padding-bottom: 1rem !important; } - .pb-lg-4 { padding-bottom: 1.5rem !important; } - .pb-lg-5 { padding-bottom: 3rem !important; } - .ps-lg-0 { padding-left: 0 !important; } - .ps-lg-1 { padding-left: 0.25rem !important; } - .ps-lg-2 { padding-left: 0.5rem !important; } - .ps-lg-3 { padding-left: 1rem !important; } - .ps-lg-4 { padding-left: 1.5rem !important; } - .ps-lg-5 { padding-left: 3rem !important; } - .gap-lg-0 { gap: 0 !important; } - .gap-lg-1 { gap: 0.25rem !important; } - .gap-lg-2 { gap: 0.5rem !important; } - .gap-lg-3 { gap: 1rem !important; } - .gap-lg-4 { gap: 1.5rem !important; } - .gap-lg-5 { gap: 3rem !important; } - .text-lg-start { text-align: left !important; } - .text-lg-end { text-align: right !important; } - .text-lg-center { text-align: center !important; } @@ -10530,649 +9869,494 @@ textarea.form-control-lg { .float-xl-start { float: left !important; } - .float-xl-end { float: right !important; } - .float-xl-none { float: none !important; } - .d-xl-inline { display: inline !important; } - .d-xl-inline-block { display: inline-block !important; } - .d-xl-block { display: block !important; } - .d-xl-grid { display: grid !important; } - .d-xl-table { display: table !important; } - .d-xl-table-row { display: table-row !important; } - .d-xl-table-cell { display: table-cell !important; } - .d-xl-flex { display: flex !important; } - .d-xl-inline-flex { display: inline-flex !important; } - .d-xl-none { display: none !important; } - .flex-xl-fill { flex: 1 1 auto !important; } - .flex-xl-row { flex-direction: row !important; } - .flex-xl-column { flex-direction: column !important; } - .flex-xl-row-reverse { flex-direction: row-reverse !important; } - .flex-xl-column-reverse { flex-direction: column-reverse !important; } - .flex-xl-grow-0 { flex-grow: 0 !important; } - .flex-xl-grow-1 { flex-grow: 1 !important; } - .flex-xl-shrink-0 { flex-shrink: 0 !important; } - .flex-xl-shrink-1 { flex-shrink: 1 !important; } - .flex-xl-wrap { flex-wrap: wrap !important; } - .flex-xl-nowrap { flex-wrap: nowrap !important; } - .flex-xl-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-xl-start { justify-content: flex-start !important; } - .justify-content-xl-end { justify-content: flex-end !important; } - .justify-content-xl-center { justify-content: center !important; } - .justify-content-xl-between { justify-content: space-between !important; } - .justify-content-xl-around { justify-content: space-around !important; } - .justify-content-xl-evenly { justify-content: space-evenly !important; } - .align-items-xl-start { align-items: flex-start !important; } - .align-items-xl-end { align-items: flex-end !important; } - .align-items-xl-center { align-items: center !important; } - .align-items-xl-baseline { align-items: baseline !important; } - .align-items-xl-stretch { align-items: stretch !important; } - .align-content-xl-start { align-content: flex-start !important; } - .align-content-xl-end { align-content: flex-end !important; } - .align-content-xl-center { align-content: center !important; } - .align-content-xl-between { align-content: space-between !important; } - .align-content-xl-around { align-content: space-around !important; } - .align-content-xl-stretch { align-content: stretch !important; } - .align-self-xl-auto { align-self: auto !important; } - .align-self-xl-start { align-self: flex-start !important; } - .align-self-xl-end { align-self: flex-end !important; } - .align-self-xl-center { align-self: center !important; } - .align-self-xl-baseline { align-self: baseline !important; } - .align-self-xl-stretch { align-self: stretch !important; } - .order-xl-first { order: -1 !important; } - .order-xl-0 { order: 0 !important; } - .order-xl-1 { order: 1 !important; } - .order-xl-2 { order: 2 !important; } - .order-xl-3 { order: 3 !important; } - .order-xl-4 { order: 4 !important; } - .order-xl-5 { order: 5 !important; } - .order-xl-last { order: 6 !important; } - .m-xl-0 { margin: 0 !important; } - .m-xl-1 { margin: 0.25rem !important; } - .m-xl-2 { margin: 0.5rem !important; } - .m-xl-3 { margin: 1rem !important; } - .m-xl-4 { margin: 1.5rem !important; } - .m-xl-5 { margin: 3rem !important; } - .m-xl-auto { margin: auto !important; } - .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-xl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-xl-auto { margin-right: auto !important; margin-left: auto !important; } - .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-xl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-xl-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-xl-0 { margin-top: 0 !important; } - .mt-xl-1 { margin-top: 0.25rem !important; } - .mt-xl-2 { margin-top: 0.5rem !important; } - .mt-xl-3 { margin-top: 1rem !important; } - .mt-xl-4 { margin-top: 1.5rem !important; } - .mt-xl-5 { margin-top: 3rem !important; } - .mt-xl-auto { margin-top: auto !important; } - .me-xl-0 { margin-right: 0 !important; } - .me-xl-1 { margin-right: 0.25rem !important; } - .me-xl-2 { margin-right: 0.5rem !important; } - .me-xl-3 { margin-right: 1rem !important; } - .me-xl-4 { margin-right: 1.5rem !important; } - .me-xl-5 { margin-right: 3rem !important; } - .me-xl-auto { margin-right: auto !important; } - .mb-xl-0 { margin-bottom: 0 !important; } - .mb-xl-1 { margin-bottom: 0.25rem !important; } - .mb-xl-2 { margin-bottom: 0.5rem !important; } - .mb-xl-3 { margin-bottom: 1rem !important; } - .mb-xl-4 { margin-bottom: 1.5rem !important; } - .mb-xl-5 { margin-bottom: 3rem !important; } - .mb-xl-auto { margin-bottom: auto !important; } - .ms-xl-0 { margin-left: 0 !important; } - .ms-xl-1 { margin-left: 0.25rem !important; } - .ms-xl-2 { margin-left: 0.5rem !important; } - .ms-xl-3 { margin-left: 1rem !important; } - .ms-xl-4 { margin-left: 1.5rem !important; } - .ms-xl-5 { margin-left: 3rem !important; } - .ms-xl-auto { margin-left: auto !important; } - .p-xl-0 { padding: 0 !important; } - .p-xl-1 { padding: 0.25rem !important; } - .p-xl-2 { padding: 0.5rem !important; } - .p-xl-3 { padding: 1rem !important; } - .p-xl-4 { padding: 1.5rem !important; } - .p-xl-5 { padding: 3rem !important; } - .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-xl-0 { padding-top: 0 !important; } - .pt-xl-1 { padding-top: 0.25rem !important; } - .pt-xl-2 { padding-top: 0.5rem !important; } - .pt-xl-3 { padding-top: 1rem !important; } - .pt-xl-4 { padding-top: 1.5rem !important; } - .pt-xl-5 { padding-top: 3rem !important; } - .pe-xl-0 { padding-right: 0 !important; } - .pe-xl-1 { padding-right: 0.25rem !important; } - .pe-xl-2 { padding-right: 0.5rem !important; } - .pe-xl-3 { padding-right: 1rem !important; } - .pe-xl-4 { padding-right: 1.5rem !important; } - .pe-xl-5 { padding-right: 3rem !important; } - .pb-xl-0 { padding-bottom: 0 !important; } - .pb-xl-1 { padding-bottom: 0.25rem !important; } - .pb-xl-2 { padding-bottom: 0.5rem !important; } - .pb-xl-3 { padding-bottom: 1rem !important; } - .pb-xl-4 { padding-bottom: 1.5rem !important; } - .pb-xl-5 { padding-bottom: 3rem !important; } - .ps-xl-0 { padding-left: 0 !important; } - .ps-xl-1 { padding-left: 0.25rem !important; } - .ps-xl-2 { padding-left: 0.5rem !important; } - .ps-xl-3 { padding-left: 1rem !important; } - .ps-xl-4 { padding-left: 1.5rem !important; } - .ps-xl-5 { padding-left: 3rem !important; } - .gap-xl-0 { gap: 0 !important; } - .gap-xl-1 { gap: 0.25rem !important; } - .gap-xl-2 { gap: 0.5rem !important; } - .gap-xl-3 { gap: 1rem !important; } - .gap-xl-4 { gap: 1.5rem !important; } - .gap-xl-5 { gap: 3rem !important; } - .text-xl-start { text-align: left !important; } - .text-xl-end { text-align: right !important; } - .text-xl-center { text-align: center !important; } @@ -11181,649 +10365,494 @@ textarea.form-control-lg { .float-xxl-start { float: left !important; } - .float-xxl-end { float: right !important; } - .float-xxl-none { float: none !important; } - .d-xxl-inline { display: inline !important; } - .d-xxl-inline-block { display: inline-block !important; } - .d-xxl-block { display: block !important; } - .d-xxl-grid { display: grid !important; } - .d-xxl-table { display: table !important; } - .d-xxl-table-row { display: table-row !important; } - .d-xxl-table-cell { display: table-cell !important; } - .d-xxl-flex { display: flex !important; } - .d-xxl-inline-flex { display: inline-flex !important; } - .d-xxl-none { display: none !important; } - .flex-xxl-fill { flex: 1 1 auto !important; } - .flex-xxl-row { flex-direction: row !important; } - .flex-xxl-column { flex-direction: column !important; } - .flex-xxl-row-reverse { flex-direction: row-reverse !important; } - .flex-xxl-column-reverse { flex-direction: column-reverse !important; } - .flex-xxl-grow-0 { flex-grow: 0 !important; } - .flex-xxl-grow-1 { flex-grow: 1 !important; } - .flex-xxl-shrink-0 { flex-shrink: 0 !important; } - .flex-xxl-shrink-1 { flex-shrink: 1 !important; } - .flex-xxl-wrap { flex-wrap: wrap !important; } - .flex-xxl-nowrap { flex-wrap: nowrap !important; } - .flex-xxl-wrap-reverse { flex-wrap: wrap-reverse !important; } - .justify-content-xxl-start { justify-content: flex-start !important; } - .justify-content-xxl-end { justify-content: flex-end !important; } - .justify-content-xxl-center { justify-content: center !important; } - .justify-content-xxl-between { justify-content: space-between !important; } - .justify-content-xxl-around { justify-content: space-around !important; } - .justify-content-xxl-evenly { justify-content: space-evenly !important; } - .align-items-xxl-start { align-items: flex-start !important; } - .align-items-xxl-end { align-items: flex-end !important; } - .align-items-xxl-center { align-items: center !important; } - .align-items-xxl-baseline { align-items: baseline !important; } - .align-items-xxl-stretch { align-items: stretch !important; } - .align-content-xxl-start { align-content: flex-start !important; } - .align-content-xxl-end { align-content: flex-end !important; } - .align-content-xxl-center { align-content: center !important; } - .align-content-xxl-between { align-content: space-between !important; } - .align-content-xxl-around { align-content: space-around !important; } - .align-content-xxl-stretch { align-content: stretch !important; } - .align-self-xxl-auto { align-self: auto !important; } - .align-self-xxl-start { align-self: flex-start !important; } - .align-self-xxl-end { align-self: flex-end !important; } - .align-self-xxl-center { align-self: center !important; } - .align-self-xxl-baseline { align-self: baseline !important; } - .align-self-xxl-stretch { align-self: stretch !important; } - .order-xxl-first { order: -1 !important; } - .order-xxl-0 { order: 0 !important; } - .order-xxl-1 { order: 1 !important; } - .order-xxl-2 { order: 2 !important; } - .order-xxl-3 { order: 3 !important; } - .order-xxl-4 { order: 4 !important; } - .order-xxl-5 { order: 5 !important; } - .order-xxl-last { order: 6 !important; } - .m-xxl-0 { margin: 0 !important; } - .m-xxl-1 { margin: 0.25rem !important; } - .m-xxl-2 { margin: 0.5rem !important; } - .m-xxl-3 { margin: 1rem !important; } - .m-xxl-4 { margin: 1.5rem !important; } - .m-xxl-5 { margin: 3rem !important; } - .m-xxl-auto { margin: auto !important; } - .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } - .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } - .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } - .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } - .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } - .mx-xxl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } - .mx-xxl-auto { margin-right: auto !important; margin-left: auto !important; } - .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } - .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } - .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } - .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } - .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } - .my-xxl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } - .my-xxl-auto { margin-top: auto !important; margin-bottom: auto !important; } - .mt-xxl-0 { margin-top: 0 !important; } - .mt-xxl-1 { margin-top: 0.25rem !important; } - .mt-xxl-2 { margin-top: 0.5rem !important; } - .mt-xxl-3 { margin-top: 1rem !important; } - .mt-xxl-4 { margin-top: 1.5rem !important; } - .mt-xxl-5 { margin-top: 3rem !important; } - .mt-xxl-auto { margin-top: auto !important; } - .me-xxl-0 { margin-right: 0 !important; } - .me-xxl-1 { margin-right: 0.25rem !important; } - .me-xxl-2 { margin-right: 0.5rem !important; } - .me-xxl-3 { margin-right: 1rem !important; } - .me-xxl-4 { margin-right: 1.5rem !important; } - .me-xxl-5 { margin-right: 3rem !important; } - .me-xxl-auto { margin-right: auto !important; } - .mb-xxl-0 { margin-bottom: 0 !important; } - .mb-xxl-1 { margin-bottom: 0.25rem !important; } - .mb-xxl-2 { margin-bottom: 0.5rem !important; } - .mb-xxl-3 { margin-bottom: 1rem !important; } - .mb-xxl-4 { margin-bottom: 1.5rem !important; } - .mb-xxl-5 { margin-bottom: 3rem !important; } - .mb-xxl-auto { margin-bottom: auto !important; } - .ms-xxl-0 { margin-left: 0 !important; } - .ms-xxl-1 { margin-left: 0.25rem !important; } - .ms-xxl-2 { margin-left: 0.5rem !important; } - .ms-xxl-3 { margin-left: 1rem !important; } - .ms-xxl-4 { margin-left: 1.5rem !important; } - .ms-xxl-5 { margin-left: 3rem !important; } - .ms-xxl-auto { margin-left: auto !important; } - .p-xxl-0 { padding: 0 !important; } - .p-xxl-1 { padding: 0.25rem !important; } - .p-xxl-2 { padding: 0.5rem !important; } - .p-xxl-3 { padding: 1rem !important; } - .p-xxl-4 { padding: 1.5rem !important; } - .p-xxl-5 { padding: 3rem !important; } - .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } - .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } - .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } - .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } - .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } - .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } - .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } - .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } - .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } - .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } - .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } - .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } - .pt-xxl-0 { padding-top: 0 !important; } - .pt-xxl-1 { padding-top: 0.25rem !important; } - .pt-xxl-2 { padding-top: 0.5rem !important; } - .pt-xxl-3 { padding-top: 1rem !important; } - .pt-xxl-4 { padding-top: 1.5rem !important; } - .pt-xxl-5 { padding-top: 3rem !important; } - .pe-xxl-0 { padding-right: 0 !important; } - .pe-xxl-1 { padding-right: 0.25rem !important; } - .pe-xxl-2 { padding-right: 0.5rem !important; } - .pe-xxl-3 { padding-right: 1rem !important; } - .pe-xxl-4 { padding-right: 1.5rem !important; } - .pe-xxl-5 { padding-right: 3rem !important; } - .pb-xxl-0 { padding-bottom: 0 !important; } - .pb-xxl-1 { padding-bottom: 0.25rem !important; } - .pb-xxl-2 { padding-bottom: 0.5rem !important; } - .pb-xxl-3 { padding-bottom: 1rem !important; } - .pb-xxl-4 { padding-bottom: 1.5rem !important; } - .pb-xxl-5 { padding-bottom: 3rem !important; } - .ps-xxl-0 { padding-left: 0 !important; } - .ps-xxl-1 { padding-left: 0.25rem !important; } - .ps-xxl-2 { padding-left: 0.5rem !important; } - .ps-xxl-3 { padding-left: 1rem !important; } - .ps-xxl-4 { padding-left: 1.5rem !important; } - .ps-xxl-5 { padding-left: 3rem !important; } - .gap-xxl-0 { gap: 0 !important; } - .gap-xxl-1 { gap: 0.25rem !important; } - .gap-xxl-2 { gap: 0.5rem !important; } - .gap-xxl-3 { gap: 1rem !important; } - .gap-xxl-4 { gap: 1.5rem !important; } - .gap-xxl-5 { gap: 3rem !important; } - .text-xxl-start { text-align: left !important; } - .text-xxl-end { text-align: right !important; } - .text-xxl-center { text-align: center !important; } @@ -11832,15 +10861,12 @@ textarea.form-control-lg { .fs-1 { font-size: 2.5rem !important; } - .fs-2 { font-size: 2rem !important; } - .fs-3 { font-size: 1.75rem !important; } - .fs-4 { font-size: 1.5rem !important; } @@ -11849,39 +10875,30 @@ textarea.form-control-lg { .d-print-inline { display: inline !important; } - .d-print-inline-block { display: inline-block !important; } - .d-print-block { display: block !important; } - .d-print-grid { display: grid !important; } - .d-print-table { display: table !important; } - .d-print-table-row { display: table-row !important; } - .d-print-table-cell { display: table-cell !important; } - .d-print-flex { display: flex !important; } - .d-print-inline-flex { display: inline-flex !important; } - .d-print-none { display: none !important; } diff --git a/src/static/scripts/jquery-3.6.0.slim.js b/src/static/scripts/jquery-3.6.1.slim.js similarity index 98% rename from src/static/scripts/jquery-3.6.0.slim.js rename to src/static/scripts/jquery-3.6.1.slim.js index 665bf108..91512c95 100644 --- a/src/static/scripts/jquery-3.6.0.slim.js +++ b/src/static/scripts/jquery-3.6.1.slim.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector + * jQuery JavaScript Library v3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2021-03-02T17:08Z + * Date: 2022-08-26T17:52Z */ ( function( global, factory ) { @@ -23,7 +23,7 @@ // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. + // See ticket trac-14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { @@ -151,7 +151,7 @@ function toType( obj ) { var - version = "3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector", + version = "3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -3129,8 +3129,8 @@ jQuery.fn.extend( { var rootjQuery, // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) + // Prioritize #id over to avoid XSS via location.hash (trac-9521) + // Strict HTML recognition (trac-11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, @@ -4087,7 +4087,7 @@ jQuery.extend( { isReady: false, // A counter to track how many items to wait for before - // the ready event fires. See #6781 + // the ready event fires. See trac-6781 readyWait: 1, // Handle when the DOM is ready @@ -4215,7 +4215,7 @@ function fcamelCase( _all, letter ) { // Convert dashed to camelCase; used by the css and data modules // Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) +// Microsoft forgot to hump their vendor prefix (trac-9572) function camelCase( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); } @@ -4251,7 +4251,7 @@ Data.prototype = { value = {}; // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. + // but we should not, see trac-8335. // Always return an empty object. if ( acceptData( owner ) ) { @@ -4490,7 +4490,7 @@ jQuery.fn.extend( { while ( i-- ) { // Support: IE 11 only - // The attrs elements can be null (#14894) + // The attrs elements can be null (trac-14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { @@ -4913,9 +4913,9 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); input = document.createElement( "input" ); // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) + // Check state lost if the name is set (trac-11217) // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) + // `name` and `type` must use .setAttribute for WWA (trac-14901) input.setAttribute( "type", "radio" ); input.setAttribute( "checked", "checked" ); input.setAttribute( "name", "t" ); @@ -4939,7 +4939,7 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); } )(); -// We have to close these tags to support XHTML (#13200) +// We have to close these tags to support XHTML (trac-13200) var wrapMap = { // XHTML parsers do not magically insert elements in the @@ -4965,7 +4965,7 @@ if ( !support.option ) { function getAll( context, tag ) { // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) + // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) var ret; if ( typeof context.getElementsByTagName !== "undefined" ) { @@ -5048,7 +5048,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { // Remember the top-level container tmp = fragment.firstChild; - // Ensure the created nodes are orphaned (#12392) + // Ensure the created nodes are orphaned (trac-12392) tmp.textContent = ""; } } @@ -5469,15 +5469,15 @@ jQuery.event = { for ( ; cur !== this; cur = cur.parentNode || this ) { - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + // Don't check non-elements (trac-13208) + // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { matchedHandlers = []; matchedSelectors = {}; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; - // Don't conflict with Object.prototype properties (#13203) + // Don't conflict with Object.prototype properties (trac-13203) sel = handleObj.selector + " "; if ( matchedSelectors[ sel ] === undefined ) { @@ -5731,7 +5731,7 @@ jQuery.Event = function( src, props ) { // Create target properties // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) + // Target should not be a text node (trac-504, trac-13143) this.target = ( src.target && src.target.nodeType === 3 ) ? src.target.parentNode : src.target; @@ -5854,10 +5854,10 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, - // Suppress native focus or blur as it's already being fired - // in leverageNative. - _default: function() { - return true; + // Suppress native focus or blur if we're currently inside + // a leveraged native-event stack + _default: function( event ) { + return dataPriv.get( event.target, type ); }, delegateType: delegateType @@ -5956,7 +5956,8 @@ var // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, - rcleanScript = /^\s*\s*$/g; + + rcleanScript = /^\s*\s*$/g; // Prefer a tbody over its parent table for containing new rows function manipulationTarget( elem, content ) { @@ -6070,7 +6071,7 @@ function domManip( collection, args, callback, ignored ) { // Use the original fragment for the last item // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). + // being emptied incorrectly in certain situations (trac-8070). for ( ; i < l; i++ ) { node = fragment; @@ -6111,6 +6112,12 @@ function domManip( collection, args, callback, ignored ) { }, doc ); } } else { + + // Unwrap a CDATA section containing script contents. This shouldn't be + // needed as in XML documents they're already not visible when + // inspecting element contents and in HTML documents they have no + // meaning but we're preserving that logic for backwards compatibility. + // This will be removed completely in 4.0. See gh-4904. DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); } } @@ -6393,9 +6400,12 @@ jQuery.each( { } ); var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); +var rcustomProp = /^--/; + + var getStyles = function( elem ) { - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) // IE throws on elements created in popups // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" var view = elem.ownerDocument.defaultView; @@ -6430,6 +6440,15 @@ var swap = function( elem, options, callback ) { var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + ( function() { @@ -6495,7 +6514,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); } // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) + // Style of cloned element affects source element cloned (trac-8908) div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; @@ -6575,6 +6594,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, + isCustomProp = rcustomProp.test( name ), // Support: Firefox 51+ // Retrieving style before computed somehow @@ -6585,11 +6605,22 @@ function curCSS( elem, name, computed ) { computed = computed || getStyles( elem ); // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) + // .css('filter') (IE 9 only, trac-12537) + // .css('--customProperty) (gh-3144) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; + // trim whitespace for custom property (issue gh-4926) + if ( isCustomProp ) { + + // rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED + // as whitespace while CSS does not, but this is not a problem + // because CSS preprocessing replaces them with U+000A LINE FEED + // (which *is* CSS whitespace) + // https://www.w3.org/TR/css-syntax-3/#input-preprocessing + ret = ret.replace( rtrimCSS, "$1" ); + } + if ( ret === "" && !isAttached( elem ) ) { ret = jQuery.style( elem, name ); } @@ -6685,7 +6716,6 @@ var // except "table", "table-cell", or "table-caption" // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", @@ -6921,15 +6951,15 @@ jQuery.extend( { if ( value !== undefined ) { type = typeof value; - // Convert "+=" or "-=" to relative numbers (#7345) + // Convert "+=" or "-=" to relative numbers (trac-7345) if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { value = adjustCSS( elem, name, ret ); - // Fixes bug #9237 + // Fixes bug trac-9237 type = "number"; } - // Make sure that null and NaN values aren't set (#7116) + // Make sure that null and NaN values aren't set (trac-7116) if ( value == null || value !== value ) { return; } @@ -7149,7 +7179,6 @@ jQuery.fn.extend( { // Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ jQuery.fn.delay = function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; @@ -7374,8 +7403,7 @@ jQuery.extend( { // Support: IE <=9 - 11 only // elem.tabIndex doesn't always return the // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) + // Use proper attribute retrieval (trac-12072) var tabindex = jQuery.find.attr( elem, "tabindex" ); if ( tabindex ) { @@ -7479,8 +7507,7 @@ function classesToArray( value ) { jQuery.fn.extend( { addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; + var classNames, cur, curValue, className, i, finalValue; if ( isFunction( value ) ) { return this.each( function( j ) { @@ -7488,36 +7515,35 @@ jQuery.fn.extend( { } ); } - classes = classesToArray( value ); + classNames = classesToArray( value ); - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; + if ( cur.indexOf( " " + className + " " ) < 0 ) { + cur += className + " "; } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); + this.setAttribute( "class", finalValue ); } } - } + } ); } return this; }, removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; + var classNames, cur, curValue, className, i, finalValue; if ( isFunction( value ) ) { return this.each( function( j ) { @@ -7529,45 +7555,42 @@ jQuery.fn.extend( { return this.attr( "class", "" ); } - classes = classesToArray( value ); + classNames = classesToArray( value ); - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); + if ( classNames.length ) { + return this.each( function() { + curValue = getClass( this ); // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); + while ( cur.indexOf( " " + className + " " ) > -1 ) { + cur = cur.replace( " " + className + " ", " " ); } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); + this.setAttribute( "class", finalValue ); } } - } + } ); } return this; }, toggleClass: function( value, stateVal ) { - var type = typeof value, + var classNames, className, i, self, + type = typeof value, isValidValue = type === "string" || Array.isArray( value ); - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - if ( isFunction( value ) ) { return this.each( function( i ) { jQuery( this ).toggleClass( @@ -7577,17 +7600,20 @@ jQuery.fn.extend( { } ); } - return this.each( function() { - var className, i, self, classNames; + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + classNames = classesToArray( value ); + return this.each( function() { if ( isValidValue ) { // Toggle individual class names - i = 0; self = jQuery( this ); - classNames = classesToArray( value ); - while ( ( className = classNames[ i++ ] ) ) { + for ( i = 0; i < classNames.length; i++ ) { + className = classNames[ i ]; // Check each className given, space separated list if ( self.hasClass( className ) ) { @@ -7721,7 +7747,7 @@ jQuery.extend( { val : // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) + // option.text throws exceptions (trac-14686, trac-14858) // Strip and collapse whitespace // https://html.spec.whatwg.org/#strip-and-collapse-whitespace stripAndCollapse( jQuery.text( elem ) ); @@ -7748,7 +7774,7 @@ jQuery.extend( { option = options[ i ]; // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) + // IE8-9 doesn't update selected after form reset (trac-2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup @@ -7891,8 +7917,8 @@ jQuery.extend( jQuery.event, { return; } - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + // Determine event propagation path in advance, per W3C events spec (trac-9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { bubbleType = special.delegateType || type; @@ -7944,7 +7970,7 @@ jQuery.extend( jQuery.event, { acceptData( elem ) ) { // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) + // Don't do default actions on window, that's where global variables be (trac-6170) if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method @@ -8654,7 +8680,9 @@ jQuery.each( // Support: Android <=4.0 only // Make sure we trim BOM and NBSP -var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; +// Require that the "whitespace run" starts from a non-whitespace +// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position. +var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g; // Bind a function to a context, optionally partially applying any // arguments. @@ -8721,7 +8749,7 @@ jQuery.isNumeric = function( obj ) { jQuery.trim = function( text ) { return text == null ? "" : - ( text + "" ).replace( rtrim, "" ); + ( text + "" ).replace( rtrim, "$1" ); }; @@ -8769,8 +8797,8 @@ jQuery.noConflict = function( deep ) { }; // Expose jQuery and $ identifiers, even in AMD -// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) -// and CommonJS for browser emulators (#13566) +// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557) +// and CommonJS for browser emulators (trac-13566) if ( typeof noGlobal === "undefined" ) { window.jQuery = window.$ = jQuery; } diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs index ac3c0f30..71485901 100644 --- a/src/static/templates/admin/organizations.hbs +++ b/src/static/templates/admin/organizations.hbs @@ -49,7 +49,7 @@ - + +