diff --git a/services/tunnelbroker/src/cxx_bridge.rs b/services/tunnelbroker/src/cxx_bridge.rs index 964f22508..44092e4d9 100644 --- a/services/tunnelbroker/src/cxx_bridge.rs +++ b/services/tunnelbroker/src/cxx_bridge.rs @@ -1,9 +1,38 @@ #[cxx::bridge] pub mod ffi { + enum GRPCStatusCodes { + Ok, + Cancelled, + Unknown, + InvalidArgument, + DeadlineExceeded, + NotFound, + AlreadyExists, + PermissionDenied, + ResourceExhausted, + FailedPrecondition, + Aborted, + OutOfRange, + Unimplemented, + Internal, + Unavailable, + DataLoss, + Unauthenticated, + } + struct GrpcResult { + statusCode: GRPCStatusCodes, + errorText: String, + } + struct SessionSignatureResult { + toSign: String, + grpcStatus: GrpcResult, + } + unsafe extern "C++" { include!("tunnelbroker/src/libcpp/Tunnelbroker.h"); pub fn initialize(); pub fn getConfigParameter(parameter: &str) -> Result; pub fn isSandbox() -> Result; + pub fn sessionSignatureHandler(deviceID: &str) -> SessionSignatureResult; } } diff --git a/services/tunnelbroker/src/libcpp/Tunnelbroker.cpp b/services/tunnelbroker/src/libcpp/Tunnelbroker.cpp index 2e8f9bb11..60a856727 100644 --- a/services/tunnelbroker/src/libcpp/Tunnelbroker.cpp +++ b/services/tunnelbroker/src/libcpp/Tunnelbroker.cpp @@ -1,47 +1,68 @@ #include "Tunnelbroker.h" #include "AmqpManager.h" #include "AwsTools.h" #include "ConfigManager.h" #include "DatabaseManager.h" #include "GlobalTools.h" #include "Tools.h" #include "rust/cxx.h" +#include "tunnelbroker/src/cxx_bridge.rs.h" void initialize() { comm::network::tools::InitLogging("tunnelbroker"); comm::network::config::ConfigManager::getInstance().load(); Aws::InitAPI({}); // List of AWS DynamoDB tables to check if they are created and can be // accessed before any AWS API methods const std::list tablesList = { comm::network::config::ConfigManager::getInstance().getParameter( comm::network::config::ConfigManager::OPTION_DYNAMODB_SESSIONS_TABLE), comm::network::config::ConfigManager::getInstance().getParameter( comm::network::config::ConfigManager:: OPTION_DYNAMODB_SESSIONS_VERIFICATION_TABLE), comm::network::config::ConfigManager::getInstance().getParameter( comm::network::config::ConfigManager:: OPTION_DYNAMODB_SESSIONS_PUBLIC_KEY_TABLE), comm::network::config::ConfigManager::getInstance().getParameter( comm::network::config::ConfigManager:: OPTION_DYNAMODB_MESSAGES_TABLE)}; for (const std::string &table : tablesList) { if (!comm::network::database::DatabaseManager::getInstance() .isTableAvailable(table)) { throw std::runtime_error( "Error: AWS DynamoDB table '" + table + "' is not available"); } }; comm::network::AmqpManager::getInstance().init(); } rust::String getConfigParameter(rust::Str parameter) { return rust::String{ comm::network::config::ConfigManager::getInstance().getParameter( std::string{parameter})}; } bool isSandbox() { return comm::network::tools::isSandbox(); } + +SessionSignatureResult sessionSignatureHandler(rust::Str deviceID) { + const std::string requestedDeviceID(deviceID); + if (!comm::network::tools::validateDeviceID(requestedDeviceID)) { + return SessionSignatureResult{ + .grpcStatus = { + .statusCode = GRPCStatusCodes::InvalidArgument, + .errorText = + "Format validation failed for deviceID: " + requestedDeviceID}}; + } + const std::string toSign = comm::network::tools::generateRandomString( + comm::network::SIGNATURE_REQUEST_LENGTH); + std::shared_ptr SessionSignItem = + std::make_shared( + toSign, requestedDeviceID); + comm::network::database::DatabaseManager::getInstance().putSessionSignItem( + *SessionSignItem); + + return SessionSignatureResult{.toSign = toSign}; +} diff --git a/services/tunnelbroker/src/libcpp/Tunnelbroker.h b/services/tunnelbroker/src/libcpp/Tunnelbroker.h index 973a1fc1f..3cc894c80 100644 --- a/services/tunnelbroker/src/libcpp/Tunnelbroker.h +++ b/services/tunnelbroker/src/libcpp/Tunnelbroker.h @@ -1,7 +1,9 @@ #pragma once #include "rust/cxx.h" +#include "tunnelbroker/src/cxx_bridge.rs.h" void initialize(); rust::String getConfigParameter(rust::Str parameter); bool isSandbox(); +SessionSignatureResult sessionSignatureHandler(rust::Str deviceID); diff --git a/services/tunnelbroker/src/server/mod.rs b/services/tunnelbroker/src/server/mod.rs index dc99b7641..98663232d 100644 --- a/services/tunnelbroker/src/server/mod.rs +++ b/services/tunnelbroker/src/server/mod.rs @@ -1,96 +1,106 @@ use super::constants; +use super::cxx_bridge::ffi::{sessionSignatureHandler, GRPCStatusCodes}; use anyhow::Result; use futures::Stream; use std::pin::Pin; use tonic::transport::Server; use tonic::{Request, Response, Status, Streaming}; use tunnelbroker::tunnelbroker_service_server::{ TunnelbrokerService, TunnelbrokerServiceServer, }; - +mod tools; mod tunnelbroker { tonic::include_proto!("tunnelbroker"); } #[derive(Debug, Default)] struct TunnelbrokerServiceHandlers {} #[tonic::async_trait] impl TunnelbrokerService for TunnelbrokerServiceHandlers { async fn session_signature( &self, - _request: Request, + request: Request, ) -> Result, Status> { - Err(Status::unimplemented("Not implemented yet")) + let result = sessionSignatureHandler(&request.into_inner().device_id); + if result.grpcStatus.statusCode != GRPCStatusCodes::Ok { + return Err(tools::create_tonic_status( + result.grpcStatus.statusCode, + &result.grpcStatus.errorText, + )); + } + Ok(Response::new(tunnelbroker::SessionSignatureResponse { + to_sign: result.toSign, + })) } async fn new_session( &self, _request: Request, ) -> Result, Status> { Err(Status::unimplemented("Not implemented yet")) } type MessagesStreamStream = Pin< Box< dyn Stream> + Send, >, >; async fn messages_stream( &self, _request: Request>, ) -> Result, Status> { Err(Status::unimplemented("Not implemented yet")) } // These empty old API handlers are deprecated and should be removed. // They are implemented only to fix the building process. async fn check_if_primary_device_online( &self, _request: Request, ) -> Result, Status> { Err(Status::cancelled("Deprecated")) } async fn become_new_primary_device( &self, _request: Request, ) -> Result, Status> { Err(Status::cancelled("Deprecated")) } async fn send_pong( &self, _request: Request, ) -> Result, Status> { Err(Status::cancelled("Deprecated")) } async fn send( &self, _request: Request, ) -> Result, Status> { Err(Status::cancelled("Deprecated")) } type GetStream = Pin< Box> + Send>, >; async fn get( &self, _request: Request, ) -> Result, Status> { Err(Status::cancelled("Deprecated")) } } pub async fn run_grpc_server() -> Result<()> { let addr = format!("[::1]:{}", constants::GRPC_SERVER_PORT).parse()?; Server::builder() .add_service(TunnelbrokerServiceServer::new( TunnelbrokerServiceHandlers::default(), )) .serve(addr) .await?; Ok(()) } diff --git a/services/tunnelbroker/src/server/tools.rs b/services/tunnelbroker/src/server/tools.rs new file mode 100644 index 000000000..1b965603f --- /dev/null +++ b/services/tunnelbroker/src/server/tools.rs @@ -0,0 +1,26 @@ +use crate::server::GRPCStatusCodes; +use tonic::{Code, Status}; + +pub fn create_tonic_status(code: GRPCStatusCodes, text: &str) -> Status { + let status = match code { + GRPCStatusCodes::Ok => Code::Ok, + GRPCStatusCodes::Cancelled => Code::Cancelled, + GRPCStatusCodes::Unknown => Code::Unknown, + GRPCStatusCodes::InvalidArgument => Code::InvalidArgument, + GRPCStatusCodes::DeadlineExceeded => Code::DeadlineExceeded, + GRPCStatusCodes::NotFound => Code::NotFound, + GRPCStatusCodes::AlreadyExists => Code::AlreadyExists, + GRPCStatusCodes::PermissionDenied => Code::PermissionDenied, + GRPCStatusCodes::ResourceExhausted => Code::ResourceExhausted, + GRPCStatusCodes::FailedPrecondition => Code::FailedPrecondition, + GRPCStatusCodes::Aborted => Code::Aborted, + GRPCStatusCodes::OutOfRange => Code::OutOfRange, + GRPCStatusCodes::Unimplemented => Code::Unimplemented, + GRPCStatusCodes::Internal => Code::Internal, + GRPCStatusCodes::Unavailable => Code::Unavailable, + GRPCStatusCodes::DataLoss => Code::DataLoss, + GRPCStatusCodes::Unauthenticated => Code::Unauthenticated, + _ => Code::Internal, + }; + Status::new(status, text) +}