mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-10-29 23:36:48 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edbb86047b | ||
|
|
64c56411f6 | ||
|
|
c3f5477525 | ||
|
|
9c8aa2359f | ||
|
|
8719f86fcf | ||
|
|
fddc8e71be |
No files matched your search
@@ -402,10 +402,12 @@
|
|||||||
## - "cxp-import-mobile": Enable the import via CXP on iOS (Clients >= 2025.9.2)
|
## - "cxp-import-mobile": Enable the import via CXP on iOS (Clients >= 2025.9.2)
|
||||||
## - "cxp-export-mobile": Enable the export via CXP on iOS (Clients >= 2025.9.2)
|
## - "cxp-export-mobile": Enable the export via CXP on iOS (Clients >= 2025.9.2)
|
||||||
## - "pm-30529-webauthn-related-origins":
|
## - "pm-30529-webauthn-related-origins":
|
||||||
|
## - "pm-32009-new-item-types": Enable new item types: Bank Account, Driver's License, and Passport (Clients >= 2026.4.0)
|
||||||
## - "desktop-ui-migration-milestone-1": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
## - "desktop-ui-migration-milestone-1": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
||||||
## - "desktop-ui-migration-milestone-2": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
## - "desktop-ui-migration-milestone-2": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
||||||
## - "desktop-ui-migration-milestone-3": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
## - "desktop-ui-migration-milestone-3": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
||||||
## - "desktop-ui-migration-milestone-4": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
## - "desktop-ui-migration-milestone-4": Special feature flag for desktop UI (Desktop >= 2026.2.0)
|
||||||
|
## - "enable-basic-auth-response": Enable HTTP Basic Auth autofill in the browser extension (Browser >= 2026.9.0)
|
||||||
# EXPERIMENTAL_CLIENT_FEATURE_FLAGS=
|
# EXPERIMENTAL_CLIENT_FEATURE_FLAGS=
|
||||||
|
|
||||||
## Require new device emails. When a user logs in an email is required to be sent.
|
## Require new device emails. When a user logs in an email is required to be sent.
|
||||||
|
|||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE users ADD COLUMN key_id TEXT;
|
||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE users ADD COLUMN key_id TEXT;
|
||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE users ADD COLUMN key_id TEXT;
|
||||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE users ADD COLUMN key_id TEXT;
|
||||||
@@ -21,9 +21,9 @@ use crate::{
|
|||||||
DbConn, DbPool,
|
DbConn, DbPool,
|
||||||
models::{
|
models::{
|
||||||
AuthRequest, AuthRequestId, Cipher, CipherId, Device, DeviceId, DeviceType, DeviceWithAuthRequest,
|
AuthRequest, AuthRequestId, Cipher, CipherId, Device, DeviceId, DeviceType, DeviceWithAuthRequest,
|
||||||
EmergencyAccess, EmergencyAccessId, EventType, Folder, FolderId, Invitation, Membership, MembershipId,
|
EmergencyAccess, EmergencyAccessId, EventType, Folder, FolderId, Invitation, KeyId, Membership,
|
||||||
OrgPolicy, OrgPolicyType, Organization, OrganizationId, Send, SendId, SignatureAlgorithm, User, UserId,
|
MembershipId, OrgPolicy, OrgPolicyType, Organization, OrganizationId, Send, SendId, SignatureAlgorithm,
|
||||||
UserKdfType, UserSignatureKeyPair,
|
User, UserId, UserKdfType, UserSignatureKeyPair,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mail,
|
mail,
|
||||||
@@ -49,6 +49,7 @@ pub fn routes() -> Vec<rocket::Route> {
|
|||||||
post_set_password,
|
post_set_password,
|
||||||
post_kdf,
|
post_kdf,
|
||||||
post_rotatekey,
|
post_rotatekey,
|
||||||
|
post_user_key,
|
||||||
post_sstamp,
|
post_sstamp,
|
||||||
post_email_token,
|
post_email_token,
|
||||||
post_email,
|
post_email,
|
||||||
@@ -1252,6 +1253,23 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, conn: DbConn, nt:
|
|||||||
save_result
|
save_result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct KeyIdData {
|
||||||
|
user_key_id: KeyId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/accounts/key-management/user-key-id", data = "<data>")]
|
||||||
|
async fn post_user_key(data: Json<KeyIdData>, headers: Headers, conn: DbConn) -> EmptyResult {
|
||||||
|
let mut user = headers.user;
|
||||||
|
if user.key_id.is_some() {
|
||||||
|
err_code!("Unexpected data", Status::UnprocessableEntity.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
user.key_id = Some(data.into_inner().user_key_id);
|
||||||
|
user.save(&conn).await
|
||||||
|
}
|
||||||
|
|
||||||
#[post("/accounts/security-stamp", data = "<data>")]
|
#[post("/accounts/security-stamp", data = "<data>")]
|
||||||
async fn post_sstamp(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
async fn post_sstamp(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||||
let data: PasswordOrOtpData = data.into_inner();
|
let data: PasswordOrOtpData = data.into_inner();
|
||||||
|
|||||||
+39
-2
@@ -6,6 +6,7 @@ use rocket::{
|
|||||||
Route,
|
Route,
|
||||||
form::{Form, FromForm},
|
form::{Form, FromForm},
|
||||||
fs::TempFile,
|
fs::TempFile,
|
||||||
|
http::Status,
|
||||||
serde::json::Json,
|
serde::json::Json,
|
||||||
};
|
};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -21,8 +22,8 @@ use crate::{
|
|||||||
DbConn, DbPool,
|
DbConn, DbPool,
|
||||||
models::{
|
models::{
|
||||||
Archive, Attachment, AttachmentId, Cipher, CipherId, Collection, CollectionCipher, CollectionGroup,
|
Archive, Attachment, AttachmentId, Cipher, CipherId, Collection, CollectionCipher, CollectionGroup,
|
||||||
CollectionId, CollectionUser, EventType, Favorite, Folder, FolderCipher, FolderId, Group, Membership,
|
CollectionId, CollectionUser, EventType, Favorite, Folder, FolderCipher, FolderId, Group, KeyId,
|
||||||
MembershipType, OrgPolicy, OrgPolicyType, OrganizationId, RepromptType, Send, UserId,
|
Membership, MembershipType, OrgPolicy, OrgPolicyType, OrganizationId, RepromptType, Send, UserId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
util::{NumberOrString, deser_opt_nonempty_str, save_temp_file},
|
util::{NumberOrString, deser_opt_nonempty_str, save_temp_file},
|
||||||
@@ -161,6 +162,12 @@ async fn sync(data: SyncData, headers: Headers, client_version: Option<ClientVer
|
|||||||
let policies_json: Vec<Value> =
|
let policies_json: Vec<Value> =
|
||||||
OrgPolicy::find_confirmed_by_user(&headers.user.uuid, &conn).await.iter().map(OrgPolicy::to_json).collect();
|
OrgPolicy::find_confirmed_by_user(&headers.user.uuid, &conn).await.iter().map(OrgPolicy::to_json).collect();
|
||||||
|
|
||||||
|
let policies_new_json: Vec<Value> = OrgPolicy::find_accepted_and_confirmed_by_user(&headers.user.uuid, &conn)
|
||||||
|
.await
|
||||||
|
.iter()
|
||||||
|
.map(OrgPolicy::to_json)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let domains_json = if data.exclude_domains {
|
let domains_json = if data.exclude_domains {
|
||||||
Value::Null
|
Value::Null
|
||||||
} else {
|
} else {
|
||||||
@@ -193,11 +200,13 @@ async fn sync(data: SyncData, headers: Headers, client_version: Option<ClientVer
|
|||||||
"folders": folders_json,
|
"folders": folders_json,
|
||||||
"collections": collections_json,
|
"collections": collections_json,
|
||||||
"policies": policies_json,
|
"policies": policies_json,
|
||||||
|
"policiesNew": policies_new_json,
|
||||||
"ciphers": ciphers_json,
|
"ciphers": ciphers_json,
|
||||||
"domains": domains_json,
|
"domains": domains_json,
|
||||||
"sends": sends_json,
|
"sends": sends_json,
|
||||||
"userDecryption": {
|
"userDecryption": {
|
||||||
"masterPasswordUnlock": master_password_unlock,
|
"masterPasswordUnlock": master_password_unlock,
|
||||||
|
"userKeyId": headers.user.key_id,
|
||||||
"v2UpgradeToken": headers.user.v2_upgrade_token_json(),
|
"v2UpgradeToken": headers.user.v2_upgrade_token_json(),
|
||||||
},
|
},
|
||||||
"object": "sync"
|
"object": "sync"
|
||||||
@@ -261,12 +270,19 @@ pub struct CipherData {
|
|||||||
|
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
|
|
||||||
|
pub encrypted_for: UserId, // Added in web-v2025.6.0
|
||||||
|
// Added in web-v2025.8.1, Optional for compat
|
||||||
|
pub encrypted_by_key_id: Option<KeyId>,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Login = 1,
|
Login = 1,
|
||||||
SecureNote = 2,
|
SecureNote = 2,
|
||||||
Card = 3,
|
Card = 3,
|
||||||
Identity = 4,
|
Identity = 4,
|
||||||
SshKey = 5
|
SshKey = 5
|
||||||
|
BankAccount = 6
|
||||||
|
DriversLicense = 7
|
||||||
|
Passport = 8
|
||||||
*/
|
*/
|
||||||
pub r#type: i32,
|
pub r#type: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -279,6 +295,9 @@ pub struct CipherData {
|
|||||||
card: Option<Value>,
|
card: Option<Value>,
|
||||||
identity: Option<Value>,
|
identity: Option<Value>,
|
||||||
ssh_key: Option<Value>,
|
ssh_key: Option<Value>,
|
||||||
|
bank_account: Option<Value>,
|
||||||
|
drivers_license: Option<Value>,
|
||||||
|
passport: Option<Value>,
|
||||||
|
|
||||||
favorite: Option<bool>,
|
favorite: Option<bool>,
|
||||||
reprompt: Option<i32>,
|
reprompt: Option<i32>,
|
||||||
@@ -334,6 +353,10 @@ async fn post_ciphers_create(
|
|||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let mut data: ShareCipherData = data.into_inner();
|
let mut data: ShareCipherData = data.into_inner();
|
||||||
|
|
||||||
|
if data.cipher.encrypted_for != headers.user.uuid {
|
||||||
|
err_code!("Invalid user cipher", Status::UnprocessableEntity.code);
|
||||||
|
}
|
||||||
|
|
||||||
// This check is usually only needed in update_cipher_from_data(), but we
|
// This check is usually only needed in update_cipher_from_data(), but we
|
||||||
// need it here as well to avoid creating an empty cipher in the call to
|
// need it here as well to avoid creating an empty cipher in the call to
|
||||||
// cipher.save() below.
|
// cipher.save() below.
|
||||||
@@ -363,6 +386,17 @@ async fn post_ciphers_create(
|
|||||||
async fn post_ciphers(data: Json<CipherData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
async fn post_ciphers(data: Json<CipherData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||||
let mut data: CipherData = data.into_inner();
|
let mut data: CipherData = data.into_inner();
|
||||||
|
|
||||||
|
if data.encrypted_for != headers.user.uuid {
|
||||||
|
err_code!("Invalid user cipher", Status::UnprocessableEntity.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cipher_key_id) = &data.encrypted_by_key_id
|
||||||
|
&& let Some(user_key_id) = &headers.user.key_id
|
||||||
|
&& cipher_key_id != user_key_id
|
||||||
|
{
|
||||||
|
err_code!("Invalid key cipher", Status::UnprocessableEntity.code);
|
||||||
|
}
|
||||||
|
|
||||||
// The web/browser clients set this field to null as expected, but the
|
// The web/browser clients set this field to null as expected, but the
|
||||||
// mobile clients seem to set the invalid value `0001-01-01T00:00:00`,
|
// mobile clients seem to set the invalid value `0001-01-01T00:00:00`,
|
||||||
// which results in a warning message being logged. This field isn't
|
// which results in a warning message being logged. This field isn't
|
||||||
@@ -511,6 +545,9 @@ pub async fn update_cipher_from_data(
|
|||||||
3 => data.card,
|
3 => data.card,
|
||||||
4 => data.identity,
|
4 => data.identity,
|
||||||
5 => data.ssh_key,
|
5 => data.ssh_key,
|
||||||
|
6 => data.bank_account,
|
||||||
|
7 => data.drivers_license,
|
||||||
|
8 => data.passport,
|
||||||
_ => err!("Invalid type"),
|
_ => err!("Invalid type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -199,6 +199,26 @@ async fn post_events_collect(data: Json<Vec<EventCollection>>, headers: Headers,
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Only the vault notification banner click is accepted from clients. The rest of
|
||||||
|
// the 1500..=1599 range is written server-side and must not be forgeable by a client.
|
||||||
|
t if t == EventType::OrganizationUserNotificationBannerActionClicked as i32 => {
|
||||||
|
if let Some(org_id) = &event.organization_id
|
||||||
|
&& let Some(membership) =
|
||||||
|
Membership::find_confirmed_by_user_and_org(&headers.user.uuid, org_id, &conn).await
|
||||||
|
{
|
||||||
|
log_event_impl(
|
||||||
|
event.r#type,
|
||||||
|
&membership.uuid,
|
||||||
|
org_id,
|
||||||
|
&headers.user.uuid,
|
||||||
|
headers.device.atype,
|
||||||
|
Some(event_date),
|
||||||
|
&headers.ip.ip,
|
||||||
|
&conn,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// The cipher determines the organization the event is logged to, so make sure the
|
// The cipher determines the organization the event is logged to, so make sure the
|
||||||
// user can actually access it instead of trusting the provided cipher uuid.
|
// user can actually access it instead of trusting the provided cipher uuid.
|
||||||
|
|||||||
@@ -1427,6 +1427,7 @@ pub const SUPPORTED_FEATURE_FLAGS: &[&str] = &[
|
|||||||
"pm-5594-safari-account-switching",
|
"pm-5594-safari-account-switching",
|
||||||
"pm-32413-multi-client-password-management",
|
"pm-32413-multi-client-password-management",
|
||||||
// Autofill Team
|
// Autofill Team
|
||||||
|
"enable-basic-auth-response",
|
||||||
"ssh-agent",
|
"ssh-agent",
|
||||||
"ssh-agent-v2",
|
"ssh-agent-v2",
|
||||||
// Key Management Team
|
// Key Management Team
|
||||||
@@ -1441,6 +1442,8 @@ pub const SUPPORTED_FEATURE_FLAGS: &[&str] = &[
|
|||||||
"cxp-export-mobile",
|
"cxp-export-mobile",
|
||||||
// Platform Team
|
// Platform Team
|
||||||
"pm-30529-webauthn-related-origins",
|
"pm-30529-webauthn-related-origins",
|
||||||
|
// Vault Team
|
||||||
|
"pm-32009-new-item-types",
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ pub enum EventType {
|
|||||||
OrganizationUserAdminResetTwoFactor = 1519,
|
OrganizationUserAdminResetTwoFactor = 1519,
|
||||||
// OrganizationUserRevoked_TwoFactorNonCompliance = 1520,
|
// OrganizationUserRevoked_TwoFactorNonCompliance = 1520,
|
||||||
// OrganizationUserRevoked_SingleOrganizationNonCompliance = 1521,
|
// OrganizationUserRevoked_SingleOrganizationNonCompliance = 1521,
|
||||||
// OrganizationUserNotificationBannerActionClicked = 1522,
|
OrganizationUserNotificationBannerActionClicked = 1522,
|
||||||
|
|
||||||
// Organization
|
// Organization
|
||||||
OrganizationUpdated = 1600,
|
OrganizationUpdated = 1600,
|
||||||
|
|||||||
@@ -40,5 +40,5 @@ pub use self::sso_auth::{OIDCAuthenticatedUser, OIDCCodeResponseError, SsoAuth};
|
|||||||
pub use self::two_factor::{TwoFactor, TwoFactorType};
|
pub use self::two_factor::{TwoFactor, TwoFactorType};
|
||||||
pub use self::two_factor_duo_context::TwoFactorDuoContext;
|
pub use self::two_factor_duo_context::TwoFactorDuoContext;
|
||||||
pub use self::two_factor_incomplete::TwoFactorIncomplete;
|
pub use self::two_factor_incomplete::TwoFactorIncomplete;
|
||||||
pub use self::user::{Invitation, SsoUser, User, UserId, UserKdfType, UserStampException};
|
pub use self::user::{Invitation, KeyId, SsoUser, User, UserId, UserKdfType, UserStampException};
|
||||||
pub use self::user_signature_key_pair::{SignatureAlgorithm, UserSignatureKeyPair};
|
pub use self::user_signature_key_pair::{SignatureAlgorithm, UserSignatureKeyPair};
|
||||||
@@ -49,6 +49,7 @@ pub enum OrgPolicyType {
|
|||||||
// AutotypeDefaultSetting = 17, // Not supported yet
|
// AutotypeDefaultSetting = 17, // Not supported yet
|
||||||
// AutoConfirm = 18, // Not supported (not implemented yet)
|
// AutoConfirm = 18, // Not supported (not implemented yet)
|
||||||
// BlockClaimedDomainAccountCreation = 19, // Not supported (Not AGPLv3 Licensed)
|
// BlockClaimedDomainAccountCreation = 19, // Not supported (Not AGPLv3 Licensed)
|
||||||
|
OrganizationUserNotification = 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
||||||
@@ -186,6 +187,26 @@ impl OrgPolicy {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_accepted_and_confirmed_by_user(user_uuid: &UserId, conn: &DbConn) -> Vec<Self> {
|
||||||
|
conn.run(move |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(MembershipStatus::Accepted as i32)
|
||||||
|
.or(users_organizations::status.eq(MembershipStatus::Confirmed as i32)),
|
||||||
|
)
|
||||||
|
.select(org_policies::all_columns)
|
||||||
|
.load::<Self>(conn)
|
||||||
|
.expect("Error loading org_policy")
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_org_and_type(
|
pub async fn find_by_org_and_type(
|
||||||
org_uuid: &OrganizationId,
|
org_uuid: &OrganizationId,
|
||||||
policy_type: OrgPolicyType,
|
policy_type: OrgPolicyType,
|
||||||
|
|||||||
@@ -844,6 +844,21 @@ impl Membership {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_accepted_and_confirmed_by_user(user_uuid: &UserId, conn: &DbConn) -> Vec<Self> {
|
||||||
|
conn.run(move |conn| {
|
||||||
|
users_organizations::table
|
||||||
|
.filter(users_organizations::user_uuid.eq(user_uuid))
|
||||||
|
.filter(
|
||||||
|
users_organizations::status
|
||||||
|
.eq(MembershipStatus::Accepted as i32)
|
||||||
|
.or(users_organizations::status.eq(MembershipStatus::Confirmed as i32)),
|
||||||
|
)
|
||||||
|
.load::<Self>(conn)
|
||||||
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_invited_by_user(user_uuid: &UserId, conn: &DbConn) -> Vec<Self> {
|
pub async fn find_invited_by_user(user_uuid: &UserId, conn: &DbConn) -> Vec<Self> {
|
||||||
conn.run(move |conn| {
|
conn.run(move |conn| {
|
||||||
users_organizations::table
|
users_organizations::table
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ pub struct User {
|
|||||||
|
|
||||||
pub external_id: Option<String>, // Todo: Needs to be removed in the future, this is not used anymore.
|
pub external_id: Option<String>, // Todo: Needs to be removed in the future, this is not used anymore.
|
||||||
|
|
||||||
|
pub key_id: Option<KeyId>,
|
||||||
|
|
||||||
// "v2" account cryptographic state. Either all of these are set (together with a row in
|
// "v2" account cryptographic state. Either all of these are set (together with a row in
|
||||||
// `user_signature_key_pairs`) or none of them are; see `User::is_v2`.
|
// `user_signature_key_pairs`) or none of them are; see `User::is_v2`.
|
||||||
pub signed_public_key: Option<String>,
|
pub signed_public_key: Option<String>,
|
||||||
@@ -165,6 +167,8 @@ impl User {
|
|||||||
|
|
||||||
external_id: None, // Todo: Needs to be removed in the future, this is not used anymore.
|
external_id: None, // Todo: Needs to be removed in the future, this is not used anymore.
|
||||||
|
|
||||||
|
key_id: None,
|
||||||
|
|
||||||
signed_public_key: None,
|
signed_public_key: None,
|
||||||
security_state: None,
|
security_state: None,
|
||||||
security_version: None,
|
security_version: None,
|
||||||
@@ -333,6 +337,11 @@ impl User {
|
|||||||
orgs_json.push(c.to_json(conn).await);
|
orgs_json.push(c.to_json(conn).await);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut orgs_new_json = Vec::new();
|
||||||
|
for c in Membership::find_accepted_and_confirmed_by_user(&self.uuid, conn).await {
|
||||||
|
orgs_new_json.push(c.to_json(conn).await);
|
||||||
|
}
|
||||||
|
|
||||||
let twofactor_enabled = !TwoFactor::find_by_user(&self.uuid, conn).await.is_empty();
|
let twofactor_enabled = !TwoFactor::find_by_user(&self.uuid, conn).await.is_empty();
|
||||||
|
|
||||||
// TODO: Might want to save the status field in the DB
|
// TODO: Might want to save the status field in the DB
|
||||||
@@ -359,6 +368,7 @@ impl User {
|
|||||||
"privateKey": self.private_key,
|
"privateKey": self.private_key,
|
||||||
"securityStamp": self.security_stamp,
|
"securityStamp": self.security_stamp,
|
||||||
"organizations": orgs_json,
|
"organizations": orgs_json,
|
||||||
|
"organizationsNew": orgs_new_json,
|
||||||
"providers": [],
|
"providers": [],
|
||||||
"providerOrganizations": [],
|
"providerOrganizations": [],
|
||||||
"forcePasswordReset": false,
|
"forcePasswordReset": false,
|
||||||
@@ -588,6 +598,26 @@ impl Invitation {
|
|||||||
#[from(forward)]
|
#[from(forward)]
|
||||||
pub struct UserId(String);
|
pub struct UserId(String);
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Debug,
|
||||||
|
DieselNewType,
|
||||||
|
FromForm,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
AsRef,
|
||||||
|
Deref,
|
||||||
|
Display,
|
||||||
|
From,
|
||||||
|
UuidFromParam,
|
||||||
|
)]
|
||||||
|
#[deref(forward)]
|
||||||
|
#[from(forward)]
|
||||||
|
pub struct KeyId(String);
|
||||||
|
|
||||||
impl SsoUser {
|
impl SsoUser {
|
||||||
pub async fn save(&self, conn: &DbConn) -> EmptyResult {
|
pub async fn save(&self, conn: &DbConn) -> EmptyResult {
|
||||||
db_run! { conn:
|
db_run! { conn:
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ table! {
|
|||||||
api_key -> Nullable<Text>,
|
api_key -> Nullable<Text>,
|
||||||
avatar_color -> Nullable<Text>,
|
avatar_color -> Nullable<Text>,
|
||||||
external_id -> Nullable<Text>,
|
external_id -> Nullable<Text>,
|
||||||
|
key_id -> Nullable<Text>,
|
||||||
signed_public_key -> Nullable<Text>,
|
signed_public_key -> Nullable<Text>,
|
||||||
security_state -> Nullable<Text>,
|
security_state -> Nullable<Text>,
|
||||||
security_version -> Nullable<Integer>,
|
security_version -> Nullable<Integer>,
|
||||||
|
|||||||
Reference in new issue
Block a user