21
21
* for more details.
22
22
*/
23
23
24
- use std:: { borrow:: Cow , collections:: BTreeSet } ;
24
+ use std:: { borrow:: Cow , collections:: BTreeSet , fmt :: Display } ;
25
25
26
26
use aes:: cipher:: { block_padding:: Pkcs7 , BlockEncryptMut , KeyIvInit } ;
27
27
use jmap_proto:: types:: { collection:: Collection , property:: Property } ;
@@ -53,6 +53,7 @@ const CRYPT_HTML_HEADER: &str = include_str!("../../../../resources/htx/crypto_h
53
53
const CRYPT_HTML_FOOTER : & str = include_str ! ( "../../../../resources/htx/crypto_footer.htx" ) ;
54
54
const CRYPT_HTML_FORM : & str = include_str ! ( "../../../../resources/htx/crypto_form.htx" ) ;
55
55
const CRYPT_HTML_SUCCESS : & str = include_str ! ( "../../../../resources/htx/crypto_success.htx" ) ;
56
+ const CRYPT_HTML_DISABLED : & str = include_str ! ( "../../../../resources/htx/crypto_disabled.htx" ) ;
56
57
const CRYPT_HTML_ERROR : & str = include_str ! ( "../../../../resources/htx/crypto_error.htx" ) ;
57
58
58
59
#[ derive( Debug ) ]
@@ -75,9 +76,9 @@ pub enum EncryptionMethod {
75
76
76
77
#[ derive( Debug , serde:: Serialize , serde:: Deserialize ) ]
77
78
pub struct EncryptionParams {
78
- method : EncryptionMethod ,
79
- algo : Algorithm ,
80
- certs : Vec < Vec < u8 > > ,
79
+ pub method : EncryptionMethod ,
80
+ pub algo : Algorithm ,
81
+ pub certs : Vec < Vec < u8 > > ,
81
82
}
82
83
83
84
#[ async_trait:: async_trait]
@@ -496,7 +497,7 @@ fn try_parse_pem(bytes: &[u8]) -> Result<Option<(EncryptionMethod, Vec<Vec<u8>>)
496
497
Ok ( method. map ( |method| ( method, certs) ) )
497
498
}
498
499
499
- impl Serialize for EncryptionParams {
500
+ impl Serialize for & EncryptionParams {
500
501
fn serialize ( self ) -> Vec < u8 > {
501
502
let len = bincode:: serialized_size ( & self ) . unwrap_or_default ( ) ;
502
503
let mut buf = Vec :: with_capacity ( len as usize + 1 ) ;
@@ -529,7 +530,7 @@ impl Deserialize for EncryptionParams {
529
530
}
530
531
}
531
532
532
- impl ToBitmaps for EncryptionParams {
533
+ impl ToBitmaps for & EncryptionParams {
533
534
fn to_bitmaps ( & self , _: & mut Vec < store:: write:: Operation > , _: u8 , _: bool ) {
534
535
unreachable ! ( )
535
536
}
@@ -538,70 +539,65 @@ impl ToBitmaps for EncryptionParams {
538
539
impl JMAP {
539
540
// Code authorization flow, handles an authorization request
540
541
pub async fn handle_crypto_update ( & self , req : & mut HttpRequest ) -> HttpResponse {
541
- let response = match * req. method ( ) {
542
+ let mut response = String :: with_capacity (
543
+ CRYPT_HTML_HEADER . len ( ) + CRYPT_HTML_FOOTER . len ( ) + CRYPT_HTML_FORM . len ( ) ,
544
+ ) ;
545
+ response. push_str ( & CRYPT_HTML_HEADER . replace ( "@@@" , "/crypto" ) ) ;
546
+
547
+ match * req. method ( ) {
542
548
hyper:: Method :: POST => {
543
549
// Parse form
544
550
let form = match FormData :: from_request ( req, 1024 * 1024 ) . await {
545
551
Ok ( form) => form,
546
552
Err ( err) => return err,
547
553
} ;
548
554
549
- if let Err ( error) = self . validate_form ( form) . await {
550
- let mut response = String :: with_capacity (
551
- CRYPT_HTML_HEADER . len ( )
552
- + CRYPT_HTML_FOOTER . len ( )
553
- + CRYPT_HTML_ERROR . len ( )
554
- + error. len ( ) ,
555
- ) ;
556
-
557
- response. push_str ( & CRYPT_HTML_HEADER . replace ( "@@@" , "/crypto" ) ) ;
558
- response. push_str ( & CRYPT_HTML_ERROR . replace ( "@@@" , & error) ) ;
559
- response. push_str ( CRYPT_HTML_FOOTER ) ;
560
-
561
- response
562
- } else {
563
- let mut response = String :: with_capacity (
564
- CRYPT_HTML_HEADER . len ( )
565
- + CRYPT_HTML_FOOTER . len ( )
566
- + CRYPT_HTML_SUCCESS . len ( ) ,
567
- ) ;
568
-
569
- response. push_str ( & CRYPT_HTML_HEADER . replace ( "@@@" , "/crypto" ) ) ;
570
- response. push_str ( CRYPT_HTML_SUCCESS ) ;
571
- response. push_str ( CRYPT_HTML_FOOTER ) ;
572
-
573
- response
555
+ match self . validate_form ( form) . await {
556
+ Ok ( Some ( params) ) => {
557
+ response. push_str (
558
+ & CRYPT_HTML_SUCCESS
559
+ . replace (
560
+ "$$$" ,
561
+ format ! ( "{} ({})" , params. method, params. algo) . as_str ( ) ,
562
+ )
563
+ . replace ( "@@@" , params. certs . len ( ) . to_string ( ) . as_str ( ) ) ,
564
+ ) ;
565
+ }
566
+ Ok ( None ) => {
567
+ response. push_str ( CRYPT_HTML_DISABLED ) ;
568
+ }
569
+ Err ( error) => {
570
+ response. push_str ( & CRYPT_HTML_ERROR . replace ( "@@@" , & error) ) ;
571
+ }
574
572
}
575
573
}
576
574
577
575
hyper:: Method :: GET => {
578
- let mut response = String :: with_capacity (
579
- CRYPT_HTML_HEADER . len ( ) + CRYPT_HTML_FOOTER . len ( ) + CRYPT_HTML_FORM . len ( ) ,
580
- ) ;
581
-
582
- response. push_str ( & CRYPT_HTML_HEADER . replace ( "@@@" , "/crypto" ) ) ;
583
576
response. push_str ( CRYPT_HTML_FORM ) ;
584
- response. push_str ( CRYPT_HTML_FOOTER ) ;
585
-
586
- response
587
577
}
588
578
_ => unreachable ! ( ) ,
589
579
} ;
590
580
581
+ response. push_str ( CRYPT_HTML_FOOTER ) ;
582
+
591
583
HtmlResponse :: new ( response) . into_http_response ( )
592
584
}
593
585
594
- async fn validate_form ( & self , mut form : FormData ) -> Result < ( ) , Cow < str > > {
595
- if let ( Some ( certificate) , Some ( email) , Some ( password) , Some ( encryption) ) = (
596
- form. remove_bytes ( "certificate" ) ,
586
+ async fn validate_form (
587
+ & self ,
588
+ mut form : FormData ,
589
+ ) -> Result < Option < EncryptionParams > , Cow < str > > {
590
+ let certificate = form. remove_bytes ( "certificate" ) ;
591
+ if let ( Some ( email) , Some ( password) , Some ( encryption) ) = (
597
592
form. get ( "email" ) ,
598
593
form. get ( "password" ) ,
599
594
form. get ( "encryption" ) ,
600
595
) {
601
596
// Validate fields
602
597
if email. is_empty ( ) || password. is_empty ( ) {
603
598
return Err ( Cow :: from ( "Please enter your login and password" ) ) ;
604
- } else if encryption != "disable" && certificate. is_empty ( ) {
599
+ } else if encryption != "disable" && certificate. as_ref ( ) . map_or ( true , |c| c. is_empty ( ) )
600
+ {
605
601
return Err ( Cow :: from ( "Please select one or more certificates" ) ) ;
606
602
}
607
603
@@ -611,7 +607,8 @@ impl JMAP {
611
607
. await
612
608
. ok_or_else ( || Cow :: from ( "Invalid login or password" ) ) ?;
613
609
if encryption != "disable" {
614
- let ( method, certs) = try_parse_certs ( certificate) . map_err ( Cow :: from) ?;
610
+ let ( method, certs) =
611
+ try_parse_certs ( certificate. unwrap_or_default ( ) ) . map_err ( Cow :: from) ?;
615
612
let algo = match ( encryption, method) {
616
613
( "pgp-256" , EncryptionMethod :: PGP ) => Algorithm :: Aes256 ,
617
614
( "pgp-128" , EncryptionMethod :: PGP ) => Algorithm :: Aes128 ,
@@ -645,10 +642,12 @@ impl JMAP {
645
642
. with_account_id ( token. primary_id ( ) )
646
643
. with_collection ( Collection :: Principal )
647
644
. update_document ( 0 )
648
- . value ( Property :: Parameters , params, F_VALUE ) ;
645
+ . value ( Property :: Parameters , & params, F_VALUE ) ;
649
646
self . write_batch ( batch) . await . map_err ( |_| {
650
647
Cow :: from ( "Failed to save encryption parameters, please try again later" )
651
648
} ) ?;
649
+
650
+ Ok ( Some ( params) )
652
651
} else {
653
652
// Remove encryption params
654
653
let mut batch = BatchBuilder :: new ( ) ;
@@ -660,11 +659,28 @@ impl JMAP {
660
659
self . write_batch ( batch) . await . map_err ( |_| {
661
660
Cow :: from ( "Failed to save encryption parameters, please try again later" )
662
661
} ) ?;
662
+ Ok ( None )
663
663
}
664
-
665
- Ok ( ( ) )
666
664
} else {
667
665
Err ( Cow :: from ( "Missing form parameters" ) )
668
666
}
669
667
}
670
668
}
669
+
670
+ impl Display for EncryptionMethod {
671
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
672
+ match self {
673
+ EncryptionMethod :: PGP => write ! ( f, "PGP" ) ,
674
+ EncryptionMethod :: SMIME => write ! ( f, "S/MIME" ) ,
675
+ }
676
+ }
677
+ }
678
+
679
+ impl Display for Algorithm {
680
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
681
+ match self {
682
+ Algorithm :: Aes128 => write ! ( f, "AES-128" ) ,
683
+ Algorithm :: Aes256 => write ! ( f, "AES-256" ) ,
684
+ }
685
+ }
686
+ }
0 commit comments