Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3542553
D7540.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
18 KB
Referenced Files
None
Subscribers
None
D7540.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
@@ -23,7 +23,8 @@
database::{DatabaseClient, Error as DBError, KeyPayload},
id::generate_uuid,
nonce::generate_nonce_data,
- token::AccessTokenData,
+ siwe::parse_and_verify_siwe_message,
+ token::{AccessTokenData, AuthType},
};
use aws_sdk_dynamodb::Error as DynamoDBError;
pub use client_proto::identity_client_service_server::{
@@ -178,13 +179,13 @@
let device_id = state.flattened_device_key_upload.device_id_key.clone();
let user_id = self
.client
- .add_user_to_users_table(state, password_file)
+ .add_password_user_to_users_table(state, password_file)
.await
.map_err(handle_db_error)?;
// Create access token
let token = AccessTokenData::new(
- message.session_id,
+ user_id.clone(),
device_id,
crate::token::AuthType::Password,
&mut OsRng,
@@ -324,13 +325,16 @@
self
.client
- .add_device_to_users_table(state.clone())
+ .add_password_user_device_to_users_table(
+ state.user_id.clone(),
+ state.flattened_device_key_upload.clone(),
+ )
.await
.map_err(handle_db_error)?;
// Create access token
let token = AccessTokenData::new(
- message.session_id,
+ state.user_id.clone(),
state.flattened_device_key_upload.device_id_key,
crate::token::AuthType::Password,
&mut OsRng,
@@ -356,9 +360,116 @@
async fn login_wallet_user(
&self,
- _request: tonic::Request<WalletLoginRequest>,
+ request: tonic::Request<WalletLoginRequest>,
) -> Result<tonic::Response<WalletLoginResponse>, tonic::Status> {
- unimplemented!();
+ let message = request.into_inner();
+
+ let wallet_address = parse_and_verify_siwe_message(
+ &message.siwe_message,
+ &message.siwe_signature,
+ )?;
+
+ let (flattened_device_key_upload, social_proof) =
+ if let client_proto::WalletLoginRequest {
+ siwe_message: _,
+ siwe_signature: _,
+ device_key_upload:
+ Some(client_proto::DeviceKeyUpload {
+ device_key_info:
+ Some(client_proto::IdentityKeyInfo {
+ payload,
+ payload_signature,
+ social_proof: Some(social_proof),
+ }),
+ identity_upload:
+ Some(client_proto::PreKey {
+ pre_key: identity_prekey,
+ pre_key_signature: identity_prekey_signature,
+ }),
+ notif_upload:
+ Some(client_proto::PreKey {
+ pre_key: notif_prekey,
+ pre_key_signature: notif_prekey_signature,
+ }),
+ onetime_identity_prekeys,
+ onetime_notif_prekeys,
+ }),
+ } = message
+ {
+ let key_info = KeyPayload::from_str(&payload)
+ .map_err(|_| tonic::Status::invalid_argument("malformed payload"))?;
+ (
+ FlattenedDeviceKeyUpload {
+ device_id_key: key_info.primary_identity_public_keys.curve25519,
+ key_payload: payload,
+ key_payload_signature: payload_signature,
+ identity_prekey,
+ identity_prekey_signature,
+ identity_onetime_keys: onetime_identity_prekeys,
+ notif_prekey,
+ notif_prekey_signature,
+ notif_onetime_keys: onetime_notif_prekeys,
+ },
+ social_proof,
+ )
+ } else {
+ return Err(tonic::Status::invalid_argument("unexpected message data"));
+ };
+
+ let user_id = match self
+ .client
+ .get_user_id_from_user_info(wallet_address.clone(), AuthType::Wallet)
+ .await
+ .map_err(handle_db_error)?
+ {
+ Some(id) => {
+ // User already exists, so we should update the DDB item
+ self
+ .client
+ .add_wallet_user_device_to_users_table(
+ id.clone(),
+ flattened_device_key_upload.clone(),
+ social_proof,
+ )
+ .await
+ .map_err(handle_db_error)?;
+ id
+ }
+ None => {
+ // User doesn't exist yet, so we should add a new user in DDB
+ self
+ .client
+ .add_wallet_user_to_users_table(
+ flattened_device_key_upload.clone(),
+ wallet_address,
+ social_proof,
+ )
+ .await
+ .map_err(handle_db_error)?
+ }
+ };
+
+ // Create access token
+ let token = AccessTokenData::new(
+ user_id.clone(),
+ flattened_device_key_upload.device_id_key,
+ crate::token::AuthType::Password,
+ &mut OsRng,
+ );
+
+ let access_token = token.access_token.clone();
+
+ self
+ .client
+ .put_access_token_data(token)
+ .await
+ .map_err(handle_db_error)?;
+
+ let response = WalletLoginResponse {
+ user_id: user_id,
+ access_token,
+ };
+ Ok(Response::new(response))
}
async fn delete_user(
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
@@ -34,6 +34,7 @@
// notifPreKey: String,
// notifPreKeySignature: String,
// notifOneTimeKeys: Vec<String>,
+// socialProof: Option<String>
// }
// }
//
@@ -65,6 +66,8 @@
pub const USERS_TABLE_DEVICES_MAP_NOTIF_ONETIME_KEYS_ATTRIBUTE_NAME: &str =
"notifOneTimeKeys";
pub const USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE: &str = "walletAddress";
+pub const USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME: &str =
+ "socialProof";
pub const USERS_TABLE_USERNAME_INDEX: &str = "username-index";
pub const USERS_TABLE_WALLET_ADDRESS_INDEX: &str = "walletAddress-index";
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
@@ -15,7 +15,7 @@
use serde::{Deserialize, Serialize};
use tracing::{debug, error, info, warn};
-use crate::client_service::{UserLoginInfo, UserRegistrationInfo};
+use crate::client_service::{FlattenedDeviceKeyUpload, UserRegistrationInfo};
use crate::config::CONFIG;
use crate::constants::{
ACCESS_TOKEN_SORT_KEY, ACCESS_TOKEN_TABLE,
@@ -33,6 +33,7 @@
USERS_TABLE_DEVICES_MAP_NOTIF_ONETIME_KEYS_ATTRIBUTE_NAME,
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME,
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME,
+ USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME,
USERS_TABLE_PARTITION_KEY, USERS_TABLE_REGISTRATION_ATTRIBUTE,
USERS_TABLE_USERNAME_ATTRIBUTE, USERS_TABLE_USERNAME_INDEX,
USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE, USERS_TABLE_WALLET_ADDRESS_INDEX,
@@ -104,55 +105,75 @@
}
}
- pub async fn add_user_to_users_table(
+ pub async fn add_password_user_to_users_table(
&self,
registration_state: UserRegistrationInfo,
password_file: Vec<u8>,
+ ) -> Result<String, Error> {
+ self
+ .add_user_to_users_table(
+ registration_state.flattened_device_key_upload,
+ Some((registration_state.username, Blob::new(password_file))),
+ None,
+ None,
+ )
+ .await
+ }
+
+ pub async fn add_wallet_user_to_users_table(
+ &self,
+ flattened_device_key_upload: FlattenedDeviceKeyUpload,
+ wallet_address: String,
+ social_proof: String,
+ ) -> Result<String, Error> {
+ self
+ .add_user_to_users_table(
+ flattened_device_key_upload,
+ None,
+ Some(wallet_address),
+ Some(social_proof),
+ )
+ .await
+ }
+
+ async fn add_user_to_users_table(
+ &self,
+ flattened_device_key_upload: FlattenedDeviceKeyUpload,
+ username_and_password_file: Option<(String, Blob)>,
+ wallet_address: Option<String>,
+ social_proof: Option<String>,
) -> Result<String, Error> {
let user_id = generate_uuid();
- let device_info = HashMap::from([
+ let mut device_info = HashMap::from([
(
USERS_TABLE_DEVICES_MAP_DEVICE_TYPE_ATTRIBUTE_NAME.to_string(),
AttributeValue::S(Device::Client.to_string()),
),
(
USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(
- registration_state.flattened_device_key_upload.key_payload,
- ),
+ AttributeValue::S(flattened_device_key_upload.key_payload),
),
(
USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
- AttributeValue::S(
- registration_state
- .flattened_device_key_upload
- .key_payload_signature,
- ),
+ AttributeValue::S(flattened_device_key_upload.key_payload_signature),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(
- registration_state
- .flattened_device_key_upload
- .identity_prekey,
- ),
+ AttributeValue::S(flattened_device_key_upload.identity_prekey),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
AttributeValue::S(
- registration_state
- .flattened_device_key_upload
- .identity_prekey_signature,
+ flattened_device_key_upload.identity_prekey_signature,
),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_ONETIME_KEYS_ATTRIBUTE_NAME
.to_string(),
AttributeValue::L(
- registration_state
- .flattened_device_key_upload
+ flattened_device_key_upload
.identity_onetime_keys
.into_iter()
.map(AttributeValue::S)
@@ -161,24 +182,17 @@
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(
- registration_state.flattened_device_key_upload.notif_prekey,
- ),
+ AttributeValue::S(flattened_device_key_upload.notif_prekey),
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
- AttributeValue::S(
- registration_state
- .flattened_device_key_upload
- .notif_prekey_signature,
- ),
+ AttributeValue::S(flattened_device_key_upload.notif_prekey_signature),
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_ONETIME_KEYS_ATTRIBUTE_NAME.to_string(),
AttributeValue::L(
- registration_state
- .flattened_device_key_upload
+ flattened_device_key_upload
.notif_onetime_keys
.into_iter()
.map(AttributeValue::S)
@@ -186,30 +200,46 @@
),
),
]);
+
+ if let Some(social_proof) = social_proof {
+ device_info.insert(
+ USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(social_proof),
+ );
+ }
let devices = HashMap::from([(
- registration_state.flattened_device_key_upload.device_id_key,
+ flattened_device_key_upload.device_id_key,
AttributeValue::M(device_info),
)]);
-
- let user = HashMap::from([
+ let mut user = HashMap::from([
(
USERS_TABLE_PARTITION_KEY.to_string(),
AttributeValue::S(user_id.clone()),
),
- (
- USERS_TABLE_USERNAME_ATTRIBUTE.to_string(),
- AttributeValue::S(registration_state.username),
- ),
(
USERS_TABLE_DEVICES_ATTRIBUTE.to_string(),
AttributeValue::M(devices),
),
- (
- USERS_TABLE_REGISTRATION_ATTRIBUTE.to_string(),
- AttributeValue::B(Blob::new(password_file)),
- ),
]);
+ if let Some((username, password_file)) = username_and_password_file {
+ user.insert(
+ USERS_TABLE_USERNAME_ATTRIBUTE.to_string(),
+ AttributeValue::S(username),
+ );
+ user.insert(
+ USERS_TABLE_REGISTRATION_ATTRIBUTE.to_string(),
+ AttributeValue::B(password_file),
+ );
+ }
+
+ if let Some(address) = wallet_address {
+ user.insert(
+ USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE.to_string(),
+ AttributeValue::S(address),
+ );
+ }
+
self
.client
.put_item()
@@ -222,49 +252,67 @@
Ok(user_id)
}
- pub async fn add_device_to_users_table(
+ pub async fn add_password_user_device_to_users_table(
+ &self,
+ user_id: String,
+ flattened_device_key_upload: FlattenedDeviceKeyUpload,
+ ) -> Result<(), Error> {
+ self
+ .add_device_to_users_table(user_id, flattened_device_key_upload, None)
+ .await
+ }
+
+ pub async fn add_wallet_user_device_to_users_table(
+ &self,
+ user_id: String,
+ flattened_device_key_upload: FlattenedDeviceKeyUpload,
+ social_proof: String,
+ ) -> Result<(), Error> {
+ self
+ .add_device_to_users_table(
+ user_id,
+ flattened_device_key_upload,
+ Some(social_proof),
+ )
+ .await
+ }
+
+ async fn add_device_to_users_table(
&self,
- login_state: UserLoginInfo,
+ user_id: String,
+ flattened_device_key_upload: FlattenedDeviceKeyUpload,
+ social_proof: Option<String>,
) -> Result<(), Error> {
- let device_info = HashMap::from([
+ let mut device_info = HashMap::from([
(
USERS_TABLE_DEVICES_MAP_DEVICE_TYPE_ATTRIBUTE_NAME.to_string(),
AttributeValue::S(Device::Client.to_string()),
),
(
USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(login_state.flattened_device_key_upload.key_payload),
+ AttributeValue::S(flattened_device_key_upload.key_payload),
),
(
USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
- AttributeValue::S(
- login_state
- .flattened_device_key_upload
- .key_payload_signature,
- ),
+ AttributeValue::S(flattened_device_key_upload.key_payload_signature),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(
- login_state.flattened_device_key_upload.identity_prekey,
- ),
+ AttributeValue::S(flattened_device_key_upload.identity_prekey),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_PREKEY_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
AttributeValue::S(
- login_state
- .flattened_device_key_upload
- .identity_prekey_signature,
+ flattened_device_key_upload.identity_prekey_signature,
),
),
(
USERS_TABLE_DEVICES_MAP_IDENTITY_ONETIME_KEYS_ATTRIBUTE_NAME
.to_string(),
AttributeValue::L(
- login_state
- .flattened_device_key_upload
+ flattened_device_key_upload
.identity_onetime_keys
.into_iter()
.map(AttributeValue::S)
@@ -273,22 +321,17 @@
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME.to_string(),
- AttributeValue::S(login_state.flattened_device_key_upload.notif_prekey),
+ AttributeValue::S(flattened_device_key_upload.notif_prekey),
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME
.to_string(),
- AttributeValue::S(
- login_state
- .flattened_device_key_upload
- .notif_prekey_signature,
- ),
+ AttributeValue::S(flattened_device_key_upload.notif_prekey_signature),
),
(
USERS_TABLE_DEVICES_MAP_NOTIF_ONETIME_KEYS_ATTRIBUTE_NAME.to_string(),
AttributeValue::L(
- login_state
- .flattened_device_key_upload
+ flattened_device_key_upload
.notif_onetime_keys
.into_iter()
.map(AttributeValue::S)
@@ -297,11 +340,17 @@
),
]);
+ if let Some(social_proof) = social_proof {
+ device_info.insert(
+ USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME.to_string(),
+ AttributeValue::S(social_proof),
+ );
+ }
let update_expression =
format!("SET {}.#{} = :v", USERS_TABLE_DEVICES_ATTRIBUTE, "deviceID",);
let expression_attribute_names = HashMap::from([(
format!("#{}", "deviceID"),
- login_state.flattened_device_key_upload.device_id_key,
+ flattened_device_key_upload.device_id_key,
)]);
let expression_attribute_values =
HashMap::from([(":v".to_string(), AttributeValue::M(device_info))]);
@@ -310,10 +359,7 @@
.client
.update_item()
.table_name(USERS_TABLE)
- .key(
- USERS_TABLE_PARTITION_KEY,
- AttributeValue::S(login_state.user_id),
- )
+ .key(USERS_TABLE_PARTITION_KEY, AttributeValue::S(user_id))
.update_expression(update_expression)
.set_expression_attribute_names(Some(expression_attribute_names))
.set_expression_attribute_values(Some(expression_attribute_values))
diff --git a/services/identity/src/main.rs b/services/identity/src/main.rs
--- a/services/identity/src/main.rs
+++ b/services/identity/src/main.rs
@@ -14,6 +14,7 @@
mod interceptor;
mod keygen;
mod nonce;
+mod siwe;
mod token;
use config::load_config;
diff --git a/services/identity/src/siwe.rs b/services/identity/src/siwe.rs
new file mode 100644
--- /dev/null
+++ b/services/identity/src/siwe.rs
@@ -0,0 +1,34 @@
+use chrono::Utc;
+use siwe::{eip55, Message};
+use tonic::Status;
+use tracing::error;
+
+pub fn parse_and_verify_siwe_message(
+ siwe_message: &str,
+ siwe_signature: &str,
+) -> Result<String, Status> {
+ let siwe_message: Message = siwe_message.parse().map_err(|e| {
+ error!("Failed to parse SIWE message: {}", e);
+ Status::invalid_argument("invalid message")
+ })?;
+
+ let decoded_signature = hex::decode(siwe_signature.trim_start_matches("0x"))
+ .map_err(|e| {
+ error!("Failed to decode SIWE signature: {}", e);
+ Status::invalid_argument("invalid signature")
+ })?;
+
+ let signature = decoded_signature.try_into().map_err(|e| {
+ error!("Conversion to SIWE signature failed: {:?}", e);
+ Status::invalid_argument("invalid message")
+ })?;
+
+ siwe_message
+ .verify(signature, None, None, Some(&Utc::now()))
+ .map_err(|e| {
+ error!("Signature verification failed: {}", e);
+ Status::unauthenticated("message not authenticated")
+ })?;
+
+ Ok(eip55(&siwe_message.address))
+}
diff --git a/shared/protos/identity_client.proto b/shared/protos/identity_client.proto
--- a/shared/protos/identity_client.proto
+++ b/shared/protos/identity_client.proto
@@ -82,7 +82,7 @@
string payload = 1;
// Payload signed with the signing ed25519 key
string payloadSignature = 2;
- // Signed message used for SIWE (optional)
+ // Signed message used for SIWE
// This correlates a given wallet with the identity of a device
optional string socialProof = 3;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Dec 27, 8:29 AM (10 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2706825
Default Alt Text
D7540.diff (18 KB)
Attached To
Mode
D7540: [identity] wallet login
Attached
Detach File
Event Timeline
Log In to Comment