@ -11,6 +11,8 @@ use crate::{
mail , CONFIG ,
mail , CONFIG ,
} ;
} ;
use futures ::{ stream , stream ::StreamExt } ;
pub fn routes ( ) -> Vec < Route > {
pub fn routes ( ) -> Vec < Route > {
routes ! [
routes ! [
get_contacts ,
get_contacts ,
@ -36,13 +38,17 @@ pub fn routes() -> Vec<Route> {
// region get
// region get
#[ get( " /emergency-access/trusted " ) ]
#[ get( " /emergency-access/trusted " ) ]
fn get_contacts ( headers : Headers , conn : DbConn ) -> JsonResult {
async fn get_contacts ( headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let emergency_access_list = EmergencyAccess ::find_all_by_grantor_uuid ( & headers . user . uuid , & conn ) ;
let emergency_access_list_json =
stream ::iter ( EmergencyAccess ::find_all_by_grantor_uuid ( & headers . user . uuid , & conn ) . await )
let emergency_access_list_json : Vec < Value > =
. then ( | e | async {
emergency_access_list . iter ( ) . map ( | e | e . to_json_grantee_details ( & conn ) ) . collect ( ) ;
let e = e ; // Move out this single variable
e . to_json_grantee_details ( & conn ) . await
} )
. collect ::< Vec < Value > > ( )
. await ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"Data" : emergency_access_list_json ,
"Data" : emergency_access_list_json ,
@ -52,13 +58,17 @@ fn get_contacts(headers: Headers, conn: DbConn) -> JsonResult {
}
}
#[ get( " /emergency-access/granted " ) ]
#[ get( " /emergency-access/granted " ) ]
fn get_grantees ( headers : Headers , conn : DbConn ) -> JsonResult {
async fn get_grantees ( headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let emergency_access_list = EmergencyAccess ::find_all_by_grantee_uuid ( & headers . user . uuid , & conn ) ;
let emergency_access_list_json =
stream ::iter ( EmergencyAccess ::find_all_by_grantee_uuid ( & headers . user . uuid , & conn ) . await )
let emergency_access_list_json : Vec < Value > =
. then ( | e | async {
emergency_access_list . iter ( ) . map ( | e | e . to_json_grantor_details ( & conn ) ) . collect ( ) ;
let e = e ; // Move out this single variable
e . to_json_grantor_details ( & conn ) . await
} )
. collect ::< Vec < Value > > ( )
. await ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"Data" : emergency_access_list_json ,
"Data" : emergency_access_list_json ,
@ -68,11 +78,11 @@ fn get_grantees(headers: Headers, conn: DbConn) -> JsonResult {
}
}
#[ get( " /emergency-access/<emer_id> " ) ]
#[ get( " /emergency-access/<emer_id> " ) ]
fn get_emergency_access ( emer_id : String , conn : DbConn ) -> JsonResult {
async fn get_emergency_access ( emer_id : String , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emergency_access ) = > Ok ( Json ( emergency_access . to_json_grantee_details ( & conn ) )) ,
Some ( emergency_access ) = > Ok ( Json ( emergency_access . to_json_grantee_details ( & conn ) .await )) ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
}
}
}
}
@ -90,17 +100,25 @@ struct EmergencyAccessUpdateData {
}
}
#[ put( " /emergency-access/<emer_id> " , data = " <data> " ) ]
#[ put( " /emergency-access/<emer_id> " , data = " <data> " ) ]
fn put_emergency_access ( emer_id : String , data : JsonUpcase < EmergencyAccessUpdateData > , conn : DbConn ) -> JsonResult {
async fn put_emergency_access (
post_emergency_access ( emer_id , data , conn )
emer_id : String ,
data : JsonUpcase < EmergencyAccessUpdateData > ,
conn : DbConn ,
) -> JsonResult {
post_emergency_access ( emer_id , data , conn ) . await
}
}
#[ post( " /emergency-access/<emer_id> " , data = " <data> " ) ]
#[ post( " /emergency-access/<emer_id> " , data = " <data> " ) ]
fn post_emergency_access ( emer_id : String , data : JsonUpcase < EmergencyAccessUpdateData > , conn : DbConn ) -> JsonResult {
async fn post_emergency_access (
emer_id : String ,
data : JsonUpcase < EmergencyAccessUpdateData > ,
conn : DbConn ,
) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let data : EmergencyAccessUpdateData = data . into_inner ( ) . data ;
let data : EmergencyAccessUpdateData = data . into_inner ( ) . data ;
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emergency_access ) = > emergency_access ,
Some ( emergency_access ) = > emergency_access ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -114,7 +132,7 @@ fn post_emergency_access(emer_id: String, data: JsonUpcase<EmergencyAccessUpdate
emergency_access . wait_time_days = data . WaitTimeDays ;
emergency_access . wait_time_days = data . WaitTimeDays ;
emergency_access . key_encrypted = data . KeyEncrypted ;
emergency_access . key_encrypted = data . KeyEncrypted ;
emergency_access . save ( & conn ) ? ;
emergency_access . save ( & conn ) . await ? ;
Ok ( Json ( emergency_access . to_json ( ) ) )
Ok ( Json ( emergency_access . to_json ( ) ) )
}
}
@ -123,12 +141,12 @@ fn post_emergency_access(emer_id: String, data: JsonUpcase<EmergencyAccessUpdate
// region delete
// region delete
#[ delete( " /emergency-access/<emer_id> " ) ]
#[ delete( " /emergency-access/<emer_id> " ) ]
fn delete_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn delete_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let grantor_user = headers . user ;
let grantor_user = headers . user ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > {
Some ( emer ) = > {
if emer . grantor_uuid ! = grantor_user . uuid & & emer . grantee_uuid ! = Some ( grantor_user . uuid ) {
if emer . grantor_uuid ! = grantor_user . uuid & & emer . grantee_uuid ! = Some ( grantor_user . uuid ) {
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
@ -137,13 +155,13 @@ fn delete_emergency_access(emer_id: String, headers: Headers, conn: DbConn) -> E
}
}
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
emergency_access . delete ( & conn ) ? ;
emergency_access . delete ( & conn ) . await ? ;
Ok ( ( ) )
Ok ( ( ) )
}
}
#[ post( " /emergency-access/<emer_id>/delete " ) ]
#[ post( " /emergency-access/<emer_id>/delete " ) ]
fn post_delete_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn post_delete_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
delete_emergency_access ( emer_id , headers , conn )
delete_emergency_access ( emer_id , headers , conn ) . await
}
}
// endregion
// endregion
@ -159,7 +177,7 @@ struct EmergencyAccessInviteData {
}
}
#[ post( " /emergency-access/invite " , data = " <data> " ) ]
#[ post( " /emergency-access/invite " , data = " <data> " ) ]
fn send_invite ( data : JsonUpcase < EmergencyAccessInviteData > , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn send_invite ( data : JsonUpcase < EmergencyAccessInviteData > , headers : Headers , conn : DbConn ) -> EmptyResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let data : EmergencyAccessInviteData = data . into_inner ( ) . data ;
let data : EmergencyAccessInviteData = data . into_inner ( ) . data ;
@ -180,7 +198,7 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
err ! ( "You can not set yourself as an emergency contact." )
err ! ( "You can not set yourself as an emergency contact." )
}
}
let grantee_user = match User ::find_by_mail ( & email , & conn ) {
let grantee_user = match User ::find_by_mail ( & email , & conn ) . await {
None = > {
None = > {
if ! CONFIG . invitations_allowed ( ) {
if ! CONFIG . invitations_allowed ( ) {
err ! ( format! ( "Grantee user does not exist: {}" , email ) )
err ! ( format! ( "Grantee user does not exist: {}" , email ) )
@ -192,11 +210,11 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
if ! CONFIG . mail_enabled ( ) {
if ! CONFIG . mail_enabled ( ) {
let invitation = Invitation ::new ( email . clone ( ) ) ;
let invitation = Invitation ::new ( email . clone ( ) ) ;
invitation . save ( & conn ) ? ;
invitation . save ( & conn ) . await ? ;
}
}
let mut user = User ::new ( email . clone ( ) ) ;
let mut user = User ::new ( email . clone ( ) ) ;
user . save ( & conn ) ? ;
user . save ( & conn ) . await ? ;
user
user
}
}
Some ( user ) = > user ,
Some ( user ) = > user ,
@ -208,6 +226,7 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
& grantee_user . email ,
& grantee_user . email ,
& conn ,
& conn ,
)
)
. await
. is_some ( )
. is_some ( )
{
{
err ! ( format! ( "Grantee user already invited: {}" , email ) )
err ! ( format! ( "Grantee user already invited: {}" , email ) )
@ -220,7 +239,7 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
new_type ,
new_type ,
wait_time_days ,
wait_time_days ,
) ;
) ;
new_emergency_access . save ( & conn ) ? ;
new_emergency_access . save ( & conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
mail ::send_emergency_access_invite (
mail ::send_emergency_access_invite (
@ -232,9 +251,9 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
) ? ;
) ? ;
} else {
} else {
// Automatically mark user as accepted if no email invites
// Automatically mark user as accepted if no email invites
match User ::find_by_mail ( & email , & conn ) {
match User ::find_by_mail ( & email , & conn ) . await {
Some ( user ) = > {
Some ( user ) = > {
match accept_invite_process ( user . uuid , new_emergency_access . uuid , Some ( email ) , conn . borrow ( ) ) {
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 ( ) ) ,
Err ( e ) = > err ! ( e . to_string ( ) ) ,
}
}
@ -247,10 +266,10 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
}
}
#[ post( " /emergency-access/<emer_id>/reinvite " ) ]
#[ post( " /emergency-access/<emer_id>/reinvite " ) ]
fn resend_invite ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
async fn resend_invite ( emer_id : String , headers : Headers , conn : DbConn ) -> EmptyResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -268,7 +287,7 @@ fn resend_invite(emer_id: String, headers: Headers, conn: DbConn) -> EmptyResult
None = > err ! ( "Email not valid." ) ,
None = > err ! ( "Email not valid." ) ,
} ;
} ;
let grantee_user = match User ::find_by_mail ( & email , & conn ) {
let grantee_user = match User ::find_by_mail ( & email , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantee user not found." ) ,
None = > err ! ( "Grantee user not found." ) ,
} ;
} ;
@ -284,13 +303,15 @@ fn resend_invite(emer_id: String, headers: Headers, conn: DbConn) -> EmptyResult
Some ( grantor_user . email ) ,
Some ( grantor_user . email ) ,
) ? ;
) ? ;
} else {
} else {
if Invitation ::find_by_mail ( & email , & conn ) . is_none ( ) {
if Invitation ::find_by_mail ( & email , & conn ) . await . is_none ( ) {
let invitation = Invitation ::new ( email ) ;
let invitation = Invitation ::new ( email ) ;
invitation . save ( & conn ) ? ;
invitation . save ( & conn ) . await ? ;
}
}
// Automatically mark user as accepted if no email invites
// Automatically mark user as accepted if no email invites
match accept_invite_process ( grantee_user . uuid , emergency_access . uuid , emergency_access . email , conn . borrow ( ) ) {
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 ( ) ) ,
Err ( e ) = > err ! ( e . to_string ( ) ) ,
}
}
@ -306,28 +327,28 @@ struct AcceptData {
}
}
#[ post( " /emergency-access/<emer_id>/accept " , data = " <data> " ) ]
#[ post( " /emergency-access/<emer_id>/accept " , data = " <data> " ) ]
fn accept_invite ( emer_id : String , data : JsonUpcase < AcceptData > , conn : DbConn ) -> EmptyResult {
async fn accept_invite ( emer_id : String , data : JsonUpcase < AcceptData > , conn : DbConn ) -> EmptyResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let data : AcceptData = data . into_inner ( ) . data ;
let data : AcceptData = data . into_inner ( ) . data ;
let token = & data . Token ;
let token = & data . Token ;
let claims = decode_emergency_access_invite ( token ) ? ;
let claims = decode_emergency_access_invite ( token ) ? ;
let grantee_user = match User ::find_by_mail ( & claims . email , & conn ) {
let grantee_user = match User ::find_by_mail ( & claims . email , & conn ) . await {
Some ( user ) = > {
Some ( user ) = > {
Invitation ::take ( & claims . email , & conn ) ;
Invitation ::take ( & claims . email , & conn ) .await ;
user
user
}
}
None = > err ! ( "Invited user not found" ) ,
None = > err ! ( "Invited user not found" ) ,
} ;
} ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
// get grantor user to send Accepted email
// get grantor user to send Accepted email
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
@ -336,7 +357,7 @@ fn accept_invite(emer_id: String, data: JsonUpcase<AcceptData>, conn: DbConn) ->
& & ( claims . grantor_name . is_some ( ) & & grantor_user . name = = claims . grantor_name . unwrap ( ) )
& & ( claims . grantor_name . is_some ( ) & & grantor_user . name = = claims . grantor_name . unwrap ( ) )
& & ( claims . grantor_email . is_some ( ) & & grantor_user . email = = claims . grantor_email . unwrap ( ) )
& & ( 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 ) {
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 ( ) ) ,
Err ( e ) = > err ! ( e . to_string ( ) ) ,
}
}
@ -351,8 +372,13 @@ fn accept_invite(emer_id: String, data: JsonUpcase<AcceptData>, conn: DbConn) ->
}
}
}
}
fn accept_invite_process ( grantee_uuid : String , emer_id : String , email : Option < String > , conn : & DbConn ) -> EmptyResult {
async fn accept_invite_process (
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , conn ) {
grantee_uuid : String ,
emer_id : String ,
email : Option < String > ,
conn : & DbConn ,
) -> EmptyResult {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -369,7 +395,7 @@ fn accept_invite_process(grantee_uuid: String, emer_id: String, email: Option<St
emergency_access . status = EmergencyAccessStatus ::Accepted as i32 ;
emergency_access . status = EmergencyAccessStatus ::Accepted as i32 ;
emergency_access . grantee_uuid = Some ( grantee_uuid ) ;
emergency_access . grantee_uuid = Some ( grantee_uuid ) ;
emergency_access . email = None ;
emergency_access . email = None ;
emergency_access . save ( conn )
emergency_access . save ( conn ) . await
}
}
#[ derive(Deserialize) ]
#[ derive(Deserialize) ]
@ -379,7 +405,7 @@ struct ConfirmData {
}
}
#[ post( " /emergency-access/<emer_id>/confirm " , data = " <data> " ) ]
#[ post( " /emergency-access/<emer_id>/confirm " , data = " <data> " ) ]
fn confirm_emergency_access (
async fn confirm_emergency_access (
emer_id : String ,
emer_id : String ,
data : JsonUpcase < ConfirmData > ,
data : JsonUpcase < ConfirmData > ,
headers : Headers ,
headers : Headers ,
@ -391,7 +417,7 @@ fn confirm_emergency_access(
let data : ConfirmData = data . into_inner ( ) . data ;
let data : ConfirmData = data . into_inner ( ) . data ;
let key = data . Key ;
let key = data . Key ;
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -402,13 +428,13 @@ fn confirm_emergency_access(
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & confirming_user . uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & confirming_user . uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantee user not found." ) ,
None = > err ! ( "Grantee user not found." ) ,
} ;
} ;
@ -417,7 +443,7 @@ fn confirm_emergency_access(
emergency_access . key_encrypted = Some ( key ) ;
emergency_access . key_encrypted = Some ( key ) ;
emergency_access . email = None ;
emergency_access . email = None ;
emergency_access . save ( & conn ) ? ;
emergency_access . save ( & conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
mail ::send_emergency_access_invite_confirmed ( & grantee_user . email , & grantor_user . name ) ? ;
mail ::send_emergency_access_invite_confirmed ( & grantee_user . email , & grantor_user . name ) ? ;
@ -433,11 +459,11 @@ fn confirm_emergency_access(
// region access emergency access
// region access emergency access
#[ post( " /emergency-access/<emer_id>/initiate " ) ]
#[ post( " /emergency-access/<emer_id>/initiate " ) ]
fn initiate_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn initiate_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let initiating_user = headers . user ;
let initiating_user = headers . user ;
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -448,7 +474,7 @@ fn initiate_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
@ -458,7 +484,7 @@ fn initiate_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
emergency_access . updated_at = now ;
emergency_access . updated_at = now ;
emergency_access . recovery_initiated_at = Some ( now ) ;
emergency_access . recovery_initiated_at = Some ( now ) ;
emergency_access . last_notification_at = Some ( now ) ;
emergency_access . last_notification_at = Some ( now ) ;
emergency_access . save ( & conn ) ? ;
emergency_access . save ( & conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
mail ::send_emergency_access_recovery_initiated (
mail ::send_emergency_access_recovery_initiated (
@ -472,11 +498,11 @@ fn initiate_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
}
}
#[ post( " /emergency-access/<emer_id>/approve " ) ]
#[ post( " /emergency-access/<emer_id>/approve " ) ]
fn approve_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn approve_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let approving_user = headers . user ;
let approving_user = headers . user ;
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -487,19 +513,19 @@ fn approve_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & approving_user . uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & approving_user . uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantee user not found." ) ,
None = > err ! ( "Grantee user not found." ) ,
} ;
} ;
emergency_access . status = EmergencyAccessStatus ::RecoveryApproved as i32 ;
emergency_access . status = EmergencyAccessStatus ::RecoveryApproved as i32 ;
emergency_access . save ( & conn ) ? ;
emergency_access . save ( & conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
mail ::send_emergency_access_recovery_approved ( & grantee_user . email , & grantor_user . name ) ? ;
mail ::send_emergency_access_recovery_approved ( & grantee_user . email , & grantor_user . name ) ? ;
@ -511,11 +537,11 @@ fn approve_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
}
}
#[ post( " /emergency-access/<emer_id>/reject " ) ]
#[ post( " /emergency-access/<emer_id>/reject " ) ]
fn reject_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn reject_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let rejecting_user = headers . user ;
let rejecting_user = headers . user ;
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let mut emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -527,19 +553,19 @@ fn reject_emergency_access(emer_id: String, headers: Headers, conn: DbConn) -> J
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & rejecting_user . uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & rejecting_user . uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
if let Some ( grantee_uuid ) = emergency_access . grantee_uuid . as_ref ( ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) {
let grantee_user = match User ::find_by_uuid ( grantee_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantee user not found." ) ,
None = > err ! ( "Grantee user not found." ) ,
} ;
} ;
emergency_access . status = EmergencyAccessStatus ::Confirmed as i32 ;
emergency_access . status = EmergencyAccessStatus ::Confirmed as i32 ;
emergency_access . save ( & conn ) ? ;
emergency_access . save ( & conn ) . await ? ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
mail ::send_emergency_access_recovery_rejected ( & grantee_user . email , & grantor_user . name ) ? ;
mail ::send_emergency_access_recovery_rejected ( & grantee_user . email , & grantor_user . name ) ? ;
@ -555,12 +581,12 @@ fn reject_emergency_access(emer_id: String, headers: Headers, conn: DbConn) -> J
// region action
// region action
#[ post( " /emergency-access/<emer_id>/view " ) ]
#[ post( " /emergency-access/<emer_id>/view " ) ]
fn view_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn view_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let requesting_user = headers . user ;
let requesting_user = headers . user ;
let host = headers . host ;
let host = headers . host ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -569,10 +595,13 @@ fn view_emergency_access(emer_id: String, headers: Headers, conn: DbConn) -> Jso
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let ciphers = Cipher ::find_owned_by_user ( & emergency_access . grantor_uuid , & conn ) ;
let ciphers_json = stream ::iter ( Cipher ::find_owned_by_user ( & emergency_access . grantor_uuid , & conn ) . await )
. then ( | c | async {
let ciphers_json : Vec < Value > =
let c = c ; // Move out this single variable
ciphers . iter ( ) . map ( | c | c . to_json ( & host , & emergency_access . grantor_uuid , & conn ) ) . collect ( ) ;
c . to_json ( & host , & emergency_access . grantor_uuid , & conn ) . await
} )
. collect ::< Vec < Value > > ( )
. await ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"Ciphers" : ciphers_json ,
"Ciphers" : ciphers_json ,
@ -582,11 +611,11 @@ fn view_emergency_access(emer_id: String, headers: Headers, conn: DbConn) -> Jso
}
}
#[ post( " /emergency-access/<emer_id>/takeover " ) ]
#[ post( " /emergency-access/<emer_id>/takeover " ) ]
fn takeover_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn takeover_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
check_emergency_access_allowed ( ) ? ;
check_emergency_access_allowed ( ) ? ;
let requesting_user = headers . user ;
let requesting_user = headers . user ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -595,7 +624,7 @@ fn takeover_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
@ -616,7 +645,7 @@ struct EmergencyAccessPasswordData {
}
}
#[ post( " /emergency-access/<emer_id>/password " , data = " <data> " ) ]
#[ post( " /emergency-access/<emer_id>/password " , data = " <data> " ) ]
fn password_emergency_access (
async fn password_emergency_access (
emer_id : String ,
emer_id : String ,
data : JsonUpcase < EmergencyAccessPasswordData > ,
data : JsonUpcase < EmergencyAccessPasswordData > ,
headers : Headers ,
headers : Headers ,
@ -629,7 +658,7 @@ fn password_emergency_access(
let key = data . Key ;
let key = data . Key ;
let requesting_user = headers . user ;
let requesting_user = headers . user ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -638,7 +667,7 @@ fn password_emergency_access(
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let mut grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) {
let mut grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
@ -646,18 +675,15 @@ fn password_emergency_access(
// change grantor_user password
// change grantor_user password
grantor_user . set_password ( new_master_password_hash , None ) ;
grantor_user . set_password ( new_master_password_hash , None ) ;
grantor_user . akey = key ;
grantor_user . akey = key ;
grantor_user . save ( & conn ) ? ;
grantor_user . save ( & conn ) . await ? ;
// Disable TwoFactor providers since they will otherwise block logins
// Disable TwoFactor providers since they will otherwise block logins
TwoFactor ::delete_all_by_user ( & grantor_user . uuid , & conn ) ? ;
TwoFactor ::delete_all_by_user ( & grantor_user . uuid , & conn ) . await ? ;
// Removing owner, check that there are at least another owner
let user_org_grantor = UserOrganization ::find_any_state_by_user ( & grantor_user . uuid , & conn ) ;
// Remove grantor from all organisations unless Owner
// Remove grantor from all organisations unless Owner
for user_org in user_org_grantor {
for user_org in UserOrganization ::find_any_state_by_user ( & grantor_user . uuid , & conn ) . await {
if user_org . atype ! = UserOrgType ::Owner as i32 {
if user_org . atype ! = UserOrgType ::Owner as i32 {
user_org . delete ( & conn ) ? ;
user_org . delete ( & conn ) . await ? ;
}
}
}
}
Ok ( ( ) )
Ok ( ( ) )
@ -666,9 +692,9 @@ fn password_emergency_access(
// endregion
// endregion
#[ get( " /emergency-access/<emer_id>/policies " ) ]
#[ get( " /emergency-access/<emer_id>/policies " ) ]
fn policies_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
async fn policies_emergency_access ( emer_id : String , headers : Headers , conn : DbConn ) -> JsonResult {
let requesting_user = headers . user ;
let requesting_user = headers . user ;
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) {
let emergency_access = match EmergencyAccess ::find_by_uuid ( & emer_id , & conn ) . await {
Some ( emer ) = > emer ,
Some ( emer ) = > emer ,
None = > err ! ( "Emergency access not valid." ) ,
None = > err ! ( "Emergency access not valid." ) ,
} ;
} ;
@ -677,13 +703,13 @@ fn policies_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
err ! ( "Emergency access not valid." )
err ! ( "Emergency access not valid." )
}
}
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) {
let grantor_user = match User ::find_by_uuid ( & emergency_access . grantor_uuid , & conn ) . await {
Some ( user ) = > user ,
Some ( user ) = > user ,
None = > err ! ( "Grantor user not found." ) ,
None = > err ! ( "Grantor user not found." ) ,
} ;
} ;
let policies = OrgPolicy ::find_confirmed_by_user ( & grantor_user . uuid , & conn ) ;
let policies = OrgPolicy ::find_confirmed_by_user ( & grantor_user . uuid , & conn ) ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
let policies_json : Vec < Value > = policies . await . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
Ok ( Json ( json ! ( {
Ok ( Json ( json ! ( {
"Data" : policies_json ,
"Data" : policies_json ,
@ -716,7 +742,7 @@ pub async fn emergency_request_timeout_job(pool: DbPool) {
}
}
if let Ok ( conn ) = pool . get ( ) . await {
if let Ok ( conn ) = pool . get ( ) . await {
let emergency_access_list = EmergencyAccess ::find_all_recoveries ( & conn ) ;
let emergency_access_list = EmergencyAccess ::find_all_recoveries ( & conn ) .await ;
if emergency_access_list . is_empty ( ) {
if emergency_access_list . is_empty ( ) {
debug ! ( "No emergency request timeout to approve" ) ;
debug ! ( "No emergency request timeout to approve" ) ;
@ -728,15 +754,17 @@ pub async fn emergency_request_timeout_job(pool: DbPool) {
> = emer . recovery_initiated_at . unwrap ( ) + Duration ::days ( emer . wait_time_days as i64 )
> = emer . recovery_initiated_at . unwrap ( ) + Duration ::days ( emer . wait_time_days as i64 )
{
{
emer . status = EmergencyAccessStatus ::RecoveryApproved as i32 ;
emer . status = EmergencyAccessStatus ::RecoveryApproved as i32 ;
emer . save ( & conn ) . expect ( "Cannot save emergency access on job" ) ;
emer . save ( & conn ) . await . expect ( "Cannot save emergency access on job" ) ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
// get grantor user to send Accepted email
// get grantor user to send Accepted email
let grantor_user = User ::find_by_uuid ( & emer . grantor_uuid , & conn ) . expect ( "Grantor user not found." ) ;
let grantor_user =
User ::find_by_uuid ( & emer . grantor_uuid , & conn ) . await . expect ( "Grantor user not found." ) ;
// get grantee user to send Accepted email
// get grantee user to send Accepted email
let grantee_user =
let grantee_user =
User ::find_by_uuid ( & emer . grantee_uuid . clone ( ) . expect ( "Grantee user invalid." ) , & conn )
User ::find_by_uuid ( & emer . grantee_uuid . clone ( ) . expect ( "Grantee user invalid." ) , & conn )
. await
. expect ( "Grantee user not found." ) ;
. expect ( "Grantee user not found." ) ;
mail ::send_emergency_access_recovery_timed_out (
mail ::send_emergency_access_recovery_timed_out (
@ -763,7 +791,7 @@ pub async fn emergency_notification_reminder_job(pool: DbPool) {
}
}
if let Ok ( conn ) = pool . get ( ) . await {
if let Ok ( conn ) = pool . get ( ) . await {
let emergency_access_list = EmergencyAccess ::find_all_recoveries ( & conn ) ;
let emergency_access_list = EmergencyAccess ::find_all_recoveries ( & conn ) .await ;
if emergency_access_list . is_empty ( ) {
if emergency_access_list . is_empty ( ) {
debug ! ( "No emergency request reminder notification to send" ) ;
debug ! ( "No emergency request reminder notification to send" ) ;
@ -777,15 +805,17 @@ pub async fn emergency_notification_reminder_job(pool: DbPool) {
| | ( emer . last_notification_at . is_some ( )
| | ( emer . last_notification_at . is_some ( )
& & Utc ::now ( ) . naive_utc ( ) > = emer . last_notification_at . unwrap ( ) + Duration ::days ( 1 ) ) )
& & Utc ::now ( ) . naive_utc ( ) > = emer . last_notification_at . unwrap ( ) + Duration ::days ( 1 ) ) )
{
{
emer . save ( & conn ) . expect ( "Cannot save emergency access on job" ) ;
emer . save ( & conn ) . await . expect ( "Cannot save emergency access on job" ) ;
if CONFIG . mail_enabled ( ) {
if CONFIG . mail_enabled ( ) {
// get grantor user to send Accepted email
// get grantor user to send Accepted email
let grantor_user = User ::find_by_uuid ( & emer . grantor_uuid , & conn ) . expect ( "Grantor user not found." ) ;
let grantor_user =
User ::find_by_uuid ( & emer . grantor_uuid , & conn ) . await . expect ( "Grantor user not found." ) ;
// get grantee user to send Accepted email
// get grantee user to send Accepted email
let grantee_user =
let grantee_user =
User ::find_by_uuid ( & emer . grantee_uuid . clone ( ) . expect ( "Grantee user invalid." ) , & conn )
User ::find_by_uuid ( & emer . grantee_uuid . clone ( ) . expect ( "Grantee user invalid." ) , & conn )
. await
. expect ( "Grantee user not found." ) ;
. expect ( "Grantee user not found." ) ;
mail ::send_emergency_access_recovery_reminder (
mail ::send_emergency_access_recovery_reminder (