diff --git a/keyserver/addons/rust-node-addon/rust-binding-types.js b/keyserver/addons/rust-node-addon/rust-binding-types.js index 8987e7229..10eb50ca1 100644 --- a/keyserver/addons/rust-node-addon/rust-binding-types.js +++ b/keyserver/addons/rust-node-addon/rust-binding-types.js @@ -1,18 +1,40 @@ // @flow import type { SignedIdentityKeysBlob } from 'lib/types/crypto-types.js'; +type UserLoginResponse = { + +userID: string, + +accessToken: string, +}; + type RustNativeBindingAPI = { + +loginUser: ( + username: string, + password: string, + signedIdentityKeysBlob: SignedIdentityKeysBlob, + contentPrekey: string, + contentPrekeySignature: string, + notifPrekey: string, + notifPrekeySignature: string, + contentOneTimeKeys: $ReadOnlyArray, + notifOneTimeKeys: $ReadOnlyArray, + ) => Promise, +registerUser: ( username: string, password: string, signedIdentityKeysBlob: SignedIdentityKeysBlob, - ) => Promise, + contentPrekey: string, + contentPrekeySignature: string, + notifPrekey: string, + notifPrekeySignature: string, + contentOneTimeKeys: $ReadOnlyArray, + notifOneTimeKeys: $ReadOnlyArray, + ) => Promise, +addReservedUsernames: (message: string, signature: string) => Promise, +removeReservedUsername: ( message: string, signature: string, ) => Promise, }; export type { RustNativeBindingAPI }; diff --git a/keyserver/addons/rust-node-addon/src/identity_client/login.rs b/keyserver/addons/rust-node-addon/src/identity_client/login.rs new file mode 100644 index 000000000..04016db70 --- /dev/null +++ b/keyserver/addons/rust-node-addon/src/identity_client/login.rs @@ -0,0 +1,77 @@ +use super::*; + +use comm_opaque2::client::Login; +use identity_client::{OpaqueLoginFinishRequest, OpaqueLoginStartRequest}; + +#[napi] +#[instrument(skip_all)] +pub async fn login_user( + username: String, + password: String, + signed_identity_keys_blob: SignedIdentityKeysBlob, + content_prekey: String, + content_prekey_signature: String, + notif_prekey: String, + notif_prekey_signature: String, + content_one_time_keys: Vec, + notif_one_time_keys: Vec, +) -> Result { + // Set up the gRPC client that will be used to talk to the Identity service + let channel = get_identity_service_channel().await?; + let mut identity_client = IdentityClientServiceClient::new(channel); + + // Start OPAQUE registration and send initial registration request + let mut client_login = Login::new(); + let opaque_login_request = client_login + .start(&password) + .map_err(|_| Error::from_status(Status::GenericFailure))?; + + let login_start_request = OpaqueLoginStartRequest { + opaque_login_request, + username: username, + device_key_upload: Some(DeviceKeyUpload { + device_key_info: Some(IdentityKeyInfo { + payload: signed_identity_keys_blob.payload, + payload_signature: signed_identity_keys_blob.signature, + social_proof: None, + }), + content_upload: Some(PreKey { + pre_key: content_prekey, + pre_key_signature: content_prekey_signature, + }), + notif_upload: Some(PreKey { + pre_key: notif_prekey, + pre_key_signature: notif_prekey_signature, + }), + onetime_content_prekeys: content_one_time_keys, + onetime_notif_prekeys: notif_one_time_keys, + }), + }; + + let login_start_response = identity_client + .login_password_user_start(login_start_request) + .await + .map_err(|_| Error::from_status(Status::GenericFailure))? + .into_inner(); + + let opaque_login_upload = client_login + .finish(&login_start_response.opaque_login_response) + .map_err(|_| Error::from_status(Status::GenericFailure))?; + let login_finish_request = OpaqueLoginFinishRequest { + session_id: login_start_response.session_id, + opaque_login_upload, + }; + + let login_finish_response = identity_client + .login_password_user_finish(login_finish_request) + .await + .map_err(|_| Error::from_status(Status::GenericFailure))? + .into_inner(); + + let user_info = UserLoginInfo { + user_id: login_finish_response.user_id, + access_token: login_finish_response.access_token, + }; + + Ok(user_info) +} diff --git a/keyserver/addons/rust-node-addon/src/identity_client/mod.rs b/keyserver/addons/rust-node-addon/src/identity_client/mod.rs index 474ef6aa8..d0d0c3f0f 100644 --- a/keyserver/addons/rust-node-addon/src/identity_client/mod.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client/mod.rs @@ -1,64 +1,71 @@ pub mod add_reserved_usernames; +pub mod login; pub mod register_user; -pub mod remove_reserved_username; +pub mod remove_reserved_usernames; pub mod identity_client { tonic::include_proto!("identity.client"); } use identity_client::identity_client_service_client::IdentityClientServiceClient; use identity_client::{ - AddReservedUsernamesRequest, DeviceKeyUpload, IdentityKeyInfo, + AddReservedUsernamesRequest, DeviceKeyUpload, IdentityKeyInfo, PreKey, RegistrationFinishRequest, RegistrationStartRequest, RemoveReservedUsernameRequest, }; use lazy_static::lazy_static; use napi::bindgen_prelude::*; use serde::{Deserialize, Serialize}; use std::env::var; -use tonic::{metadata::MetadataValue, transport::Channel, Request}; +use tonic::{transport::Channel, Request}; use tracing::instrument; lazy_static! { static ref IDENTITY_SERVICE_CONFIG: IdentityServiceConfig = { let config_json_string = var("COMM_JSONCONFIG_secrets_identity_service_config"); match config_json_string { Ok(json) => serde_json::from_str(&json).unwrap(), Err(_) => IdentityServiceConfig::default(), } }; } #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct IdentityServiceConfig { identity_socket_addr: String, identity_auth_token: String, } impl Default for IdentityServiceConfig { fn default() -> Self { Self { identity_socket_addr: "https://[::1]:50054".to_string(), identity_auth_token: "test".to_string(), } } } async fn get_identity_service_channel() -> Result { Channel::from_static(&IDENTITY_SERVICE_CONFIG.identity_socket_addr) .connect() .await .map_err(|_| { Error::new( Status::GenericFailure, "Unable to connect to identity service".to_string(), ) }) } #[napi(object)] pub struct SignedIdentityKeysBlob { pub payload: String, pub signature: String, } + +#[napi(object)] +pub struct UserLoginInfo { + pub user_id: String, + pub access_token: String, +} diff --git a/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs b/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs index 0f7113d75..37dbc6652 100644 --- a/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs @@ -1,79 +1,79 @@ use super::*; #[napi] #[instrument(skip_all)] pub async fn register_user( username: String, password: String, signed_identity_keys_blob: SignedIdentityKeysBlob, -) -> Result { + content_prekey: String, + content_prekey_signature: String, + notif_prekey: String, + notif_prekey_signature: String, + content_one_time_keys: Vec, + notif_one_time_keys: Vec, +) -> Result { // Set up the gRPC client that will be used to talk to the Identity service let channel = get_identity_service_channel().await?; - let token: MetadataValue<_> = IDENTITY_SERVICE_CONFIG - .identity_auth_token - .parse() - .map_err(|_| Error::from_status(Status::GenericFailure))?; - let mut identity_client = IdentityClientServiceClient::with_interceptor( - channel, - |mut req: Request<()>| { - req.metadata_mut().insert("authorization", token.clone()); - Ok(req) - }, - ); + let mut identity_client = IdentityClientServiceClient::new(channel); // Start OPAQUE registration and send initial registration request let mut opaque_registration = comm_opaque2::client::Registration::new(); let opaque_registration_request = opaque_registration .start(&password) .map_err(|_| Error::from_status(Status::GenericFailure))?; let device_key_upload = DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: signed_identity_keys_blob.payload, payload_signature: signed_identity_keys_blob.signature, social_proof: None, }), - content_upload: Some(identity_client::PreKey { - pre_key: String::new(), - pre_key_signature: String::new(), + content_upload: Some(PreKey { + pre_key: content_prekey, + pre_key_signature: content_prekey_signature, }), - notif_upload: Some(identity_client::PreKey { - pre_key: String::new(), - pre_key_signature: String::new(), + notif_upload: Some(PreKey { + pre_key: notif_prekey, + pre_key_signature: notif_prekey_signature, }), - onetime_content_prekeys: Vec::new(), - onetime_notif_prekeys: Vec::new(), + onetime_content_prekeys: content_one_time_keys, + onetime_notif_prekeys: notif_one_time_keys, }; let registration_start_request = Request::new(RegistrationStartRequest { opaque_registration_request, username, device_key_upload: Some(device_key_upload), }); // Finish OPAQUE registration and send final registration request let registration_start_response = identity_client .register_password_user_start(registration_start_request) .await .map_err(|_| Error::from_status(Status::GenericFailure))? .into_inner(); let opaque_registration_upload = opaque_registration .finish( &password, ®istration_start_response.opaque_registration_response, ) .map_err(|_| Error::from_status(Status::GenericFailure))?; let registration_finish_request = Request::new(RegistrationFinishRequest { session_id: registration_start_response.session_id, opaque_registration_upload, }); - identity_client + let registration_response = identity_client .register_password_user_finish(registration_finish_request) .await .map_err(|_| Error::from_status(Status::GenericFailure))? .into_inner(); - // Keyserver doesn't need the access token, so we just return a bool - Ok(true) + let user_info = UserLoginInfo { + user_id: registration_response.user_id, + access_token: registration_response.access_token, + }; + + Ok(user_info) } diff --git a/keyserver/addons/rust-node-addon/src/identity_client/remove_reserved_username.rs b/keyserver/addons/rust-node-addon/src/identity_client/remove_reserved_usernames.rs similarity index 100% rename from keyserver/addons/rust-node-addon/src/identity_client/remove_reserved_username.rs rename to keyserver/addons/rust-node-addon/src/identity_client/remove_reserved_usernames.rs