Page MenuHomePhabricator

D12090.id40602.diff
No OneTemporary

D12090.id40602.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
@@ -18,8 +18,9 @@
error_types
};
use crate::database::{
- DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload,
+ DBDeviceTypeInt, DatabaseClient, DeviceType, KeyPayload
};
+use crate::device_list::SignedDeviceList;
use crate::error::{DeviceListError, Error as DBError};
use crate::grpc_services::authenticated::DeletePasswordUserInfo;
use crate::grpc_services::protos::unauth::{
@@ -35,7 +36,7 @@
};
use crate::grpc_services::shared::get_value;
use crate::grpc_utils::{
- SignedNonce, DeviceKeyUploadActions,
+ DeviceKeyUploadActions, RegistrationActions, SignedNonce
};
use crate::nonce::generate_nonce_data;
use crate::reserved_users::{
@@ -66,6 +67,7 @@
pub flattened_device_key_upload: FlattenedDeviceKeyUpload,
pub user_id: Option<String>,
pub farcaster_id: Option<String>,
+ pub initial_device_list: Option<SignedDeviceList>,
}
#[derive(Clone, Serialize, Deserialize)]
@@ -439,6 +441,13 @@
let code_version = get_code_version(&request);
let message = request.into_inner();
+ // WalletAuthRequest is used for both log_in_wallet_user and register_wallet_user
+ if !message.initial_device_list.is_empty() {
+ return Err(tonic::Status::invalid_argument(
+ "unexpected initial device list",
+ ));
+ }
+
let parsed_message = parse_and_verify_siwe_message(
&message.siwe_message,
&message.siwe_signature,
@@ -1129,7 +1138,7 @@
}
fn construct_user_registration_info(
- message: &impl DeviceKeyUploadActions,
+ message: &(impl DeviceKeyUploadActions + RegistrationActions),
user_id: Option<String>,
username: String,
farcaster_id: Option<String>,
@@ -1141,6 +1150,7 @@
)?,
user_id,
farcaster_id,
+ initial_device_list: message.get_and_verify_initial_device_list()?,
})
}
diff --git a/services/identity/src/device_list.rs b/services/identity/src/device_list.rs
--- a/services/identity/src/device_list.rs
+++ b/services/identity/src/device_list.rs
@@ -1,5 +1,5 @@
use chrono::{DateTime, Duration, Utc};
-use std::collections::HashSet;
+use std::{collections::HashSet, str::FromStr};
use tracing::{debug, error, warn};
use crate::{
@@ -20,7 +20,7 @@
/// Signed device list payload that is serializable to JSON.
/// For the DDB payload, see [`DeviceListUpdate`]
-#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignedDeviceList {
/// JSON-stringified [`RawDeviceList`]
@@ -88,13 +88,20 @@
impl TryFrom<UpdateDeviceListRequest> for SignedDeviceList {
type Error = tonic::Status;
fn try_from(request: UpdateDeviceListRequest) -> Result<Self, Self::Error> {
- serde_json::from_str(&request.new_device_list).map_err(|err| {
+ request.new_device_list.parse().map_err(|err| {
warn!("Failed to deserialize device list update: {}", err);
tonic::Status::invalid_argument("invalid device list payload")
})
}
}
+impl FromStr for SignedDeviceList {
+ type Err = serde_json::Error;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ serde_json::from_str(s)
+ }
+}
+
impl TryFrom<SignedDeviceList> for DeviceListUpdate {
type Error = tonic::Status;
fn try_from(signed_list: SignedDeviceList) -> Result<Self, Self::Error> {
diff --git a/services/identity/src/grpc_utils.rs b/services/identity/src/grpc_utils.rs
--- a/services/identity/src/grpc_utils.rs
+++ b/services/identity/src/grpc_utils.rs
@@ -2,11 +2,12 @@
use ed25519_dalek::{PublicKey, Signature, Verifier};
use serde::Deserialize;
use tonic::Status;
+use tracing::warn;
use crate::{
- database::DeviceRow,
- ddb_utils::DBIdentity,
- ddb_utils::Identifier as DBIdentifier,
+ database::{DeviceListUpdate, DeviceRow, KeyPayload},
+ ddb_utils::{DBIdentity, Identifier as DBIdentifier},
+ device_list::SignedDeviceList,
grpc_services::protos::{
auth::{EthereumIdentity, Identity, InboundKeyInfo, OutboundKeyInfo},
unauth::{
@@ -249,6 +250,68 @@
}
}
+/// Common functionality for registration request messages
+trait RegistrationData {
+ fn initial_device_list(&self) -> &str;
+}
+
+impl RegistrationData for RegistrationStartRequest {
+ fn initial_device_list(&self) -> &str {
+ &self.initial_device_list
+ }
+}
+impl RegistrationData for ReservedRegistrationStartRequest {
+ fn initial_device_list(&self) -> &str {
+ &self.initial_device_list
+ }
+}
+impl RegistrationData for WalletAuthRequest {
+ fn initial_device_list(&self) -> &str {
+ &self.initial_device_list
+ }
+}
+impl RegistrationData for ReservedWalletRegistrationRequest {
+ fn initial_device_list(&self) -> &str {
+ &self.initial_device_list
+ }
+}
+
+/// Similar to `[DeviceKeyUploadActions]` but only for registration requests
+pub trait RegistrationActions {
+ fn get_and_verify_initial_device_list(
+ &self,
+ ) -> Result<Option<SignedDeviceList>, tonic::Status>;
+}
+
+impl<T: RegistrationData + DeviceKeyUploadActions> RegistrationActions for T {
+ fn get_and_verify_initial_device_list(
+ &self,
+ ) -> Result<Option<SignedDeviceList>, tonic::Status> {
+ let payload = self.initial_device_list();
+ if payload.is_empty() {
+ return Ok(None);
+ }
+ let signed_list: SignedDeviceList = payload.parse().map_err(|err| {
+ warn!("Failed to deserialize initial device list: {}", err);
+ tonic::Status::invalid_argument("invalid device list payload")
+ })?;
+
+ let key_info = self
+ .payload()?
+ .parse::<KeyPayload>()
+ .map_err(|_| tonic::Status::invalid_argument("malformed payload"))?;
+ let primary_device_id = key_info.primary_identity_public_keys.ed25519;
+
+ let update_payload = DeviceListUpdate::try_from(signed_list.clone())?;
+ crate::device_list::verify_initial_device_list(
+ &update_payload,
+ &primary_device_id,
+ )?;
+
+ Ok(Some(signed_list))
+ }
+}
+
impl From<DBIdentity> for Identity {
fn from(value: DBIdentity) -> Self {
match value.identifier {

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 29, 2:23 AM (8 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2726179
Default Alt Text
D12090.id40602.diff (6 KB)

Event Timeline