diff --git a/services/tunnelbroker/docker-server/contents/server/src/Amqp/AmqpManager.cpp b/services/tunnelbroker/docker-server/contents/server/src/Amqp/AmqpManager.cpp index 3e2db3450..5c7675489 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Amqp/AmqpManager.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Amqp/AmqpManager.cpp @@ -1,130 +1,143 @@ #include "AmqpManager.h" +#include "ConfigManager.h" #include "Constants.h" #include "DeliveryBroker.h" #include "Tools.h" #include #include namespace comm { namespace network { static std::unique_ptr amqpChannel; static std::atomic amqpReady; static long long lastConnectionTimestamp; void AMQPConnectInternal() { - std::cout << "AMQP: Connecting to " << AMQP_URI << std::endl; + const std::string amqpUri = config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_AMQP_URI); + const std::string tunnelbrokerId = + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_TUNNELBROKER_ID); + const std::string fanoutExchangeName = + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_AMQP_FANOUT_EXCHANGE); + std::cout << "AMQP: Connecting to " << amqpUri << std::endl; auto *loop = uv_default_loop(); AMQP::LibUvHandler handler(loop); - AMQP::TcpConnection connection(&handler, AMQP::Address(AMQP_URI)); + AMQP::TcpConnection connection(&handler, AMQP::Address(amqpUri)); amqpChannel = std::make_unique(&connection); amqpChannel->onError([](const char *message) { std::cout << "AMQP: channel error: " << message << ", will try to reconnect" << std::endl; amqpReady = false; }); AMQP::Table arguments; arguments["x-message-ttl"] = AMQP_MESSAGE_TTL; arguments["x-expires"] = AMQP_QUEUE_TTL; - amqpChannel->declareExchange(AMQP_FANOUT_EXCHANGE_NAME, AMQP::fanout); - amqpChannel->declareQueue(TUNNELBROKER_ID, AMQP::durable, arguments) - .onSuccess([&](const std::string &name, + amqpChannel->declareExchange(fanoutExchangeName, AMQP::fanout); + amqpChannel->declareQueue(tunnelbrokerId, AMQP::durable, arguments) + .onSuccess([tunnelbrokerId, fanoutExchangeName]( + const std::string &name, uint32_t messagecount, uint32_t consumercount) { std::cout << "AMQP: Queue " << name << " created" << std::endl; - amqpChannel->bindQueue(AMQP_FANOUT_EXCHANGE_NAME, TUNNELBROKER_ID, "") - .onError([](const char *message) { - std::cout << "AMQP: Failed to bind queue: " << TUNNELBROKER_ID - << " to exchange: " << AMQP_FANOUT_EXCHANGE_NAME - << std::endl; + amqpChannel->bindQueue(fanoutExchangeName, tunnelbrokerId, "") + .onError([tunnelbrokerId, fanoutExchangeName](const char *message) { + std::cout << "AMQP: Failed to bind queue: " << tunnelbrokerId + << " to exchange: " << fanoutExchangeName << std::endl; amqpReady = false; }); amqpReady = true; - amqpChannel->consume(TUNNELBROKER_ID) + amqpChannel->consume(tunnelbrokerId) .onReceived([&](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) { try { AMQP::Table headers = message.headers(); const std::string payload(message.body()); const std::string toDeviceID(headers[AMQP_HEADER_TO_DEVICEID]); const std::string fromDeviceID( headers[AMQP_HEADER_FROM_DEVICEID]); std::cout << "AMQP: Message consumed for deviceId: " << toDeviceID << std::endl; DeliveryBroker::getInstance().push( deliveryTag, toDeviceID, fromDeviceID, payload); } catch (const std::exception &e) { std::cout << "AMQP: Message parsing exception: " << e.what() << std::endl; } }) .onError([](const char *message) { std::cout << "AMQP: Error on message consume: " << message << std::endl; }); }) .onError([](const char *message) { throw std::runtime_error( "AMQP: Queue creation error: " + std::string(message)); }); uv_run(loop, UV_RUN_DEFAULT); }; void AMQPConnect() { while (true) { long long currentTimestamp = getCurrentTimestamp(); if (lastConnectionTimestamp && currentTimestamp - lastConnectionTimestamp < AMQP_SHORTEST_RECONNECTION_ATTEMPT_INTERVAL) { throw std::runtime_error( "AMQP reconnection attempt interval too short, tried to reconnect " "after " + std::to_string(currentTimestamp - lastConnectionTimestamp) + "ms, the shortest allowed interval is " + std::to_string(AMQP_SHORTEST_RECONNECTION_ATTEMPT_INTERVAL) + "ms"); } lastConnectionTimestamp = currentTimestamp; AMQPConnectInternal(); } } bool AMQPSend( std::string toDeviceID, std::string fromDeviceID, std::string payload) { if (!amqpReady) { std::cout << "AMQP: Message send error: channel not ready" << std::endl; return false; } try { AMQP::Envelope env(payload.c_str(), payload.size()); AMQP::Table headers; headers[AMQP_HEADER_FROM_DEVICEID] = fromDeviceID; headers[AMQP_HEADER_TO_DEVICEID] = toDeviceID; // Set delivery mode to: Durable (2) env.setDeliveryMode(2); env.setHeaders(std::move(headers)); - amqpChannel->publish(AMQP_FANOUT_EXCHANGE_NAME, "", env); + amqpChannel->publish( + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_AMQP_FANOUT_EXCHANGE), + "", + env); } catch (std::runtime_error &e) { std::cout << "AMQP: Error while publishing message: " << e.what() << std::endl; return false; } return true; }; void AMQPAck(uint64_t deliveryTag) { if (!amqpReady) { std::cout << "AMQP: Message ACK error: channel not ready" << std::endl; return; } amqpChannel->ack(deliveryTag); } } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.cpp b/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.cpp index 4dc3c848a..f311c6b37 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.cpp @@ -1,113 +1,113 @@ #include "DeviceSessionItem.h" -#include "Constants.h" +#include "ConfigManager.h" namespace comm { namespace network { namespace database { -std::string DeviceSessionItem::tableName = DEVICE_SESSIONS_TABLE_NAME; const std::string DeviceSessionItem::FIELD_SESSION_ID = "SessionId"; const std::string DeviceSessionItem::FIELD_DEVICE_ID = "DeviceId"; const std::string DeviceSessionItem::FIELD_PUBKEY = "PubKey"; const std::string DeviceSessionItem::FIELD_NOTIFY_TOKEN = "NotifyToken"; const std::string DeviceSessionItem::FIELD_DEVICE_TYPE = "DeviceType"; const std::string DeviceSessionItem::FIELD_APP_VERSION = "AppVersion"; const std::string DeviceSessionItem::FIELD_DEVICE_OS = "DeviceOS"; const std::string DeviceSessionItem::FIELD_CHECKPOINT_TIME = "CheckpointTime"; const std::string DeviceSessionItem::FIELD_EXPIRE = "Expire"; DeviceSessionItem::DeviceSessionItem( const std::string sessionId, const std::string deviceId, const std::string pubKey, const std::string notifyToken, const std::string deviceType, const std::string appVersion, const std::string deviceOs) : sessionId(sessionId), deviceId(deviceId), pubKey(pubKey), notifyToken(notifyToken), deviceType(deviceType), appVersion(appVersion), deviceOs(deviceOs) { this->validate(); } DeviceSessionItem::DeviceSessionItem(const AttributeValues &itemFromDB) { this->assignItemFromDatabase(itemFromDB); } void DeviceSessionItem::validate() const { if (!this->sessionId.size()) { throw std::runtime_error("Error: SessionId is empty."); } } void DeviceSessionItem::assignItemFromDatabase( const AttributeValues &itemFromDB) { try { this->sessionId = itemFromDB.at(DeviceSessionItem::FIELD_SESSION_ID).GetS(); this->deviceId = itemFromDB.at(DeviceSessionItem::FIELD_DEVICE_ID).GetS(); this->pubKey = itemFromDB.at(DeviceSessionItem::FIELD_PUBKEY).GetS(); this->notifyToken = itemFromDB.at(DeviceSessionItem::FIELD_NOTIFY_TOKEN).GetS(); this->deviceType = itemFromDB.at(DeviceSessionItem::FIELD_DEVICE_TYPE).GetS(); this->appVersion = itemFromDB.at(DeviceSessionItem::FIELD_APP_VERSION).GetS(); this->deviceOs = itemFromDB.at(DeviceSessionItem::FIELD_DEVICE_OS).GetS(); this->checkpointTime = std::stoll( std::string( itemFromDB.at(DeviceSessionItem::FIELD_CHECKPOINT_TIME).GetS()) .c_str()); } catch (std::out_of_range &e) { throw std::runtime_error( "Invalid device session database value " + std::string(e.what())); } this->validate(); } std::string DeviceSessionItem::getTableName() const { - return DeviceSessionItem::tableName; + return config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_TABLE); } std::string DeviceSessionItem::getPrimaryKey() const { return DeviceSessionItem::FIELD_SESSION_ID; } std::string DeviceSessionItem::getSessionId() const { return this->sessionId; } std::string DeviceSessionItem::getDeviceId() const { return this->deviceId; } std::string DeviceSessionItem::getPubKey() const { return this->pubKey; } std::string DeviceSessionItem::getNotifyToken() const { return this->notifyToken; } std::string DeviceSessionItem::getDeviceType() const { return this->deviceType; } std::string DeviceSessionItem::getAppVersion() const { return this->appVersion; } std::string DeviceSessionItem::getDeviceOs() const { return this->deviceOs; } long long DeviceSessionItem::getCheckpointTime() const { return this->checkpointTime; } } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.h b/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.h index 11cff6ebd..7f0a92d82 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DeviceSessionItem.h @@ -1,62 +1,61 @@ #pragma once #include "Item.h" #include namespace comm { namespace network { namespace database { class DeviceSessionItem : public Item { std::string sessionId; std::string deviceId; std::string pubKey; std::string notifyToken; std::string deviceType; std::string appVersion; std::string deviceOs; long long checkpointTime = 0; void validate() const override; public: - static std::string tableName; static const std::string FIELD_SESSION_ID; static const std::string FIELD_DEVICE_ID; static const std::string FIELD_PUBKEY; static const std::string FIELD_NOTIFY_TOKEN; static const std::string FIELD_DEVICE_TYPE; static const std::string FIELD_APP_VERSION; static const std::string FIELD_DEVICE_OS; static const std::string FIELD_CHECKPOINT_TIME; static const std::string FIELD_EXPIRE; std::string getPrimaryKey() const override; std::string getTableName() const override; std::string getSessionId() const; std::string getDeviceId() const; std::string getPubKey() const; std::string getNotifyToken() const; std::string getDeviceType() const; std::string getAppVersion() const; std::string getDeviceOs() const; long long getCheckpointTime() const; DeviceSessionItem() { } DeviceSessionItem( const std::string sessionId, const std::string deviceId, const std::string pubKey, const std::string notifyToken, const std::string deviceType, const std::string appVersion, const std::string deviceOs); DeviceSessionItem(const AttributeValues &itemFromDB); void assignItemFromDatabase(const AttributeValues &itemFromDB) override; }; } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.cpp b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.cpp index 0d6718b19..4f63e2d47 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.cpp @@ -1,61 +1,61 @@ #include "PublicKeyItem.h" -#include "Constants.h" +#include "ConfigManager.h" namespace comm { namespace network { namespace database { -std::string PublicKeyItem::tableName = DEVICE_PUBLIC_KEY_TABLE_NAME; const std::string PublicKeyItem::FIELD_DEVICE_ID = "DeviceId"; const std::string PublicKeyItem::FIELD_PUBLIC_KEY = "PublicKey"; PublicKeyItem::PublicKeyItem( const std::string deviceId, const std::string publicKey) : deviceId(deviceId), publicKey(publicKey) { this->validate(); } PublicKeyItem::PublicKeyItem(const AttributeValues &itemFromDB) { this->assignItemFromDatabase(itemFromDB); } void PublicKeyItem::validate() const { if (!this->deviceId.size()) { throw std::runtime_error("Error: DeviceId is empty"); } if (!this->publicKey.size()) { throw std::runtime_error("Error: PublicKey is empty"); } } void PublicKeyItem::assignItemFromDatabase(const AttributeValues &itemFromDB) { try { this->publicKey = itemFromDB.at(PublicKeyItem::FIELD_PUBLIC_KEY).GetS(); this->deviceId = itemFromDB.at(PublicKeyItem::FIELD_DEVICE_ID).GetS(); } catch (const std::exception &e) { throw std::runtime_error( "Got an exception at PublicKeyItem: " + std::string(e.what())); } this->validate(); } std::string PublicKeyItem::getTableName() const { - return PublicKeyItem::tableName; + return config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_PUBLIC_KEY_TABLE); } std::string PublicKeyItem::getPrimaryKey() const { return PublicKeyItem::FIELD_DEVICE_ID; } std::string PublicKeyItem::getDeviceId() const { return this->deviceId; } std::string PublicKeyItem::getPublicKey() const { return this->publicKey; } } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.h b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.h index 75f2fc03d..cb1f25288 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.h @@ -1,36 +1,35 @@ #pragma once #include "Item.h" #include namespace comm { namespace network { namespace database { class PublicKeyItem : public Item { std::string deviceId; std::string publicKey; void validate() const override; public: - static std::string tableName; static const std::string FIELD_DEVICE_ID; static const std::string FIELD_PUBLIC_KEY; std::string getPrimaryKey() const override; std::string getTableName() const override; std::string getDeviceId() const; std::string getPublicKey() const; PublicKeyItem() { } PublicKeyItem(const std::string deviceId, const std::string publicKey); PublicKeyItem(const AttributeValues &itemFromDB); void assignItemFromDatabase(const AttributeValues &itemFromDB) override; }; } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.cpp b/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.cpp index d0a3347e5..fc51a5e67 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.cpp @@ -1,66 +1,65 @@ #include "SessionSignItem.h" -#include "Constants.h" +#include "ConfigManager.h" namespace comm { namespace network { namespace database { -std::string SessionSignItem::tableName = - DEVICE_SESSIONS_VERIFICATION_MESSAGES_TABLE_NAME; const std::string SessionSignItem::FIELD_SESSION_VERIFICATION = "VerificationMessage"; const std::string SessionSignItem::FIELD_DEVICE_ID = "DeviceId"; const std::string SessionSignItem::FIELD_EXPIRE = "Expire"; SessionSignItem::SessionSignItem( const std::string sign, const std::string deviceId) : sign(sign), deviceId(deviceId) { this->validate(); } SessionSignItem::SessionSignItem(const AttributeValues &itemFromDB) { this->assignItemFromDatabase(itemFromDB); } void SessionSignItem::validate() const { if (!this->deviceId.size()) { throw std::runtime_error("Error: DeviceId is empty"); } if (!this->sign.size()) { throw std::runtime_error("Error: Sign is empty"); } } void SessionSignItem::assignItemFromDatabase( const AttributeValues &itemFromDB) { try { this->sign = itemFromDB.at(SessionSignItem::FIELD_SESSION_VERIFICATION).GetS(); this->deviceId = itemFromDB.at(SessionSignItem::FIELD_DEVICE_ID).GetS(); } catch (const std::exception &e) { throw std::runtime_error( "Got an exception at SessionSignItem: " + std::string(e.what())); } this->validate(); } std::string SessionSignItem::getTableName() const { - return SessionSignItem::tableName; + return config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_VERIFICATION_TABLE); } std::string SessionSignItem::getPrimaryKey() const { return SessionSignItem::FIELD_DEVICE_ID; } std::string SessionSignItem::getSign() const { return this->sign; } std::string SessionSignItem::getDeviceId() const { return this->deviceId; } } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.h b/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.h index 88ba536b4..75094f9a3 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/SessionSignItem.h @@ -1,37 +1,36 @@ #pragma once #include "Item.h" #include namespace comm { namespace network { namespace database { class SessionSignItem : public Item { std::string sign; std::string deviceId; void validate() const override; public: - static std::string tableName; static const std::string FIELD_SESSION_VERIFICATION; static const std::string FIELD_DEVICE_ID; static const std::string FIELD_EXPIRE; std::string getPrimaryKey() const override; std::string getTableName() const override; std::string getSign() const; std::string getDeviceId() const; SessionSignItem() { } SessionSignItem(const std::string sign, const std::string deviceId); SessionSignItem(const AttributeValues &itemFromDB); void assignItemFromDatabase(const AttributeValues &itemFromDB) override; }; } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Service/TunnelbrokerServiceImpl.cpp b/services/tunnelbroker/docker-server/contents/server/src/Service/TunnelbrokerServiceImpl.cpp index 747f9b784..2e6cc26b4 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Service/TunnelbrokerServiceImpl.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Service/TunnelbrokerServiceImpl.cpp @@ -1,222 +1,226 @@ #include "TunnelbrokerServiceImpl.h" #include "AmqpManager.h" #include "AwsTools.h" -#include "Constants.h" +#include "ConfigManager.h" #include "CryptoTools.h" #include "DatabaseManager.h" #include "DeliveryBroker.h" #include "Tools.h" #include #include #include #include namespace comm { namespace network { TunnelBrokerServiceImpl::TunnelBrokerServiceImpl() { 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 = { - DEVICE_SESSIONS_TABLE_NAME, - DEVICE_SESSIONS_VERIFICATION_MESSAGES_TABLE_NAME}; + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_TABLE), + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_VERIFICATION_TABLE), + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DYNAMODB_SESSIONS_PUBLIC_KEY_TABLE)}; for (const std::string &table : tablesList) { if (!database::DatabaseManager::getInstance().isTableAvailable(table)) { throw std::runtime_error( "Error: AWS DynamoDB table '" + table + "' is not available"); } }; }; TunnelBrokerServiceImpl::~TunnelBrokerServiceImpl() { Aws::ShutdownAPI({}); }; grpc::Status TunnelBrokerServiceImpl::SessionSignature( grpc::ServerContext *context, const tunnelbroker::SessionSignatureRequest *request, tunnelbroker::SessionSignatureResponse *reply) { const std::string deviceId = request->deviceid(); if (!validateDeviceId(deviceId)) { std::cout << "gRPC: " << "Format validation failed for " << deviceId << std::endl; return grpc::Status( grpc::StatusCode::INVALID_ARGUMENT, "Format validation failed for deviceID"); } const std::string toSign = generateRandomString(SIGNATURE_REQUEST_LENGTH); std::shared_ptr SessionSignItem = std::make_shared(toSign, deviceId); database::DatabaseManager::getInstance().putSessionSignItem(*SessionSignItem); reply->set_tosign(toSign); return grpc::Status::OK; }; grpc::Status TunnelBrokerServiceImpl::NewSession( grpc::ServerContext *context, const tunnelbroker::NewSessionRequest *request, tunnelbroker::NewSessionResponse *reply) { std::shared_ptr deviceSessionItem; std::shared_ptr sessionSignItem; std::shared_ptr publicKeyItem; const std::string deviceId = request->deviceid(); if (!validateDeviceId(deviceId)) { std::cout << "gRPC: " << "Format validation failed for " << deviceId << std::endl; return grpc::Status( grpc::StatusCode::INVALID_ARGUMENT, "Format validation failed for deviceID"); } const std::string signature = request->signature(); const std::string publicKey = request->publickey(); const boost::uuids::uuid uuid = boost::uuids::random_generator()(); const std::string newSessionId = boost::lexical_cast(uuid); try { deviceSessionItem = database::DatabaseManager::getInstance().findSessionItem(newSessionId); if (deviceSessionItem != nullptr) { std::cout << "gRPC: " << "Session unique ID " << newSessionId << " already used" << std::endl; return grpc::Status( grpc::StatusCode::INTERNAL, "Session unique ID already used"); } sessionSignItem = database::DatabaseManager::getInstance().findSessionSignItem(deviceId); if (sessionSignItem == nullptr) { std::cout << "gRPC: " << "Session sign request not found for deviceId: " << deviceId << std::endl; return grpc::Status( grpc::StatusCode::NOT_FOUND, "Session sign request not found"); } publicKeyItem = database::DatabaseManager::getInstance().findPublicKeyItem(deviceId); if (publicKeyItem == nullptr) { std::shared_ptr newPublicKeyItem = std::make_shared(deviceId, publicKey); database::DatabaseManager::getInstance().putPublicKeyItem( *newPublicKeyItem); } else if (publicKey != publicKeyItem->getPublicKey()) { std::cout << "gRPC: " << "The public key doesn't match for deviceId" << std::endl; return grpc::Status( grpc::StatusCode::PERMISSION_DENIED, "The public key doesn't match for deviceId"); } const std::string verificationMessage = sessionSignItem->getSign(); if (!comm::network::crypto::rsaVerifyString( publicKey, verificationMessage, signature)) { std::cout << "gRPC: " << "Signature for the verification message is not valid" << std::endl; return grpc::Status( grpc::StatusCode::PERMISSION_DENIED, "Signature for the verification message is not valid"); } database::DatabaseManager::getInstance().removeSessionSignItem(deviceId); deviceSessionItem = std::make_shared( newSessionId, deviceId, request->publickey(), request->notifytoken(), tunnelbroker::NewSessionRequest_DeviceTypes_Name(request->devicetype()), request->deviceappversion(), request->deviceos()); database::DatabaseManager::getInstance().putSessionItem(*deviceSessionItem); } catch (std::runtime_error &e) { std::cout << "gRPC: " << "Error while processing 'NewSession' request: " << e.what() << std::endl; return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); } reply->set_sessionid(newSessionId); return grpc::Status::OK; }; grpc::Status TunnelBrokerServiceImpl::Send( grpc::ServerContext *context, const tunnelbroker::SendRequest *request, google::protobuf::Empty *reply) { try { const std::string sessionId = request->sessionid(); std::shared_ptr sessionItem = database::DatabaseManager::getInstance().findSessionItem(sessionId); if (sessionItem == nullptr) { std::cout << "gRPC: " << "Session " << sessionId << " not found" << std::endl; return grpc::Status( grpc::StatusCode::PERMISSION_DENIED, "No such session found. SessionId: " + sessionId); } const std::string clientDeviceId = sessionItem->getDeviceId(); if (!AMQPSend( request->todeviceid(), clientDeviceId, std::string(request->payload()))) { std::cout << "gRPC: " << "Error while publish the message to AMQP" << std::endl; return grpc::Status( grpc::StatusCode::INTERNAL, "Error while publish the message to AMQP"); } } catch (std::runtime_error &e) { std::cout << "gRPC: " << "Error while processing 'Send' request: " << e.what() << std::endl; return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); } return grpc::Status::OK; }; grpc::Status TunnelBrokerServiceImpl::Get( grpc::ServerContext *context, const tunnelbroker::GetRequest *request, grpc::ServerWriter *writer) { try { const std::string sessionId = request->sessionid(); std::shared_ptr sessionItem = database::DatabaseManager::getInstance().findSessionItem(sessionId); if (sessionItem == nullptr) { std::cout << "gRPC: " << "Session " << sessionId << " not found" << std::endl; return grpc::Status( grpc::StatusCode::PERMISSION_DENIED, "No such session found. SessionId: " + sessionId); } const std::string clientDeviceId = sessionItem->getDeviceId(); std::vector messagesToDeliver; while (1) { messagesToDeliver = DeliveryBroker::getInstance().get(clientDeviceId); for (auto const &message : messagesToDeliver) { tunnelbroker::GetResponse response; response.set_fromdeviceid(message.fromDeviceID); response.set_payload(message.payload); if (!writer->Write(response)) { throw std::runtime_error( "gRPC: 'Get' writer error on sending data to the client"); } AMQPAck(message.deliveryTag); } if (!DeliveryBroker::getInstance().isEmpty(clientDeviceId)) { DeliveryBroker::getInstance().remove(clientDeviceId); } DeliveryBroker::getInstance().wait(clientDeviceId); } } catch (std::runtime_error &e) { std::cout << "gRPC: " << "Error while processing 'Get' request: " << e.what() << std::endl; return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); } return grpc::Status::OK; }; } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Tools/Tools.cpp b/services/tunnelbroker/docker-server/contents/server/src/Tools/Tools.cpp index 910ff404f..013ba9af5 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Tools/Tools.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Tools/Tools.cpp @@ -1,46 +1,50 @@ #include "Tools.h" +#include "ConfigManager.h" #include "Constants.h" #include #include #include namespace comm { namespace network { std::string generateRandomString(std::size_t length) { const std::string CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; std::random_device random_device; std::mt19937 generator(random_device()); std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1); std::string random_string; for (std::size_t i = 0; i < length; ++i) { random_string += CHARACTERS[distribution(generator)]; } return random_string; } long long getCurrentTimestamp() { using namespace std::chrono; return duration_cast(system_clock::now().time_since_epoch()) .count(); } bool validateDeviceId(std::string deviceId) { try { static const std::regex deviceIdKeyserverRegexp("^ks:.*"); if (std::regex_match(deviceId, deviceIdKeyserverRegexp)) { - return (deviceId == DEVICEID_DEFAULT_KEYSERVER_ID); + return ( + deviceId == + config::ConfigManager::getInstance().getParameter( + config::ConfigManager::OPTION_DEFAULT_KEYSERVER_ID)); } return std::regex_match(deviceId, DEVICEID_FORMAT_REGEX); } catch (const std::exception &e) { std::cout << "Tools: " << "Got an exception at `validateDeviceId`: " << e.what() << std::endl; return false; } } } // namespace network } // namespace comm