Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3513934
D6944.id23443.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D6944.id23443.diff
View Options
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
@@ -4,6 +4,7 @@
pub mod identity {
tonic::include_proto!("identity");
}
+pub mod update_user;
use comm_opaque::Cipher;
use identity::identity_service_client::IdentityServiceClient;
diff --git a/keyserver/addons/rust-node-addon/src/identity_client/update_user.rs b/keyserver/addons/rust-node-addon/src/identity_client/update_user.rs
new file mode 100644
--- /dev/null
+++ b/keyserver/addons/rust-node-addon/src/identity_client/update_user.rs
@@ -0,0 +1,334 @@
+use std::collections::HashMap;
+
+use crate::identity_client::identity as proto;
+use crate::identity_client::identity::identity_service_client::IdentityServiceClient;
+use crate::identity_client::identity::pake_login_response::Data::AccessToken;
+use crate::identity_client::identity::{
+ update_user_request, update_user_response, UpdateUserRequest,
+ UpdateUserResponse,
+};
+use crate::identity_client::{AUTH_TOKEN, IDENTITY_SERVICE_SOCKET_ADDR};
+use comm_opaque::Cipher;
+use napi::bindgen_prelude::*;
+use opaque_ke::{
+ ClientLogin, ClientLoginFinishParameters, ClientLoginStartParameters,
+ ClientLoginStartResult, ClientRegistration,
+ ClientRegistrationFinishParameters, CredentialFinalization,
+ CredentialResponse, RegistrationUpload,
+};
+use rand::{rngs::OsRng, CryptoRng, Rng};
+use tokio::sync::mpsc;
+use tokio_stream::wrappers::ReceiverStream;
+use tonic;
+use tonic::{metadata::MetadataValue, transport::Channel};
+use tracing::{error, instrument};
+
+use super::identity::{PakeLoginResponse, SessionInitializationInfo};
+
+#[napi]
+#[instrument(skip_all)]
+pub async fn update_user(
+ user_id: String,
+ signing_public_key: String,
+ username: String,
+ password: String,
+ session_initialization_info: HashMap<String, String>,
+) -> Result<String> {
+ let channel = Channel::from_static(&IDENTITY_SERVICE_SOCKET_ADDR)
+ .connect()
+ .await
+ .map_err(|_| Error::from_status(Status::GenericFailure))?;
+ let token: MetadataValue<_> = AUTH_TOKEN
+ .parse()
+ .map_err(|_| Error::from_status(Status::GenericFailure))?;
+ let mut identity_client = IdentityServiceClient::with_interceptor(
+ channel,
+ |mut req: tonic::Request<()>| {
+ req.metadata_mut().insert("authorization", token.clone());
+ Ok(req)
+ },
+ );
+
+ // Create a RegistrationRequest channel and use ReceiverStream to turn the
+ // MPSC receiver into a Stream for outbound messages
+ let (tx, rx) = mpsc::channel(1);
+ let stream = ReceiverStream::new(rx);
+ let request = tonic::Request::new(stream);
+
+ // `response` is the Stream for inbound messages
+ let mut response = identity_client
+ .update_user(request)
+ .await
+ .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?
+ .into_inner();
+
+ // Start PAKE registration on client and send initial registration request
+ // to Identity service
+ let mut client_rng = OsRng;
+ let (registration_request, client_registration) = pake_registration_start(
+ &mut client_rng,
+ user_id,
+ signing_public_key,
+ &password,
+ username,
+ session_initialization_info,
+ )?;
+ send_to_mpsc(&tx, registration_request).await?;
+
+ // Handle responses from Identity service sequentially, making sure we get
+ // messages in the correct order
+
+ // Finish PAKE registration and begin PAKE login; send the final
+ // registration request and initial login request together to reduce the
+ // number of trips
+ let message = response
+ .message()
+ .await
+ .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
+ let registration_response = get_registration_response(message)?;
+ let client_login = handle_registration_response(
+ ®istration_response,
+ &mut client_rng,
+ client_registration,
+ &password,
+ &tx,
+ )
+ .await?;
+
+ // Finish PAKE login; send final login request to Identity service
+ let message = response
+ .message()
+ .await
+ .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
+ let credential_response = get_login_credential_response(message)?;
+ hanle_login_credential_response(&credential_response, client_login, &tx)
+ .await
+ .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
+
+ // Return access token
+ let message = response
+ .message()
+ .await
+ .map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
+ get_login_token_response(message)
+}
+
+fn handle_unexpected_response<T: std::fmt::Debug>(message: Option<T>) -> Error {
+ error!("Received an unexpected message: {:?}", message);
+ Error::from_status(Status::GenericFailure)
+}
+
+async fn send_to_mpsc<T>(tx: &mpsc::Sender<T>, request: T) -> Result<()> {
+ if let Err(e) = tx.send(request).await {
+ error!("Response was dropped: {}", e);
+ return Err(Error::from_status(Status::GenericFailure));
+ }
+ Ok(())
+}
+
+fn pake_login_start(
+ rng: &mut (impl Rng + CryptoRng),
+ password: &str,
+) -> Result<ClientLoginStartResult<Cipher>> {
+ ClientLogin::<Cipher>::start(
+ rng,
+ password.as_bytes(),
+ ClientLoginStartParameters::default(),
+ )
+ .map_err(|e| {
+ error!("Failed to start PAKE login: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })
+}
+
+fn pake_login_finish(
+ credential_response_bytes: &[u8],
+ client_login: ClientLogin<Cipher>,
+) -> Result<CredentialFinalization<Cipher>> {
+ client_login
+ .finish(
+ CredentialResponse::deserialize(credential_response_bytes).map_err(
+ |e| {
+ error!("Could not deserialize credential response bytes: {}", e);
+ Error::from_status(Status::GenericFailure)
+ },
+ )?,
+ ClientLoginFinishParameters::default(),
+ )
+ .map_err(|e| {
+ error!("Failed to finish PAKE login: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })
+ .map(|res| res.message)
+}
+
+fn pake_registration_start(
+ rng: &mut (impl Rng + CryptoRng),
+ user_id: String,
+ signing_public_key: String,
+ password: &str,
+ username: String,
+ initialization_session_info: HashMap<String, String>,
+) -> Result<(UpdateUserRequest, ClientRegistration<Cipher>)> {
+ let client_registration_start_result =
+ ClientRegistration::<Cipher>::start(rng, password.as_bytes()).map_err(
+ |e| {
+ error!("Failed to start PAKE registration: {}", e);
+ Error::from_status(Status::GenericFailure)
+ },
+ )?;
+ let pake_registration_request =
+ client_registration_start_result.message.serialize();
+ let session_info_message = SessionInitializationInfo {
+ info: initialization_session_info,
+ };
+ Ok((
+ UpdateUserRequest {
+ data: Some(update_user_request::Data::Request(
+ crate::identity_client::identity::PakeRegistrationRequestAndUserId {
+ user_id,
+ pake_registration_request,
+ username,
+ signing_public_key,
+ session_initialization_info: Some(session_info_message),
+ },
+ )),
+ },
+ client_registration_start_result.state,
+ ))
+}
+
+async fn handle_registration_response(
+ registration_reponse_payload: &[u8],
+ client_rng: &mut (impl Rng + CryptoRng),
+ client_registration: ClientRegistration<Cipher>,
+ password: &str,
+ tx: &mpsc::Sender<UpdateUserRequest>,
+) -> Result<ClientLogin<Cipher>> {
+ let pake_registration_upload = pake_registration_finish(
+ client_rng,
+ ®istration_reponse_payload,
+ client_registration,
+ )?
+ .serialize();
+ let client_login_start_result = pake_login_start(client_rng, password)?;
+ let pake_login_request =
+ client_login_start_result.message.serialize().map_err(|e| {
+ error!("Could not serialize credential request: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })?;
+
+ // `registration_request` is a gRPC message containing serialized bytes to
+ // complete PAKE registration and begin PAKE login
+ let inner_message: update_user_request::Data =
+ update_user_request::Data::PakeRegistrationUploadAndCredentialRequest(
+ crate::identity_client::identity::PakeRegistrationUploadAndCredentialRequest {
+ pake_registration_upload,
+ pake_credential_request: pake_login_request,
+ },
+ );
+ let registration_request = UpdateUserRequest {
+ data: Some(inner_message),
+ };
+ send_to_mpsc(tx, registration_request).await?;
+ Ok(client_login_start_result.state)
+}
+
+fn get_registration_response(
+ message: Option<UpdateUserResponse>,
+) -> Result<Vec<u8>> {
+ match message {
+ Some(UpdateUserResponse {
+ data:
+ Some(update_user_response::Data::PakeRegistrationResponse(
+ registration_response_bytes,
+ )),
+ ..
+ }) => Ok(registration_response_bytes),
+ _ => {
+ error!("Received an unexpected message: {:?}", message);
+ Err(Error::from_status(Status::GenericFailure))
+ }
+ }
+}
+
+async fn hanle_login_credential_response(
+ registration_response_payload: &[u8],
+ client_login: ClientLogin<Cipher>,
+ tx: &mpsc::Sender<UpdateUserRequest>,
+) -> Result<()> {
+ let pake_login_finish_result =
+ pake_login_finish(®istration_response_payload, client_login)?;
+ let login_finish_message =
+ pake_login_finish_result.serialize().map_err(|e| {
+ error!("Could not serialize credential request: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })?;
+ let registration_request = UpdateUserRequest {
+ data: Some(
+ proto::update_user_request::Data::PakeLoginFinalizationMessage(
+ login_finish_message,
+ ),
+ ),
+ };
+ send_to_mpsc(tx, registration_request).await
+}
+
+fn get_login_credential_response(
+ message: Option<UpdateUserResponse>,
+) -> Result<Vec<u8>> {
+ match message {
+ Some(UpdateUserResponse {
+ data:
+ Some(update_user_response::Data::PakeLoginResponse(
+ proto::PakeLoginResponse {
+ data:
+ Some(proto::pake_login_response::Data::PakeCredentialResponse(
+ bytes,
+ )),
+ },
+ )),
+ }) => Ok(bytes),
+ _ => Err(handle_unexpected_response(message)),
+ }
+}
+
+fn get_login_token_response(
+ message: Option<UpdateUserResponse>,
+) -> Result<String> {
+ match message {
+ Some(UpdateUserResponse {
+ data:
+ Some(update_user_response::Data::PakeLoginResponse(
+ proto::PakeLoginResponse {
+ data: Some(AccessToken(access_token)),
+ },
+ )),
+ }) => Ok(access_token),
+ _ => Err(handle_unexpected_response(message)),
+ }
+}
+
+fn pake_registration_finish(
+ rng: &mut (impl Rng + CryptoRng),
+ registration_response_bytes: &[u8],
+ client_registration: ClientRegistration<Cipher>,
+) -> Result<RegistrationUpload<Cipher>> {
+ let register_payload =
+ opaque_ke::RegistrationResponse::deserialize(registration_response_bytes)
+ .map_err(|e| {
+ error!("Could not deserialize registration response bytes: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })?;
+ client_registration
+ .finish(
+ rng,
+ register_payload,
+ ClientRegistrationFinishParameters::default(),
+ )
+ .map_err(|e| {
+ error!("Failed to finish PAKE registration: {}", e);
+ Error::from_status(Status::GenericFailure)
+ })
+ .map(|res| res.message)
+}
diff --git a/keyserver/src/updaters/account-updaters.js b/keyserver/src/updaters/account-updaters.js
--- a/keyserver/src/updaters/account-updaters.js
+++ b/keyserver/src/updaters/account-updaters.js
@@ -1,5 +1,6 @@
// @flow
+import { getRustAPI } from 'rust-node-addon';
import bcrypt from 'twin-bcrypt';
import type {
@@ -14,6 +15,7 @@
import { createUpdates } from '../creators/update-creator.js';
import { dbQuery, SQL } from '../database/database.js';
+import { handleAsyncPromise } from '../responders/handlers.js';
import type { Viewer } from '../session/viewer.js';
async function accountUpdater(
@@ -48,6 +50,18 @@
UPDATE users SET ${changedFields} WHERE id = ${viewer.userID}
`;
await dbQuery(saveQuery);
+ handleAsyncPromise(
+ (async () => {
+ const rustApi = await getRustAPI();
+ await rustApi.updateUser(
+ viewer.userID,
+ 'placeholder-device-id',
+ 'placeholder-name',
+ newPassword,
+ 'placeholder-public-key',
+ );
+ })(),
+ );
const updateDatas = [
{
diff --git a/lib/types/rust-binding-types.js b/lib/types/rust-binding-types.js
--- a/lib/types/rust-binding-types.js
+++ b/lib/types/rust-binding-types.js
@@ -38,6 +38,13 @@
socialProof: string,
) => Promise<string>,
+deleteUser: (userId: string) => Promise<boolean>,
+ +updateUser: (
+ userId: string,
+ signingPublicKey: string,
+ username: string,
+ password: string,
+ sessionInitializationInfo: SignedIdentityKeysBlob,
+ ) => Promise<string>,
+TunnelbrokerClient: Class<TunnelbrokerClientClass>,
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Dec 23, 2:37 AM (14 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2693267
Default Alt Text
D6944.id23443.diff (12 KB)
Attached To
Mode
D6944: [Keyserver/identity] Call identity service update_user
Attached
Detach File
Event Timeline
Log In to Comment