#pragma once #include "InfoHash.hpp" #include "types.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) {} }; class Database; struct DatabaseCreateNodeRequest { DISABLE_COPY(DatabaseCreateNodeRequest) const Hash *nodeHash; u64 timestamp; // In microseconds const Signature::PublicKey *creatorPublicKey; const DataView groupId; bool loadedFromCache; const Database *database; DatabaseCreateNodeRequest(const Hash *_nodeHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const DataView &_groupId, const Database *_database) : nodeHash(_nodeHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), groupId(_groupId), loadedFromCache(false), database(_database) { } }; struct DatabaseAddNodeRequest { DISABLE_COPY(DatabaseAddNodeRequest) const Hash *nodeHash; const Hash *requestHash; u64 timestamp; // In microseconds const Signature::PublicKey *creatorPublicKey; const DataView decryptedData; bool loadedFromCache; const Database *database; DatabaseAddNodeRequest(const Hash *_nodeHash, const Hash *_requestHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const DataView &_decryptedData, const Database *_database) : nodeHash(_nodeHash), requestHash(_requestHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), decryptedData(_decryptedData), loadedFromCache(false), database(_database) { } }; 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; const Database *database; DatabaseAddUserRequest(const Hash *_nodeHash, const Hash *_requestHash, u64 _timestamp, const Signature::PublicKey *_creatorPublicKey, const Signature::PublicKey *_userToAddPublicKey, const DataView &_groupToAddUserTo, const Database *_database) : nodeHash(_nodeHash), requestHash(_requestHash), timestamp(_timestamp), creatorPublicKey(_creatorPublicKey), userToAddPublicKey(_userToAddPublicKey), groupToAddUserTo(_groupToAddUserTo), loadedFromCache(false), database(_database) { } }; 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 { sibs::ListenHandle newDataListenHandle; sibs::ListenHandle responseKeyListenHandle; sibs::ListenHandle requestOldDataListenHandle; std::shared_ptr reponseKeyInfoHash; }; using CreateNodeCallbackFunc = std::function; using AddNodeCallbackFunc = std::function; using AddUserCallbackFunc = std::function; using ReceiveCustomMessageCallbackFunc = std::function; using SendCustomMessageCallbackFunc = std::function; using Value = std::vector; struct DatabaseCallbackFuncs { CreateNodeCallbackFunc createNodeCallbackFunc; AddNodeCallbackFunc addNodeCallbackFunc; AddUserCallbackFunc addUserCallbackFunc; }; class Database { DISABLE_COPY(Database) friend class DatabaseStorage; public: static std::future> connect(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); // When a node is created, you automatically seed it as well so there is no need to call seed on it. // 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; sibs::ListenHandle receiveCustomMessage(const InfoHash &requestKey, ReceiveCustomMessageCallbackFunc callbackFunc); void sendCustomMessage(const InfoHash &key, const void *data, const usize size); // Return true in @callbackFunc if you want to continue listening for responses, otherwise return false sibs::ListenHandle sendCustomMessage(const InfoHash &key, const void *data, const usize size, SendCustomMessageCallbackFunc callbackFunc); void cancelNodeListener(sibs::ListenHandle &nodeListener); int clearCache(); static InfoHash getInfoHash(const void *data, usize size); private: Database(const sibs::Ipv4 &bootstrapNodeAddr, const boost::filesystem::path &storageDir, DatabaseCallbackFuncs callbackFuncs); bool sendOldDataToPeer(const DatabaseNode nodeToSeed, const void *data, const usize size); void deserializeCreateRequest(const void *data, const usize size, const Hash &hash, const std::shared_ptr encryptionKey); void deserializeAddRequest(const void *data, const usize size, const Hash &requestDataHash, const std::shared_ptr &nodeHash, const std::shared_ptr encryptionKey); bool listenCreateData(const void *data, const usize size, const Hash &hash, const std::shared_ptr encryptionKey); bool listenAddData(const void *data, const usize size, const Hash &requestDataHash, const std::shared_ptr nodeHash, const std::shared_ptr encryptionKey); private: std::unique_ptr bootstrapConnection; DatabaseStorage databaseStorage; std::function onCreateNodeCallbackFunc; std::function onAddNodeCallbackFunc; std::function onAddUserCallbackFunc; MapHash seedInfoMap; std::thread remoteNodesSaveThread; bool shuttingDown; }; }