diff --git a/keyserver/addons/rust-node-addon/build.rs b/keyserver/addons/rust-node-addon/build.rs --- a/keyserver/addons/rust-node-addon/build.rs +++ b/keyserver/addons/rust-node-addon/build.rs @@ -5,7 +5,10 @@ tonic_build::configure() .build_server(false) .compile( - &["../../../shared/protos/identity_client.proto"], + &[ + "../../../shared/protos/identity_client.proto", + "../../../shared/protos/identity_authenticated.proto", + ], &["../../../shared/protos"], ) .unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e)); diff --git a/keyserver/addons/rust-node-addon/rust-binding-types.js b/keyserver/addons/rust-node-addon/rust-binding-types.js --- a/keyserver/addons/rust-node-addon/rust-binding-types.js +++ b/keyserver/addons/rust-node-addon/rust-binding-types.js @@ -35,6 +35,15 @@ message: string, signature: string, ) => Promise, + +publish_prekeys: ( + userId: string, + deviceId: string, + accessToken: string, + contentPrekey: string, + contentPrekeySignature: string, + notifPrekey: string, + notifPrekeySignature: string, + ) => Promise, }; export type { RustNativeBindingAPI }; diff --git a/keyserver/addons/rust-node-addon/src/identity_client/auth_client.rs b/keyserver/addons/rust-node-addon/src/identity_client/auth_client.rs new file mode 100644 --- /dev/null +++ b/keyserver/addons/rust-node-addon/src/identity_client/auth_client.rs @@ -0,0 +1,67 @@ +pub mod client { + tonic::include_proto!("identity.client"); +} +pub mod auth_proto { + tonic::include_proto!("identity.authenticated"); +} +use auth_proto::identity_client_service_client::IdentityClientServiceClient as AuthClient; +use tonic::{ + codegen::InterceptedService, + metadata::{errors::InvalidMetadataValue, Ascii, MetadataValue}, + service::Interceptor, + transport::{Channel, Endpoint}, + Request, Status, +}; + +use super::IDENTITY_SERVICE_CONFIG; + +pub struct AuthLayer { + user_id: String, + device_id: String, + access_token: String, +} + +trait ToAscii { + fn parse_to_ascii(&self) -> Result, Status>; +} + +impl ToAscii for str { + fn parse_to_ascii(&self) -> Result, Status> { + self.parse().map_err(|e: InvalidMetadataValue| { + Status::invalid_argument(format!( + "Non-Ascii character present in metadata value: {}", + e + )) + }) + } +} + +impl Interceptor for AuthLayer { + fn call(&mut self, mut request: Request<()>) -> Result, Status> { + let metadata = request.metadata_mut(); + metadata.insert("user_id", self.user_id.parse_to_ascii()?); + metadata.insert("device_id", self.device_id.parse_to_ascii()?); + metadata.insert("access_token", self.access_token.parse_to_ascii()?); + + Ok(request) + } +} +pub async fn get_auth_client( + user_id: String, + device_id: String, + access_token: String, +) -> AuthClient> { + let channel = + Endpoint::from_static(&IDENTITY_SERVICE_CONFIG.identity_socket_addr) + .connect() + .await + .unwrap(); + + let interceptor = AuthLayer { + user_id, + device_id, + access_token, + }; + + AuthClient::with_interceptor(channel, interceptor) +} diff --git a/keyserver/addons/rust-node-addon/src/identity_client/mod.rs b/keyserver/addons/rust-node-addon/src/identity_client/mod.rs --- a/keyserver/addons/rust-node-addon/src/identity_client/mod.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client/mod.rs @@ -1,5 +1,7 @@ pub mod add_reserved_usernames; +pub mod auth_client; pub mod login; +pub mod prekey; pub mod register_user; pub mod remove_reserved_usernames; pub mod identity_client { diff --git a/keyserver/addons/rust-node-addon/src/identity_client/prekey.rs b/keyserver/addons/rust-node-addon/src/identity_client/prekey.rs new file mode 100644 --- /dev/null +++ b/keyserver/addons/rust-node-addon/src/identity_client/prekey.rs @@ -0,0 +1,41 @@ +use super::auth_client::{ + auth_proto::RefreshUserPreKeysRequest, client::PreKey, get_auth_client, +}; +use super::{Error, Status}; +use napi::Result; +use tracing::warn; + +pub async fn publish_prekeys( + user_id: String, + device_id: String, + access_token: String, + content_prekey: String, + content_prekey_signature: String, + notif_prekey: String, + notif_prekey_signature: String, +) -> Result { + // Once this rust addon can do getCommConfig, remove explicit passing of user + // credentials within this scope + let mut client = get_auth_client(user_id, device_id, access_token).await; + + let message = RefreshUserPreKeysRequest { + new_content_pre_keys: Some(PreKey { + pre_key: content_prekey, + pre_key_signature: content_prekey_signature, + }), + new_notif_pre_keys: Some(PreKey { + pre_key: notif_prekey, + pre_key_signature: notif_prekey_signature, + }), + }; + + client.refresh_user_pre_keys(message).await.map_err(|e| { + warn!( + "Failed to upload new prekeys to identity service: {:?}", + e.message() + ); + Error::from_status(Status::GenericFailure) + })?; + + Ok(true) +}