@@ -42,15 +42,16 @@ pub struct FetchedRecords {
4242}
4343
4444impl FetchedRecords {
45- pub fn get_record < R : CloudKitRecord > ( & self , record_id : & str , key : Option < & PCSKey > ) -> R {
45+ pub fn get_record < R : CloudKitRecord > ( & self , record_id : & str , key : Option < & PCSKeys > ) -> R {
4646 self . responses . iter ( ) . find_map ( |response| {
4747 let r = response. record_retrieve_response . as_ref ( ) . expect ( "No retrieve response?" ) . record . as_ref ( ) . expect ( "No record?" ) ;
4848 if r. record_identifier . as_ref ( ) . expect ( "No record id?" ) . value . as_ref ( ) . expect ( "No identifier" ) . name . as_ref ( ) . expect ( "No name?" ) == record_id {
4949 let got_type = r. r#type . as_ref ( ) . expect ( "no TYpe" ) . name . as_ref ( ) . expect ( "No ta" ) ;
5050 if got_type. as_str ( ) != R :: record_type ( ) {
5151 panic ! ( "Wrong record type, got {} expected {}" , got_type, R :: record_type( ) ) ;
5252 }
53- Some ( R :: from_record_encrypted ( & r. record_field , key. map ( |k| ( k, r. record_identifier . as_ref ( ) . unwrap ( ) ) ) ) )
53+ let key = key. map ( |k| pcs_key_for_record ( r, k) . expect ( "PCS key failed" ) ) ;
54+ Some ( R :: from_record_encrypted ( & r. record_field , key. as_ref ( ) . map ( |k| ( k, r. record_identifier . as_ref ( ) . unwrap ( ) ) ) ) )
5455 } else { None }
5556 } ) . expect ( "No record found?" )
5657 }
@@ -98,6 +99,13 @@ pub trait CloudKitOp {
9899 }
99100}
100101
102+ pub fn pcs_key_for_record ( record : & Record , keys : & PCSKeys ) -> Result < PCSKey , PushError > {
103+ let Some ( protection) = & record. protection_info else {
104+ return Ok ( keys. default_record_key . clone ( ) . unwrap ( ) )
105+ } ;
106+ keys. decode_record_protection ( protection)
107+ }
108+
101109pub struct UploadAssetOperation ( pub cloudkit_proto:: AssetUploadTokenRetrieveRequest ) ;
102110impl CloudKitOp for UploadAssetOperation {
103111 type Response = cloudkit_proto:: AssetUploadTokenRetrieveResponse ;
@@ -178,15 +186,35 @@ impl CloudKitOp for SaveRecordOperation {
178186}
179187
180188impl SaveRecordOperation {
181- pub fn new < R : CloudKitRecord > ( id : RecordIdentifier , record : R , key : Option < & PCSKey > , update : bool ) -> Self {
189+ pub fn new < R : CloudKitRecord > ( id : RecordIdentifier , record : R , key : Option < & PCSKeys > , update : bool ) -> Self {
190+ let mut pcs_key_id: Option < Vec < u8 > > = None ;
191+ let mut protection_info: Option < ProtectionInfo > = None ;
192+ let mut pcs_key: Option < PCSKey > = None ;
193+
194+ if let Some ( key) = key {
195+ if let Some ( global) = & key. default_record_key {
196+ pcs_key_id = Some ( global. key_id ( ) . unwrap ( ) [ ..4 ] . to_vec ( ) ) ;
197+ pcs_key = Some ( global. clone ( ) ) ;
198+ } else {
199+ // create a key for this record
200+ let record_protection = PCSShareProtection :: create ( & key. zone_keys [ 0 ] , & [ ] ) . unwrap ( ) ;
201+ let der = rasn:: der:: encode ( & record_protection) . unwrap ( ) ;
202+ protection_info = Some ( ProtectionInfo {
203+ protection_info_tag : Some ( encode_hex ( & sha1 ( & der) ) . to_uppercase ( ) ) ,
204+ protection_info : Some ( der) ,
205+ } ) ;
206+ }
207+ }
208+
182209 Self ( cloudkit_proto:: RecordSaveRequest {
183210 record : Some ( cloudkit_proto:: Record {
184211 record_identifier : Some ( id. clone ( ) ) ,
185212 r#type : Some ( cloudkit_proto:: record:: Type {
186213 name : Some ( R :: record_type ( ) . to_string ( ) )
187214 } ) ,
188- record_field : record. to_record_encrypted ( key. map ( |k| ( k, & id) ) ) ,
189- pcs_key : key. map ( |k| k. key_id ( ) . unwrap ( ) [ ..4 ] . to_vec ( ) ) ,
215+ record_field : record. to_record_encrypted ( pcs_key. as_ref ( ) . map ( |k| ( k, & id) ) ) ,
216+ pcs_key : pcs_key_id,
217+ protection_info,
190218 ..Default :: default ( )
191219 } ) ,
192220 merge : Some ( true ) ,
@@ -203,14 +231,15 @@ pub struct FetchedRecord {
203231}
204232
205233impl FetchedRecord {
206- pub fn get_record < R : CloudKitRecord > ( & self , key : Option < & PCSKey > ) -> R {
234+ pub fn get_record < R : CloudKitRecord > ( & self , key : Option < & PCSKeys > ) -> R {
207235 let r = self . response . record_retrieve_response . as_ref ( ) . expect ( "No retrieve response?" ) . record . as_ref ( ) . expect ( "No record?" ) ;
208236
209237 let got_type = r. r#type . as_ref ( ) . expect ( "no TYpe" ) . name . as_ref ( ) . expect ( "No ta" ) ;
210238 if got_type. as_str ( ) != R :: record_type ( ) {
211239 panic ! ( "Wrong record type, got {} expected {}" , got_type, R :: record_type( ) ) ;
212240 }
213- R :: from_record_encrypted ( & r. record_field , key. map ( |k| ( k, r. record_identifier . as_ref ( ) . unwrap ( ) ) ) )
241+ let key = key. map ( |k| pcs_key_for_record ( r, k) . expect ( "no PCS key" ) ) ;
242+ R :: from_record_encrypted ( & r. record_field , key. as_ref ( ) . map ( |k| ( k, r. record_identifier . as_ref ( ) . unwrap ( ) ) ) )
214243 }
215244
216245 pub fn get_id ( & self ) -> String {
@@ -546,15 +575,17 @@ impl CloudKitOp for ZoneSaveOperation {
546575}
547576
548577impl ZoneSaveOperation {
549- pub fn new ( zone : RecordZoneIdentifier , pcs_key : Option < & CompactECKey < Private > > ) -> Result < Self , PushError > {
578+ pub fn new ( zone : RecordZoneIdentifier , pcs_key : Option < & CompactECKey < Private > > , with_record : bool ) -> Result < Self , PushError > {
550579 let mut protection_info: Option < ProtectionInfo > = None ;
551580 let mut record_protection_info: Option < ProtectionInfo > = None ;
552581 if let Some ( pcs_key) = pcs_key {
553582 let zone_key = CompactECKey :: new ( ) ?;
554- let record_protection = PCSShareProtection :: create ( & zone_key, & [ ] ) ?;
555- let main_protection = PCSShareProtection :: create ( pcs_key, & [ zone_key] ) ?;
556-
557- record_protection_info = Some ( ProtectionInfo { protection_info : Some ( rasn:: der:: encode ( & record_protection) . unwrap ( ) ) , protection_info_tag : None } ) ;
583+ let main_protection = PCSShareProtection :: create ( pcs_key, & [ zone_key. clone ( ) ] ) ?;
584+
585+ if with_record {
586+ let record_protection = PCSShareProtection :: create ( & zone_key, & [ ] ) ?;
587+ record_protection_info = Some ( ProtectionInfo { protection_info : Some ( rasn:: der:: encode ( & record_protection) . unwrap ( ) ) , protection_info_tag : None } ) ;
588+ }
558589 let main_encoded = rasn:: der:: encode ( & main_protection) . unwrap ( ) ;
559590 protection_info = Some ( ProtectionInfo {
560591 protection_info_tag : Some ( encode_hex ( & sha1 ( & main_encoded) ) . to_uppercase ( ) ) ,
@@ -715,11 +746,38 @@ pub struct QueryResult<T: CloudKitRecord> {
715746 pub result : T ,
716747}
717748
749+ #[ derive( Clone ) ]
750+ pub struct PCSKeys {
751+ zone_keys : Vec < CompactECKey < Private > > ,
752+ default_record_key : Option < PCSKey > ,
753+ }
754+
755+ impl PCSKeys {
756+ fn new ( keys : Vec < CompactECKey < Private > > ) -> Self {
757+ Self {
758+ zone_keys : keys,
759+ default_record_key : None ,
760+ }
761+ }
762+
763+ fn decode_record_protection ( & self , protection : & ProtectionInfo ) -> Result < PCSKey , PushError > {
764+ let record_protection: PCSShareProtection = rasn:: der:: decode ( protection. protection_info ( ) ) . expect ( "Bad record protection?" ) ;
765+ let mut big_num = BigNumContext :: new ( ) ?;
766+ let record_key = CompactECKey :: decompress ( record_protection. decode_key_public ( ) ?. try_into ( ) . expect ( "Decode key not compact!" ) ) ;
767+
768+ let item = self . zone_keys . iter ( ) . find ( |k| matches ! ( record_key. public_key( ) . eq( & record_key. group( ) , & k. public_key( ) , & mut big_num) , Ok ( true ) ) ) . expect ( "Record key not found!" ) ;
769+
770+ let ( key, _record_keys) = record_protection. decode ( item) . unwrap ( ) ;
771+
772+ Ok ( key)
773+ }
774+ }
775+
718776pub struct CloudKitOpenContainer < ' t , T : AnisetteProvider > {
719777 container : CloudKitContainer < ' t > ,
720778 pub user_id : String ,
721779 pub client : Arc < CloudKitClient < T > > ,
722- pub keys : Mutex < HashMap < String , PCSKey > > ,
780+ pub keys : Mutex < HashMap < String , PCSKeys > > ,
723781}
724782
725783impl < ' t , T : AnisetteProvider > Deref for CloudKitOpenContainer < ' t , T > {
@@ -744,14 +802,14 @@ impl<'t, T: AnisetteProvider> CloudKitOpenContainer<'t, T> {
744802 }
745803 }
746804
747- pub async fn get_zone_encryption_config ( & self , zone : & cloudkit_proto:: RecordZoneIdentifier , client : & KeychainClient < T > , service : & PCSService < ' _ > ) -> Result < PCSKey , PushError > {
805+ pub async fn get_zone_encryption_config ( & self , zone : & cloudkit_proto:: RecordZoneIdentifier , client : & KeychainClient < T > , pcs_service : & PCSService < ' _ > ) -> Result < PCSKeys , PushError > {
748806 let mut cached_keys = self . keys . lock ( ) . await ;
749807 let zone_name = zone. value . as_ref ( ) . unwrap ( ) . name ( ) . to_string ( ) ;
750808 if let Some ( key) = cached_keys. get ( & zone_name) {
751809 return Ok ( key. clone ( ) ) ;
752810 }
753811
754- client. sync_keychain ( & [ & service . zone , "ProtectedCloudStorage" ] ) . await ?;
812+ client. sync_keychain ( & [ & pcs_service . zone , "ProtectedCloudStorage" ] ) . await ?;
755813
756814 let zone = match self . perform ( & CloudKitSession :: new ( ) , FetchZoneOperation :: new ( zone. clone ( ) ) ) . await {
757815 Ok ( data) => data. target_zone . unwrap ( ) ,
@@ -764,9 +822,9 @@ impl<'t, T: AnisetteProvider> CloudKitOpenContainer<'t, T> {
764822 } ) ,
765823 ..
766824 } ) ) => {
767- let service = PCSPrivateKey :: get_service_key ( client, service , self . client . config . as_ref ( ) ) . await ?;
825+ let service = PCSPrivateKey :: get_service_key ( client, pcs_service , self . client . config . as_ref ( ) ) . await ?;
768826
769- let request = ZoneSaveOperation :: new ( zone. clone ( ) , Some ( & service. key ( ) ) ) . unwrap ( ) ;
827+ let request = ZoneSaveOperation :: new ( zone. clone ( ) , Some ( & service. key ( ) ) , pcs_service . global_record ) . unwrap ( ) ;
770828 let zone = request. 0 . clone ( ) . zone . unwrap ( ) ;
771829 self . perform ( & CloudKitSession :: new ( ) , request) . await . unwrap ( ) ;
772830 zone
@@ -777,20 +835,17 @@ impl<'t, T: AnisetteProvider> CloudKitOpenContainer<'t, T> {
777835
778836 let data = client. state . read ( ) . await ;
779837
780- let ( _parent_key, keys) = zone_protection. decrypt_with_keychain ( & data) ?;
838+ let ( _parent_key, keys) = zone_protection. decrypt_with_keychain ( & data, pcs_service ) ?;
781839
782- let record_protection: PCSShareProtection = rasn:: der:: decode ( zone. record_protection_info . as_ref ( ) . unwrap ( ) . protection_info ( ) ) . expect ( "Bad record protection?" ) ;
783-
784- let mut big_num = BigNumContext :: new ( ) ?;
785- let record_key = CompactECKey :: decompress ( record_protection. decode_key_public ( ) ?. try_into ( ) . expect ( "Decode key not compact!" ) ) ;
786-
787- let item = keys. iter ( ) . find ( |k| matches ! ( record_key. public_key( ) . eq( & record_key. group( ) , & k. public_key( ) , & mut big_num) , Ok ( true ) ) ) . expect ( "Record key not found!" ) ;
788-
789- let ( key, _record_keys) = record_protection. decode ( item) . unwrap ( ) ;
790-
791- cached_keys. insert ( zone_name, key. clone ( ) ) ;
840+ let mut keys = PCSKeys :: new ( keys) ;
841+
842+ if let Some ( record_protection_info) = & zone. record_protection_info {
843+ keys. default_record_key = Some ( keys. decode_record_protection ( record_protection_info) ?) ;
844+ }
845+
846+ cached_keys. insert ( zone_name, keys. clone ( ) ) ;
792847
793- Ok ( key )
848+ Ok ( keys )
794849 }
795850
796851 pub fn build_request < Op : CloudKitOp > ( & self , operation : & Op , config : & dyn OSConfig , is_first : bool , uuid : String , isolation_level : IsolationLevel ) -> Vec < u8 > {
0 commit comments