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 @@ -55,7 +55,7 @@ pub use grpc_clients::identity::DeviceType; mod device_list; -pub use device_list::{DeviceListRow, DeviceRow}; +pub use device_list::{DeviceListRow, DeviceListUpdate, DeviceRow}; use self::device_list::PreKey; 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 @@ -66,6 +66,13 @@ pub pre_key_signature: String, } +/// A struct representing device list update request +/// payload; issued by the primary device +#[derive(serde::Deserialize)] +pub struct DeviceListUpdate { + devices: Vec, +} + impl DeviceRow { pub fn from_device_key_upload( user_id: impl Into, diff --git a/services/identity/src/grpc_services/authenticated.rs b/services/identity/src/grpc_services/authenticated.rs --- a/services/identity/src/grpc_services/authenticated.rs +++ b/services/identity/src/grpc_services/authenticated.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::config::CONFIG; -use crate::database::DeviceListRow; +use crate::database::{DeviceListRow, DeviceListUpdate}; use crate::ddb_utils::Identifier; use crate::{ client_service::{ @@ -26,6 +26,7 @@ InboundKeyInfo, InboundKeysForUserRequest, InboundKeysForUserResponse, KeyserverKeysResponse, OutboundKeyInfo, OutboundKeysForUserRequest, OutboundKeysForUserResponse, RefreshUserPrekeysRequest, + UpdateDeviceListRequest, UpdateDeviceListResponse, UpdateUserPasswordFinishRequest, UpdateUserPasswordStartRequest, UpdateUserPasswordStartResponse, UploadOneTimeKeysRequest, }; @@ -412,6 +413,13 @@ device_list_updates: stringified_updates, })) } + + async fn update_device_list_for_user( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + Err(tonic::Status::unimplemented("not implemented")) + } } // raw device list that can be serialized to JSON (and then signed in the future) @@ -451,6 +459,31 @@ } } +impl TryFrom for DeviceListUpdate { + type Error = tonic::Status; + fn try_from(request: UpdateDeviceListRequest) -> Result { + serde_json::from_str(&request.new_device_list).map_err(|err| { + error!("Failed to deserialize device list update: {}", err); + tonic::Status::failed_precondition("unexpected error") + }) + } +} + +impl TryFrom for UpdateDeviceListResponse { + type Error = tonic::Status; + fn try_from(signed_list: SignedDeviceList) -> Result { + let stringified_response_payload = serde_json::to_string(&signed_list) + .map_err(|err| { + error!("Failed to serialize device list response: {}", err); + tonic::Status::failed_precondition("unexpected error") + })?; + let response = UpdateDeviceListResponse { + signed_device_list: stringified_response_payload, + }; + Ok(response) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/shared/protos/identity_auth.proto b/shared/protos/identity_auth.proto --- a/shared/protos/identity_auth.proto +++ b/shared/protos/identity_auth.proto @@ -57,6 +57,9 @@ // Returns device list history rpc GetDeviceListForUser(GetDeviceListRequest) returns (GetDeviceListResponse) {} + + rpc UpdateDeviceListForUser(UpdateDeviceListRequest) returns + (UpdateDeviceListResponse) {} } // Helper types @@ -197,3 +200,24 @@ // } repeated string device_list_updates = 1; } + +// UpdateDeviceListForUser + +message UpdateDeviceListRequest { + // A stringified JSON object of the following format: + // { + // "devices": [, ...] + // } + string new_device_list = 1; +} + +message UpdateDeviceListResponse { + // A stringified JSON object of the following format: + // { + // "rawDeviceList": JSON.stringify({ + // "devices": [, ...] + // "timestamp": , + // }) + // } + string signed_device_list = 1; +}