Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ServiceAddress by libsignal_protocol::ServiceId #334

Merged
merged 13 commits into from
Nov 5, 2024
46 changes: 23 additions & 23 deletions src/account_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use aes::cipher::{KeyIvInit, StreamCipher as _};
use hmac::digest::Output;
use hmac::{Hmac, Mac};
use libsignal_protocol::{
kem, GenericSignedPreKey, IdentityKey, IdentityKeyPair, IdentityKeyStore,
KeyPair, KyberPreKeyRecord, PrivateKey, ProtocolStore, PublicKey,
SenderKeyStore, SignedPreKeyRecord, Timestamp,
kem, Aci, GenericSignedPreKey, IdentityKey, IdentityKeyPair,
IdentityKeyStore, KeyPair, KyberPreKeyRecord, PrivateKey, ProtocolStore,
PublicKey, SenderKeyStore, ServiceIdKind, SignedPreKeyRecord, Timestamp,
};
use prost::Message;
use serde::{Deserialize, Serialize};
Expand All @@ -30,15 +30,15 @@ use crate::proto::sync_message::PniChangeNumber;
use crate::proto::{DeviceName, SyncMessage};
use crate::provisioning::generate_registration_id;
use crate::push_service::{
AvatarWrite, DeviceActivationRequest, DeviceInfo, HttpAuthOverride,
RecaptchaAttributes, RegistrationMethod, ReqwestExt, ServiceIdType,
VerifyAccountResponse, DEFAULT_DEVICE_ID,
AvatarWrite, CaptchaAttributes, DeviceActivationRequest, DeviceInfo,
HttpAuthOverride, RegistrationMethod, ReqwestExt, VerifyAccountResponse,
DEFAULT_DEVICE_ID,
};
use crate::sender::OutgoingPushMessage;
use crate::service_address::ServiceIdExt;
use crate::session_store::SessionStoreExt;
use crate::timestamp::TimestampExt as _;
use crate::utils::{random_length_padding, BASE64_RELAXED};
use crate::ServiceAddress;
use crate::{
configuration::{Endpoint, ServiceCredentials},
pre_keys::PreKeyState,
Expand Down Expand Up @@ -95,13 +95,13 @@ impl AccountManager {
>(
&mut self,
protocol_store: &mut P,
service_id_type: ServiceIdType,
service_id_kind: ServiceIdKind,
csprng: &mut R,
use_last_resort_key: bool,
) -> Result<(), ServiceError> {
let prekey_status = match self
.service
.get_pre_key_status(service_id_type)
.get_pre_key_status(service_id_kind)
.instrument(tracing::span!(
tracing::Level::DEBUG,
"Fetching pre key status"
Expand Down Expand Up @@ -203,7 +203,7 @@ impl AccountManager {
};

self.service
.register_pre_keys(service_id_type, pre_key_state)
.register_pre_keys(service_id_kind, pre_key_state)
.instrument(tracing::span!(
tracing::Level::DEBUG,
"Uploading pre keys"
Expand Down Expand Up @@ -495,7 +495,7 @@ impl AccountManager {

pub async fn retrieve_profile(
&mut self,
address: ServiceAddress,
address: Aci,
) -> Result<Profile, ProfileManagerError> {
let profile_key =
self.profile_key.expect("set profile key in AccountManager");
Expand Down Expand Up @@ -624,10 +624,10 @@ impl AccountManager {
Endpoint::service("/v1/challenge"),
HttpAuthOverride::NoOverride,
)?
.json(&RecaptchaAttributes {
r#type: String::from("recaptcha"),
token: String::from(token),
captcha: String::from(captcha),
.json(&CaptchaAttributes {
challenge_type: "captcha",
token,
captcha,
})
.send()
.await?
Expand All @@ -642,19 +642,19 @@ impl AccountManager {
/// 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.
#[tracing::instrument(skip(self, aci_protocol_store, pni_protocol_store, sender, local_aci), fields(local_aci = %local_aci))]
#[tracing::instrument(skip(self, aci_protocol_store, pni_protocol_store, sender, local_aci), fields(local_aci = %local_aci.service_id_string()))]
pub async fn pnp_initialize_devices<
// XXX So many constraints here, all imposed by the MessageSender
R: rand::Rng + rand::CryptoRng,
Aci: PreKeysStore + SessionStoreExt,
Pni: PreKeysStore,
AciStore: PreKeysStore + SessionStoreExt,
PniStore: PreKeysStore,
AciOrPni: ProtocolStore + SenderKeyStore + SessionStoreExt + Sync + Clone,
>(
&mut self,
aci_protocol_store: &mut Aci,
pni_protocol_store: &mut Pni,
aci_protocol_store: &mut AciStore,
pni_protocol_store: &mut PniStore,
mut sender: MessageSender<AciOrPni>,
local_aci: ServiceAddress,
local_aci: Aci,
e164: PhoneNumber,
) -> Result<(), MessageSenderError> {
let mut csprng = rand::thread_rng();
Expand All @@ -665,7 +665,7 @@ impl AccountManager {

// 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)
.get_sub_device_sessions(&local_aci.into())
.await?;

let mut device_messages =
Expand Down Expand Up @@ -809,7 +809,7 @@ impl AccountManager {
let content: ContentBody = msg.into();
let msg = sender
.create_encrypted_message(
&local_aci,
&local_aci.into(),
None,
local_device_id.into(),
&content.into_proto().encode_to_vec(),
Expand Down
19 changes: 11 additions & 8 deletions src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use libsignal_protocol::{
CiphertextMessageType, DeviceId, IdentityKeyStore, KyberPreKeyStore,
PreKeySignalMessage, PreKeyStore, ProtocolAddress, ProtocolStore,
PublicKey, SealedSenderDecryptionResult, SenderCertificate,
SenderKeyDistributionMessage, SenderKeyStore, SessionStore, SignalMessage,
SignalProtocolError, SignedPreKeyStore, Timestamp,
SenderKeyDistributionMessage, SenderKeyStore, ServiceId, SessionStore,
SignalMessage, SignalProtocolError, SignedPreKeyStore, Timestamp,
};
use prost::Message;
use uuid::Uuid;
Expand All @@ -22,7 +22,7 @@ use crate::{
sender::OutgoingPushMessage,
session_store::SessionStoreExt,
utils::BASE64_RELAXED,
ServiceAddress,
ServiceIdExt,
};
/// Decrypts incoming messages and encrypts outgoing messages.
///
Expand Down Expand Up @@ -271,13 +271,16 @@ where
)
.await?;

let sender = ServiceAddress::try_from(sender_uuid.as_str())
.map_err(|e| {
tracing::error!("{:?}", e);
let Some(sender) =
ServiceId::parse_from_service_id_string(&sender_uuid)
else {
return Err(
SignalProtocolError::InvalidSealedSenderMessage(
"invalid sender UUID".to_string(),
)
})?;
.into(),
);
};

let needs_receipt = if envelope.source_service_id.is_some() {
tracing::warn!(?envelope, "Received an unidentified delivery over an identified channel. Marking needs_receipt=false");
Expand Down Expand Up @@ -446,7 +449,7 @@ fn strip_padding(contents: &mut Vec<u8>) -> Result<(), ServiceError> {
/// Equivalent of `SignalServiceCipher::getPreferredProtocolAddress`
pub async fn get_preferred_protocol_address<S: SessionStore>(
session_store: &S,
address: &ServiceAddress,
address: &ServiceId,
device_id: DeviceId,
) -> Result<ProtocolAddress, libsignal_protocol::error::SignalProtocolError> {
let address = address.to_protocol_address(device_id);
Expand Down
9 changes: 5 additions & 4 deletions src/content.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use libsignal_protocol::ProtocolAddress;
use libsignal_protocol::{ProtocolAddress, ServiceId};
use std::fmt;
use uuid::Uuid;

Expand All @@ -12,15 +12,16 @@ pub use crate::{
SyncMessage, TypingMessage,
},
push_service::ServiceError,
ServiceIdExt,
};

mod data_message;
mod story_message;

#[derive(Clone, Debug)]
pub struct Metadata {
pub sender: crate::ServiceAddress,
pub destination: crate::ServiceAddress,
pub sender: ServiceId,
pub destination: ServiceId,
pub sender_device: u32,
pub timestamp: u64,
pub needs_receipt: bool,
Expand All @@ -37,7 +38,7 @@ impl fmt::Display for Metadata {
write!(
f,
"Metadata {{ sender: {}, guid: {} }}",
self.sender.to_service_id(),
self.sender.service_id_string(),
// XXX: should this still be optional?
self.server_guid
.map(|u| u.to_string())
Expand Down
93 changes: 12 additions & 81 deletions src/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
use std::convert::{TryFrom, TryInto};

use aes::cipher::block_padding::Pkcs7;
use aes::cipher::{BlockDecryptMut, KeyIvInit};
use libsignal_protocol::ServiceId;
use prost::Message;

use crate::{
configuration::SignalingKey, push_service::ServiceError,
utils::serde_optional_base64, ParseServiceAddressError, ServiceAddress,
};
use crate::{configuration::SignalingKey, push_service::ServiceError};

pub use crate::proto::Envelope;

impl TryFrom<EnvelopeEntity> for Envelope {
type Error = ParseServiceAddressError;

fn try_from(entity: EnvelopeEntity) -> Result<Self, Self::Error> {
match entity.source_uuid.as_deref() {
Some(uuid) => {
let address = uuid.try_into()?;
Ok(Envelope::new_with_source(entity, address))
},
None => Ok(Envelope::new_from_entity(entity)),
}
}
}

impl Envelope {
#[tracing::instrument(skip(input, signaling_key), fields(signaling_key_present = signaling_key.is_some(), input_size = input.len()))]
pub fn decrypt(
Expand Down Expand Up @@ -85,30 +67,6 @@ impl Envelope {
}
}

fn new_from_entity(entity: EnvelopeEntity) -> Self {
Envelope {
gferon marked this conversation as resolved.
Show resolved Hide resolved
r#type: Some(entity.r#type),
timestamp: Some(entity.timestamp),
server_timestamp: Some(entity.server_timestamp),
server_guid: Some(entity.guid),
content: entity.content,
..Default::default()
}
}

fn new_with_source(entity: EnvelopeEntity, source: ServiceAddress) -> Self {
Envelope {
r#type: Some(entity.r#type),
source_device: Some(entity.source_device),
timestamp: Some(entity.timestamp),
server_timestamp: Some(entity.server_timestamp),
server_guid: Some(entity.guid),
source_service_id: Some(source.uuid.to_string()),
content: entity.content,
..Default::default()
}
}

pub fn is_unidentified_sender(&self) -> bool {
self.r#type() == crate::proto::envelope::Type::UnidentifiedSender
}
Expand All @@ -134,54 +92,27 @@ impl Envelope {
self.story.unwrap_or(false)
}

pub fn source_address(&self) -> ServiceAddress {
pub fn source_address(&self) -> ServiceId {
match self.source_service_id.as_deref() {
Some(service_id) => ServiceAddress::try_from(service_id)
.expect("invalid source ProtocolAddress UUID or prefix"),
Some(service_id) => {
ServiceId::parse_from_service_id_string(service_id)
.expect("invalid source ProtocolAddress UUID or prefix")
},
None => panic!("source_service_id is set"),
}
}

pub fn destination_address(&self) -> ServiceAddress {
pub fn destination_address(&self) -> ServiceId {
match self.destination_service_id.as_deref() {
Some(service_id) => ServiceAddress::try_from(service_id)
.expect("invalid destination ProtocolAddress UUID or prefix"),
Some(service_id) => ServiceId::parse_from_service_id_string(
service_id,
)
.expect("invalid destination ProtocolAddress UUID or prefix"),
None => panic!("destination_address is set"),
}
}
}

#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EnvelopeEntity {
pub r#type: i32,
pub timestamp: u64,
pub source: Option<String>,
pub source_uuid: Option<String>,
pub source_device: u32,
#[serde(default)]
pub destination_uuid: Option<String>,
#[serde(default, with = "serde_optional_base64")]
pub content: Option<Vec<u8>>,
pub server_timestamp: u64,
pub guid: String,
#[serde(default = "default_true")]
pub urgent: bool,
#[serde(default)]
pub story: bool,
#[serde(default, with = "serde_optional_base64")]
pub report_spam_token: Option<Vec<u8>>,
}

fn default_true() -> bool {
true
}

#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) struct EnvelopeEntityList {
pub messages: Vec<EnvelopeEntity>,
}

pub(crate) const SUPPORTED_VERSION: u8 = 1;
pub(crate) const CIPHER_KEY_SIZE: usize = 32;
pub(crate) const MAC_KEY_SIZE: usize = 20;
Expand Down
5 changes: 2 additions & 3 deletions src/groups_v2/model.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::{convert::TryFrom, convert::TryInto};

use derivative::Derivative;
use libsignal_protocol::ServiceId;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use zkgroup::profiles::ProfileKey;

use crate::ServiceAddress;

use super::GroupDecodingError;

#[derive(Copy, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
Expand Down Expand Up @@ -34,7 +33,7 @@ impl PartialEq for Member {

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PendingMember {
pub address: ServiceAddress,
pub address: ServiceId,
pub role: Role,
pub added_by_uuid: Uuid,
pub timestamp: u64,
Expand Down
2 changes: 1 addition & 1 deletion src/groups_v2/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl GroupOperations {
let added_by_uuid = self.decrypt_aci(&member.added_by_user_id)?;

Ok(PendingMember {
address: service_id.into(),
address: service_id,
role: inner_member.role.try_into()?,
added_by_uuid: added_by_uuid.into(),
timestamp: member.timestamp,
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub mod messagepipe;
pub mod models;
pub mod pre_keys;
pub mod profile_name;
pub mod profile_service;
#[allow(clippy::derive_partial_eq_without_eq)]
pub mod proto;
pub mod provisioning;
Expand Down Expand Up @@ -49,7 +48,6 @@ pub const GROUP_UPDATE_FLAG: u32 = 1;
pub const GROUP_LEAVE_FLAG: u32 = 2;

pub mod prelude {
pub use super::ServiceAddress;
pub use crate::{
cipher::ServiceCipher,
configuration::{
Expand Down
Loading
Loading