Skip to content

Commit

Permalink
Link secondary devices as primary device
Browse files Browse the repository at this point in the history
  • Loading branch information
Schmiddiii committed Nov 11, 2023
1 parent 1f87b0f commit 9019a2a
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
4 changes: 3 additions & 1 deletion presage-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,9 @@ async fn run<C: Store + 'static>(subcommand: Cmd, config_store: C) -> anyhow::Re
async move {
match provisioning_link_rx.await {
Ok(url) => {
qr2term::print_qr(url.to_string()).expect("failed to render qrcode")
println!("Please scan in the QR code:");
qr2term::print_qr(url.to_string()).expect("failed to render qrcode");
println!("Alternatively, use the URL: {}", url);
}
Err(e) => log::error!("Error linking device: {e}"),
}
Expand Down
4 changes: 4 additions & 0 deletions presage/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ pub enum Error<S: std::error::Error> {
RequestingCodeForbidden(libsignal_service::push_service::RegistrationSessionMetadataResponse),
#[error("Unverified registration session (i.e. wrong verification code)")]
UnverifiedRegistrationSession,
#[error("Failed to link secondary device")]
ServiceLinkError(#[from] libsignal_service::LinkError),
#[error("An operation was requested that requires the registration to be primary, but it was only secondary")]
NotPrimaryDevice,
}

impl<S: StoreError> From<S> for Error<S> {
Expand Down
1 change: 1 addition & 0 deletions presage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod store;
pub use errors::Error;
pub use manager::{
Confirmation, Linking, Manager, ReceivingMode, Registered, Registration, RegistrationOptions,
RegistrationType,
};
pub use store::{ContentTimestamp, Store, StoreError, Thread};

Expand Down
55 changes: 54 additions & 1 deletion presage/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rand::{
use serde::{Deserialize, Serialize};
use url::Url;

use libsignal_service::push_service::{RegistrationMethod, VerificationTransport};
use libsignal_service::push_service::{DeviceInfo, RegistrationMethod, VerificationTransport};
use libsignal_service::{
attachment_cipher::decrypt_in_place,
cipher,
Expand Down Expand Up @@ -71,6 +71,12 @@ impl<Store, State: fmt::Debug> fmt::Debug for Manager<Store, State> {
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RegistrationType {
Primary,
Secondary,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct RegistrationOptions<'a> {
pub signal_servers: SignalServers,
Expand Down Expand Up @@ -1320,6 +1326,53 @@ impl<C: Store> Manager<C, Registered> {
}
}

/// Returns how this client was registered, either as a primary or secondary device.
pub fn registration_type(&self) -> RegistrationType {
if self.state.device_name.is_some() {
RegistrationType::Secondary
} else {
RegistrationType::Primary
}
}

/// As a primary device, link a secondary device.
pub async fn link_secondary(&self, secondary: Url) -> Result<(), Error<C::Error>> {
// XXX: What happens if secondary device? Possible to use static typing to make this method call impossible in that case?
if self.registration_type() != RegistrationType::Primary {
return Err(Error::NotPrimaryDevice);
}

let credentials = self.credentials()?.ok_or(Error::NotYetRegisteredError)?;
let mut account_manager =
AccountManager::new(self.push_service()?, Some(self.state.profile_key));
let store = &self.config_store;

account_manager
.link_device(secondary, store, credentials)
.await?;
Ok(())
}

/// As a primary device, unlink a secondary device.
pub async fn unlink_secondary(&self, device_id: i64) -> Result<(), Error<C::Error>> {
// XXX: What happens if secondary device? Possible to use static typing to make this method call impossible in that case?
if self.registration_type() != RegistrationType::Primary {
return Err(Error::NotPrimaryDevice);
}
self.push_service()?.unlink_device(device_id).await?;
Ok(())
}

/// As a primary device, list all the devices.
// XXX: Also shows the current device?
pub async fn linked_devices(&self) -> Result<Vec<DeviceInfo>, Error<C::Error>> {
// XXX: What happens if secondary device? Possible to use static typing to make this method call impossible in that case?
if self.registration_type() != RegistrationType::Primary {
return Err(Error::NotPrimaryDevice);
}
Ok(self.push_service()?.devices().await?)
}

#[deprecated = "use Manager::contact_by_id"]
pub fn get_contacts(
&self,
Expand Down

0 comments on commit 9019a2a

Please sign in to comment.