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 @@ -8,10 +8,11 @@ use rand::rngs::OsRng; use siwe::eip55; use tonic::Response; -use tracing::{debug, error}; +use tracing::{debug, error, warn}; // Workspace crate imports use crate::config::CONFIG; +use crate::constants::request_metadata; use crate::database::{ DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload, }; @@ -26,6 +27,7 @@ VerifyUserAccessTokenRequest, VerifyUserAccessTokenResponse, WalletLoginRequest, WalletLoginResponse, }; +use crate::grpc_services::shared::get_value; use crate::grpc_utils::DeviceKeyUploadActions; use crate::id::generate_uuid; use crate::nonce::generate_nonce_data; @@ -198,6 +200,7 @@ &self, request: tonic::Request, ) -> Result, tonic::Status> { + let code_version = get_code_version(&request); let message = request.into_inner(); if let Some(WorkflowInProgress::Registration(state)) = @@ -213,7 +216,12 @@ let device_id = state.flattened_device_key_upload.device_id_key.clone(); let user_id = self .client - .add_password_user_to_users_table(*state, password_file) + .add_password_user_to_users_table( + *state, + password_file, + code_version, + chrono::Utc::now(), + ) .await .map_err(handle_db_error)?; @@ -309,6 +317,7 @@ &self, request: tonic::Request, ) -> Result, tonic::Status> { + let code_version = get_code_version(&request); let message = request.into_inner(); if let Some(WorkflowInProgress::Login(state)) = @@ -326,6 +335,8 @@ .add_password_user_device_to_users_table( state.user_id.clone(), state.flattened_device_key_upload.clone(), + code_version, + chrono::Utc::now(), ) .await .map_err(handle_db_error)?; @@ -360,6 +371,7 @@ &self, request: tonic::Request, ) -> Result, tonic::Status> { + let code_version = get_code_version(&request); let message = request.into_inner(); let parsed_message = parse_and_verify_siwe_message( @@ -404,6 +416,8 @@ id.clone(), flattened_device_key_upload.clone(), social_proof, + code_version, + chrono::Utc::now(), ) .await .map_err(handle_db_error)?; @@ -436,6 +450,8 @@ wallet_address, social_proof, None, + code_version, + chrono::Utc::now(), ) .await .map_err(handle_db_error)? @@ -469,6 +485,7 @@ &self, request: tonic::Request, ) -> Result, tonic::Status> { + let code_version = get_code_version(&request); let message = request.into_inner(); let parsed_message = parse_and_verify_siwe_message( @@ -525,6 +542,8 @@ wallet_address, social_proof, Some(user_id.clone()), + code_version, + chrono::Utc::now(), ) .await .map_err(handle_db_error)?; @@ -768,3 +787,15 @@ Ok(flattened_device_key_upload) } + +fn get_code_version(req: &tonic::Request) -> u64 { + get_value(req, request_metadata::CODE_VERSION) + .and_then(|version| version.parse().ok()) + .unwrap_or_else(|| { + warn!( + "Could not retrieve code version from request: {:?}. Defaulting to 0", + req + ); + Default::default() + }) +} 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 @@ -122,6 +122,10 @@ // device-list-specific attrs pub const ATTR_TIMESTAMP: &str = "timestamp"; pub const ATTR_DEVICE_IDS: &str = "deviceIDs"; + + // migration-specific attrs + pub const ATTR_CODE_VERSION: &str = "codeVersion"; + pub const ATTR_LOGIN_TIME: &str = "loginTime"; } // One time keys table, which need to exist in their own table to ensure 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 @@ -140,6 +140,8 @@ &self, registration_state: UserRegistrationInfo, password_file: Vec, + code_version: u64, + access_token_creation_time: DateTime, ) -> Result { let device_key_upload = registration_state.flattened_device_key_upload; let user_id = self @@ -152,7 +154,15 @@ ) .await?; - self.add_device(&user_id, device_key_upload, None).await?; + self + .add_device( + &user_id, + device_key_upload, + None, + code_version, + access_token_creation_time, + ) + .await?; Ok(user_id) } @@ -163,6 +173,8 @@ wallet_address: String, social_proof: String, user_id: Option, + code_version: u64, + access_token_creation_time: DateTime, ) -> Result { let social_proof = Some(social_proof); let user_id = self @@ -176,7 +188,13 @@ .await?; self - .add_device(&user_id, flattened_device_key_upload, social_proof) + .add_device( + &user_id, + flattened_device_key_upload, + social_proof, + code_version, + access_token_creation_time, + ) .await?; Ok(user_id) @@ -253,6 +271,8 @@ &self, user_id: String, flattened_device_key_upload: FlattenedDeviceKeyUpload, + code_version: u64, + access_token_creation_time: DateTime, ) -> Result<(), Error> { // add device to the legacy device list self @@ -276,7 +296,13 @@ } self - .add_device(user_id, flattened_device_key_upload, None) + .add_device( + user_id, + flattened_device_key_upload, + None, + code_version, + access_token_creation_time, + ) .await } @@ -285,6 +311,8 @@ user_id: String, flattened_device_key_upload: FlattenedDeviceKeyUpload, social_proof: String, + code_version: u64, + access_token_creation_time: DateTime, ) -> Result<(), Error> { // add device to the legacy device list self @@ -309,7 +337,13 @@ // add device to the new device list self - .add_device(user_id, flattened_device_key_upload, Some(social_proof)) + .add_device( + user_id, + flattened_device_key_upload, + Some(social_proof), + code_version, + access_token_creation_time, + ) .await } 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 @@ -56,6 +56,11 @@ pub device_key_info: IdentityKeyInfo, pub content_prekey: PreKey, pub notif_prekey: PreKey, + + // migration-related data + pub code_version: u64, + /// Timestamp of last login (access token generation) + pub login_time: DateTime, } #[derive(Clone, Debug)] @@ -83,6 +88,8 @@ user_id: impl Into, upload: FlattenedDeviceKeyUpload, social_proof: Option, + code_version: u64, + login_time: DateTime, ) -> Self { Self { user_id: user_id.into(), @@ -101,7 +108,9 @@ notif_prekey: PreKey { pre_key: upload.notif_prekey, pre_key_signature: upload.notif_prekey_signature, - } + }, + code_version, + login_time, } } } @@ -222,6 +231,17 @@ .cloned() .and_then(PreKey::try_from)?; + let code_version = attrs + .remove(ATTR_CODE_VERSION) + .and_then(|attr| attr.as_n().ok().cloned()) + .and_then(|val| val.parse::().ok()) + .unwrap_or_default(); + + let login_time = parse_date_time_attribute( + ATTR_LOGIN_TIME, + attrs.remove(ATTR_LOGIN_TIME), + )?; + Ok(Self { user_id, device_id, @@ -229,6 +249,8 @@ device_key_info, content_prekey, notif_prekey, + code_version, + login_time, }) } } @@ -251,6 +273,15 @@ ), (ATTR_CONTENT_PREKEY.to_string(), value.content_prekey.into()), (ATTR_NOTIF_PREKEY.to_string(), value.notif_prekey.into()), + // migration attributes + ( + ATTR_CODE_VERSION.to_string(), + AttributeValue::N(value.code_version.to_string()), + ), + ( + ATTR_LOGIN_TIME.to_string(), + AttributeValue::S(value.login_time.to_rfc3339()), + ), ]) } } @@ -648,6 +679,8 @@ user_id: impl Into, device_key_upload: FlattenedDeviceKeyUpload, social_proof: Option, + code_version: u64, + login_time: DateTime, ) -> Result<(), Error> { let user_id: String = user_id.into(); self @@ -656,6 +689,8 @@ &user_id, device_key_upload, social_proof, + code_version, + login_time, ); if device_ids.iter().any(|id| &new_device.device_id == id) {