diff --git a/.buildkite/eslint_flow_jest.yml b/.buildkite/eslint_flow_jest.yml --- a/.buildkite/eslint_flow_jest.yml +++ b/.buildkite/eslint_flow_jest.yml @@ -4,7 +4,6 @@ - '(pkill flow || true)' - 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y' - '. /root/.cargo/env' - - 'apt update && apt install -y cmake' - 'yarn cleaninstall --frozen-lockfile --skip-optional --network-timeout 180000' - 'yarn eslint --max-warnings=0 && yarn workspace lib flow && yarn workspace web flow && yarn workspace landing flow && yarn workspace native flow && yarn workspace keyserver flow && yarn workspace desktop flow' - 'yarn workspace lib test && yarn workspace keyserver test' diff --git a/.buildkite/jsi_codegen.yml b/.buildkite/jsi_codegen.yml --- a/.buildkite/jsi_codegen.yml +++ b/.buildkite/jsi_codegen.yml @@ -2,9 +2,6 @@ - label: 'JSI Codegen' command: - '(pkill flow || true)' - - 'apt update && apt install -y cmake' - - 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y' - - '. /root/.cargo/env' - 'yarn cleaninstall --frozen-lockfile --skip-optional --network-timeout 180000' - 'cd native && yarn codegen-jsi && git diff --exit-code' plugins: diff --git a/keyserver/Dockerfile b/keyserver/Dockerfile --- a/keyserver/Dockerfile +++ b/keyserver/Dockerfile @@ -49,17 +49,11 @@ # We need rsync in the prod-build yarn script # We need mariadb-client so we can use mysqldump for backups -# We need cmake to install protobuf (prereq for rust-node-addon) RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ rsync \ mariadb-client \ - cmake \ && rm -rf /var/lib/apt/lists/* -# Install protobuf manually to ensure that we have the correct version -COPY scripts/install_protobuf.sh scripts/ -RUN cd scripts && ./install_protobuf.sh - #------------------------------------------------------------------------------- # STEP 2: DEVOLVE PRIVILEGES # Create another user to run the rest of the commands @@ -106,7 +100,7 @@ # We run yarn cleaninstall before copying most of the files in for build caching #------------------------------------------------------------------------------- -# Copy in package.json files, yarn.lock files, and required scripts +# Copy in package.json and yarn.lock files COPY --chown=comm package.json yarn.lock ./ COPY --chown=comm keyserver/package.json keyserver/.flowconfig keyserver/ COPY --chown=comm lib/package.json lib/.flowconfig lib/ @@ -115,7 +109,6 @@ COPY --chown=comm landing/package.json landing/.flowconfig landing/ COPY --chown=comm desktop/package.json desktop/ COPY --chown=comm keyserver/addons/rust-node-addon/package.json \ - keyserver/addons/rust-node-addon/install_ci_deps.sh \ keyserver/addons/rust-node-addon/ COPY --chown=comm native/expo-modules/android-lifecycle/package.json \ native/expo-modules/android-lifecycle/ @@ -125,9 +118,6 @@ COPY --chown=comm keyserver/addons/rust-node-addon/Cargo.toml \ keyserver/addons/rust-node-addon/ -# Copy in comm-opaque library, a dependency of rust-node-addon -COPY --chown=comm shared/comm-opaque shared/comm-opaque/ - # Copy in files needed for patch-package COPY --chown=comm patches patches/ diff --git a/keyserver/addons/rust-node-addon/Cargo.toml b/keyserver/addons/rust-node-addon/Cargo.toml --- a/keyserver/addons/rust-node-addon/Cargo.toml +++ b/keyserver/addons/rust-node-addon/Cargo.toml @@ -9,24 +9,11 @@ [dependencies] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -napi = { version = "2.10.1", default-features = false, features = [ - "napi4", - "tokio_rt", -] } +napi = { version = "2.10.1", default-features = false, features = ["napi4"] } napi-derive = { version = "2.9.1", default-features = false } -opaque-ke = "1.2" -rand = "0.8" -tonic = "0.8" -tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } -tokio-stream = "0.1" -tracing = "0.1" -prost = "0.11" -comm-opaque = {path = "../../../shared/comm-opaque"} -lazy_static = "1.4" [build-dependencies] napi-build = "2.0.1" -tonic-build = "0.8" [profile.release] lto = true 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 @@ -2,6 +2,4 @@ fn main() { napi_build::setup(); - tonic_build::compile_protos("../../../shared/protos/identity.proto") - .unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e)); } diff --git a/keyserver/addons/rust-node-addon/index.js b/keyserver/addons/rust-node-addon/index.js --- a/keyserver/addons/rust-node-addon/index.js +++ b/keyserver/addons/rust-node-addon/index.js @@ -3,13 +3,7 @@ const { platform, arch } = process; type RustAPI = { - +registerUser: ( - userId: string, - deviceId: string, - username: string, - password: string, - userPublicKey: string, - ) => Promise, + +sum: (a: number, b: number) => number, }; async function getRustAPI(): Promise { @@ -34,8 +28,8 @@ throw new Error('Failed to load native binding'); } - const { registerUser } = nativeBinding.default; - return { registerUser }; + const { sum } = nativeBinding.default; + return { sum }; } export { getRustAPI }; diff --git a/keyserver/addons/rust-node-addon/install_ci_deps.sh b/keyserver/addons/rust-node-addon/install_ci_deps.sh deleted file mode 100755 --- a/keyserver/addons/rust-node-addon/install_ci_deps.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -# We can skip this script if it's not part of a CI workflow -if [[ -z "$BUILDKITE" ]] && [[ -z "$CI" ]]; -then - echo "Not in a CI workflow, exiting" >&2 - exit -fi - -# Install protobuf if it's not already installed -if ! command -v protoc >/dev/null; -then - echo "Installing protobuf" - SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd -P) - bash "${SCRIPT_DIR}/../../../scripts/install_protobuf.sh" -fi diff --git a/keyserver/addons/rust-node-addon/package.json b/keyserver/addons/rust-node-addon/package.json --- a/keyserver/addons/rust-node-addon/package.json +++ b/keyserver/addons/rust-node-addon/package.json @@ -30,11 +30,10 @@ }, "scripts": { "artifacts": "napi artifacts", - "build": "yarn install-ci-deps && napi build --platform napi --release", + "build": "napi build --platform napi --release", "build:debug": "napi build --platform napi", "version": "napi version", "postinstall": "yarn build", - "clean": "rm -rf target/ && rm -rf napi/ && rm -rf node_modules/", - "install-ci-deps": "bash ./install_ci_deps.sh" + "clean": "rm -rf target/ && rm -rf napi/ && rm -rf node_modules/" } } diff --git a/keyserver/addons/rust-node-addon/src/identity_client.rs b/keyserver/addons/rust-node-addon/src/identity_client.rs deleted file mode 100644 --- a/keyserver/addons/rust-node-addon/src/identity_client.rs +++ /dev/null @@ -1,306 +0,0 @@ -use lazy_static::lazy_static; -use napi::bindgen_prelude::*; -use opaque_ke::{ - ClientLogin, ClientLoginFinishParameters, ClientLoginStartParameters, - ClientLoginStartResult, ClientRegistration, - ClientRegistrationFinishParameters, CredentialFinalization, - CredentialResponse, RegistrationResponse, RegistrationUpload, -}; -use rand::{rngs::OsRng, CryptoRng, Rng}; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tonic::Request; -use tracing::{error, instrument}; -mod identity { - tonic::include_proto!("identity"); -} -use comm_opaque::Cipher; -use identity::identity_service_client::IdentityServiceClient; -use identity::{ - pake_login_response::Data::AccessToken, - pake_login_response::Data::PakeCredentialResponse, - registration_request::Data::PakeCredentialFinalization as RegistrationPakeCredentialFinalization, - registration_request::Data::PakeRegistrationRequestAndUserId, - registration_request::Data::PakeRegistrationUploadAndCredentialRequest, - registration_response::Data::PakeLoginResponse as RegistrationPakeLoginResponse, - registration_response::Data::PakeRegistrationResponse, - PakeLoginResponse as PakeLoginResponseStruct, - PakeRegistrationRequestAndUserId as PakeRegistrationRequestAndUserIdStruct, - PakeRegistrationUploadAndCredentialRequest as PakeRegistrationUploadAndCredentialRequestStruct, - RegistrationRequest, RegistrationResponse as RegistrationResponseMessage, -}; -use std::env::var; - -lazy_static! { - static ref IDENTITY_SERVICE_SOCKET_ADDR: String = - var("COMM_IDENTITY_SERVICE_SOCKET_ADDR") - .unwrap_or("https://[::1]:50051".to_string()); -} - -#[napi] -#[instrument(skip_all)] -pub async fn register_user( - user_id: String, - device_id: String, - username: String, - password: String, - user_public_key: String, -) -> Result { - let mut identity_client = - IdentityServiceClient::connect(IDENTITY_SERVICE_SOCKET_ADDR.as_str()) - .await - .map_err(|_| Error::from_status(Status::GenericFailure))?; - - // 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 = Request::new(stream); - - // `response` is the Stream for inbound messages - let mut response = identity_client - .register_user(request) - .await - .map_err(|_| Error::from_status(Status::GenericFailure))? - .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, - &password, - device_id, - username, - user_public_key, - )?; - send_to_mpsc(tx.clone(), 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(|_| Error::from_status(Status::GenericFailure))?; - let client_login = handle_registration_response( - message, - &mut client_rng, - client_registration, - &password, - tx.clone(), - ) - .await?; - - // Finish PAKE login; send final login request to Identity service - let message = response - .message() - .await - .map_err(|_| Error::from_status(Status::GenericFailure))?; - handle_registration_credential_response(message, client_login, tx) - .await - .map_err(|_| Error::from_status(Status::GenericFailure))?; - - // Return access token - let message = response - .message() - .await - .map_err(|_| Error::from_status(Status::GenericFailure))?; - handle_registration_token_response(message) -} - -fn handle_unexpected_response(message: Option) -> Error { - error!("Received an unexpected message: {:?}", message); - Error::from_status(Status::GenericFailure) -} - -async fn send_to_mpsc(tx: mpsc::Sender, 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> { - ClientLogin::::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, -) -> Result> { - 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, - password: &str, - device_id: String, - username: String, - user_public_key: String, -) -> Result<(RegistrationRequest, ClientRegistration)> { - let client_registration_start_result = - ClientRegistration::::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(); - Ok(( - RegistrationRequest { - data: Some(PakeRegistrationRequestAndUserId( - PakeRegistrationRequestAndUserIdStruct { - user_id, - device_id, - pake_registration_request, - username, - user_public_key, - }, - )), - }, - client_registration_start_result.state, - )) -} - -async fn handle_registration_response( - message: Option, - client_rng: &mut (impl Rng + CryptoRng), - client_registration: ClientRegistration, - password: &str, - tx: mpsc::Sender, -) -> Result> { - if let Some(RegistrationResponseMessage { - data: Some(PakeRegistrationResponse(registration_response_bytes)), - .. - }) = message - { - let pake_registration_upload = pake_registration_finish( - client_rng, - ®istration_response_bytes, - client_registration, - )? - .serialize(); - let client_login_start_result = pake_login_start(client_rng, password)?; - - // `registration_request` is a gRPC message containing serialized bytes to - // complete PAKE registration and begin PAKE login - let registration_request = RegistrationRequest { - data: Some(PakeRegistrationUploadAndCredentialRequest( - PakeRegistrationUploadAndCredentialRequestStruct { - pake_registration_upload, - pake_credential_request: client_login_start_result - .message - .serialize() - .map_err(|e| { - error!("Could not serialize credential request: {}", e); - Error::from_status(Status::GenericFailure) - })?, - }, - )), - }; - send_to_mpsc(tx, registration_request).await?; - Ok(client_login_start_result.state) - } else { - Err(handle_unexpected_response(message)) - } -} - -async fn handle_registration_credential_response( - message: Option, - client_login: ClientLogin, - tx: mpsc::Sender, -) -> Result<()> { - if let Some(RegistrationResponseMessage { - data: - Some(RegistrationPakeLoginResponse(PakeLoginResponseStruct { - data: Some(PakeCredentialResponse(credential_response_bytes)), - })), - }) = message - { - let registration_request = RegistrationRequest { - data: Some(RegistrationPakeCredentialFinalization( - pake_login_finish(&credential_response_bytes, client_login)? - .serialize() - .map_err(|e| { - error!("Could not serialize credential request: {}", e); - Error::from_status(Status::GenericFailure) - })?, - )), - }; - send_to_mpsc(tx, registration_request).await - } else { - Err(handle_unexpected_response(message)) - } -} - -fn handle_registration_token_response( - message: Option, -) -> Result { - if let Some(RegistrationResponseMessage { - data: - Some(RegistrationPakeLoginResponse(PakeLoginResponseStruct { - data: Some(AccessToken(access_token)), - })), - }) = message - { - Ok(access_token) - } else { - Err(handle_unexpected_response(message)) - } -} - -fn pake_registration_finish( - rng: &mut (impl Rng + CryptoRng), - registration_response_bytes: &[u8], - client_registration: ClientRegistration, -) -> Result> { - client_registration - .finish( - rng, - RegistrationResponse::deserialize(registration_response_bytes).map_err( - |e| { - error!("Could not deserialize registration response bytes: {}", e); - Error::from_status(Status::GenericFailure) - }, - )?, - 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/addons/rust-node-addon/src/lib.rs b/keyserver/addons/rust-node-addon/src/lib.rs --- a/keyserver/addons/rust-node-addon/src/lib.rs +++ b/keyserver/addons/rust-node-addon/src/lib.rs @@ -1,4 +1,9 @@ -pub mod identity_client; +#![deny(clippy::all)] #[macro_use] extern crate napi_derive; + +#[napi] +pub fn sum(a: i32, b: i32) -> i32 { + a + b +}