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
@@ -141,6 +141,9 @@
message.username.clone(),
message.farcaster_id.clone(),
)?;
+ self
+ .check_device_id_taken(®istration_state.flattened_device_key_upload)
+ .await?;
let server_registration = comm_opaque2::server::Registration::new();
let server_message = server_registration
.start(
@@ -197,6 +200,9 @@
message.username.clone(),
None,
)?;
+ self
+ .check_device_id_taken(®istration_state.flattened_device_key_upload)
+ .await?;
let server_registration = comm_opaque2::server::Registration::new();
let server_message = server_registration
.start(
@@ -322,6 +328,13 @@
let flattened_device_key_upload =
construct_flattened_device_key_upload(&message)?;
+ if self
+ .check_device_id_taken(&flattened_device_key_upload)
+ .await
+ .is_err_and(|s| s.code() == tonic::Code::AlreadyExists)
+ {
+ warn!("Device ID already exists. Device data will be replaced.");
+ }
let maybe_device_to_remove = self
.get_keyserver_device_to_remove(
@@ -456,6 +469,13 @@
let flattened_device_key_upload =
construct_flattened_device_key_upload(&message)?;
+ if self
+ .check_device_id_taken(&flattened_device_key_upload)
+ .await
+ .is_err_and(|s| s.code() == tonic::Code::AlreadyExists)
+ {
+ warn!("Device ID already exists. Device data will be replaced.");
+ }
let login_time = chrono::Utc::now();
let Some(user_id) = self
@@ -573,6 +593,9 @@
let flattened_device_key_upload =
construct_flattened_device_key_upload(&message)?;
+ self
+ .check_device_id_taken(&flattened_device_key_upload)
+ .await?;
let login_time = chrono::Utc::now();
@@ -658,6 +681,9 @@
let flattened_device_key_upload =
construct_flattened_device_key_upload(&message)?;
+ self
+ .check_device_id_taken(&flattened_device_key_upload)
+ .await?;
let initial_device_list = message.get_and_verify_initial_device_list()?;
let social_proof =
@@ -722,6 +748,14 @@
let nonce = challenge_response.verify_and_get_nonce(&device_id)?;
self.verify_and_remove_nonce(&nonce).await?;
+ if self
+ .check_device_id_taken(&flattened_device_key_upload)
+ .await
+ .is_err_and(|s| s.code() == tonic::Code::AlreadyExists)
+ {
+ warn!("Device ID already exists. Device data will be replaced.");
+ }
+
let user_identity = self
.client
.get_user_identity(&user_id)
@@ -1048,6 +1082,24 @@
Ok(())
}
+ async fn check_device_id_taken(
+ &self,
+ key_upload: &FlattenedDeviceKeyUpload,
+ ) -> Result<(), tonic::Status> {
+ let device_id = key_upload.device_id_key.as_str();
+ let device_already_exists = self
+ .client
+ .find_user_id_for_device(device_id)
+ .await
+ .map_err(handle_db_error)?
+ .is_some();
+ if device_already_exists {
+ return Err(tonic::Status::already_exists("Device ID already exists"));
+ }
+
+ Ok(())
+ }
+
async fn verify_and_remove_nonce(
&self,
nonce: &str,
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
@@ -746,11 +746,13 @@
Ok(user_devices_keys)
}
+ /// Find owner's user ID for given device ID. Useful for finding
+ /// devices table partition key.
#[tracing::instrument(skip_all)]
- pub async fn find_device_by_id(
+ pub async fn find_user_id_for_device(
&self,
device_id: &str,
- ) -> Result