#pragma once #include "types.hpp" #include "Key.hpp" #include "DataView.hpp" #include "DatabaseStorage.hpp" #include "Hash.hpp" #include "utils.hpp" #include "Signature.hpp" #include "Permission.hpp" #include "DatabaseNode.hpp" #include "Encryption.hpp" #include "OwnedMemory.hpp" #include "DatabaseOperation.hpp" #include "DatabaseOrder.hpp" #include #include #include #include #include #include #include namespace odhtdb { class CommitCreateException : public std::runtime_error { public: CommitCreateException(const std::string &errMsg) : std::runtime_error(errMsg) {} }; class CommitAddException : public std::runtime_error { public: CommitAddException(const std::string &errMsg) : std::runtime_error(errMsg) {} }; class DatabaseCreateException : public std::runtime_error { public: DatabaseCreateException(const std::string &errMsg) : std::runtime_error(errMsg) {} }; class DatabaseAddException : public std::runtime_error { public: DatabaseAddException(const std::string &errMsg) : std::runtime_error(errMsg) {} }; struct DatabaseCreateNodeRequest { DISABLE_COPY(DatabaseCreateNodeRequest) const Hash *nodeHash; u64 timestamp; // In microseconds const Signature::PublicKey *creatorPublicKey; const DataView groupId; bool loadedFromCache; DatabaseCreateNodeRequest(const Hash *_nodeHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const DataView &_groupId) : nodeHash(_nodeHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), groupId(_groupId), loadedFromCache(false) { } }; struct DatabaseAddNodeRequest { DISABLE_COPY(DatabaseAddNodeRequest) const Hash *nodeHash; const Hash *requestHash; u64 timestamp; // In microseconds const Signature::PublicKey *creatorPublicKey; const DataView decryptedData; bool loadedFromCache; DatabaseAddNodeRequest(const Hash *_nodeHash, const Hash *_requestHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const DataView &_decryptedData) : nodeHash(_nodeHash), requestHash(_requestHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), decryptedData(_decryptedData), loadedFromCache(false) { } }; struct DatabaseAddUserRequest { DISABLE_COPY(DatabaseAddUserRequest) const Hash *nodeHash; const Hash *requestHash; u64 timestamp; // In microseconds const Signature::PublicKey *creatorPublicKey; const Signature::PublicKey *userToAddPublicKey; const DataView groupToAddUserTo; bool loadedFromCache; DatabaseAddUserRequest(const Hash *_nodeHash, const Hash *_requestHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const Signature::PublicKey *_userToAddPublicKey, const DataView &_groupToAddUserTo) : nodeHash(_nodeHash), requestHash(_requestHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), userToAddPublicKey(_userToAddPublicKey), groupToAddUserTo(_groupToAddUserTo), loadedFromCache(false) { } }; class DatabaseCreateResponse { public: DatabaseCreateResponse(std::shared_ptr nodeAdminKeyPair, std::shared_ptr nodeAdminGroupId, std::shared_ptr key, std::shared_ptr hash); const std::shared_ptr getNodeAdminKeyPair() const; const std::shared_ptr getNodeAdminGroupId() const; const std::shared_ptr getNodeEncryptionKey() const; const std::shared_ptr getRequestHash() const; private: std::shared_ptr nodeAdminKeyPair; std::shared_ptr nodeAdminGroupId; std::shared_ptr key; std::shared_ptr hash; }; struct DatabaseSeedInfo { std::shared_ptr> newDataListenerFuture; std::shared_ptr> responseKeyFuture; std::shared_ptr> requestOldDataListenerFuture; std::shared_ptr reponseKeyInfoHash; DatabaseSeedInfo(){} DatabaseSeedInfo(const DatabaseSeedInfo &other) { newDataListenerFuture = other.newDataListenerFuture; responseKeyFuture = other.responseKeyFuture; requestOldDataListenerFuture = other.requestOldDataListenerFuture; reponseKeyInfoHash = other.reponseKeyInfoHash; } DatabaseSeedInfo& operator=(const DatabaseSeedInfo &other) { newDataListenerFuture = other.newDataListenerFuture; responseKeyFuture = other.responseKeyFuture; requestOldDataListenerFuture = other.requestOldDataListenerFuture; reponseKeyInfoHash = other.reponseKeyInfoHash; return *this; } }; using CreateNodeCallbackFunc = std::function; using AddNodeCallbackFunc = std::function; using AddUserCallbackFunc = std::function; using ReceiveCustomMessageCallbackFunc = std::function; using SendCustomMessageCallbackFunc = std::function; struct DatabaseCallbackFuncs { CreateNodeCallbackFunc createNodeCallbackFunc; AddNodeCallbackFunc addNodeCallbackFunc; AddUserCallbackFunc addUserCallbackFunc; }; class Database { DISABLE_COPY(Database) friend class DatabaseStorage; public: Database(const char *bootstrapNodeAddr, u16 port, const boost::filesystem::path &storageDir, DatabaseCallbackFuncs callbackFuncs); ~Database(); // Safe to call multiple times with same node hash, will be ignored if the node is already beeing seeded void seed(const DatabaseNode &nodeToSeed, DatabaseFetchOrder fetchOrder = DatabaseFetchOrder::OLDEST_FIRST); void stopSeeding(const Hash &nodeHash); void loadNode(const Hash &nodeHash, DatabaseLoadOrder loadOrder = DatabaseLoadOrder::OLDEST_FIRST); // Throws DatabaseCreateException on failure. std::unique_ptr create(); // Throws PermissionDeniedException if user @userToPerformActionWith is not allowed to add data to node void addData(const DatabaseNode &nodeInfo, const Signature::KeyPair &userToPerformActionWith, DataView dataToAdd); // Throws PermissionDeniedException if user @userToPerformActionWith is not allowed to add user @userToAdd to group @groupToAddUserTo void addUser(const DatabaseNode &nodeInfo, const Signature::KeyPair &userToPerformActionWith, const Signature::PublicKey &userToAddPublicKey, const DataView &groupToAddUserTo); static ntp::NtpTimestamp getSyncedTimestampUtc(); bool doesStoredUserExist(const std::string &username) const; // Throws SqlExecException if user with same name already exists void storeUserWithoutNodes(const std::string &username, const std::string &password); // Username has to be either unique or if it's the same as existing one, then password has to match. // Node has to be unique for the user. // Throws DatabaseStorageWrongPassword or SqlExecException on failure (if username is not unique in node). void storeNodeInfoForUserEncrypted(const DatabaseNode &nodeInfo, const std::string &username, const std::string &password, const Signature::KeyPair &keyPair); // Returns nodes, node encryption key, public key and private key of encrypted user. // Throws DatabaseStorageWrongPassword if password for the stored user is wrong. MapHash getStoredNodeUserInfoDecrypted(const std::string &username, const std::string &password) const; std::vector getUserGroups(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const; // Returns -1 on failure int getUserLowestPermissionLevel(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const; std::future receiveCustomMessage(const dht::InfoHash &requestKey, ReceiveCustomMessageCallbackFunc callbackFunc); void sendCustomMessage(const dht::InfoHash &key, std::vector &&data); // Return true in @callbackFunc if you want to continue listening for responses, otherwise return false std::future sendCustomMessage(const dht::InfoHash &key, std::vector &&data, SendCustomMessageCallbackFunc callbackFunc); void cancelNodeListener(const dht::InfoHash &infoHash, std::future &nodeListener); int clearCache(); static dht::InfoHash getInfoHash(const void *data, usize size); private: void sendOldDataToPeer(const DatabaseNode nodeToSeed, const std::shared_ptr requestResponseInfoHash, const std::shared_ptr value, usize valueOffset); void deserializeCreateRequest(const std::shared_ptr &value, const Hash &hash, const std::shared_ptr encryptionKey); void deserializeAddRequest(const std::shared_ptr &value, const Hash &requestDataHash, const std::shared_ptr &nodeHash, const std::shared_ptr encryptionKey); bool listenCreateData(std::shared_ptr value, const Hash &hash, const std::shared_ptr encryptionKey); bool listenAddData(std::shared_ptr value, const Hash &requestDataHash, const std::shared_ptr nodeHash, const std::shared_ptr encryptionKey); private: dht::DhtRunner node; DatabaseStorage databaseStorage; std::function onCreateNodeCallbackFunc; std::function onAddNodeCallbackFunc; std::function onAddUserCallbackFunc; MapHash seedInfoMap; std::thread remoteNodesSaveThread; bool shuttingDown; }; }