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 @@ -2,12 +2,34 @@ 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, +addReservedUsername: (message: string, signature: string) => Promise, +removeReservedUsername: ( message: string, 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 --- /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.clone(), + access_token: login_finish_response.access_token.clone(), + }; + + 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 --- a/keyserver/addons/rust-node-addon/src/identity_client/mod.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client/mod.rs @@ -1,4 +1,5 @@ pub mod add_reserved_username; +pub mod login; pub mod register_user; pub mod remove_reserved_username; pub mod identity_client { @@ -7,7 +8,7 @@ use identity_client::identity_client_service_client::IdentityClientServiceClient; use identity_client::{ - AddReservedUsernameRequest, DeviceKeyUpload, IdentityKeyInfo, + AddReservedUsernameRequest, DeviceKeyUpload, IdentityKeyInfo, PreKey, RegistrationFinishRequest, RegistrationStartRequest, RemoveReservedUsernameRequest, }; @@ -15,7 +16,7 @@ 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! { @@ -62,3 +63,9 @@ 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 --- a/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs +++ b/keyserver/addons/rust-node-addon/src/identity_client/register_user.rs @@ -6,20 +6,16 @@ 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(); @@ -32,16 +28,16 @@ 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, @@ -68,12 +64,16 @@ 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.clone(), + access_token: registration_response.access_token.clone(), + }; + + Ok(user_info) }