diff --git a/services/tunnelbroker/docker-server/contents/server/src/Constants.h b/services/tunnelbroker/docker-server/contents/server/src/Constants.h index 791b32e49..49d91b9e8 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Constants.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Constants.h @@ -1,40 +1,41 @@ #pragma once #include namespace comm { namespace network { // Tunnelbroker server Identification const std::string TUNNELBROKER_ID = "tunnel1"; // AWS const std::string DEVICE_SESSIONS_TABLE_NAME = "tunnelbroker-device-session"; const std::string DEVICE_SESSIONS_VERIFICATION_MESSAGES_TABLE_NAME = "tunnelbroker-verification-message"; +const std::string DEVICE_PUBLIC_KEY_TABLE_NAME = "tunnelbroker-public-key"; // Sessions const size_t SIGNATURE_REQUEST_LENGTH = 64; const size_t SESSION_ID_LENGTH = 64; const size_t SESSION_RECORD_TTL = 30 * 24 * 3600; // 30 days const size_t SESSION_SIGN_RECORD_TTL = 24 * 3600; // 24 hours // gRPC Server const std::string SERVER_LISTEN_ADDRESS = "0.0.0.0:50051"; // AMQP (RabbitMQ) const std::string AMQP_URI = "amqp://guest:guest@0.0.0.0/vhost"; const std::string AMQP_FANOUT_EXCHANGE_NAME = "allBrokers"; // message TTL const size_t AMQP_MESSAGE_TTL = 300 * 1000; // 5 min // queue TTL in case of no consumers (tunnelbroker is down) const size_t AMQP_QUEUE_TTL = 24 * 3600 * 1000; // 24 hours // routing message headers name const std::string AMQP_HEADER_FROM_DEVICEID = "fromDeviceid"; const std::string AMQP_HEADER_TO_DEVICEID = "toDeviceid"; const long long AMQP_SHORTEST_RECONNECTION_ATTEMPT_INTERVAL = 1000 * 60; // 1 min } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.cpp b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.cpp index 67309fa4f..57a30341b 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.cpp @@ -1,19 +1,23 @@ #include "DatabaseEntitiesTools.h" namespace comm { namespace network { namespace database { template <> std::shared_ptr createItemByType() { return std::make_shared(); } template <> std::shared_ptr createItemByType() { return std::make_shared(); } +template <> std::shared_ptr createItemByType() { + return std::make_shared(); +} + } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.h b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.h index c0577d5fb..be2874cf2 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseEntitiesTools.h @@ -1,25 +1,28 @@ #pragma once #include "DeviceSessionItem.h" #include "Item.h" +#include "PublicKeyItem.h" #include "SessionSignItem.h" #include namespace comm { namespace network { namespace database { template std::shared_ptr createItemByType() { throw std::runtime_error("invalid Item type"); } template <> std::shared_ptr createItemByType(); template <> std::shared_ptr createItemByType(); +template <> std::shared_ptr createItemByType(); + } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.cpp b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.cpp index f4d03156c..b6119b5a3 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.cpp +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.cpp @@ -1,140 +1,165 @@ #include "DatabaseManager.h" namespace comm { namespace network { namespace database { DatabaseManager &DatabaseManager::getInstance() { static DatabaseManager instance; return instance; } bool DatabaseManager::isTableAvailable(const std::string &tableName) { Aws::DynamoDB::Model::DescribeTableRequest request; request.SetTableName(tableName); // Check table availability by invoking DescribeTable const Aws::DynamoDB::Model::DescribeTableOutcome &result = getDynamoDBClient()->DescribeTable(request); return result.IsSuccess(); } void DatabaseManager::innerPutItem( std::shared_ptr item, const Aws::DynamoDB::Model::PutItemRequest &request) { const Aws::DynamoDB::Model::PutItemOutcome outcome = getDynamoDBClient()->PutItem(request); if (!outcome.IsSuccess()) { throw std::runtime_error(outcome.GetError().GetMessage()); } } template std::shared_ptr DatabaseManager::innerFindItem(Aws::DynamoDB::Model::GetItemRequest &request) { std::shared_ptr item = createItemByType(); request.SetTableName(item->getTableName()); const Aws::DynamoDB::Model::GetItemOutcome &outcome = getDynamoDBClient()->GetItem(request); if (!outcome.IsSuccess()) { throw std::runtime_error(outcome.GetError().GetMessage()); } const AttributeValues &outcomeItem = outcome.GetResult().GetItem(); if (!outcomeItem.size()) { return nullptr; } item->assignItemFromDatabase(outcomeItem); return std::move(item); } void DatabaseManager::innerRemoveItem( const Item &item, const std::string &key) { Aws::DynamoDB::Model::DeleteItemRequest request; request.SetTableName(item.getTableName()); request.AddKey( item.getPrimaryKey(), Aws::DynamoDB::Model::AttributeValue(key)); const Aws::DynamoDB::Model::DeleteItemOutcome &outcome = getDynamoDBClient()->DeleteItem(request); if (!outcome.IsSuccess()) { throw std::runtime_error(outcome.GetError().GetMessage()); } } void DatabaseManager::putSessionItem(const DeviceSessionItem &item) { Aws::DynamoDB::Model::PutItemRequest request; request.SetTableName(item.getTableName()); request.AddItem( DeviceSessionItem::FIELD_SESSION_ID, Aws::DynamoDB::Model::AttributeValue(item.getSessionId())); request.AddItem( DeviceSessionItem::FIELD_DEVICE_ID, Aws::DynamoDB::Model::AttributeValue(item.getDeviceId())); request.AddItem( DeviceSessionItem::FIELD_PUBKEY, Aws::DynamoDB::Model::AttributeValue(item.getPubKey())); request.AddItem( DeviceSessionItem::FIELD_NOTIFY_TOKEN, Aws::DynamoDB::Model::AttributeValue(item.getNotifyToken())); request.AddItem( DeviceSessionItem::FIELD_DEVICE_TYPE, Aws::DynamoDB::Model::AttributeValue(item.getDeviceType())); request.AddItem( DeviceSessionItem::FIELD_APP_VERSION, Aws::DynamoDB::Model::AttributeValue(item.getAppVersion())); request.AddItem( DeviceSessionItem::FIELD_DEVICE_OS, Aws::DynamoDB::Model::AttributeValue(item.getDeviceOs())); request.AddItem( DeviceSessionItem::FIELD_CHECKPOINT_TIME, Aws::DynamoDB::Model::AttributeValue( std::to_string(item.getCheckpointTime()))); request.AddItem( DeviceSessionItem::FIELD_EXPIRE, Aws::DynamoDB::Model::AttributeValue(std::to_string( static_cast(std::time(0)) + SESSION_RECORD_TTL))); this->innerPutItem(std::make_shared(item), request); } std::shared_ptr DatabaseManager::findSessionItem(const std::string &sessionId) { Aws::DynamoDB::Model::GetItemRequest request; request.AddKey( DeviceSessionItem::FIELD_SESSION_ID, Aws::DynamoDB::Model::AttributeValue(sessionId)); return std::move(this->innerFindItem(request)); } void DatabaseManager::putSessionSignItem(const SessionSignItem &item) { Aws::DynamoDB::Model::PutItemRequest request; request.SetTableName(item.getTableName()); request.AddItem( SessionSignItem::FIELD_SESSION_VERIFICATION, Aws::DynamoDB::Model::AttributeValue(item.getSign())); request.AddItem( SessionSignItem::FIELD_DEVICE_ID, Aws::DynamoDB::Model::AttributeValue(item.getDeviceId())); request.AddItem( SessionSignItem::FIELD_EXPIRE, Aws::DynamoDB::Model::AttributeValue(std::to_string( static_cast(std::time(0)) + SESSION_SIGN_RECORD_TTL))); this->innerPutItem(std::make_shared(item), request); } std::shared_ptr DatabaseManager::findSessionSignItem(const std::string &deviceId) { Aws::DynamoDB::Model::GetItemRequest request; request.AddKey( SessionSignItem::FIELD_DEVICE_ID, Aws::DynamoDB::Model::AttributeValue(deviceId)); return std::move(this->innerFindItem(request)); } void DatabaseManager::removeSessionSignItem(const std::string &deviceId) { this->innerRemoveItem(*(createItemByType()), deviceId); } +void DatabaseManager::putPublicKeyItem(const PublicKeyItem &item) { + Aws::DynamoDB::Model::PutItemRequest request; + request.SetTableName(item.getTableName()); + request.AddItem( + PublicKeyItem::FIELD_DEVICE_ID, + Aws::DynamoDB::Model::AttributeValue(item.getDeviceId())); + request.AddItem( + PublicKeyItem::FIELD_PUBLIC_KEY, + Aws::DynamoDB::Model::AttributeValue(item.getPublicKey())); + this->innerPutItem(std::make_shared(item), request); +} + +std::shared_ptr +DatabaseManager::findPublicKeyItem(const std::string &deviceId) { + Aws::DynamoDB::Model::GetItemRequest request; + request.AddKey( + PublicKeyItem::FIELD_DEVICE_ID, + Aws::DynamoDB::Model::AttributeValue(deviceId)); + return std::move(this->innerFindItem(request)); +} + +void DatabaseManager::removePublicKeyItem(const std::string &deviceId) { + this->innerRemoveItem(*(createItemByType()), deviceId); +} + } // namespace database } // namespace network } // namespace comm diff --git a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.h b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.h index e45c7d363..08a6e8597 100644 --- a/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.h +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/DatabaseManager.h @@ -1,50 +1,55 @@ #pragma once #include "AwsTools.h" #include "Constants.h" #include "DatabaseEntitiesTools.h" #include "DeviceSessionItem.h" #include "Tools.h" #include #include #include #include #include #include #include #include #include #include namespace comm { namespace network { namespace database { class DatabaseManager { void innerPutItem( std::shared_ptr item, const Aws::DynamoDB::Model::PutItemRequest &request); template std::shared_ptr innerFindItem(Aws::DynamoDB::Model::GetItemRequest &request); void innerRemoveItem(const Item &item, const std::string &key); public: static DatabaseManager &getInstance(); bool isTableAvailable(const std::string &tableName); + void putSessionItem(const DeviceSessionItem &item); std::shared_ptr findSessionItem(const std::string &deviceID); void putSessionSignItem(const SessionSignItem &item); std::shared_ptr findSessionSignItem(const std::string &deviceId); void removeSessionSignItem(const std::string &deviceId); + + void putPublicKeyItem(const PublicKeyItem &item); + std::shared_ptr findPublicKeyItem(const std::string &deviceId); + void removePublicKeyItem(const std::string &deviceId); }; } // 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 new file mode 100644 index 000000000..0d6718b19 --- /dev/null +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.cpp @@ -0,0 +1,61 @@ +#include "PublicKeyItem.h" +#include "Constants.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; +} + +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 new file mode 100644 index 000000000..75f2fc03d --- /dev/null +++ b/services/tunnelbroker/docker-server/contents/server/src/Database/PublicKeyItem.h @@ -0,0 +1,36 @@ +#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