Page MenuHomePhorge

D12544.1767389719.diff
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

D12544.1767389719.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
@@ -116,9 +116,10 @@
self.check_username_taken(&message.username).await?;
let username_in_reserved_usernames_table = self
.client
- .username_in_reserved_usernames_table(&message.username)
+ .get_user_id_from_reserved_usernames_table(&message.username)
.await
- .map_err(handle_db_error)?;
+ .map_err(handle_db_error)?
+ .is_some();
if username_in_reserved_usernames_table {
return Err(tonic::Status::already_exists(
@@ -187,9 +188,10 @@
let username_in_reserved_usernames_table = self
.client
- .username_in_reserved_usernames_table(&message.username)
+ .get_user_id_from_reserved_usernames_table(&message.username)
.await
- .map_err(handle_db_error)?;
+ .map_err(handle_db_error)?
+ .is_some();
if !username_in_reserved_usernames_table {
return Err(tonic::Status::permission_denied(
tonic_status_messages::USERNAME_NOT_RESERVED,
@@ -326,9 +328,10 @@
// service.
let username_in_reserved_usernames_table = self
.client
- .username_in_reserved_usernames_table(&message.username)
+ .get_user_id_from_reserved_usernames_table(&message.username)
.await
- .map_err(handle_db_error)?;
+ .map_err(handle_db_error)?
+ .is_some();
if username_in_reserved_usernames_table {
return Err(tonic::Status::permission_denied(
@@ -484,48 +487,77 @@
construct_flattened_device_key_upload(&message)?;
let login_time = chrono::Utc::now();
- let Some(user_id) = self
+
+ let user_id = if let Some(user_id) = self
.client
- .get_user_id_from_user_info(wallet_address.clone(), &AuthType::Wallet)
+ .get_user_id_from_reserved_usernames_table(&wallet_address)
.await
.map_err(handle_db_error)?
- else {
+ {
// It's possible that the user attempting login is already registered
- // on Ashoat's keyserver. If they are, we should send back a gRPC status
- // code instructing them to get a signed message from Ashoat's keyserver
- // in order to claim their wallet address and register with the Identity
- // service.
- let username_in_reserved_usernames_table = self
+ // on Ashoat's keyserver. If they are, we should try to register them if
+ // they're on a mobile device, otherwise we should send back a gRPC status
+ // code instructing them to try logging in from a mobile device first.
+ if platform_metadata.device_type.to_uppercase() != "ANDROID"
+ && platform_metadata.device_type.to_uppercase() != "IOS"
+ {
+ return Err(tonic::Status::permission_denied(
+ tonic_status_messages::RETRY_FROM_NATIVE,
+ ));
+ };
+
+ let social_proof =
+ SocialProof::new(message.siwe_message, message.siwe_signature);
+
+ self
+ .check_device_id_taken(&flattened_device_key_upload, Some(&user_id))
+ .await?;
+
+ self
.client
- .username_in_reserved_usernames_table(&wallet_address)
+ .add_wallet_user_to_users_table(
+ flattened_device_key_upload.clone(),
+ wallet_address.clone(),
+ social_proof,
+ Some(user_id.clone()),
+ platform_metadata,
+ login_time,
+ message.farcaster_id,
+ None,
+ )
.await
.map_err(handle_db_error)?;
- if username_in_reserved_usernames_table {
- return Err(tonic::Status::permission_denied(
- tonic_status_messages::NEED_KEYSERVER_MESSAGE_TO_CLAIM_USERNAME,
+ user_id
+ } else {
+ let Some(user_id) = self
+ .client
+ .get_user_id_from_user_info(wallet_address.clone(), &AuthType::Wallet)
+ .await
+ .map_err(handle_db_error)?
+ else {
+ return Err(tonic::Status::not_found(
+ tonic_status_messages::USER_NOT_FOUND,
));
- }
+ };
- return Err(tonic::Status::not_found(
- tonic_status_messages::USER_NOT_FOUND,
- ));
- };
+ self
+ .check_device_id_taken(&flattened_device_key_upload, Some(&user_id))
+ .await?;
- self
- .check_device_id_taken(&flattened_device_key_upload, Some(&user_id))
- .await?;
+ self
+ .client
+ .add_user_device(
+ user_id.clone(),
+ flattened_device_key_upload.clone(),
+ platform_metadata,
+ chrono::Utc::now(),
+ )
+ .await
+ .map_err(handle_db_error)?;
- self
- .client
- .add_user_device(
- user_id.clone(),
- flattened_device_key_upload.clone(),
- platform_metadata,
- chrono::Utc::now(),
- )
- .await
- .map_err(handle_db_error)?;
+ user_id
+ };
// Create access token
let token = AccessTokenData::with_created_time(
@@ -565,39 +597,17 @@
&message.siwe_signature,
)?;
- match self
- .client
- .get_nonce_from_nonces_table(&parsed_message.nonce)
- .await
- .map_err(handle_db_error)?
- {
- None => {
- return Err(tonic::Status::invalid_argument(
- tonic_status_messages::INVALID_NONCE,
- ))
- }
- Some(nonce) if nonce.is_expired() => {
- // we don't need to remove the nonce from the table here
- // because the DynamoDB TTL will take care of it
- return Err(tonic::Status::aborted(
- tonic_status_messages::NONCE_EXPIRED,
- ));
- }
- Some(_) => self
- .client
- .remove_nonce_from_nonces_table(&parsed_message.nonce)
- .await
- .map_err(handle_db_error)?,
- };
+ self.verify_and_remove_nonce(&parsed_message.nonce).await?;
let wallet_address = eip55(&parsed_message.address);
self.check_wallet_address_taken(&wallet_address).await?;
let username_in_reserved_usernames_table = self
.client
- .username_in_reserved_usernames_table(&wallet_address)
+ .get_user_id_from_reserved_usernames_table(&wallet_address)
.await
- .map_err(handle_db_error)?;
+ .map_err(handle_db_error)?
+ .is_some();
if username_in_reserved_usernames_table {
return Err(tonic::Status::already_exists(
@@ -680,22 +690,16 @@
self.check_wallet_address_taken(&wallet_address).await?;
- let wallet_address_in_reserved_usernames_table = self
+ let maybe_user_id = self
.client
- .username_in_reserved_usernames_table(&wallet_address)
+ .get_user_id_from_reserved_usernames_table(&wallet_address)
.await
.map_err(handle_db_error)?;
- if !wallet_address_in_reserved_usernames_table {
+ let Some(user_id) = maybe_user_id else {
return Err(tonic::Status::permission_denied(
tonic_status_messages::WALLET_ADDRESS_NOT_RESERVED,
));
- }
-
- let user_id = validate_account_ownership_message_and_get_user_id(
- &wallet_address,
- &message.keyserver_message,
- &message.keyserver_signature,
- )?;
+ };
let flattened_device_key_upload =
construct_flattened_device_key_upload(&message)?;
@@ -1015,15 +1019,17 @@
Some(Identifier::WalletAddress(address)) => (address, AuthType::Wallet),
};
- let (is_reserved_result, user_id_result) = tokio::join!(
+ let (get_user_id_from_reserved_usernames_table_result, user_id_result) = tokio::join!(
self
.client
- .username_in_reserved_usernames_table(&user_ident),
+ .get_user_id_from_reserved_usernames_table(&user_ident),
self
.client
.get_user_id_from_user_info(user_ident.clone(), &auth_type),
);
- let is_reserved = is_reserved_result.map_err(handle_db_error)?;
+ let is_reserved = get_user_id_from_reserved_usernames_table_result
+ .map_err(handle_db_error)?
+ .is_some();
let user_id = user_id_result.map_err(handle_db_error)?;
Ok(Response::new(FindUserIdResponse {
diff --git a/services/identity/src/constants.rs b/services/identity/src/constants.rs
--- a/services/identity/src/constants.rs
+++ b/services/identity/src/constants.rs
@@ -266,6 +266,7 @@
"missing_platform_or_code_version_metadata";
pub const MISSING_KEY: &str = "missing_key";
pub const MESSAGE_NOT_AUTHENTICATED: &str = "message_not_authenticated";
+ pub const RETRY_FROM_NATIVE: &str = "retry_from_native";
}
// Tunnelbroker
diff --git a/services/identity/src/database.rs b/services/identity/src/database.rs
--- a/services/identity/src/database.rs
+++ b/services/identity/src/database.rs
@@ -4,7 +4,9 @@
put_item::PutItemOutput, query::QueryOutput,
},
primitives::Blob,
- types::{AttributeValue, PutRequest, WriteRequest},
+ types::{
+ AttributeValue, Delete, Put, PutRequest, TransactWriteItem, WriteRequest,
+ },
};
use comm_lib::aws::{AwsConfig, DynamoDBClient};
use comm_lib::database::{
@@ -223,7 +225,7 @@
initial_device_list: Option<SignedDeviceList>,
) -> Result<String, Error> {
let wallet_identity = EthereumIdentity {
- wallet_address,
+ wallet_address: wallet_address.clone(),
social_proof,
};
let user_id = self
@@ -284,7 +286,8 @@
AttributeValue::S(user_id.clone()),
)]);
- if let Some((username, password_file)) = username_and_password_file {
+ if let Some((username, password_file)) = username_and_password_file.clone()
+ {
user.insert(
USERS_TABLE_USERNAME_ATTRIBUTE.to_string(),
AttributeValue::S(username),
@@ -295,7 +298,7 @@
);
}
- if let Some(eth_identity) = wallet_identity {
+ if let Some(eth_identity) = wallet_identity.clone() {
user.insert(
USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE.to_string(),
AttributeValue::S(eth_identity.wallet_address),
@@ -313,17 +316,54 @@
);
}
- self
- .client
- .put_item()
+ let put_user = Put::builder()
.table_name(USERS_TABLE)
.set_item(Some(user))
- // make sure we don't accidentaly overwrite existing row
+ // make sure we don't accidentally overwrite existing row
.condition_expression("attribute_not_exists(#pk)")
.expression_attribute_names("#pk", USERS_TABLE_PARTITION_KEY)
+ .build();
+
+ let put_user_operation = TransactWriteItem::builder().put(put_user).build();
+
+ let partition_key_value =
+ match (username_and_password_file, wallet_identity) {
+ (Some((username, _)), _) => username,
+ (_, Some(ethereum_identity)) => ethereum_identity.wallet_address,
+ _ => return Err(Error::MalformedItem),
+ };
+
+ // We make sure to delete the user from the reserved usernames table when we
+ // add them to the users table
+ let delete_user_from_reserved_usernames = Delete::builder()
+ .table_name(RESERVED_USERNAMES_TABLE)
+ .key(
+ RESERVED_USERNAMES_TABLE_PARTITION_KEY,
+ AttributeValue::S(partition_key_value),
+ )
+ .build();
+
+ let delete_user_from_reserved_usernames_operation =
+ TransactWriteItem::builder()
+ .delete(delete_user_from_reserved_usernames)
+ .build();
+
+ self
+ .client
+ .transact_write_items()
+ .set_transact_items(Some(vec![
+ put_user_operation,
+ delete_user_from_reserved_usernames_operation,
+ ]))
.send()
.await
- .map_err(|e| Error::AwsSdk(e.into()))?;
+ .map_err(|e| {
+ error!(
+ errorType = error_types::GENERIC_DB_LOG,
+ "Add user transaction failed: {:?}", e
+ );
+ Error::AwsSdk(e.into())
+ })?;
Ok(user_id)
}
@@ -1078,11 +1118,11 @@
}
}
- pub async fn username_in_reserved_usernames_table(
+ pub async fn get_user_id_from_reserved_usernames_table(
&self,
username: &str,
- ) -> Result<bool, Error> {
- match self
+ ) -> Result<Option<String>, Error> {
+ let response = self
.client
.get_item()
.table_name(RESERVED_USERNAMES_TABLE)
@@ -1093,11 +1133,19 @@
.consistent_read(true)
.send()
.await
- {
- Ok(GetItemOutput { item: Some(_), .. }) => Ok(true),
- Ok(_) => Ok(false),
- Err(e) => Err(Error::AwsSdk(e.into())),
- }
+ .map_err(|e| Error::AwsSdk(e.into()))?;
+
+ let GetItemOutput {
+ item: Some(mut item),
+ ..
+ } = response
+ else {
+ return Ok(None);
+ };
+
+ // We should not return `Ok(None)` if `userID` is missing from the item
+ let user_id = item.take_attr(RESERVED_USERNAMES_TABLE_USER_ID_ATTRIBUTE)?;
+ Ok(Some(user_id))
}
}
diff --git a/services/identity/src/ddb_utils.rs b/services/identity/src/ddb_utils.rs
--- a/services/identity/src/ddb_utils.rs
+++ b/services/identity/src/ddb_utils.rs
@@ -179,6 +179,7 @@
}
}
+#[derive(Clone)]
pub struct EthereumIdentity {
pub wallet_address: String,
pub social_proof: SocialProof,
diff --git a/services/identity/src/siwe.rs b/services/identity/src/siwe.rs
--- a/services/identity/src/siwe.rs
+++ b/services/identity/src/siwe.rs
@@ -62,7 +62,7 @@
ethereum_address_regex.is_match(candidate)
}
-#[derive(derive_more::Constructor)]
+#[derive(derive_more::Constructor, Clone)]
pub struct SocialProof {
pub message: String,
pub signature: String,

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 2, 9:35 PM (3 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5882462
Default Alt Text
D12544.1767389719.diff (13 KB)

Event Timeline