#pragma once #include "types.hpp" #include "Hash.hpp" #include "DataView.hpp" #include "Signature.hpp" #include "Encryption.hpp" #include "Group.hpp" #include "Permission.hpp" #include "OwnedMemory.hpp" #include "DatabaseOperation.hpp" #include "DatabaseOrder.hpp" #include #include #include #include #include #include #include class sqlite3; class sqlite3_stmt; namespace odhtdb { class Database; class DatabaseStorageException : public std::runtime_error { public: DatabaseStorageException(const std::string &errMsg) : std::runtime_error(errMsg) {} virtual ~DatabaseStorageException() {} }; class DatabaseStorageAlreadyExists : public DatabaseStorageException { public: DatabaseStorageAlreadyExists(const std::string &errMsg) : DatabaseStorageException(errMsg) {} }; class DatabaseStorageNotFound : public DatabaseStorageException { public: DatabaseStorageNotFound(const std::string &errMsg) : DatabaseStorageException(errMsg) {} }; class DatabaseStorageCorrupt : public DatabaseStorageException { public: DatabaseStorageCorrupt(const std::string &errMsg) : DatabaseStorageException(errMsg) {} }; class DatabaseStorageNoSuchLocalStorageUser : public DatabaseStorageException { public: DatabaseStorageNoSuchLocalStorageUser(const std::string &errMsg) : DatabaseStorageException(errMsg) {} }; class DatabaseStorageWrongPassword : public DatabaseStorageException { public: DatabaseStorageWrongPassword(const std::string &errMsg) : DatabaseStorageException(errMsg) {} }; const int PASSWORD_SALT_LEN = 16; const int HASHED_PASSWORD_LEN = 32; using FetchNodeRawCallbackFunc = std::function; using FetchNodeAddDataRawCallbackFunc = std::function; using FetchNodeUserActionGapsCallbackFunc = std::function; using FetchNodeUserLatestActionCounterCallbackFunc = std::function; class DatabaseStorage { public: // Throws DatabaseStorageCorrupt if storage is corrupted. Throws DatabaseStorageException on other failures DatabaseStorage(Database *database, const boost::filesystem::path &storagePath); ~DatabaseStorage(); void loadNode(const Hash &nodeHash, DatabaseLoadOrder loadOrder); bool doesNodeExist(const Hash &nodeHash) const; bool doesDataExist(const Hash &requestHash) const; // Throws DatabaseStorageAlreadyExists if data with hash already exists void createStorage(const Hash &hash, const Signature::PublicKey &adminPublicKey, const DataView &adminGroupId, u64 timestamp, const void *data, usize size); // Throws DatabaseStorageNotFound if data with @nodeHash hash has not been created yet. // Throws DatabaseStorageAlreadyExists if same data has been added before (hash of @data, in @dataHash) void appendStorage(const Hash &nodeHash, const Hash &dataHash, DatabaseOperation operation, u64 newUserActionCounter, const Signature::PublicKey &creatorPublicKey, u64 timestamp, const void *data, usize size, const DataView &additionalDataView); // Throws DatabaseStorageAlreadyExists if group already exists in node void addGroup(const Hash &nodeHash, const DataView &groupId, const Permission &permissions); void addUserToGroup(const Hash &nodeHash, const Signature::PublicKey &userPublicKey, const DataView &groupId); // Throws DatabaseStorageAlreadyExists is user already exists in node void addUser(const Hash &nodeHash, const Signature::PublicKey &userPublicKey, const DataView &groupId); void fetchNodeRaw(const Hash &nodeHash, FetchNodeRawCallbackFunc callbackFunc); void fetchNodeAddDataRaw(const Hash &nodeHash, FetchNodeAddDataRawCallbackFunc callbackFunc, DatabaseFetchOrder fetchOrder); void fetchNodeUserActionGaps(const Hash &nodeHash, FetchNodeUserActionGapsCallbackFunc callbackFunc); void fetchNodeUserLatestActionCounter(const Hash &nodeHash, FetchNodeUserLatestActionCounterCallbackFunc callbackFunc); bool isUserAllowedToAddDataInNode(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const; bool isUserAllowedToAddUserToGroupInNode(const Hash &nodeHash, const Signature::PublicKey &userPublicKey, const DataView &groupToAddUserTo) const; // Throws DatabaseStorageNotFound if user doesn't exist in node u64 getUserActionCounter(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const; // Username and key pair has to be unique, returns true on success //bool storeLocalUser(const std::string &username, const Signature::KeyPair &keyPair, const std::string &password); // Returns public key and private key of encrypted local user. // Throws DatabaseStorageNoSuchLocalStorageUser if user does not exist in local storage. // Throws DatabaseStorageWrongPassword if password for the stored local user is wrong. //Signature::KeyPair decryptLocalEncryptedUser(const std::string &username, const std::string &password); // Returns true and node decryption key if node exists and we have the decryption key, // otherwise return false and OwnedMemory with data set to nullptr std::pair> getNodeDecryptionKey(const Hash &nodeHash); void setNodeDecryptionKey(const Hash &nodeHash, const DataView &decryptionKey); const std::vector& getRemoteNodes() const; void setRemoteNodes(const std::vector &remoteNodes); const dht::crypto::Identity& getIdentity() const; // Update storage state (remove quarantine objects if they are too old, etc) void update(); private: void init(const boost::filesystem::path &storagePath); void cleanup(); void bindCheckError(int sqliteBindResult); void loadMetadataFromFile(); void loadRemoteNodesFromFile(); bool decryptNodeData(const Hash &nodeHash, const std::shared_ptr decryptionKey); bool decryptNodeData(const Hash &nodeHash, const std::shared_ptr decryptionKey, const Signature::PublicKey *creatorPublicKey, const DataView &adminGroupId, u64 timestamp); bool decryptNodeAddData(i64 rowId, const Hash &nodeHash, const Hash &dataHash, u64 timestamp, const Signature::PublicKey *creatorPublicKey, const DataView &encryptedData, const std::shared_ptr decryptionKey); bool decryptNodeAddUser(i64 rowId, const Hash &nodeHash, const Hash &dataHash, u64 timestamp, const Signature::PublicKey *creatorPublicKey, const Signature::PublicKey *userToAddPublicKey, const DataView &groupToAddUserTo, const std::shared_ptr decryptionKey); i64 getNodeRowId(const Hash &nodeHash); i64 getNodeAddDataRowId(const Hash &requestHash); void setNodeAddDataDecrypted(i64 rowId); void setNodeAddDataDecryptedData(i64 rowId, const DataView &decryptedData); private: Database *database; sqlite3 *sqliteDb; sqlite3_stmt *insertNodeStmt; sqlite3_stmt *insertUserStmt; sqlite3_stmt *insertGroupStmt; sqlite3_stmt *insertNodeAddDataStmt; sqlite3_stmt *setNodeDecryptionKeyStmt; sqlite3_stmt *getNodeDecryptionKeyStmt; sqlite3_stmt *insertNodeUserGroupAssocStmt; sqlite3_stmt *selectNodeStmt; sqlite3_stmt *selectNodeAddDataByNodeStmt; sqlite3_stmt *selectNodeIdStatement; sqlite3_stmt *selectNodeAddDataIdStatement; sqlite3_stmt *insertNodeRawStmt; sqlite3_stmt *insertNodeAddDataRawStmt; sqlite3_stmt *insertNodeAddDataAdditionalStmt; sqlite3_stmt *insertNodeAddUserDataStmt; sqlite3_stmt *selectNodeAddDataAdditionalStmt; sqlite3_stmt *selectNodeAddUserDataStmt; sqlite3_stmt *setNodeAddDataDecryptedStmt; sqlite3_stmt *setNodeAddDataAdditionalDataStmt; boost::filesystem::path metadataFilePath; boost::filesystem::path remoteNodesFilePath; u8 passwordSalt[PASSWORD_SALT_LEN]; std::pair, std::shared_ptr> identity; std::vector remoteNodes; }; }