@ -10,11 +10,10 @@ use crate::{
} ,
} ,
auth ::{ decode_invite , AdminHeaders , Headers , ManagerHeaders , ManagerHeadersLoose , OwnerHeaders } ,
auth ::{ decode_invite , AdminHeaders , Headers , ManagerHeaders , ManagerHeadersLoose , OwnerHeaders } ,
db ::{ models ::* , DbConn } ,
db ::{ models ::* , DbConn } ,
error ::Error ,
mail , CONFIG ,
mail , CONFIG ,
} ;
} ;
use futures ::{ stream , stream ::StreamExt } ;
pub fn routes ( ) -> Vec < Route > {
pub fn routes ( ) -> Vec < Route > {
routes ! [
routes ! [
get_organization ,
get_organization ,
@ -107,11 +106,11 @@ struct OrgBulkIds {
}
}
#[ post( " /organizations " , data = " <data> " ) ]
#[ post( " /organizations " , data = " <data> " ) ]
async fn create_organization ( headers : Headers , data : JsonUpcase < OrgData > , conn : DbConn ) -> JsonResult {
async fn create_organization ( headers : Headers , data : JsonUpcase < OrgData > , mut conn : DbConn ) -> JsonResult {
if ! CONFIG . is_org_creation_allowed ( & headers . user . email ) {
if ! CONFIG . is_org_creation_allowed ( & headers . user . email ) {
err ! ( "User not allowed to create organizations" )
err ! ( "User not allowed to create organizations" )
}
}
if OrgPolicy ::is_applicable_to_user ( & headers . user . uuid , OrgPolicyType ::SingleOrg , None , & conn ) . await {
if OrgPolicy ::is_applicable_to_user ( & headers . user . uuid , OrgPolicyType ::SingleOrg , None , & mut conn ) . await {
err ! (
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."
"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."
)
)
@ -134,9 +133,9 @@ async fn create_organization(headers: Headers, data: JsonUpcase<OrgData>, conn:
user_org . atype = UserOrgType ::Owner as i32 ;
user_org . atype = UserOrgType ::Owner as i32 ;
user_org . status = UserOrgStatus ::Confirmed as i32 ;
user_org . status = UserOrgStatus ::Confirmed as i32 ;
org . save ( & conn ) . await ? ;
org . save ( & mut conn ) . await ? ;
user_org . save ( & conn ) . await ? ;
user_org . save ( & mut conn ) . await ? ;
collection . save ( & conn ) . await ? ;
collection . save ( & mut conn ) . await ? ;
Ok ( Json ( org . to_json ( ) ) )
Ok ( Json ( org . to_json ( ) ) )
}
}
@ -146,7 +145,7 @@ async fn delete_organization(
org_id : String ,
org_id : String ,
data : JsonUpcase < PasswordData > ,
data : JsonUpcase < PasswordData > ,
headers : OwnerHeaders ,
headers : OwnerHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
let data : PasswordData = data . into_inner ( ) . data ;
let data : PasswordData = data . into_inner ( ) . data ;
let password_hash = data . MasterPasswordHash ;
let password_hash = data . MasterPasswordHash ;
@ -155,9 +154,9 @@ async fn delete_organization(
err ! ( "Invalid password" )
err ! ( "Invalid password" )
}
}
match Organization ::find_by_uuid ( & org_id , & conn ) . await {
match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
None = > err ! ( "Organization not found" ) ,
None = > err ! ( "Organization not found" ) ,
Some ( org ) = > org . delete ( & conn ) . await ,
Some ( org ) = > org . delete ( & mut conn ) . await ,
}
}
}
}
@ -172,24 +171,24 @@ async fn post_delete_organization(
}
}
#[ post( " /organizations/<org_id>/leave " ) ]
#[ post( " /organizations/<org_id>/leave " ) ]
async fn leave_organization ( org_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn leave_organization ( org_id : String , headers : Headers , mut conn : DbConn ) -> EmptyResult {
match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & conn ) . await {
match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & mut conn ) . await {
None = > err ! ( "User not part of organization" ) ,
None = > err ! ( "User not part of organization" ) ,
Some ( user_org ) = > {
Some ( user_org ) = > {
if user_org . atype = = UserOrgType ::Owner
if user_org . atype = = UserOrgType ::Owner
& & UserOrganization ::count_confirmed_by_org_and_type ( & org_id , UserOrgType ::Owner , & conn ) . await < = 1
& & UserOrganization ::count_confirmed_by_org_and_type ( & org_id , UserOrgType ::Owner , & mut conn ) . await < = 1
{
{
err ! ( "The last owner can't leave" )
err ! ( "The last owner can't leave" )
}
}
user_org . delete ( & conn ) . await
user_org . delete ( & mut conn ) . await
}
}
}
}
}
}
#[ get( " /organizations/<org_id> " ) ]
#[ get( " /organizations/<org_id> " ) ]
async fn get_organization ( org_id : String , _headers : OwnerHeaders , conn : DbConn ) -> JsonResult {
async fn get_organization ( org_id : String , _headers : OwnerHeaders , mut conn : DbConn ) -> JsonResult {
match Organization ::find_by_uuid ( & org_id , & conn ) . await {
match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( organization ) = > Ok ( Json ( organization . to_json ( ) ) ) ,
Some ( organization ) = > Ok ( Json ( organization . to_json ( ) ) ) ,
None = > err ! ( "Can't find organization details" ) ,
None = > err ! ( "Can't find organization details" ) ,
}
}
@ -210,11 +209,11 @@ async fn post_organization(
org_id : String ,
org_id : String ,
_headers : OwnerHeaders ,
_headers : OwnerHeaders ,
data : JsonUpcase < OrganizationUpdateData > ,
data : JsonUpcase < OrganizationUpdateData > ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
let data : OrganizationUpdateData = data . into_inner ( ) . data ;
let data : OrganizationUpdateData = data . into_inner ( ) . data ;
let mut org = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let mut org = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( organization ) = > organization ,
Some ( organization ) = > organization ,
None = > err ! ( "Can't find organization details" ) ,
None = > err ! ( "Can't find organization details" ) ,
} ;
} ;
@ -222,16 +221,16 @@ async fn post_organization(
org . name = data . Name ;
org . name = data . Name ;
org . billing_email = data . BillingEmail ;
org . billing_email = data . BillingEmail ;
org . save ( & conn ) . await ? ;
org . save ( & mut conn ) . await ? ;
Ok ( Json ( org . to_json ( ) ) )
Ok ( Json ( org . to_json ( ) ) )
}
}
// GET /api/collections?writeOnly=false
// GET /api/collections?writeOnly=false
#[ get( " /collections " ) ]
#[ get( " /collections " ) ]
async fn get_user_collections ( headers : Headers , conn : DbConn ) -> Json < Value > {
async fn get_user_collections ( headers : Headers , mut conn : DbConn ) -> Json < Value > {
Json ( json ! ( {
Json ( json ! ( {
"Data" :
"Data" :
Collection ::find_by_user_uuid ( & headers . user . uuid , & conn ) . await
Collection ::find_by_user_uuid ( headers . user . uuid . clone ( ) , & mut conn ) . await
. iter ( )
. iter ( )
. map ( Collection ::to_json )
. map ( Collection ::to_json )
. collect ::< Value > ( ) ,
. collect ::< Value > ( ) ,
@ -241,10 +240,10 @@ async fn get_user_collections(headers: Headers, conn: DbConn) -> Json<Value> {
}
}
#[ get( " /organizations/<org_id>/collections " ) ]
#[ get( " /organizations/<org_id>/collections " ) ]
async fn get_org_collections ( org_id : String , _headers : ManagerHeadersLoose , conn : DbConn ) -> Json < Value > {
async fn get_org_collections ( org_id : String , _headers : ManagerHeadersLoose , mut conn : DbConn ) -> Json < Value > {
Json ( json ! ( {
Json ( json ! ( {
"Data" :
"Data" :
Collection ::find_by_organization ( & org_id , & conn ) . await
Collection ::find_by_organization ( & org_id , & mut conn ) . await
. iter ( )
. iter ( )
. map ( Collection ::to_json )
. map ( Collection ::to_json )
. collect ::< Value > ( ) ,
. collect ::< Value > ( ) ,
@ -258,29 +257,29 @@ async fn post_organization_collections(
org_id : String ,
org_id : String ,
headers : ManagerHeadersLoose ,
headers : ManagerHeadersLoose ,
data : JsonUpcase < NewCollectionData > ,
data : JsonUpcase < NewCollectionData > ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
let data : NewCollectionData = data . into_inner ( ) . data ;
let data : NewCollectionData = data . into_inner ( ) . data ;
let org = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let org = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( organization ) = > organization ,
Some ( organization ) = > organization ,
None = > err ! ( "Can't find organization details" ) ,
None = > err ! ( "Can't find organization details" ) ,
} ;
} ;
// Get the user_organization record so that we can check if the user has access to all collections.
// Get the user_organization record so that we can check if the user has access to all collections.
let user_org = match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & conn ) . await {
let user_org = match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & mut conn ) . await {
Some ( u ) = > u ,
Some ( u ) = > u ,
None = > err ! ( "User is not part of organization" ) ,
None = > err ! ( "User is not part of organization" ) ,
} ;
} ;
let collection = Collection ::new ( org . uuid , data . Name ) ;
let collection = Collection ::new ( org . uuid , data . Name ) ;
collection . save ( & conn ) . await ? ;
collection . save ( & mut conn ) . await ? ;
// If the user doesn't have access to all collections, only in case of a Manger,
// If the user doesn't have access to all collections, only in case of a Manger,
// then we need to save the creating user uuid (Manager) to the users_collection table.
// then we need to save the creating user uuid (Manager) to the users_collection table.
// Else the user will not have access to his own created collection.
// Else the user will not have access to his own created collection.
if ! user_org . access_all {
if ! user_org . access_all {
CollectionUser ::save ( & headers . user . uuid , & collection . uuid , false , false , & conn ) . await ? ;
CollectionUser ::save ( & headers . user . uuid , & collection . uuid , false , false , & mut conn ) . await ? ;
}
}
Ok ( Json ( collection . to_json ( ) ) )
Ok ( Json ( collection . to_json ( ) ) )
@ -303,16 +302,16 @@ async fn post_organization_collection_update(
col_id : String ,
col_id : String ,
_headers : ManagerHeaders ,
_headers : ManagerHeaders ,
data : JsonUpcase < NewCollectionData > ,
data : JsonUpcase < NewCollectionData > ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
let data : NewCollectionData = data . into_inner ( ) . data ;
let data : NewCollectionData = data . into_inner ( ) . data ;
let org = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let org = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( organization ) = > organization ,
Some ( organization ) = > organization ,
None = > err ! ( "Can't find organization details" ) ,
None = > err ! ( "Can't find organization details" ) ,
} ;
} ;
let mut collection = match Collection ::find_by_uuid ( & col_id , & conn ) . await {
let mut collection = match Collection ::find_by_uuid ( & col_id , & mut conn ) . await {
Some ( collection ) = > collection ,
Some ( collection ) = > collection ,
None = > err ! ( "Collection not found" ) ,
None = > err ! ( "Collection not found" ) ,
} ;
} ;
@ -322,7 +321,7 @@ async fn post_organization_collection_update(
}
}
collection . name = data . Name ;
collection . name = data . Name ;
collection . save ( & conn ) . await ? ;
collection . save ( & mut conn ) . await ? ;
Ok ( Json ( collection . to_json ( ) ) )
Ok ( Json ( collection . to_json ( ) ) )
}
}
@ -333,9 +332,9 @@ async fn delete_organization_collection_user(
col_id : String ,
col_id : String ,
org_user_id : String ,
org_user_id : String ,
_headers : AdminHeaders ,
_headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
let collection = match Collection ::find_by_uuid ( & col_id , & conn ) . await {
let collection = match Collection ::find_by_uuid ( & col_id , & mut conn ) . await {
None = > err ! ( "Collection not found" ) ,
None = > err ! ( "Collection not found" ) ,
Some ( collection ) = > {
Some ( collection ) = > {
if collection . org_uuid = = org_id {
if collection . org_uuid = = org_id {
@ -346,12 +345,12 @@ async fn delete_organization_collection_user(
}
}
} ;
} ;
match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & conn ) . await {
match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & mut conn ) . await {
None = > err ! ( "User not found in organization" ) ,
None = > err ! ( "User not found in organization" ) ,
Some ( user_org ) = > {
Some ( user_org ) = > {
match CollectionUser ::find_by_collection_and_user ( & collection . uuid , & user_org . user_uuid , & conn ) . await {
match CollectionUser ::find_by_collection_and_user ( & collection . uuid , & user_org . user_uuid , & mut conn ) . await {
None = > err ! ( "User not assigned to collection" ) ,
None = > err ! ( "User not assigned to collection" ) ,
Some ( col_user ) = > col_user . delete ( & conn ) . await ,
Some ( col_user ) = > col_user . delete ( & mut conn ) . await ,
}
}
}
}
}
}
@ -373,13 +372,13 @@ async fn delete_organization_collection(
org_id : String ,
org_id : String ,
col_id : String ,
col_id : String ,
_headers : ManagerHeaders ,
_headers : ManagerHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
match Collection ::find_by_uuid ( & col_id , & conn ) . await {
match Collection ::find_by_uuid ( & col_id , & mut conn ) . await {
None = > err ! ( "Collection not found" ) ,
None = > err ! ( "Collection not found" ) ,
Some ( collection ) = > {
Some ( collection ) = > {
if collection . org_uuid = = org_id {
if collection . org_uuid = = org_id {
collection . delete ( & conn ) . await
collection . delete ( & mut conn ) . await
} else {
} else {
err ! ( "Collection and Organization id do not match" )
err ! ( "Collection and Organization id do not match" )
}
}
@ -410,9 +409,9 @@ async fn get_org_collection_detail(
org_id : String ,
org_id : String ,
coll_id : String ,
coll_id : String ,
headers : ManagerHeaders ,
headers : ManagerHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
match Collection ::find_by_uuid_and_user ( & coll_id , & headers . user . uuid , & conn ) . await {
match Collection ::find_by_uuid_and_user ( & coll_id , headers . user . uuid . clone ( ) , & mut conn ) . await {
None = > err ! ( "Collection not found" ) ,
None = > err ! ( "Collection not found" ) ,
Some ( collection ) = > {
Some ( collection ) = > {
if collection . org_uuid ! = org_id {
if collection . org_uuid ! = org_id {
@ -425,23 +424,27 @@ async fn get_org_collection_detail(
}
}
#[ get( " /organizations/<org_id>/collections/<coll_id>/users " ) ]
#[ get( " /organizations/<org_id>/collections/<coll_id>/users " ) ]
async fn get_collection_users ( org_id : String , coll_id : String , _headers : ManagerHeaders , conn : DbConn ) -> JsonResult {
async fn get_collection_users (
org_id : String ,
coll_id : String ,
_headers : ManagerHeaders ,
mut conn : DbConn ,
) -> JsonResult {
// Get org and collection, check that collection is from org
// Get org and collection, check that collection is from org
let collection = match Collection ::find_by_uuid_and_org ( & coll_id , & org_id , & conn ) . await {
let collection = match Collection ::find_by_uuid_and_org ( & coll_id , & org_id , & mut conn ) . await {
None = > err ! ( "Collection not found in Organization" ) ,
None = > err ! ( "Collection not found in Organization" ) ,
Some ( collection ) = > collection ,
Some ( collection ) = > collection ,
} ;
} ;
let user_list = stream ::iter ( CollectionUser ::find_by_collection ( & collection . uuid , & conn ) . await )
let mut user_list = Vec ::new ( ) ;
. then ( | col_user | async {
for col_user in CollectionUser ::find_by_collection ( & collection . uuid , & mut conn ) . await {
let col_user = col_user ; // Move out this single variable
user_list . push (
UserOrganization ::find_by_user_and_org ( & col_user . user_uuid , & org_id , & conn )
UserOrganization ::find_by_user_and_org ( & col_user . user_uuid , & org_id , & mut conn )
. await
. await
. unwrap ( )
. unwrap ( )
. to_json_user_access_restrictions ( & col_user )
. to_json_user_access_restrictions ( & col_user ) ,
} )
) ;
. collect ::< Vec < Value > > ( )
}
. await ;
Ok ( Json ( json ! ( user_list ) ) )
Ok ( Json ( json ! ( user_list ) ) )
}
}
@ -452,19 +455,19 @@ async fn put_collection_users(
coll_id : String ,
coll_id : String ,
data : JsonUpcaseVec < CollectionData > ,
data : JsonUpcaseVec < CollectionData > ,
_headers : ManagerHeaders ,
_headers : ManagerHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
// Get org and collection, check that collection is from org
// Get org and collection, check that collection is from org
if Collection ::find_by_uuid_and_org ( & coll_id , & org_id , & conn ) . await . is_none ( ) {
if Collection ::find_by_uuid_and_org ( & coll_id , & org_id , & mut conn ) . await . is_none ( ) {
err ! ( "Collection not found in Organization" )
err ! ( "Collection not found in Organization" )
}
}
// Delete all the user-collections
// Delete all the user-collections
CollectionUser ::delete_all_by_collection ( & coll_id , & conn ) . await ? ;
CollectionUser ::delete_all_by_collection ( & coll_id , & mut conn ) . await ? ;
// And then add all the received ones (except if the user has access_all)
// And then add all the received ones (except if the user has access_all)
for d in data . iter ( ) . map ( | d | & d . data ) {
for d in data . iter ( ) . map ( | d | & d . data ) {
let user = match UserOrganization ::find_by_uuid ( & d . Id , & conn ) . await {
let user = match UserOrganization ::find_by_uuid ( & d . Id , & mut conn ) . await {
Some ( u ) = > u ,
Some ( u ) = > u ,
None = > err ! ( "User is not part of organization" ) ,
None = > err ! ( "User is not part of organization" ) ,
} ;
} ;
@ -473,7 +476,7 @@ async fn put_collection_users(
continue ;
continue ;
}
}
CollectionUser ::save ( & user . user_uuid , & coll_id , d . ReadOnly , d . HidePasswords , & conn ) . await ? ;
CollectionUser ::save ( & user . user_uuid , & coll_id , d . ReadOnly , d . HidePasswords , & mut conn ) . await ? ;
}
}
Ok ( ( ) )
Ok ( ( ) )
@ -486,17 +489,15 @@ struct OrgIdData {
}
}
#[ get( " /ciphers/organization-details?<data..> " ) ]
#[ get( " /ciphers/organization-details?<data..> " ) ]
async fn get_org_details ( data : OrgIdData , headers : Headers , conn : DbConn ) -> Json < Value > {
async fn get_org_details ( data : OrgIdData , headers : Headers , mut conn : DbConn ) -> Json < Value > {
let ciphers = Cipher ::find_by_org ( & data . organization_id , & conn ) . await ;
let ciphers = Cipher ::find_by_org ( & data . organization_id , & mut conn ) . await ;
let cipher_sync_data = CipherSyncData ::new ( & headers . user . uuid , & ciphers , CipherSyncType ::Organization , & conn ) . await ;
let cipher_sync_data =
CipherSyncData ::new ( & headers . user . uuid , & ciphers , CipherSyncType ::Organization , & mut conn ) . await ;
let ciphers_json = stream ::iter ( ciphers )
. then ( | c | async {
let mut ciphers_json = Vec ::new ( ) ;
let c = c ; // Move out this single variable
for c in ciphers {
c . to_json ( & headers . host , & headers . user . uuid , Some ( & cipher_sync_data ) , & conn ) . await
ciphers_json . push ( c . to_json ( & headers . host , & headers . user . uuid , Some ( & cipher_sync_data ) , & mut conn ) . await ) ;
} )
}
. collect ::< Vec < Value > > ( )
. await ;
Json ( json ! ( {
Json ( json ! ( {
"Data" : ciphers_json ,
"Data" : ciphers_json ,
@ -506,14 +507,11 @@ async fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> Jso
}
}
#[ get( " /organizations/<org_id>/users " ) ]
#[ get( " /organizations/<org_id>/users " ) ]
async fn get_org_users ( org_id : String , _headers : ManagerHeadersLoose , conn : DbConn ) -> Json < Value > {
async fn get_org_users ( org_id : String , _headers : ManagerHeadersLoose , mut conn : DbConn ) -> Json < Value > {
let users_json = stream ::iter ( UserOrganization ::find_by_org ( & org_id , & conn ) . await )
let mut users_json = Vec ::new ( ) ;
. then ( | u | async {
for u in UserOrganization ::find_by_org ( & org_id , & mut conn ) . await {
let u = u ; // Move out this single variable
users_json . push ( u . to_json_user_details ( & mut conn ) . await ) ;
u . to_json_user_details ( & conn ) . await
}
} )
. collect ::< Vec < Value > > ( )
. await ;
Json ( json ! ( {
Json ( json ! ( {
"Data" : users_json ,
"Data" : users_json ,
@ -527,11 +525,11 @@ async fn post_org_keys(
org_id : String ,
org_id : String ,
data : JsonUpcase < OrgKeyData > ,
data : JsonUpcase < OrgKeyData > ,
_headers : AdminHeaders ,
_headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
let data : OrgKeyData = data . into_inner ( ) . data ;
let data : OrgKeyData = data . into_inner ( ) . data ;
let mut org = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let mut org = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( organization ) = > {
Some ( organization ) = > {
if organization . private_key . is_some ( ) & & organization . public_key . is_some ( ) {
if organization . private_key . is_some ( ) & & organization . public_key . is_some ( ) {
err ! ( "Organization Keys already exist" )
err ! ( "Organization Keys already exist" )
@ -544,7 +542,7 @@ async fn post_org_keys(
org . private_key = Some ( data . EncryptedPrivateKey ) ;
org . private_key = Some ( data . EncryptedPrivateKey ) ;
org . public_key = Some ( data . PublicKey ) ;
org . public_key = Some ( data . PublicKey ) ;
org . save ( & conn ) . await ? ;
org . save ( & mut conn ) . await ? ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"Object" : "organizationKeys" ,
"Object" : "organizationKeys" ,
@ -571,7 +569,12 @@ struct InviteData {
}
}
#[ post( " /organizations/<org_id>/users/invite " , data = " <data> " ) ]
#[ post( " /organizations/<org_id>/users/invite " , data = " <data> " ) ]
async fn send_invite ( org_id : String , data : JsonUpcase < InviteData > , headers : AdminHeaders , conn : DbConn ) -> EmptyResult {
async fn send_invite (
org_id : String ,
data : JsonUpcase < InviteData > ,
headers : AdminHeaders ,
mut conn : DbConn ,
) -> EmptyResult {
let data : InviteData = data . into_inner ( ) . data ;
let data : InviteData = data . into_inner ( ) . data ;
let new_type = match UserOrgType ::from_str ( & data . Type . into_string ( ) ) {
let new_type = match UserOrgType ::from_str ( & data . Type . into_string ( ) ) {
@ -590,7 +593,7 @@ async fn send_invite(org_id: String, data: JsonUpcase<InviteData>, headers: Admi
} else {
} else {
UserOrgStatus ::Accepted as i32 // Automatically mark user as accepted if no email invites
UserOrgStatus ::Accepted as i32 // Automatically mark user as accepted if no email invites
} ;
} ;
let user = match User ::find_by_mail ( & email , & conn ) . await {
let user = match User ::find_by_mail ( & email , & mut conn ) . await {
None = > {
None = > {
if ! CONFIG . invitations_allowed ( ) {
if ! CONFIG . invitations_allowed ( ) {
err ! ( format ! ( "User does not exist: {}" , email ) )
err ! ( format ! ( "User does not exist: {}" , email ) )
@ -602,16 +605,16 @@ async fn send_invite(org_id: String, data: JsonUpcase<InviteData>, headers: Admi
if ! CONFIG . mail_enabled ( ) {
if ! CONFIG . mail_enabled ( ) {
let invitation = Invitation ::new ( email . clone ( ) ) ;
let invitation = Invitation ::new ( email . clone ( ) ) ;
invitation . save ( & conn ) . await ? ;
invitation . save ( & mut conn ) . await ? ;
}
}
let mut user = User ::new ( email . clone ( ) ) ;
let mut user = User ::new ( email . clone ( ) ) ;
user . save ( & conn ) . await ? ;
user . save ( & mut conn ) . await ? ;
user_org_status = UserOrgStatus ::Invited as i32 ;
user_org_status = UserOrgStatus ::Invited as i32 ;
user
user
}
}
Some ( user ) = > {
Some ( user ) = > {
if UserOrganization ::find_by_user_and_org ( & user . uuid , & org_id , & conn ) . await . is_some ( ) {
if UserOrganization ::find_by_user_and_org ( & user . uuid , & org_id , & mut conn ) . await . is_some ( ) {
err ! ( format ! ( "User already in organization: {}" , email ) )
err ! ( format ! ( "User already in organization: {}" , email ) )
} else {
} else {
user
user
@ -628,20 +631,20 @@ async fn send_invite(org_id: String, data: JsonUpcase<InviteData>, headers: Admi
// If no accessAll, add the collections received
// If no accessAll, add the collections received
if ! access_all {
if ! access_all {
for col in data . Collections . iter ( ) . flatten ( ) {
for col in data . Collections . iter ( ) . flatten ( ) {
match Collection ::find_by_uuid_and_org ( & col . Id , & org_id , & conn ) . await {
match Collection ::find_by_uuid_and_org ( & col . Id , & org_id , & mut conn ) . await {
None = > err ! ( "Collection not found in Organization" ) ,
None = > err ! ( "Collection not found in Organization" ) ,
Some ( collection ) = > {
Some ( collection ) = > {
CollectionUser ::save ( & user . uuid , & collection . uuid , col . ReadOnly , col . HidePasswords , & conn )
CollectionUser ::save ( & user . uuid , & collection . uuid , col . ReadOnly , col . HidePasswords , & mut conn )
. await ? ;
. await ? ;
}
}
}
}
}
}
}
}
new_user . save ( & conn ) . await ? ;
new_user . save ( & mut conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
let org_name = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let org_name = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( org ) = > org . name ,
Some ( org ) = > org . name ,
None = > err ! ( "Error looking up organization" ) ,
None = > err ! ( "Error looking up organization" ) ,
} ;
} ;
@ -666,13 +669,13 @@ async fn bulk_reinvite_user(
org_id : String ,
org_id : String ,
data : JsonUpcase < OrgBulkIds > ,
data : JsonUpcase < OrgBulkIds > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data : OrgBulkIds = data . into_inner ( ) . data ;
let data : OrgBulkIds = data . into_inner ( ) . data ;
let mut bulk_response = Vec ::new ( ) ;
let mut bulk_response = Vec ::new ( ) ;
for org_user_id in data . Ids {
for org_user_id in data . Ids {
let err_msg = match _reinvite_user ( & org_id , & org_user_id , & headers . user . email , & conn ) . await {
let err_msg = match _reinvite_user ( & org_id , & org_user_id , & headers . user . email , & mut conn ) . await {
Ok ( _ ) = > String ::from ( "" ) ,
Ok ( _ ) = > String ::from ( "" ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
} ;
} ;
@ -694,11 +697,11 @@ async fn bulk_reinvite_user(
}
}
#[ post( " /organizations/<org_id>/users/<user_org>/reinvite " ) ]
#[ post( " /organizations/<org_id>/users/<user_org>/reinvite " ) ]
async fn reinvite_user ( org_id : String , user_org : String , headers : AdminHeaders , conn : DbConn ) -> EmptyResult {
async fn reinvite_user ( org_id : String , user_org : String , headers : AdminHeaders , mut conn : DbConn ) -> EmptyResult {
_reinvite_user ( & org_id , & user_org , & headers . user . email , & conn ) . await
_reinvite_user ( & org_id , & user_org , & headers . user . email , & mut conn ) . await
}
}
async fn _reinvite_user ( org_id : & str , user_org : & str , invited_by_email : & str , conn : & DbConn ) -> EmptyResult {
async fn _reinvite_user ( org_id : & str , user_org : & str , invited_by_email : & str , conn : & mut DbConn ) -> EmptyResult {
if ! CONFIG . invitations_allowed ( ) {
if ! CONFIG . invitations_allowed ( ) {
err ! ( "Invitations are not allowed." )
err ! ( "Invitations are not allowed." )
}
}
@ -755,18 +758,18 @@ async fn accept_invite(
org_id : String ,
org_id : String ,
_org_user_id : String ,
_org_user_id : String ,
data : JsonUpcase < AcceptData > ,
data : JsonUpcase < AcceptData > ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
// The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead
// 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 data : AcceptData = data . into_inner ( ) . data ;
let claims = decode_invite ( & data . Token ) ? ;
let claims = decode_invite ( & data . Token ) ? ;
match User ::find_by_mail ( & claims . email , & conn ) . await {
match User ::find_by_mail ( & claims . email , & mut conn ) . await {
Some ( _ ) = > {
Some ( _ ) = > {
Invitation ::take ( & claims . email , & conn ) . await ;
Invitation ::take ( & claims . email , & mut conn ) . await ;
if let ( Some ( user_org ) , Some ( org ) ) = ( & claims . user_org_id , & claims . org_id ) {
if let ( Some ( user_org ) , Some ( org ) ) = ( & claims . user_org_id , & claims . org_id ) {
let mut user_org = match UserOrganization ::find_by_uuid_and_org ( user_org , org , & conn ) . await {
let mut user_org = match UserOrganization ::find_by_uuid_and_org ( user_org , org , & mut conn ) . await {
Some ( user_org ) = > user_org ,
Some ( user_org ) = > user_org ,
None = > err ! ( "Error accepting the invitation" ) ,
None = > err ! ( "Error accepting the invitation" ) ,
} ;
} ;
@ -778,7 +781,7 @@ async fn accept_invite(
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type
// 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.
// It returns different error messages per function.
if user_org . atype < UserOrgType ::Admin {
if user_org . atype < UserOrgType ::Admin {
match OrgPolicy ::is_user_allowed ( & user_org . user_uuid , & org_id , false , & conn ) . await {
match OrgPolicy ::is_user_allowed ( & user_org . user_uuid , & org_id , false , & mut conn ) . await {
Ok ( _ ) = > { }
Ok ( _ ) = > { }
Err ( OrgPolicyErr ::TwoFactorMissing ) = > {
Err ( OrgPolicyErr ::TwoFactorMissing ) = > {
err ! ( "You cannot join this organization until you enable two-step login on your user account" ) ;
err ! ( "You cannot join this organization until you enable two-step login on your user account" ) ;
@ -790,7 +793,7 @@ async fn accept_invite(
}
}
user_org . status = UserOrgStatus ::Accepted as i32 ;
user_org . status = UserOrgStatus ::Accepted as i32 ;
user_org . save ( & conn ) . await ? ;
user_org . save ( & mut conn ) . await ? ;
}
}
}
}
None = > err ! ( "Invited user not found" ) ,
None = > err ! ( "Invited user not found" ) ,
@ -799,7 +802,7 @@ async fn accept_invite(
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
let mut org_name = CONFIG . invitation_org_name ( ) ;
let mut org_name = CONFIG . invitation_org_name ( ) ;
if let Some ( org_id ) = & claims . org_id {
if let Some ( org_id ) = & claims . org_id {
org_name = match Organization ::find_by_uuid ( org_id , & conn ) . await {
org_name = match Organization ::find_by_uuid ( org_id , & mut conn ) . await {
Some ( org ) = > org . name ,
Some ( org ) = > org . name ,
None = > err ! ( "Organization not found." ) ,
None = > err ! ( "Organization not found." ) ,
} ;
} ;
@ -821,7 +824,7 @@ async fn bulk_confirm_invite(
org_id : String ,
org_id : String ,
data : JsonUpcase < Value > ,
data : JsonUpcase < Value > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data = data . into_inner ( ) . data ;
let data = data . into_inner ( ) . data ;
@ -831,7 +834,7 @@ async fn bulk_confirm_invite(
for invite in keys {
for invite in keys {
let org_user_id = invite [ "Id" ] . as_str ( ) . unwrap_or_default ( ) ;
let org_user_id = invite [ "Id" ] . as_str ( ) . unwrap_or_default ( ) ;
let user_key = invite [ "Key" ] . as_str ( ) . unwrap_or_default ( ) ;
let user_key = invite [ "Key" ] . as_str ( ) . unwrap_or_default ( ) ;
let err_msg = match _confirm_invite ( & org_id , org_user_id , user_key , & headers , & conn ) . await {
let err_msg = match _confirm_invite ( & org_id , org_user_id , user_key , & headers , & mut conn ) . await {
Ok ( _ ) = > String ::from ( "" ) ,
Ok ( _ ) = > String ::from ( "" ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
} ;
} ;
@ -861,11 +864,11 @@ async fn confirm_invite(
org_user_id : String ,
org_user_id : String ,
data : JsonUpcase < Value > ,
data : JsonUpcase < Value > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
let data = data . into_inner ( ) . data ;
let data = data . into_inner ( ) . data ;
let user_key = data [ "Key" ] . as_str ( ) . unwrap_or_default ( ) ;
let user_key = data [ "Key" ] . as_str ( ) . unwrap_or_default ( ) ;
_confirm_invite ( & org_id , & org_user_id , user_key , & headers , & conn ) . await
_confirm_invite ( & org_id , & org_user_id , user_key , & headers , & mut conn ) . await
}
}
async fn _confirm_invite (
async fn _confirm_invite (
@ -873,7 +876,7 @@ async fn _confirm_invite(
org_user_id : & str ,
org_user_id : & str ,
key : & str ,
key : & str ,
headers : & AdminHeaders ,
headers : & AdminHeaders ,
conn : & DbConn ,
conn : & mut DbConn ,
) -> EmptyResult {
) -> EmptyResult {
if key . is_empty ( ) | | org_user_id . is_empty ( ) {
if key . is_empty ( ) | | org_user_id . is_empty ( ) {
err ! ( "Key or UserId is not set, unable to process request" ) ;
err ! ( "Key or UserId is not set, unable to process request" ) ;
@ -925,13 +928,13 @@ async fn _confirm_invite(
}
}
#[ get( " /organizations/<org_id>/users/<org_user_id> " ) ]
#[ get( " /organizations/<org_id>/users/<org_user_id> " ) ]
async fn get_user ( org_id : String , org_user_id : String , _headers : AdminHeaders , conn : DbConn ) -> JsonResult {
async fn get_user ( org_id : String , org_user_id : String , _headers : AdminHeaders , mut conn : DbConn ) -> JsonResult {
let user = match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & conn ) . await {
let user = match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & mut conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "The specified user isn't a member of the organization" ) ,
None = > err ! ( "The specified user isn't a member of the organization" ) ,
} ;
} ;
Ok ( Json ( user . to_json_details ( & conn ) . await ) )
Ok ( Json ( user . to_json_details ( & mut conn ) . await ) )
}
}
#[ derive(Deserialize) ]
#[ derive(Deserialize) ]
@ -959,7 +962,7 @@ async fn edit_user(
org_user_id : String ,
org_user_id : String ,
data : JsonUpcase < EditUserData > ,
data : JsonUpcase < EditUserData > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
let data : EditUserData = data . into_inner ( ) . data ;
let data : EditUserData = data . into_inner ( ) . data ;
@ -968,7 +971,7 @@ async fn edit_user(
None = > err ! ( "Invalid type" ) ,
None = > err ! ( "Invalid type" ) ,
} ;
} ;
let mut user_to_edit = match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & conn ) . await {
let mut user_to_edit = match UserOrganization ::find_by_uuid_and_org ( & org_user_id , & org_id , & mut conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "The specified user isn't member of the organization" ) ,
None = > err ! ( "The specified user isn't member of the organization" ) ,
} ;
} ;
@ -986,7 +989,7 @@ async fn edit_user(
if user_to_edit . atype = = UserOrgType ::Owner & & new_type ! = UserOrgType ::Owner {
if user_to_edit . atype = = UserOrgType ::Owner & & new_type ! = UserOrgType ::Owner {
// Removing owner permmission, check that there is at least one other confirmed owner
// 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 {
if UserOrganization ::count_confirmed_by_org_and_type ( & org_id , UserOrgType ::Owner , & mut conn ) . await < = 1 {
err ! ( "Can't delete the last owner" )
err ! ( "Can't delete the last owner" )
}
}
}
}
@ -994,7 +997,7 @@ async fn edit_user(
// This check is also done at accept_invite(), _confirm_invite, _activate_user(), edit_user(), admin::update_user_org_type
// 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.
// It returns different error messages per function.
if new_type < UserOrgType ::Admin {
if new_type < UserOrgType ::Admin {
match OrgPolicy ::is_user_allowed ( & user_to_edit . user_uuid , & org_id , true , & conn ) . await {
match OrgPolicy ::is_user_allowed ( & user_to_edit . user_uuid , & org_id , true , & mut conn ) . await {
Ok ( _ ) = > { }
Ok ( _ ) = > { }
Err ( OrgPolicyErr ::TwoFactorMissing ) = > {
Err ( OrgPolicyErr ::TwoFactorMissing ) = > {
err ! ( "You cannot modify this user to this type because it has no two-step login method activated" ) ;
err ! ( "You cannot modify this user to this type because it has no two-step login method activated" ) ;
@ -1009,14 +1012,14 @@ async fn edit_user(
user_to_edit . atype = new_type as i32 ;
user_to_edit . atype = new_type as i32 ;
// Delete all the odd collections
// Delete all the odd collections
for c in CollectionUser ::find_by_organization_and_user_uuid ( & org_id , & user_to_edit . user_uuid , & conn ) . await {
for c in CollectionUser ::find_by_organization_and_user_uuid ( & org_id , & user_to_edit . user_uuid , & mut conn ) . await {
c . delete ( & conn ) . await ? ;
c . delete ( & mut conn ) . await ? ;
}
}
// If no accessAll, add the collections received
// If no accessAll, add the collections received
if ! data . AccessAll {
if ! data . AccessAll {
for col in data . Collections . iter ( ) . flatten ( ) {
for col in data . Collections . iter ( ) . flatten ( ) {
match Collection ::find_by_uuid_and_org ( & col . Id , & org_id , & conn ) . await {
match Collection ::find_by_uuid_and_org ( & col . Id , & org_id , & mut conn ) . await {
None = > err ! ( "Collection not found in Organization" ) ,
None = > err ! ( "Collection not found in Organization" ) ,
Some ( collection ) = > {
Some ( collection ) = > {
CollectionUser ::save (
CollectionUser ::save (
@ -1024,7 +1027,7 @@ async fn edit_user(
& collection . uuid ,
& collection . uuid ,
col . ReadOnly ,
col . ReadOnly ,
col . HidePasswords ,
col . HidePasswords ,
& conn ,
& mut conn ,
)
)
. await ? ;
. await ? ;
}
}
@ -1032,7 +1035,7 @@ async fn edit_user(
}
}
}
}
user_to_edit . save ( & conn ) . await
user_to_edit . save ( & mut conn ) . await
}
}
#[ delete( " /organizations/<org_id>/users " , data = " <data> " ) ]
#[ delete( " /organizations/<org_id>/users " , data = " <data> " ) ]
@ -1040,13 +1043,13 @@ async fn bulk_delete_user(
org_id : String ,
org_id : String ,
data : JsonUpcase < OrgBulkIds > ,
data : JsonUpcase < OrgBulkIds > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data : OrgBulkIds = data . into_inner ( ) . data ;
let data : OrgBulkIds = data . into_inner ( ) . data ;
let mut bulk_response = Vec ::new ( ) ;
let mut bulk_response = Vec ::new ( ) ;
for org_user_id in data . Ids {
for org_user_id in data . Ids {
let err_msg = match _delete_user ( & org_id , & org_user_id , & headers , & conn ) . await {
let err_msg = match _delete_user ( & org_id , & org_user_id , & headers , & mut conn ) . await {
Ok ( _ ) = > String ::from ( "" ) ,
Ok ( _ ) = > String ::from ( "" ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
} ;
} ;
@ -1068,11 +1071,11 @@ async fn bulk_delete_user(
}
}
#[ delete( " /organizations/<org_id>/users/<org_user_id> " ) ]
#[ delete( " /organizations/<org_id>/users/<org_user_id> " ) ]
async fn delete_user ( org_id : String , org_user_id : String , headers : AdminHeaders , conn : DbConn ) -> EmptyResult {
async fn delete_user ( org_id : String , org_user_id : String , headers : AdminHeaders , mut conn : DbConn ) -> EmptyResult {
_delete_user ( & org_id , & org_user_id , & headers , & conn ) . await
_delete_user ( & org_id , & org_user_id , & headers , & mut conn ) . await
}
}
async fn _delete_user ( org_id : & str , org_user_id : & str , headers : & AdminHeaders , conn : & DbConn ) -> EmptyResult {
async fn _delete_user ( org_id : & str , org_user_id : & str , headers : & AdminHeaders , conn : & mut DbConn ) -> EmptyResult {
let user_to_delete = match UserOrganization ::find_by_uuid_and_org ( org_user_id , org_id , conn ) . await {
let user_to_delete = match UserOrganization ::find_by_uuid_and_org ( org_user_id , org_id , conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "User to delete isn't member of the organization" ) ,
None = > err ! ( "User to delete isn't member of the organization" ) ,
@ -1102,7 +1105,7 @@ async fn bulk_public_keys(
org_id : String ,
org_id : String ,
data : JsonUpcase < OrgBulkIds > ,
data : JsonUpcase < OrgBulkIds > ,
_headers : AdminHeaders ,
_headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data : OrgBulkIds = data . into_inner ( ) . data ;
let data : OrgBulkIds = data . into_inner ( ) . data ;
@ -1111,8 +1114,8 @@ async fn bulk_public_keys(
// If the user does not exists, just ignore it, and do not return any information regarding that UserOrg UUID.
// If the user does not exists, just ignore it, and do not return any information regarding that UserOrg UUID.
// The web-vault will then ignore that user for the folowing steps.
// The web-vault will then ignore that user for the folowing steps.
for user_org_id in data . Ids {
for user_org_id in data . Ids {
match UserOrganization ::find_by_uuid_and_org ( & user_org_id , & org_id , & conn ) . await {
match UserOrganization ::find_by_uuid_and_org ( & user_org_id , & org_id , & mut conn ) . await {
Some ( user_org ) = > match User ::find_by_uuid ( & user_org . user_uuid , & conn ) . await {
Some ( user_org ) = > match User ::find_by_uuid ( & user_org . user_uuid , & mut conn ) . await {
Some ( user ) = > bulk_response . push ( json ! (
Some ( user ) = > bulk_response . push ( json ! (
{
{
"Object" : "organizationUserPublicKeyResponseModel" ,
"Object" : "organizationUserPublicKeyResponseModel" ,
@ -1159,23 +1162,21 @@ async fn post_org_import(
query : OrgIdData ,
query : OrgIdData ,
data : JsonUpcase < ImportData > ,
data : JsonUpcase < ImportData > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
nt : Notify < '_ > ,
nt : Notify < '_ > ,
) -> EmptyResult {
) -> EmptyResult {
let data : ImportData = data . into_inner ( ) . data ;
let data : ImportData = data . into_inner ( ) . data ;
let org_id = query . organization_id ;
let org_id = query . organization_id ;
let collections = stream ::iter ( data . Collections )
let mut collections = Vec ::new ( ) ;
. then ( | coll | async {
for coll in data . Collections {
let collection = Collection ::new ( org_id . clone ( ) , coll . Name ) ;
let collection = Collection ::new ( org_id . clone ( ) , coll . Name ) ;
if collection . save ( & conn ) . await . is_err ( ) {
if collection . save ( & mut conn ) . await . is_err ( ) {
err ! ( "Failed to create Collection" ) ;
collections . push ( Err ( Error ::new ( "Failed to create Collection" , "Failed to create Collection" ) ) ) ;
} else {
collections . push ( Ok ( collection ) ) ;
}
}
}
Ok ( collection )
} )
. collect ::< Vec < _ > > ( )
. await ;
// Read the relations between collections and ciphers
// Read the relations between collections and ciphers
let mut relations = Vec ::new ( ) ;
let mut relations = Vec ::new ( ) ;
@ -1185,14 +1186,12 @@ async fn post_org_import(
let headers : Headers = headers . into ( ) ;
let headers : Headers = headers . into ( ) ;
let ciphers = stream ::iter ( data . Ciphers )
let mut ciphers = Vec ::new ( ) ;
. then ( | cipher_data | async {
for cipher_data in data . Ciphers {
let mut cipher = Cipher ::new ( cipher_data . Type , cipher_data . Name . clone ( ) ) ;
let mut cipher = Cipher ::new ( cipher_data . Type , cipher_data . Name . clone ( ) ) ;
update_cipher_from_data ( & mut cipher , cipher_data , & headers , false , & conn , & nt , UpdateType ::None ) . await . ok ( ) ;
update_cipher_from_data ( & mut cipher , cipher_data , & headers , false , & mut conn , & nt , UpdateType ::None ) . await . ok ( ) ;
cipher
ciphers . push ( cipher ) ;
} )
}
. collect ::< Vec < Cipher > > ( )
. await ;
// Assign the collections
// Assign the collections
for ( cipher_index , coll_index ) in relations {
for ( cipher_index , coll_index ) in relations {
@ -1203,16 +1202,16 @@ async fn post_org_import(
Err ( _ ) = > err ! ( "Failed to assign to collection" ) ,
Err ( _ ) = > err ! ( "Failed to assign to collection" ) ,
} ;
} ;
CollectionCipher ::save ( cipher_id , coll_id , & conn ) . await ? ;
CollectionCipher ::save ( cipher_id , coll_id , & mut conn ) . await ? ;
}
}
let mut user = headers . user ;
let mut user = headers . user ;
user . update_revision ( & conn ) . await
user . update_revision ( & mut conn ) . await
}
}
#[ get( " /organizations/<org_id>/policies " ) ]
#[ get( " /organizations/<org_id>/policies " ) ]
async fn list_policies ( org_id : String , _headers : AdminHeaders , conn : DbConn ) -> Json < Value > {
async fn list_policies ( org_id : String , _headers : AdminHeaders , mut conn : DbConn ) -> Json < Value > {
let policies = OrgPolicy ::find_by_org ( & org_id , & conn ) . await ;
let policies = OrgPolicy ::find_by_org ( & org_id , & mut conn ) . await ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
Json ( json ! ( {
Json ( json ! ( {
@ -1223,7 +1222,7 @@ async fn list_policies(org_id: String, _headers: AdminHeaders, conn: DbConn) ->
}
}
#[ get( " /organizations/<org_id>/policies/token?<token> " ) ]
#[ get( " /organizations/<org_id>/policies/token?<token> " ) ]
async fn list_policies_token ( org_id : String , token : String , conn : DbConn ) -> JsonResult {
async fn list_policies_token ( org_id : String , token : String , mut conn : DbConn ) -> JsonResult {
let invite = crate ::auth ::decode_invite ( & token ) ? ;
let invite = crate ::auth ::decode_invite ( & token ) ? ;
let invite_org_id = match invite . org_id {
let invite_org_id = match invite . org_id {
@ -1236,7 +1235,7 @@ async fn list_policies_token(org_id: String, token: String, conn: DbConn) -> Jso
}
}
// TODO: We receive the invite token as ?token=<>, validate it contains the org id
// TODO: We receive the invite token as ?token=<>, validate it contains the org id
let policies = OrgPolicy ::find_by_org ( & org_id , & conn ) . await ;
let policies = OrgPolicy ::find_by_org ( & org_id , & mut conn ) . await ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
@ -1247,13 +1246,13 @@ async fn list_policies_token(org_id: String, token: String, conn: DbConn) -> Jso
}
}
#[ get( " /organizations/<org_id>/policies/<pol_type> " ) ]
#[ get( " /organizations/<org_id>/policies/<pol_type> " ) ]
async fn get_policy ( org_id : String , pol_type : i32 , _headers : AdminHeaders , conn : DbConn ) -> JsonResult {
async fn get_policy ( org_id : String , pol_type : i32 , _headers : AdminHeaders , mut conn : DbConn ) -> JsonResult {
let pol_type_enum = match OrgPolicyType ::from_i32 ( pol_type ) {
let pol_type_enum = match OrgPolicyType ::from_i32 ( pol_type ) {
Some ( pt ) = > pt ,
Some ( pt ) = > pt ,
None = > err ! ( "Invalid or unsupported policy type" ) ,
None = > err ! ( "Invalid or unsupported policy type" ) ,
} ;
} ;
let policy = match OrgPolicy ::find_by_org_and_type ( & org_id , pol_type_enum , & conn ) . await {
let policy = match OrgPolicy ::find_by_org_and_type ( & org_id , pol_type_enum , & mut conn ) . await {
Some ( p ) = > p ,
Some ( p ) = > p ,
None = > OrgPolicy ::new ( org_id , pol_type_enum , "{}" . to_string ( ) ) ,
None = > OrgPolicy ::new ( org_id , pol_type_enum , "{}" . to_string ( ) ) ,
} ;
} ;
@ -1275,7 +1274,7 @@ async fn put_policy(
pol_type : i32 ,
pol_type : i32 ,
data : Json < PolicyData > ,
data : Json < PolicyData > ,
_headers : AdminHeaders ,
_headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> JsonResult {
) -> JsonResult {
let data : PolicyData = data . into_inner ( ) ;
let data : PolicyData = data . into_inner ( ) ;
@ -1286,8 +1285,8 @@ async fn put_policy(
// When 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 {
if pol_type_enum = = OrgPolicyType ::TwoFactorAuthentication & & data . enabled {
for member in UserOrganization ::find_by_org ( & org_id , & conn ) . await . into_iter ( ) {
for member in UserOrganization ::find_by_org ( & org_id , & mut conn ) . await . into_iter ( ) {
let user_twofactor_disabled = TwoFactor ::find_by_user ( & member . user_uuid , & conn ) . await . is_empty ( ) ;
let user_twofactor_disabled = TwoFactor ::find_by_user ( & member . user_uuid , & mut conn ) . await . is_empty ( ) ;
// Policy only applies to non-Owner/non-Admin members who have accepted joining the org
// 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.
// Invited users still need to accept the invite and will get an error when they try to accept the invite.
@ -1296,46 +1295,46 @@ async fn put_policy(
& & member . status ! = UserOrgStatus ::Invited as i32
& & member . status ! = UserOrgStatus ::Invited as i32
{
{
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
let org = Organization ::find_by_uuid ( & member . org_uuid , & conn ) . await . unwrap ( ) ;
let org = Organization ::find_by_uuid ( & member . org_uuid , & mut conn ) . await . unwrap ( ) ;
let user = User ::find_by_uuid ( & member . user_uuid , & conn ) . await . unwrap ( ) ;
let user = User ::find_by_uuid ( & member . user_uuid , & mut conn ) . await . unwrap ( ) ;
mail ::send_2fa_removed_from_org ( & user . email , & org . name ) . await ? ;
mail ::send_2fa_removed_from_org ( & user . email , & org . name ) . await ? ;
}
}
member . delete ( & conn ) . await ? ;
member . delete ( & mut conn ) . await ? ;
}
}
}
}
}
}
// When 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 {
if pol_type_enum = = OrgPolicyType ::SingleOrg & & data . enabled {
for member in UserOrganization ::find_by_org ( & org_id , & conn ) . await . into_iter ( ) {
for member in UserOrganization ::find_by_org ( & org_id , & mut conn ) . await . into_iter ( ) {
// Policy only applies to non-Owner/non-Admin members who have accepted joining the org
// Policy only applies to non-Owner/non-Admin members who have accepted joining the org
// Exclude invited and revoked users when checking for this policy.
// 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.
// 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.
// We check if the count is larger then 1, because it includes this organization also.
if member . atype < UserOrgType ::Admin
if member . atype < UserOrgType ::Admin
& & member . status ! = UserOrgStatus ::Invited as i32
& & member . status ! = UserOrgStatus ::Invited as i32
& & UserOrganization ::count_accepted_and_confirmed_by_user ( & member . user_uuid , & conn ) . await > 1
& & UserOrganization ::count_accepted_and_confirmed_by_user ( & member . user_uuid , & mut conn ) . await > 1
{
{
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
let org = Organization ::find_by_uuid ( & member . org_uuid , & conn ) . await . unwrap ( ) ;
let org = Organization ::find_by_uuid ( & member . org_uuid , & mut conn ) . await . unwrap ( ) ;
let user = User ::find_by_uuid ( & member . user_uuid , & conn ) . await . unwrap ( ) ;
let user = User ::find_by_uuid ( & member . user_uuid , & mut conn ) . await . unwrap ( ) ;
mail ::send_single_org_removed_from_org ( & user . email , & org . name ) . await ? ;
mail ::send_single_org_removed_from_org ( & user . email , & org . name ) . await ? ;
}
}
member . delete ( & conn ) . await ? ;
member . delete ( & mut conn ) . await ? ;
}
}
}
}
}
}
let mut policy = match OrgPolicy ::find_by_org_and_type ( & org_id , pol_type_enum , & conn ) . await {
let mut policy = match OrgPolicy ::find_by_org_and_type ( & org_id , pol_type_enum , & mut conn ) . await {
Some ( p ) = > p ,
Some ( p ) = > p ,
None = > OrgPolicy ::new ( org_id , pol_type_enum , "{}" . to_string ( ) ) ,
None = > OrgPolicy ::new ( org_id , pol_type_enum , "{}" . to_string ( ) ) ,
} ;
} ;
policy . enabled = data . enabled ;
policy . enabled = data . enabled ;
policy . data = serde_json ::to_string ( & data . data ) ? ;
policy . data = serde_json ::to_string ( & data . data ) ? ;
policy . save ( & conn ) . await ? ;
policy . save ( & mut conn ) . await ? ;
Ok ( Json ( policy . to_json ( ) ) )
Ok ( Json ( policy . to_json ( ) ) )
}
}
@ -1408,7 +1407,7 @@ struct OrgImportData {
}
}
#[ post( " /organizations/<org_id>/import " , data = " <data> " ) ]
#[ post( " /organizations/<org_id>/import " , data = " <data> " ) ]
async fn import ( org_id : String , data : JsonUpcase < OrgImportData > , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn import ( org_id : String , data : JsonUpcase < OrgImportData > , headers : Headers , mut conn : DbConn ) -> EmptyResult {
let data = data . into_inner ( ) . data ;
let data = data . into_inner ( ) . data ;
// TODO: Currently we aren't storing the externalId's anywhere, so we also don't have a way
// TODO: Currently we aren't storing the externalId's anywhere, so we also don't have a way
@ -1417,7 +1416,7 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header
// as opposed to upstream which only removes auto-imported users.
// as opposed to upstream which only removes auto-imported users.
// User needs to be admin or owner to use the Directry Connector
// User needs to be admin or owner to use the Directry Connector
match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & conn ) . await {
match UserOrganization ::find_by_user_and_org ( & headers . user . uuid , & org_id , & mut conn ) . await {
Some ( user_org ) if user_org . atype > = UserOrgType ::Admin = > { /* Okay, nothing to do */ }
Some ( user_org ) if user_org . atype > = UserOrgType ::Admin = > { /* Okay, nothing to do */ }
Some ( _ ) = > err ! ( "User has insufficient permissions to use Directory Connector" ) ,
Some ( _ ) = > err ! ( "User has insufficient permissions to use Directory Connector" ) ,
None = > err ! ( "User not part of organization" ) ,
None = > err ! ( "User not part of organization" ) ,
@ -1426,13 +1425,14 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header
for user_data in & data . Users {
for user_data in & data . Users {
if user_data . Deleted {
if user_data . Deleted {
// If user is marked for deletion and it exists, delete it
// If user is marked for deletion and it exists, delete it
if let Some ( user_org ) = UserOrganization ::find_by_email_and_org ( & user_data . Email , & org_id , & conn ) . await {
if let Some ( user_org ) = UserOrganization ::find_by_email_and_org ( & user_data . Email , & org_id , & mut conn ) . await
user_org . delete ( & conn ) . await ? ;
{
user_org . delete ( & mut conn ) . await ? ;
}
}
// If user is not part of the organization, but it exists
// If user is not part of the organization, but it exists
} else if UserOrganization ::find_by_email_and_org ( & user_data . Email , & org_id , & conn ) . await . is_none ( ) {
} else if UserOrganization ::find_by_email_and_org ( & user_data . Email , & org_id , & mut conn ) . await . is_none ( ) {
if let Some ( user ) = User ::find_by_mail ( & user_data . Email , & conn ) . await {
if let Some ( user ) = User ::find_by_mail ( & user_data . Email , & mut conn ) . await {
let user_org_status = if CONFIG . mail_enabled ( ) {
let user_org_status = if CONFIG . mail_enabled ( ) {
UserOrgStatus ::Invited as i32
UserOrgStatus ::Invited as i32
} else {
} else {
@ -1444,10 +1444,10 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Header
new_org_user . atype = UserOrgType ::User as i32 ;
new_org_user . atype = UserOrgType ::User as i32 ;
new_org_user . status = user_org_status ;
new_org_user . status = user_org_status ;
new_org_user . save ( & conn ) . await ? ;
new_org_user . save ( & mut conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
let org_name = match Organization ::find_by_uuid ( & org_id , & conn ) . await {
let org_name = match Organization ::find_by_uuid ( & org_id , & mut conn ) . await {
Some ( org ) = > org . name ,
Some ( org ) = > org . name ,
None = > err ! ( "Error looking up organization" ) ,
None = > err ! ( "Error looking up organization" ) ,
} ;
} ;
@ -1468,10 +1468,10 @@ async fn import(org_id: String, data: JsonUpcase<OrgImportData>, 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 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 {
if data . OverwriteExisting {
for user_org in UserOrganization ::find_by_org_and_type ( & org_id , UserOrgType ::User , & conn ) . await {
for user_org in UserOrganization ::find_by_org_and_type ( & org_id , UserOrgType ::User , & mut conn ) . await {
if let Some ( user_email ) = User ::find_by_uuid ( & user_org . user_uuid , & conn ) . await . map ( | u | u . email ) {
if let Some ( user_email ) = User ::find_by_uuid ( & user_org . user_uuid , & mut conn ) . await . map ( | u | u . email ) {
if ! data . Users . iter ( ) . any ( | u | u . Email = = user_email ) {
if ! data . Users . iter ( ) . any ( | u | u . Email = = user_email ) {
user_org . delete ( & conn ) . await ? ;
user_org . delete ( & mut conn ) . await ? ;
}
}
}
}
}
}
@ -1485,9 +1485,9 @@ async fn deactivate_organization_user(
org_id : String ,
org_id : String ,
org_user_id : String ,
org_user_id : String ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
_deactivate_organization_user ( & org_id , & org_user_id , & headers , & conn ) . await
_deactivate_organization_user ( & org_id , & org_user_id , & headers , & mut conn ) . await
}
}
#[ put( " /organizations/<org_id>/users/deactivate " , data = " <data> " ) ]
#[ put( " /organizations/<org_id>/users/deactivate " , data = " <data> " ) ]
@ -1495,7 +1495,7 @@ async fn bulk_deactivate_organization_user(
org_id : String ,
org_id : String ,
data : JsonUpcase < Value > ,
data : JsonUpcase < Value > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data = data . into_inner ( ) . data ;
let data = data . into_inner ( ) . data ;
@ -1504,7 +1504,7 @@ async fn bulk_deactivate_organization_user(
Some ( org_users ) = > {
Some ( org_users ) = > {
for org_user_id in org_users {
for org_user_id in org_users {
let org_user_id = org_user_id . as_str ( ) . unwrap_or_default ( ) ;
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 {
let err_msg = match _deactivate_organization_user ( & org_id , org_user_id , & headers , & mut conn ) . await {
Ok ( _ ) = > String ::from ( "" ) ,
Ok ( _ ) = > String ::from ( "" ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
} ;
} ;
@ -1532,7 +1532,7 @@ async fn _deactivate_organization_user(
org_id : & str ,
org_id : & str ,
org_user_id : & str ,
org_user_id : & str ,
headers : & AdminHeaders ,
headers : & AdminHeaders ,
conn : & DbConn ,
conn : & mut DbConn ,
) -> EmptyResult {
) -> EmptyResult {
match UserOrganization ::find_by_uuid_and_org ( org_user_id , org_id , conn ) . await {
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 = > {
Some ( mut user_org ) if user_org . status > UserOrgStatus ::Revoked as i32 = > {
@ -1562,9 +1562,9 @@ async fn activate_organization_user(
org_id : String ,
org_id : String ,
org_user_id : String ,
org_user_id : String ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> EmptyResult {
) -> EmptyResult {
_activate_organization_user ( & org_id , & org_user_id , & headers , & conn ) . await
_activate_organization_user ( & org_id , & org_user_id , & headers , & mut conn ) . await
}
}
#[ put( " /organizations/<org_id>/users/activate " , data = " <data> " ) ]
#[ put( " /organizations/<org_id>/users/activate " , data = " <data> " ) ]
@ -1572,7 +1572,7 @@ async fn bulk_activate_organization_user(
org_id : String ,
org_id : String ,
data : JsonUpcase < Value > ,
data : JsonUpcase < Value > ,
headers : AdminHeaders ,
headers : AdminHeaders ,
conn : DbConn ,
mut conn : DbConn ,
) -> Json < Value > {
) -> Json < Value > {
let data = data . into_inner ( ) . data ;
let data = data . into_inner ( ) . data ;
@ -1581,7 +1581,7 @@ async fn bulk_activate_organization_user(
Some ( org_users ) = > {
Some ( org_users ) = > {
for org_user_id in org_users {
for org_user_id in org_users {
let org_user_id = org_user_id . as_str ( ) . unwrap_or_default ( ) ;
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 {
let err_msg = match _activate_organization_user ( & org_id , org_user_id , & headers , & mut conn ) . await {
Ok ( _ ) = > String ::from ( "" ) ,
Ok ( _ ) = > String ::from ( "" ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
Err ( e ) = > format ! ( "{:?}" , e ) ,
} ;
} ;
@ -1609,7 +1609,7 @@ async fn _activate_organization_user(
org_id : & str ,
org_id : & str ,
org_user_id : & str ,
org_user_id : & str ,
headers : & AdminHeaders ,
headers : & AdminHeaders ,
conn : & DbConn ,
conn : & mut DbConn ,
) -> EmptyResult {
) -> EmptyResult {
match UserOrganization ::find_by_uuid_and_org ( org_user_id , org_id , conn ) . await {
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 = > {
Some ( mut user_org ) if user_org . status < UserOrgStatus ::Accepted as i32 = > {