@ -22,8 +22,8 @@ use crate::{
models ::{
models ::{
AuthRequest , AuthRequestId , Cipher , CipherId , Device , DeviceId , DeviceType , DeviceWithAuthRequest ,
AuthRequest , AuthRequestId , Cipher , CipherId , Device , DeviceId , DeviceType , DeviceWithAuthRequest ,
EmergencyAccess , EmergencyAccessId , EventType , Folder , FolderId , Invitation , KeyId , Membership ,
EmergencyAccess , EmergencyAccessId , EventType , Folder , FolderId , Invitation , KeyId , Membership ,
MembershipId , OrgPolicy , OrgPolicyType , Organization , OrganizationId , Send , SendId , User , UserId ,
MembershipId , MembershipStatus , OrgPolicy , OrgPolicyType , Organization , OrganizationId , Send , SendId , User ,
UserKdfType ,
UserId , User KdfType ,
} ,
} ,
} ,
} ,
mail ,
mail ,
@ -445,6 +445,12 @@ pub async fn register(data: Json<RegisterData>, conn: DbConn) -> JsonResult {
async fn post_set_password ( data : Json < SetPasswordData > , headers : Headers , conn : DbConn ) -> JsonResult {
async fn post_set_password ( data : Json < SetPasswordData > , headers : Headers , conn : DbConn ) -> JsonResult {
let data : SetPasswordData = data . into_inner ( ) ;
let data : SetPasswordData = data . into_inner ( ) ;
let mut user = headers . user ;
let mut user = headers . user ;
let default_org_id = crate ::sso ::default_organization_id ( ) ? ;
let enroll_in_default_organization = matches ! (
( data . org_identifier . as_deref ( ) , default_org_id . as_ref ( ) ) ,
( Some ( identifier ) , Some ( org_id ) )
if identifier = = crate ::sso ::FAKE_SSO_IDENTIFIER | | identifier = = org_id . as_ref ( )
) ;
if user . private_key . is_some ( ) | | ! user . password_hash . is_empty ( ) {
if user . private_key . is_some ( ) | | ! user . password_hash . is_empty ( ) {
err ! ( "Account already initialized, cannot set password" )
err ! ( "Account already initialized, cannot set password" )
@ -473,6 +479,7 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, conn:
}
}
if let Some ( identifier ) = data . org_identifier
if let Some ( identifier ) = data . org_identifier
& & ! enroll_in_default_organization
& & identifier ! = crate ::sso ::FAKE_SSO_IDENTIFIER
& & identifier ! = crate ::sso ::FAKE_SSO_IDENTIFIER
& & identifier ! = crate ::api ::admin ::FAKE_ADMIN_UUID
& & identifier ! = crate ::api ::admin ::FAKE_ADMIN_UUID
{
{
@ -487,21 +494,56 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, conn:
accept_org_invite ( & user , membership , None , & conn ) . await ? ;
accept_org_invite ( & user , membership , None , & conn ) . await ? ;
}
}
if CONFIG . mail_enabled ( ) {
let mail_enabled = CONFIG . mail_enabled ( ) ;
if mail_enabled {
mail ::send_welcome ( & user . email . to_lowercase ( ) ) . await ? ;
mail ::send_welcome ( & user . email . to_lowercase ( ) ) . await ? ;
} else {
Membership ::accept_user_invitations ( & user . uuid , & conn ) . await ? ;
}
}
log_user_event ( EventType ::UserChangedPassword , & user . uuid , headers . device . atype , & headers . ip . ip , & conn ) . await ;
log_user_event ( EventType ::UserChangedPassword , & user . uuid , headers . device . atype , & headers . ip . ip , & conn ) . await ;
user . save ( & conn ) . await ? ;
user . save ( & conn ) . await ? ;
if enroll_in_default_organization & & let Some ( org_id ) = default_org_id {
accept_sso_default_organization_invite ( & user , & org_id , & conn ) . await ? ;
}
// Accept any remaining invitations only after the default organization policy checks above.
if ! mail_enabled {
Membership ::accept_user_invitations ( & user . uuid , & conn ) . await ? ;
}
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"object" : "set-password" ,
"object" : "set-password" ,
} ) ) )
} ) ) )
}
}
async fn accept_sso_default_organization_invite ( user : & User , org_id : & OrganizationId , conn : & DbConn ) -> EmptyResult {
let Some ( mut membership ) = Membership ::find_by_user_and_org ( & user . uuid , org_id , conn ) . await else {
err ! ( "Failed to retrieve the default organization invitation" )
} ;
if membership . status ! = MembershipStatus ::Invited as i32 {
return Ok ( ( ) ) ;
}
let Some ( org ) = Organization ::find_by_uuid ( org_id , conn ) . await else {
err ! ( "The organization configured in `SSO_DEFAULT_ORGANIZATION_UUID` does not exist" )
} ;
membership . status = MembershipStatus ::Accepted as i32 ;
OrgPolicy ::check_user_allowed ( & membership , "join" , conn ) . await ? ;
membership . save ( conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
let address = membership . invited_by_email . unwrap_or ( org . billing_email ) ;
if let Err ( e ) = mail ::send_invite_accepted ( & user . email , & address , & org . name ) . await {
error ! ( "Error sending default organization enrollment notification: {e:#?}" ) ;
}
}
info ! ( "Added SSO user {} to default organization {} pending confirmation" , user . uuid , org_id ) ;
Ok ( ( ) )
}
#[ get( " /accounts/profile " ) ]
#[ get( " /accounts/profile " ) ]
async fn profile ( headers : Headers , conn : DbConn ) -> Json < Value > {
async fn profile ( headers : Headers , conn : DbConn ) -> Json < Value > {
Json ( headers . user . to_json ( & conn ) . await )
Json ( headers . user . to_json ( & conn ) . await )