1 // 2 // Copyright 2021 Signal Messenger, LLC. 3 // SPDX-License-Identifier: AGPL-3.0-only 4 // 5 6 use super::*; 7 8 use async_trait::async_trait; 9 use signal_neon_futures::*; 10 use std::cell::RefCell; 11 use std::sync::Arc; 12 use uuid::Uuid; 13 14 pub struct NodePreKeyStore { 15 js_channel: Channel, 16 store_object: Arc<Root<JsObject>>, 17 } 18 19 impl NodePreKeyStore { new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self20 pub(crate) fn new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self { 21 Self { 22 js_channel: cx.channel(), 23 store_object: Arc::new(store.root(cx)), 24 } 25 } 26 do_get_pre_key(&self, id: u32) -> Result<PreKeyRecord, String>27 async fn do_get_pre_key(&self, id: u32) -> Result<PreKeyRecord, String> { 28 let store_object_shared = self.store_object.clone(); 29 JsFuture::get_promise(&self.js_channel, move |cx| { 30 let store_object = store_object_shared.to_inner(cx); 31 let id = id.convert_into(cx)?; 32 let result = call_method(cx, store_object, "_getPreKey", vec![id.upcast()])?; 33 let result = result.downcast_or_throw(cx)?; 34 store_object_shared.finalize(cx); 35 Ok(result) 36 }) 37 .then(|cx, result| match result { 38 Ok(value) => match value.downcast::<DefaultJsBox<PreKeyRecord>, _>(cx) { 39 Ok(obj) => Ok((***obj).clone()), 40 Err(_) => Err("result must be an object".to_owned()), 41 }, 42 Err(error) => Err(error 43 .to_string(cx) 44 .expect("can convert to string") 45 .value(cx)), 46 }) 47 .await 48 } 49 do_save_pre_key(&self, id: u32, record: PreKeyRecord) -> Result<(), String>50 async fn do_save_pre_key(&self, id: u32, record: PreKeyRecord) -> Result<(), String> { 51 let store_object_shared = self.store_object.clone(); 52 JsFuture::get_promise(&self.js_channel, move |cx| { 53 let store_object = store_object_shared.to_inner(cx); 54 let id: Handle<JsNumber> = id.convert_into(cx)?; 55 let record: Handle<JsValue> = record.convert_into(cx)?; 56 let result = call_method(cx, store_object, "_savePreKey", vec![id.upcast(), record])? 57 .downcast_or_throw(cx)?; 58 store_object_shared.finalize(cx); 59 Ok(result) 60 }) 61 .then(|cx, result| match result { 62 Ok(value) => match value.downcast::<JsUndefined, _>(cx) { 63 Ok(_) => Ok(()), 64 Err(_) => Err("unexpected result from _savePreKey".into()), 65 }, 66 Err(error) => Err(error 67 .to_string(cx) 68 .expect("can convert to string") 69 .value(cx)), 70 }) 71 .await 72 } 73 do_remove_pre_key(&self, id: u32) -> Result<(), String>74 async fn do_remove_pre_key(&self, id: u32) -> Result<(), String> { 75 let store_object_shared = self.store_object.clone(); 76 JsFuture::get_promise(&self.js_channel, move |cx| { 77 let store_object = store_object_shared.to_inner(cx); 78 let id: Handle<JsNumber> = id.convert_into(cx)?; 79 let result = call_method(cx, store_object, "_removePreKey", vec![id.upcast()])? 80 .downcast_or_throw(cx)?; 81 store_object_shared.finalize(cx); 82 Ok(result) 83 }) 84 .then(|cx, result| match result { 85 Ok(value) => match value.downcast::<JsUndefined, _>(cx) { 86 Ok(_) => Ok(()), 87 Err(_) => Err("unexpected result from _removePreKey".into()), 88 }, 89 Err(error) => Err(error 90 .to_string(cx) 91 .expect("can convert to string") 92 .value(cx)), 93 }) 94 .await 95 } 96 } 97 98 impl Finalize for NodePreKeyStore { finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C)99 fn finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C) { 100 self.store_object.finalize(cx) 101 } 102 } 103 104 #[async_trait(?Send)] 105 impl PreKeyStore for NodePreKeyStore { get_pre_key( &self, pre_key_id: u32, _ctx: libsignal_protocol::Context, ) -> Result<PreKeyRecord, SignalProtocolError>106 async fn get_pre_key( 107 &self, 108 pre_key_id: u32, 109 _ctx: libsignal_protocol::Context, 110 ) -> Result<PreKeyRecord, SignalProtocolError> { 111 self.do_get_pre_key(pre_key_id) 112 .await 113 .map_err(|s| js_error_to_rust("getPreKey", s)) 114 } 115 save_pre_key( &mut self, pre_key_id: u32, record: &PreKeyRecord, _ctx: libsignal_protocol::Context, ) -> Result<(), SignalProtocolError>116 async fn save_pre_key( 117 &mut self, 118 pre_key_id: u32, 119 record: &PreKeyRecord, 120 _ctx: libsignal_protocol::Context, 121 ) -> Result<(), SignalProtocolError> { 122 self.do_save_pre_key(pre_key_id, record.clone()) 123 .await 124 .map_err(|s| js_error_to_rust("savePreKey", s)) 125 } 126 remove_pre_key( &mut self, pre_key_id: u32, _ctx: libsignal_protocol::Context, ) -> Result<(), SignalProtocolError>127 async fn remove_pre_key( 128 &mut self, 129 pre_key_id: u32, 130 _ctx: libsignal_protocol::Context, 131 ) -> Result<(), SignalProtocolError> { 132 self.do_remove_pre_key(pre_key_id) 133 .await 134 .map_err(|s| js_error_to_rust("removePreKey", s)) 135 } 136 } 137 138 pub struct NodeSignedPreKeyStore { 139 js_channel: Channel, 140 store_object: Arc<Root<JsObject>>, 141 } 142 143 impl NodeSignedPreKeyStore { new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self144 pub(crate) fn new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self { 145 Self { 146 js_channel: cx.channel(), 147 store_object: Arc::new(store.root(cx)), 148 } 149 } 150 do_get_signed_pre_key(&self, id: u32) -> Result<SignedPreKeyRecord, String>151 async fn do_get_signed_pre_key(&self, id: u32) -> Result<SignedPreKeyRecord, String> { 152 let store_object_shared = self.store_object.clone(); 153 JsFuture::get_promise(&self.js_channel, move |cx| { 154 let store_object = store_object_shared.to_inner(cx); 155 let id = id.convert_into(cx)?; 156 let result = call_method(cx, store_object, "_getSignedPreKey", vec![id.upcast()])?; 157 let result = result.downcast_or_throw(cx)?; 158 store_object_shared.finalize(cx); 159 Ok(result) 160 }) 161 .then(|cx, result| match result { 162 Ok(value) => match value.downcast::<DefaultJsBox<SignedPreKeyRecord>, _>(cx) { 163 Ok(obj) => Ok((***obj).clone()), 164 Err(_) => Err("result must be an object".to_owned()), 165 }, 166 Err(error) => Err(error 167 .to_string(cx) 168 .expect("can convert to string") 169 .value(cx)), 170 }) 171 .await 172 } 173 do_save_signed_pre_key( &self, id: u32, record: SignedPreKeyRecord, ) -> Result<(), String>174 async fn do_save_signed_pre_key( 175 &self, 176 id: u32, 177 record: SignedPreKeyRecord, 178 ) -> Result<(), String> { 179 let store_object_shared = self.store_object.clone(); 180 JsFuture::get_promise(&self.js_channel, move |cx| { 181 let store_object = store_object_shared.to_inner(cx); 182 let id: Handle<JsNumber> = id.convert_into(cx)?; 183 let record: Handle<JsValue> = record.convert_into(cx)?; 184 let result = call_method( 185 cx, 186 store_object, 187 "_saveSignedPreKey", 188 vec![id.upcast(), record], 189 )? 190 .downcast_or_throw(cx)?; 191 store_object_shared.finalize(cx); 192 Ok(result) 193 }) 194 .then(|cx, result| match result { 195 Ok(value) => match value.downcast::<JsUndefined, _>(cx) { 196 Ok(_) => Ok(()), 197 Err(_) => Err("unexpected result from _saveSignedPreKey".into()), 198 }, 199 Err(error) => Err(error 200 .to_string(cx) 201 .expect("can convert to string") 202 .value(cx)), 203 }) 204 .await 205 } 206 } 207 208 impl Finalize for NodeSignedPreKeyStore { finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C)209 fn finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C) { 210 self.store_object.finalize(cx) 211 } 212 } 213 214 #[async_trait(?Send)] 215 impl SignedPreKeyStore for NodeSignedPreKeyStore { get_signed_pre_key( &self, signed_pre_key_id: u32, _ctx: libsignal_protocol::Context, ) -> Result<SignedPreKeyRecord, SignalProtocolError>216 async fn get_signed_pre_key( 217 &self, 218 signed_pre_key_id: u32, 219 _ctx: libsignal_protocol::Context, 220 ) -> Result<SignedPreKeyRecord, SignalProtocolError> { 221 self.do_get_signed_pre_key(signed_pre_key_id) 222 .await 223 .map_err(|s| js_error_to_rust("getSignedPreKey", s)) 224 } 225 save_signed_pre_key( &mut self, signed_pre_key_id: u32, record: &SignedPreKeyRecord, _ctx: libsignal_protocol::Context, ) -> Result<(), SignalProtocolError>226 async fn save_signed_pre_key( 227 &mut self, 228 signed_pre_key_id: u32, 229 record: &SignedPreKeyRecord, 230 _ctx: libsignal_protocol::Context, 231 ) -> Result<(), SignalProtocolError> { 232 self.do_save_signed_pre_key(signed_pre_key_id, record.clone()) 233 .await 234 .map_err(|s| js_error_to_rust("saveSignedPreKey", s)) 235 } 236 } 237 238 pub struct NodeSessionStore { 239 js_channel: Channel, 240 store_object: Arc<Root<JsObject>>, 241 } 242 243 impl NodeSessionStore { new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self244 pub(crate) fn new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self { 245 Self { 246 js_channel: cx.channel(), 247 store_object: Arc::new(store.root(cx)), 248 } 249 } 250 do_get_session(&self, name: ProtocolAddress) -> Result<Option<SessionRecord>, String>251 async fn do_get_session(&self, name: ProtocolAddress) -> Result<Option<SessionRecord>, String> { 252 let store_object_shared = self.store_object.clone(); 253 JsFuture::get_promise(&self.js_channel, move |cx| { 254 let store_object = store_object_shared.to_inner(cx); 255 let name: Handle<JsValue> = name.convert_into(cx)?; 256 let result = call_method(cx, store_object, "_getSession", vec![name])?; 257 let result = result.downcast_or_throw(cx)?; 258 store_object_shared.finalize(cx); 259 Ok(result) 260 }) 261 .then(|cx, result| match result { 262 Ok(value) => match value.downcast::<DefaultJsBox<RefCell<SessionRecord>>, _>(cx) { 263 Ok(obj) => Ok(Some((***obj).borrow().clone())), 264 Err(_) => { 265 if value.is_a::<JsNull, _>(cx) || value.is_a::<JsUndefined, _>(cx) { 266 Ok(None) 267 } else { 268 Err("_getSession returned unexpected type".into()) 269 } 270 } 271 }, 272 Err(error) => Err(error 273 .to_string(cx) 274 .expect("can convert to string") 275 .value(cx)), 276 }) 277 .await 278 } 279 do_save_session( &self, name: ProtocolAddress, record: SessionRecord, ) -> Result<(), String>280 async fn do_save_session( 281 &self, 282 name: ProtocolAddress, 283 record: SessionRecord, 284 ) -> Result<(), String> { 285 let store_object_shared = self.store_object.clone(); 286 JsFuture::get_promise(&self.js_channel, move |cx| { 287 let store_object = store_object_shared.to_inner(cx); 288 let name = name.convert_into(cx)?; 289 let record = record.convert_into(cx)?; 290 let result = call_method( 291 cx, 292 store_object, 293 "_saveSession", 294 vec![name, record.upcast()], 295 )? 296 .downcast_or_throw(cx)?; 297 store_object_shared.finalize(cx); 298 Ok(result) 299 }) 300 .then(|cx, result| match result { 301 Ok(value) => match value.downcast::<JsUndefined, _>(cx) { 302 Ok(_) => Ok(()), 303 Err(_) => Err("unexpected result from _saveSession".into()), 304 }, 305 Err(error) => Err(error 306 .to_string(cx) 307 .expect("can convert to string") 308 .value(cx)), 309 }) 310 .await 311 } 312 } 313 314 impl Finalize for NodeSessionStore { finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C)315 fn finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C) { 316 self.store_object.finalize(cx) 317 } 318 } 319 320 #[async_trait(?Send)] 321 impl SessionStore for NodeSessionStore { load_session( &self, name: &ProtocolAddress, _ctx: libsignal_protocol::Context, ) -> Result<Option<SessionRecord>, SignalProtocolError>322 async fn load_session( 323 &self, 324 name: &ProtocolAddress, 325 _ctx: libsignal_protocol::Context, 326 ) -> Result<Option<SessionRecord>, SignalProtocolError> { 327 self.do_get_session(name.clone()) 328 .await 329 .map_err(|s| js_error_to_rust("getSession", s)) 330 } 331 store_session( &mut self, name: &ProtocolAddress, record: &SessionRecord, _ctx: libsignal_protocol::Context, ) -> Result<(), SignalProtocolError>332 async fn store_session( 333 &mut self, 334 name: &ProtocolAddress, 335 record: &SessionRecord, 336 _ctx: libsignal_protocol::Context, 337 ) -> Result<(), SignalProtocolError> { 338 self.do_save_session(name.clone(), record.clone()) 339 .await 340 .map_err(|s| js_error_to_rust("saveSession", s)) 341 } 342 } 343 344 pub struct NodeIdentityKeyStore { 345 js_channel: Channel, 346 store_object: Arc<Root<JsObject>>, 347 } 348 349 impl NodeIdentityKeyStore { new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self350 pub(crate) fn new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self { 351 Self { 352 js_channel: cx.channel(), 353 store_object: Arc::new(store.root(cx)), 354 } 355 } 356 do_get_identity_key(&self) -> Result<PrivateKey, String>357 async fn do_get_identity_key(&self) -> Result<PrivateKey, String> { 358 let store_object_shared = self.store_object.clone(); 359 JsFuture::get_promise(&self.js_channel, move |cx| { 360 let store_object = store_object_shared.to_inner(cx); 361 let result = call_method(cx, store_object, "_getIdentityKey", vec![])?; 362 let result = result.downcast_or_throw(cx)?; 363 store_object_shared.finalize(cx); 364 Ok(result) 365 }) 366 .then(|cx, result| match result { 367 Ok(value) => match value.downcast::<DefaultJsBox<PrivateKey>, _>(cx) { 368 Ok(obj) => Ok(***obj), 369 Err(_) => Err("result must be an object".to_owned()), 370 }, 371 Err(error) => Err(error 372 .to_string(cx) 373 .expect("can convert to string") 374 .value(cx)), 375 }) 376 .await 377 } 378 do_get_local_registration_id(&self) -> Result<u32, String>379 async fn do_get_local_registration_id(&self) -> Result<u32, String> { 380 let store_object_shared = self.store_object.clone(); 381 JsFuture::get_promise(&self.js_channel, move |cx| { 382 let store_object = store_object_shared.to_inner(cx); 383 let result = call_method(cx, store_object, "_getLocalRegistrationId", vec![])? 384 .downcast_or_throw(cx)?; 385 store_object_shared.finalize(cx); 386 Ok(result) 387 }) 388 .then(|cx, result| match result { 389 Ok(value) => match value.downcast::<JsNumber, _>(cx) { 390 Ok(b) => Ok(b.value(cx) as u32), 391 Err(_) => Err("unexpected result from _getLocalRegistrationId".into()), 392 }, 393 Err(error) => Err(error 394 .to_string(cx) 395 .expect("can convert to string") 396 .value(cx)), 397 }) 398 .await 399 } 400 do_get_identity(&self, name: ProtocolAddress) -> Result<Option<PublicKey>, String>401 async fn do_get_identity(&self, name: ProtocolAddress) -> Result<Option<PublicKey>, String> { 402 let store_object_shared = self.store_object.clone(); 403 JsFuture::get_promise(&self.js_channel, move |cx| { 404 let store_object = store_object_shared.to_inner(cx); 405 let name: Handle<JsValue> = name.convert_into(cx)?; 406 let result = call_method(cx, store_object, "_getIdentity", vec![name])?; 407 let result = result.downcast_or_throw(cx)?; 408 store_object_shared.finalize(cx); 409 Ok(result) 410 }) 411 .then(|cx, result| match result { 412 Ok(value) => match value.downcast::<DefaultJsBox<PublicKey>, _>(cx) { 413 Ok(obj) => Ok(Some(***obj)), 414 Err(_) => { 415 if value.is_a::<JsNull, _>(cx) { 416 Ok(None) 417 } else { 418 Err("result must be an object".to_owned()) 419 } 420 } 421 }, 422 Err(error) => Err(error 423 .to_string(cx) 424 .expect("can convert to string") 425 .value(cx)), 426 }) 427 .await 428 } 429 do_save_identity( &self, name: ProtocolAddress, key: PublicKey, ) -> Result<bool, String>430 async fn do_save_identity( 431 &self, 432 name: ProtocolAddress, 433 key: PublicKey, 434 ) -> Result<bool, String> { 435 let store_object_shared = self.store_object.clone(); 436 JsFuture::get_promise(&self.js_channel, move |cx| { 437 let store_object = store_object_shared.to_inner(cx); 438 let name: Handle<JsValue> = name.convert_into(cx)?; 439 let key: Handle<JsValue> = key.convert_into(cx)?; 440 let result = call_method(cx, store_object, "_saveIdentity", vec![name, key])? 441 .downcast_or_throw(cx)?; 442 store_object_shared.finalize(cx); 443 Ok(result) 444 }) 445 .then(|cx, result| match result { 446 Ok(value) => match value.downcast::<JsBoolean, _>(cx) { 447 Ok(b) => Ok(b.value(cx)), 448 Err(_) => Err("unexpected result from _saveIdentity".into()), 449 }, 450 Err(error) => Err(error 451 .to_string(cx) 452 .expect("can convert to string") 453 .value(cx)), 454 }) 455 .await 456 } 457 do_is_trusted( &self, name: ProtocolAddress, key: PublicKey, direction: Direction, ) -> Result<bool, String>458 async fn do_is_trusted( 459 &self, 460 name: ProtocolAddress, 461 key: PublicKey, 462 direction: Direction, 463 ) -> Result<bool, String> { 464 let store_object_shared = self.store_object.clone(); 465 JsFuture::get_promise(&self.js_channel, move |cx| { 466 let store_object = store_object_shared.to_inner(cx); 467 let name: Handle<JsValue> = name.convert_into(cx)?; 468 let key: Handle<JsValue> = key.convert_into(cx)?; 469 let sending = direction == Direction::Sending; 470 471 let sending = sending.convert_into(cx)?; 472 let result = call_method( 473 cx, 474 store_object, 475 "_isTrustedIdentity", 476 vec![name, key, sending.upcast()], 477 )? 478 .downcast_or_throw(cx)?; 479 store_object_shared.finalize(cx); 480 Ok(result) 481 }) 482 .then(|cx, result| match result { 483 Ok(value) => match value.downcast::<JsBoolean, _>(cx) { 484 Ok(b) => Ok(b.value(cx)), 485 Err(_) => Err("unexpected result from _isTrustedIdentity".into()), 486 }, 487 Err(error) => Err(error 488 .to_string(cx) 489 .expect("can convert to string") 490 .value(cx)), 491 }) 492 .await 493 } 494 } 495 496 impl Finalize for NodeIdentityKeyStore { finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C)497 fn finalize<'b, C: neon::prelude::Context<'b>>(self, cx: &mut C) { 498 self.store_object.finalize(cx) 499 } 500 } 501 502 #[async_trait(?Send)] 503 impl IdentityKeyStore for NodeIdentityKeyStore { get_identity_key_pair( &self, _ctx: libsignal_protocol::Context, ) -> Result<IdentityKeyPair, SignalProtocolError>504 async fn get_identity_key_pair( 505 &self, 506 _ctx: libsignal_protocol::Context, 507 ) -> Result<IdentityKeyPair, SignalProtocolError> { 508 let pk = self 509 .do_get_identity_key() 510 .await 511 .map_err(|s| js_error_to_rust("getIdentityPrivateKey", s))?; 512 513 IdentityKeyPair::try_from(pk) 514 } 515 get_local_registration_id( &self, _ctx: libsignal_protocol::Context, ) -> Result<u32, SignalProtocolError>516 async fn get_local_registration_id( 517 &self, 518 _ctx: libsignal_protocol::Context, 519 ) -> Result<u32, SignalProtocolError> { 520 self.do_get_local_registration_id() 521 .await 522 .map_err(|s| js_error_to_rust("getLocalRegistrationId", s)) 523 } 524 get_identity( &self, address: &ProtocolAddress, _ctx: libsignal_protocol::Context, ) -> Result<Option<IdentityKey>, SignalProtocolError>525 async fn get_identity( 526 &self, 527 address: &ProtocolAddress, 528 _ctx: libsignal_protocol::Context, 529 ) -> Result<Option<IdentityKey>, SignalProtocolError> { 530 Ok(self 531 .do_get_identity(address.clone()) 532 .await 533 .map_err(|s| js_error_to_rust("getIdentity", s))? 534 .map(IdentityKey::new)) 535 } 536 save_identity( &mut self, address: &ProtocolAddress, identity: &IdentityKey, _ctx: libsignal_protocol::Context, ) -> Result<bool, SignalProtocolError>537 async fn save_identity( 538 &mut self, 539 address: &ProtocolAddress, 540 identity: &IdentityKey, 541 _ctx: libsignal_protocol::Context, 542 ) -> Result<bool, SignalProtocolError> { 543 self.do_save_identity(address.clone(), *identity.public_key()) 544 .await 545 .map_err(|s| js_error_to_rust("saveIdentity", s)) 546 } 547 is_trusted_identity( &self, address: &ProtocolAddress, identity: &IdentityKey, direction: libsignal_protocol::Direction, _ctx: libsignal_protocol::Context, ) -> Result<bool, SignalProtocolError>548 async fn is_trusted_identity( 549 &self, 550 address: &ProtocolAddress, 551 identity: &IdentityKey, 552 direction: libsignal_protocol::Direction, 553 _ctx: libsignal_protocol::Context, 554 ) -> Result<bool, SignalProtocolError> { 555 self.do_is_trusted(address.clone(), *identity.public_key(), direction) 556 .await 557 .map_err(|s| js_error_to_rust("isTrustedIdentity", s)) 558 } 559 } 560 561 pub struct NodeSenderKeyStore { 562 js_channel: Channel, 563 store_object: Arc<Root<JsObject>>, 564 } 565 566 impl NodeSenderKeyStore { new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self567 pub(crate) fn new(cx: &mut FunctionContext, store: Handle<JsObject>) -> Self { 568 Self { 569 js_channel: cx.channel(), 570 store_object: Arc::new(store.root(cx)), 571 } 572 } 573 do_get_sender_key( &self, sender: ProtocolAddress, distribution_id: Uuid, ) -> Result<Option<SenderKeyRecord>, String>574 async fn do_get_sender_key( 575 &self, 576 sender: ProtocolAddress, 577 distribution_id: Uuid, 578 ) -> Result<Option<SenderKeyRecord>, String> { 579 let store_object_shared = self.store_object.clone(); 580 JsFuture::get_promise(&self.js_channel, move |cx| { 581 let store_object = store_object_shared.to_inner(cx); 582 let sender: Handle<JsValue> = sender.convert_into(cx)?; 583 let distribution_id: Handle<JsValue> = distribution_id.convert_into(cx)?.upcast(); 584 let result = call_method( 585 cx, 586 store_object, 587 "_getSenderKey", 588 vec![sender, distribution_id], 589 )?; 590 let result = result.downcast_or_throw(cx)?; 591 store_object_shared.finalize(cx); 592 Ok(result) 593 }) 594 .then(|cx, result| match result { 595 Ok(value) => match value.downcast::<DefaultJsBox<SenderKeyRecord>, _>(cx) { 596 Ok(obj) => Ok(Some((***obj).clone())), 597 Err(_) => { 598 if value.is_a::<JsNull, _>(cx) { 599 Ok(None) 600 } else { 601 Err("result must be an object".to_owned()) 602 } 603 } 604 }, 605 Err(error) => Err(error 606 .to_string(cx) 607 .expect("can convert to string") 608 .value(cx)), 609 }) 610 .await 611 } 612 do_save_sender_key( &self, sender: ProtocolAddress, distribution_id: Uuid, record: SenderKeyRecord, ) -> Result<(), String>613 async fn do_save_sender_key( 614 &self, 615 sender: ProtocolAddress, 616 distribution_id: Uuid, 617 record: SenderKeyRecord, 618 ) -> Result<(), String> { 619 let store_object_shared = self.store_object.clone(); 620 JsFuture::get_promise(&self.js_channel, move |cx| { 621 let store_object = store_object_shared.to_inner(cx); 622 let sender: Handle<JsValue> = sender.convert_into(cx)?; 623 let distribution_id: Handle<JsValue> = distribution_id.convert_into(cx)?.upcast(); 624 let record: Handle<JsValue> = record.convert_into(cx)?; 625 let result = call_method( 626 cx, 627 store_object, 628 "_saveSenderKey", 629 vec![sender, distribution_id, record], 630 )? 631 .downcast_or_throw(cx)?; 632 store_object_shared.finalize(cx); 633 Ok(result) 634 }) 635 .then(|cx, result| match result { 636 Ok(value) => match value.downcast::<JsUndefined, _>(cx) { 637 Ok(_) => Ok(()), 638 Err(_) => Err("unexpected result from _saveSenderKey".into()), 639 }, 640 Err(error) => Err(error 641 .to_string(cx) 642 .expect("can convert to string") 643 .value(cx)), 644 }) 645 .await 646 } 647 } 648 649 impl Finalize for NodeSenderKeyStore { finalize<'a, C: Context<'a>>(self, cx: &mut C)650 fn finalize<'a, C: Context<'a>>(self, cx: &mut C) { 651 self.store_object.finalize(cx) 652 } 653 } 654 655 #[async_trait(?Send)] 656 impl SenderKeyStore for NodeSenderKeyStore { load_sender_key( &mut self, sender: &ProtocolAddress, distribution_id: Uuid, _ctx: libsignal_protocol::Context, ) -> Result<Option<SenderKeyRecord>, SignalProtocolError>657 async fn load_sender_key( 658 &mut self, 659 sender: &ProtocolAddress, 660 distribution_id: Uuid, 661 _ctx: libsignal_protocol::Context, 662 ) -> Result<Option<SenderKeyRecord>, SignalProtocolError> { 663 self.do_get_sender_key(sender.clone(), distribution_id) 664 .await 665 .map_err(|s| js_error_to_rust("getSenderKey", s)) 666 } 667 store_sender_key( &mut self, sender: &ProtocolAddress, distribution_id: Uuid, record: &SenderKeyRecord, _ctx: libsignal_protocol::Context, ) -> Result<(), SignalProtocolError>668 async fn store_sender_key( 669 &mut self, 670 sender: &ProtocolAddress, 671 distribution_id: Uuid, 672 record: &SenderKeyRecord, 673 _ctx: libsignal_protocol::Context, 674 ) -> Result<(), SignalProtocolError> { 675 self.do_save_sender_key(sender.clone(), distribution_id, record.clone()) 676 .await 677 .map_err(|s| js_error_to_rust("saveSenderKey", s)) 678 } 679 } 680