Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32576550
D12544.1767389719.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D12544.1767389719.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D12544: [identity] fix reserved username workflow for wallet users
Attached
Detach File
Event Timeline
Log In to Comment