Page MenuHomePhabricator

D13226.id43848.diff
No OneTemporary

D13226.id43848.diff

diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs
--- a/services/identity/src/client_service.rs
+++ b/services/identity/src/client_service.rs
@@ -5,6 +5,7 @@
use comm_lib::aws::DynamoDBError;
use comm_lib::shared::reserved_users::RESERVED_USERNAME_SET;
use comm_opaque2::grpc::protocol_error_to_grpc_status;
+use grpc_clients::identity::PlatformMetadata;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use siwe::eip55;
@@ -15,7 +16,7 @@
use crate::config::CONFIG;
use crate::constants::{error_types, tonic_status_messages};
use crate::database::{
- DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload, UserInfoAndPasswordFile
+ DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload, UserInfoAndPasswordFile, DeviceListRow
};
use crate::device_list::SignedDeviceList;
use crate::error::{DeviceListError, Error as DBError};
@@ -692,14 +693,93 @@
&self,
request: tonic::Request<RestorePasswordUserRequest>,
) -> Result<tonic::Response<AuthResponse>, tonic::Status> {
- unimplemented!();
+ let platform_metadata = get_platform_metadata(&request)?;
+ let message = request.into_inner();
+ debug!("Attempting to restore user: {:?}", &message.username);
+
+ let user_id = self
+ .client
+ .get_user_id_from_user_info(message.username.clone(), &AuthType::Password)
+ .await
+ .map_err(handle_db_error)?
+ .ok_or_else(|| {
+ tonic::Status::not_found(tonic_status_messages::USER_NOT_FOUND)
+ })?;
+
+ let flattened_device_key_upload =
+ construct_flattened_device_key_upload(&message)?;
+
+ // verify nonce
+ let challenge_response = SignedNonce::try_from(&message)?;
+ let nonce = challenge_response
+ .verify_and_get_nonce(&flattened_device_key_upload.device_id_key)?;
+ self.verify_and_remove_nonce(&nonce).await?;
+
+ let access_token = self
+ .restore_primary_device_and_get_csat(
+ user_id.clone(),
+ message.device_list,
+ platform_metadata,
+ flattened_device_key_upload,
+ )
+ .await?;
+
+ let response = AuthResponse {
+ user_id,
+ access_token,
+ username: message.username,
+ };
+ Ok(Response::new(response))
}
async fn restore_wallet_user(
&self,
request: tonic::Request<RestoreWalletUserRequest>,
) -> Result<tonic::Response<AuthResponse>, tonic::Status> {
- unimplemented!();
+ let platform_metadata = get_platform_metadata(&request)?;
+ let message = request.into_inner();
+
+ let parsed_message = parse_and_verify_siwe_message(
+ &message.siwe_message,
+ &message.siwe_signature,
+ )
+ .await?;
+ self.verify_and_remove_nonce(&parsed_message.nonce).await?;
+ let wallet_address = eip55(&parsed_message.address);
+
+ let user_id = self
+ .client
+ .get_user_id_from_user_info(wallet_address.clone(), &AuthType::Wallet)
+ .await
+ .map_err(handle_db_error)?
+ .ok_or_else(|| {
+ tonic::Status::not_found(tonic_status_messages::USER_NOT_FOUND)
+ })?;
+ let flattened_device_key_upload =
+ construct_flattened_device_key_upload(&message)?;
+
+ let social_proof =
+ SocialProof::new(message.siwe_message, message.siwe_signature);
+ self
+ .client
+ .update_wallet_user_social_proof(&user_id, social_proof)
+ .await?;
+
+ let access_token = self
+ .restore_primary_device_and_get_csat(
+ user_id.clone(),
+ message.device_list,
+ platform_metadata,
+ flattened_device_key_upload,
+ )
+ .await?;
+
+ let response = AuthResponse {
+ user_id,
+ access_token,
+ username: wallet_address,
+ };
+ Ok(Response::new(response))
}
#[tracing::instrument(skip_all)]
@@ -1166,6 +1246,91 @@
))
}
}
+
+ /// This function is used in Backup Restore protocol. It:
+ /// - Verifies singleton device list with both old and new primary signature
+ /// - Performs device list update (updates with singleton payload)
+ /// - Removes all CSATs, OTKs, Devices data for all devices
+ /// - Closes Tunnelbroker connections with these devices
+ /// - Registers the new primary device (Device Key Upload)
+ /// - Issues a new CSAT for the new primary device and returns it
+ async fn restore_primary_device_and_get_csat(
+ &self,
+ user_id: String,
+ device_list_payload: String,
+ platform_metadata: PlatformMetadata,
+ device_key_upload: FlattenedDeviceKeyUpload,
+ ) -> Result<String, tonic::Status> {
+ let new_primary_device_id = device_key_upload.device_id_key.clone();
+ let previous_primary_device_id = self
+ .client
+ .get_current_device_list(&user_id)
+ .await?
+ .and_then(|device_list| device_list.primary_device_id().cloned())
+ .ok_or_else(|| {
+ error!(
+ user_id = redact_sensitive_data(&user_id),
+ errorType = error_types::GRPC_SERVICES_LOG,
+ "User had missing or empty device list (before backup restore)!"
+ );
+ tonic::Status::failed_precondition(
+ tonic_status_messages::NO_DEVICE_LIST,
+ )
+ })?;
+
+ // Verify device list payload
+ let signed_list: SignedDeviceList = device_list_payload.parse()?;
+ let device_list_payload =
+ crate::database::DeviceListUpdate::try_from(signed_list)?;
+ crate::device_list::verify_singleton_device_list(
+ &device_list_payload,
+ &new_primary_device_id,
+ Some(&previous_primary_device_id),
+ )?;
+
+ debug!(user_id, "Attempting to revoke user's old access tokens");
+ self.client.delete_all_tokens_for_user(&user_id).await?;
+ // We must delete the one-time keys first because doing so requires device
+ // IDs from the devices table
+ debug!(user_id, "Attempting to delete user's old one-time keys");
+ self
+ .client
+ .delete_otks_table_rows_for_user(&user_id)
+ .await?;
+ debug!(user_id, "Attempting to delete user's old devices");
+ let _old_device_ids =
+ self.client.delete_devices_data_for_user(&user_id).await?;
+
+ // TODO: Revoke TB sessions with previous devices
+
+ // Reset device list (perform update)
+ let login_time = chrono::Utc::now();
+ self
+ .client
+ .register_primary_device(
+ &user_id,
+ device_key_upload,
+ platform_metadata,
+ login_time,
+ device_list_payload,
+ )
+ .await
+ .map_err(handle_db_error)?;
+
+ // Create new access token
+ let token_data = AccessTokenData::with_created_time(
+ user_id.clone(),
+ new_primary_device_id,
+ login_time,
+ crate::token::AuthType::Password,
+ &mut OsRng,
+ );
+
+ let access_token = token_data.access_token.clone();
+ self.client.put_access_token_data(token_data).await?;
+
+ Ok(access_token)
+ }
}
#[tracing::instrument(skip_all)]
@@ -1200,6 +1365,12 @@
}
}
+impl From<DBError> for tonic::Status {
+ fn from(err: DBError) -> Self {
+ handle_db_error(err)
+ }
+}
+
fn construct_user_registration_info(
message: &(impl DeviceKeyUploadActions + RegistrationActions),
user_id: Option<String>,
diff --git a/services/identity/src/database/device_list.rs b/services/identity/src/database/device_list.rs
--- a/services/identity/src/database/device_list.rs
+++ b/services/identity/src/database/device_list.rs
@@ -197,6 +197,10 @@
pub fn has_secondary_device(&self, device_id: &String) -> bool {
self.has_device(device_id) && !self.is_primary_device(device_id)
}
+
+ pub fn primary_device_id(&self) -> Option<&String> {
+ self.device_ids.first()
+ }
}
impl PlatformDetails {

File Metadata

Mime Type
text/plain
Expires
Thu, Sep 19, 3:11 PM (6 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2140060
Default Alt Text
D13226.id43848.diff (7 KB)

Event Timeline