Skip to content

Commit

Permalink
WIP pnp_initialize_devices
Browse files Browse the repository at this point in the history
  • Loading branch information
rubdos committed Jan 14, 2024
1 parent 0faee1b commit 0530633
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 34 deletions.
104 changes: 77 additions & 27 deletions libsignal-service/src/account_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ use zkgroup::profiles::ProfileKey;

use crate::pre_keys::{KyberPreKeyEntity, PreKeysStore, SignedPreKeyEntity};
use crate::proto::DeviceName;
use crate::provisioning::generate_registration_id;
use crate::push_service::{AvatarWrite, RecaptchaAttributes, ServiceIdType};
use crate::sender::OutgoingPushMessage;
use crate::session_store::SessionStoreExt;
use crate::ServiceAddress;
use crate::{
configuration::{Endpoint, ServiceCredentials},
Expand Down Expand Up @@ -598,45 +600,93 @@ impl<Service: PushService> AccountManager<Service> {
/// Initialize PNI on linked devices.
///
/// Should be called as the primary device to migrate from pre-PNI to PNI.
///
/// This is the equivalent of Android's PnpInitializeDevicesJob or iOS' PniHelloWorldManager.
pub async fn pnp_initialize_devices<
R: rand::Rng + rand::CryptoRng,
P: PreKeysStore,
Aci: PreKeysStore + SessionStoreExt,
Pni: PreKeysStore,
>(
&mut self,
pni_protocol_store: &mut P,
aci_protocol_store: &mut Aci,
pni_protocol_store: &mut Pni,
local_aci: ServiceAddress,
csprng: &mut R,
use_last_resort_key: bool,
) -> Result<(), ServiceError> {
let pni_identity_key_pair =
pni_protocol_store.get_identity_key_pair().await?;

let pni_identity_key = pni_identity_key_pair.identity_key();
let device_messages: Vec<OutgoingPushMessage>; // XXX TODO
let device_pni_signed_prekeys: HashMap<&str, SignedPreKeyEntity>;
let device_pni_last_resort_kyber_prekeys: HashMap<
&str,
KyberPreKeyEntity,
>;
let pni_registration_ids: HashMap<&str, u32>;
let signature_valid_on_each_signed_pre_key: bool;

// This needs to be repeated for every device that we have linked.
let (
_pre_keys,
signed_pre_key_entity,
kyber_pre_key_entities,
last_resort_kyber_prekey,
) = self
.generate_pre_keys(
pni_protocol_store,
ServiceIdType::PhoneNumberIdentity,
csprng,
use_last_resort_key,
0,
PRE_KEY_BATCH_SIZE,
)

// For every linked device, we generate a new set of pre-keys, and send them to the device.
let local_device_ids = aci_protocol_store
.get_sub_device_sessions(&local_aci)
.await?;
assert_eq!(_pre_keys.len(), 0);

let mut device_messages =
Vec::<OutgoingPushMessage>::with_capacity(local_device_ids.len());
let mut device_pni_signed_prekeys =
HashMap::<String, SignedPreKeyEntity>::with_capacity(
local_device_ids.len(),
);
let mut device_pni_last_resort_kyber_prekeys =
HashMap::<String, KyberPreKeyEntity>::with_capacity(
local_device_ids.len(),
);
let mut pni_registration_ids =
HashMap::<String, u32>::with_capacity(local_device_ids.len());

let signature_valid_on_each_signed_pre_key = false; // XXX?
for local_device_id in local_device_ids {
let local_protocol_address =
local_aci.to_protocol_address(local_device_id);
let span = tracing::trace_span!(
"filtering devices",
address = %local_protocol_address
);
// Skip if local_device_id is self device id
// Skip if we don't have a session with the device
if aci_protocol_store
.load_session(&local_protocol_address)
.instrument(span)
.await?
.is_none()
{
tracing::warn!(
"No session with device {}, skipping PNI provisioning",
local_device_id
);
continue;
}

let (
_pre_keys,
signed_pre_key_entity,
kyber_pre_key_entities,
last_resort_kyber_prekey,
) = self
.generate_pre_keys(
pni_protocol_store,
ServiceIdType::PhoneNumberIdentity,
csprng,
use_last_resort_key,
0,
PRE_KEY_BATCH_SIZE,
)
.await?;
let registration_id = generate_registration_id(csprng);

let local_device_id_s = local_device_id.to_string();
device_pni_signed_prekeys
.insert(local_device_id_s.clone(), signed_pre_key_entity);
device_pni_last_resort_kyber_prekeys
.insert(local_device_id_s.clone(), last_resort_kyber_prekey);

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service, Rust stable)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / clippy

mismatched types

error[E0308]: mismatched types --> libsignal-service/src/account_manager.rs:684:52 | 684 | .insert(local_device_id_s.clone(), last_resort_kyber_prekey); | ------ ^^^^^^^^^^^^^^^^^^^^^^^^ expected `KyberPreKeyEntity`, found `Option<KyberPreKeyEntity>` | | | arguments to this method are incorrect | = note: expected struct `pre_keys::KyberPreKeyEntity` found enum `std::option::Option<pre_keys::KyberPreKeyEntity>` help: the return type of this call is `std::option::Option<pre_keys::KyberPreKeyEntity>` due to the type of the argument passed --> libsignal-service/src/account_manager.rs:683:13 | 683 | / device_pni_last_resort_kyber_prekeys 684 | | .insert(local_device_id_s.clone(), last_resort_kyber_prekey); | |____________________________________________________------------------------^ | | | this argument influences the return type of `insert` note: method defined here --> /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/std/src/collections/hash/map.rs:1104:12 help: consider using `Option::expect` to unwrap the `std::option::Option<pre_keys::KyberPreKeyEntity>` value, panicking if the value is an `Option::None` | 684 | .insert(local_device_id_s.clone(), last_resort_kyber_prekey.expect("REASON")); | +++++++++++++++++

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service, Rust beta)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service, Rust nightly)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service, Rust stable)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust stable)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust nightly)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust beta)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust nightly)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust stable)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust beta)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust stable)

mismatched types

Check failure on line 684 in libsignal-service/src/account_manager.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust 1.70)

mismatched types
pni_registration_ids
.insert(local_device_id_s.clone(), registration_id);

assert_eq!(_pre_keys.len(), 0);
}

self.service
.distribute_pni_keys(
Expand Down
17 changes: 10 additions & 7 deletions libsignal-service/src/push_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,22 +1316,25 @@ pub trait PushService: MaybeSend {
&mut self,
pni_identity_key: &IdentityKey,
device_messages: Vec<OutgoingPushMessage>,
device_pni_signed_prekeys: HashMap<&str, SignedPreKeyEntity>,
device_pni_last_resort_kyber_prekeys: HashMap<&str, KyberPreKeyEntity>,
pni_registration_ids: HashMap<&str, u32>,
device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
device_pni_last_resort_kyber_prekeys: HashMap<
String,
KyberPreKeyEntity,
>,
pni_registration_ids: HashMap<String, u32>,
signature_valid_on_each_signed_pre_key: bool,
) -> Result<VerifyAccountResponse, ServiceError> {
#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "camelCase")]
struct PniKeyDistributionRequest<'a> {
struct PniKeyDistributionRequest {
#[serde(with = "serde_base64")]
pni_identity_key: Vec<u8>,
device_messages: Vec<OutgoingPushMessage>,
device_pni_signed_prekeys: HashMap<&'a str, SignedPreKeyEntity>,
device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
#[serde(rename = "devicePniPqLastResortPrekeys")]
device_pni_last_resort_kyber_prekeys:
HashMap<&'a str, KyberPreKeyEntity>,
pni_registration_ids: HashMap<&'a str, u32>,
HashMap<String, KyberPreKeyEntity>,
pni_registration_ids: HashMap<String, u32>,
signature_valid_on_each_signed_pre_key: bool,
}

Expand Down

0 comments on commit 0530633

Please sign in to comment.