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

Implement PNI #285

Merged
merged 34 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
588ca72
PushService::distribute_pni_keys
rubdos Jan 14, 2024
db4466b
Stop returning next pre key id's from update_pre_key_bundle
rubdos Jan 14, 2024
6e29804
Take IdentityKey by ref
rubdos Jan 14, 2024
b3f6f2b
Factor out generation of pre keys to separate function
rubdos Jan 14, 2024
27b07fb
WIP pnp_initialize_devices
rubdos Jan 14, 2024
5581048
Deduplicate SignedPreKeyEntity and SignedPreKey
rubdos Jan 14, 2024
4555591
WIP pnp_initialize_devices
rubdos Jan 14, 2024
dc42322
Implement last resort pre key through extension trait
rubdos Jan 30, 2024
b57d4d6
Deduplicate pre key gen code for device linking
rubdos Jan 30, 2024
6c7b1cc
Move generate_pre_keys into pre_keys.rs
rubdos Jan 30, 2024
78aa4a8
Use IdentityKey where it makes sense
rubdos Jan 30, 2024
f8ea086
Don't generate last resort key if already stored
rubdos Mar 9, 2024
5b8b840
WIP distribution message
rubdos Mar 9, 2024
30e5ef5
Remove Clone bound on some generics
rubdos Mar 9, 2024
bc9d1f6
generate_prekeys to return Records instead of Entity
rubdos Mar 9, 2024
ba774e7
PreKeyEntity TryFrom based on ref instead of move
rubdos Mar 9, 2024
68894e5
Distribution message
rubdos Mar 9, 2024
e87df73
Implement random padding
rubdos Mar 9, 2024
afb41ec
Some asserts for pre key gen
rubdos Mar 9, 2024
04edb85
More flexible trait bounds on pnp_initialize_devices
rubdos Mar 9, 2024
3077ada
Implement PNI signatures
rubdos Mar 9, 2024
48bd383
Rename generate_pre_keys to replenish_pre_keys
rubdos Mar 11, 2024
2b51a34
Add DeviceActivationRequest to linking and registration
rubdos Mar 12, 2024
e00c5a0
AccountManager::register_account
rubdos Mar 12, 2024
99c7f2b
Add example store
rubdos Mar 13, 2024
8c1b9b6
Fix registration examples
rubdos Mar 13, 2024
df600f6
Fix storage example fn main
rubdos Mar 13, 2024
55486a5
Don't require signaling key when not needed
rubdos Mar 13, 2024
ae373b4
Log pre key upload
rubdos Mar 13, 2024
f92b19d
Rename pnp -> pni field
rubdos Mar 13, 2024
5a5150c
Update DeviceCapabilities to be in sync with SA
rubdos Mar 13, 2024
95e859f
Bump protobufs
rubdos Mar 13, 2024
05b4fcc
Allow force-refreshing prekeys
rubdos Mar 13, 2024
4255520
Fix envelope decryption test
rubdos Mar 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libsignal-service-actix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ async-trait = "0.1"
phonenumber = "0.3"

[dev-dependencies]
chrono = "0.4"
image = { version = "0.23", default-features = false, features = ["png"] }
opener = "0.5"
qrcode = "0.12"
Expand Down
18 changes: 15 additions & 3 deletions libsignal-service-actix/examples/registering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ use libsignal_service::push_service::{
AccountAttributes, DeviceCapabilities, PushService, RegistrationMethod,
VerificationTransport,
};
use libsignal_service::USER_AGENT;
use libsignal_service::{AccountManager, USER_AGENT};
use libsignal_service_actix::prelude::AwcPushService;
use rand::RngCore;
use structopt::StructOpt;

#[path = "../../libsignal-service/examples/storage.rs"]
mod storage;

#[actix_rt::main]
async fn main() -> Result<(), Error> {
let client = "libsignal-service-hyper-example";
Expand Down Expand Up @@ -136,8 +139,15 @@ async fn main() -> Result<(), Error> {
rand::thread_rng().fill_bytes(&mut profile_key);
let profile_key = ProfileKey::create(profile_key);
let skip_device_transfer = false;
let _registration_data = push_service
.submit_registration_request(

// Create the prekeys storage
let mut aci_store = storage::ExampleStore::new();
let mut pni_store = storage::ExampleStore::new();

let mut account_manager = AccountManager::new(push_service, None);
let _registration_data = account_manager
.register_account(
&mut rand::thread_rng(),
RegistrationMethod::SessionId(&session.id),
AccountAttributes {
signaling_key: Some(signaling_key.to_vec()),
Expand All @@ -156,6 +166,8 @@ async fn main() -> Result<(), Error> {
name: Some("libsignal-service-hyper test".into()),
capabilities: DeviceCapabilities::default(),
},
&mut aci_store,
&mut pni_store,
skip_device_transfer,
)
.await;
Expand Down
1 change: 1 addition & 0 deletions libsignal-service-hyper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ tokio-rustls = "0.25"
rustls-pemfile = "2.0"

[dev-dependencies]
chrono = "0.4"
rand = "0.8"
tokio = { version = "1.0", features = ["rt-multi-thread"] }

Expand Down
18 changes: 15 additions & 3 deletions libsignal-service-hyper/examples/registering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ use libsignal_service::push_service::{
AccountAttributes, DeviceCapabilities, PushService, RegistrationMethod,
VerificationTransport,
};
use libsignal_service::USER_AGENT;
use libsignal_service::{AccountManager, USER_AGENT};

use libsignal_service_hyper::prelude::HyperPushService;

use rand::RngCore;

#[path = "../../libsignal-service/examples/storage.rs"]
mod storage;

#[tokio::main]
async fn main() {
let client = "libsignal-service-hyper-example";
Expand Down Expand Up @@ -104,8 +107,15 @@ async fn main() {
rand::thread_rng().fill_bytes(&mut profile_key);
let profile_key = ProfileKey::create(profile_key);
let skip_device_transfer = false;
let _registration_data = push_service
.submit_registration_request(

// Create the prekeys storage
let mut aci_store = storage::ExampleStore::new();
let mut pni_store = storage::ExampleStore::new();

let mut account_manager = AccountManager::new(push_service, None);
let _registration_data = account_manager
.register_account(
&mut rand::thread_rng(),
RegistrationMethod::SessionId(&session.id),
AccountAttributes {
signaling_key: Some(signaling_key.to_vec()),
Expand All @@ -124,6 +134,8 @@ async fn main() {
name: Some("libsignal-service-hyper test".into()),
capabilities: DeviceCapabilities::default(),
},
&mut aci_store,
&mut pni_store,
skip_device_transfer,
)
.await;
Expand Down
235 changes: 235 additions & 0 deletions libsignal-service/examples/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
use libsignal_service::pre_keys::{PreKeysStore, ServiceKyberPreKeyStore};
use libsignal_service::protocol::{
Direction, IdentityKey, IdentityKeyPair, IdentityKeyStore, KyberPreKeyId,
KyberPreKeyRecord, KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore,
ProtocolAddress, SignalProtocolError, SignedPreKeyId, SignedPreKeyRecord,
SignedPreKeyStore,
};

pub struct ExampleStore {}

impl ExampleStore {
pub fn new() -> Self {
Self {}
}
}

#[async_trait::async_trait(?Send)]
impl PreKeyStore for ExampleStore {
/// Look up the pre-key corresponding to `prekey_id`.
async fn get_pre_key(
&self,
_prekey_id: PreKeyId,
) -> Result<PreKeyRecord, SignalProtocolError> {
todo!()
}

/// Set the entry for `prekey_id` to the value of `record`.
async fn save_pre_key(
&mut self,
_prekey_id: PreKeyId,
_record: &PreKeyRecord,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// Remove the entry for `prekey_id`.
async fn remove_pre_key(
&mut self,
_prekey_id: PreKeyId,
) -> Result<(), SignalProtocolError> {
todo!()
}
}

#[async_trait::async_trait(?Send)]
impl KyberPreKeyStore for ExampleStore {
/// Look up the signed kyber pre-key corresponding to `kyber_prekey_id`.
async fn get_kyber_pre_key(
&self,
_kyber_prekey_id: KyberPreKeyId,
) -> Result<KyberPreKeyRecord, SignalProtocolError> {
todo!()
}

/// Set the entry for `kyber_prekey_id` to the value of `record`.
async fn save_kyber_pre_key(
&mut self,
_kyber_prekey_id: KyberPreKeyId,
_record: &KyberPreKeyRecord,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// Mark the entry for `kyber_prekey_id` as "used".
/// This would mean different things for one-time and last-resort Kyber keys.
async fn mark_kyber_pre_key_used(
&mut self,
_kyber_prekey_id: KyberPreKeyId,
) -> Result<(), SignalProtocolError> {
todo!()
}
}

#[async_trait::async_trait(?Send)]
impl SignedPreKeyStore for ExampleStore {
/// Look up the signed pre-key corresponding to `signed_prekey_id`.
async fn get_signed_pre_key(
&self,
_signed_prekey_id: SignedPreKeyId,
) -> Result<SignedPreKeyRecord, SignalProtocolError> {
todo!()
}

/// Set the entry for `signed_prekey_id` to the value of `record`.
async fn save_signed_pre_key(
&mut self,
_signed_prekey_id: SignedPreKeyId,
_record: &SignedPreKeyRecord,
) -> Result<(), SignalProtocolError> {
todo!()
}
}

#[async_trait::async_trait(?Send)]
impl ServiceKyberPreKeyStore for ExampleStore {
async fn store_last_resort_kyber_pre_key(
&mut self,
_kyber_prekey_id: KyberPreKeyId,
_record: &KyberPreKeyRecord,
) -> Result<(), SignalProtocolError> {
todo!()
}

async fn load_last_resort_kyber_pre_keys(
&self,
) -> Result<Vec<KyberPreKeyRecord>, SignalProtocolError> {
todo!()
}

async fn remove_kyber_pre_key(
&mut self,
_kyber_prekey_id: KyberPreKeyId,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// Analogous to markAllOneTimeKyberPreKeysStaleIfNecessary
async fn mark_all_one_time_kyber_pre_keys_stale_if_necessary(
&mut self,
_stale_time: chrono::DateTime<chrono::Utc>,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// Analogue of deleteAllStaleOneTimeKyberPreKeys
async fn delete_all_stale_one_time_kyber_pre_keys(
&mut self,
_threshold: chrono::DateTime<chrono::Utc>,
_min_count: usize,
) -> Result<(), SignalProtocolError> {
todo!()
}
}

#[async_trait::async_trait(?Send)]
impl IdentityKeyStore for ExampleStore {
/// Return the single specific identity the store is assumed to represent, with private key.
async fn get_identity_key_pair(
&self,
) -> Result<IdentityKeyPair, SignalProtocolError> {
todo!()
}

/// Return a [u32] specific to this store instance.
///
/// This local registration id is separate from the per-device identifier used in
/// [ProtocolAddress] and should not change run over run.
///
/// If the same *device* is unregistered, then registers again, the [ProtocolAddress::device_id]
/// may be the same, but the store registration id returned by this method should
/// be regenerated.
async fn get_local_registration_id(
&self,
) -> Result<u32, SignalProtocolError> {
todo!()
}

// TODO: make this into an enum instead of a bool!
/// Record an identity into the store. The identity is then considered "trusted".
///
/// The return value represents whether an existing identity was replaced (`Ok(true)`). If it is
/// new or hasn't changed, the return value should be `Ok(false)`.
async fn save_identity(
&mut self,
_address: &ProtocolAddress,
_identity: &IdentityKey,
) -> Result<bool, SignalProtocolError> {
todo!()
}

/// Return whether an identity is trusted for the role specified by `direction`.
async fn is_trusted_identity(
&self,
_address: &ProtocolAddress,
_identity: &IdentityKey,
_direction: Direction,
) -> Result<bool, SignalProtocolError> {
todo!()
}

/// Return the public identity for the given `address`, if known.
async fn get_identity(
&self,
_address: &ProtocolAddress,
) -> Result<Option<IdentityKey>, SignalProtocolError> {
todo!()
}
}

#[async_trait::async_trait(?Send)]
impl PreKeysStore for ExampleStore {
/// ID of the next pre key
async fn next_pre_key_id(&self) -> Result<u32, SignalProtocolError> {
todo!()
}

/// ID of the next signed pre key
async fn next_signed_pre_key_id(&self) -> Result<u32, SignalProtocolError> {
todo!()
}

/// ID of the next PQ pre key
async fn next_pq_pre_key_id(&self) -> Result<u32, SignalProtocolError> {
todo!()
}

/// set the ID of the next pre key
async fn set_next_pre_key_id(
&mut self,
_id: u32,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// set the ID of the next signed pre key
async fn set_next_signed_pre_key_id(
&mut self,
_id: u32,
) -> Result<(), SignalProtocolError> {
todo!()
}

/// set the ID of the next PQ pre key
async fn set_next_pq_pre_key_id(
&mut self,
_id: u32,
) -> Result<(), SignalProtocolError> {
todo!()
}
}

#[allow(dead_code)]
fn main() {
let _ = ExampleStore::new();
}
4 changes: 2 additions & 2 deletions libsignal-service/protobuf/Groups.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ message Member {
bytes userId = 1;
Role role = 2;
bytes profileKey = 3;
bytes presentation = 4;
bytes presentation = 4; // Only set when sending to server
uint32 joinedAtRevision = 5;
}

Expand All @@ -41,7 +41,7 @@ message PendingMember {
message RequestingMember {
bytes userId = 1;
bytes profileKey = 2;
bytes presentation = 3;
bytes presentation = 3; // Only set when sending to server
uint64 timestamp = 4;
}

Expand Down
3 changes: 2 additions & 1 deletion libsignal-service/protobuf/Provisioning.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ message ProvisionMessage {
optional bytes profileKey = 6;
optional bool readReceipts = 7;
optional uint32 provisioningVersion = 9;
// NEXT ID: 13
optional bytes masterKey = 13;
// NEXT ID: 14
}

enum ProvisioningVersion {
Expand Down
Loading
Loading