aboutsummaryrefslogtreecommitdiff
path: root/include/odhtdb/DatabaseStorage.hpp
blob: a004619d2970546339f61f29531f3d3f9683a903 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#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 <vector>
#include <stdexcept>
#include <boost/filesystem/path.hpp>
#include <sibs/SafeDeserializer.hpp>
#include <opendht/crypto.h>
#include <functional>

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<void(const DataView rawData)>;
    using FetchNodeAddDataRawCallbackFunc = std::function<void(const DataView rawData, const DataView creatorPublicKey, u64 actionCounter)>;
    using FetchNodeUserActionGapsCallbackFunc = std::function<void(const DataView userPublicKey, u64 start, u64 range)>;
    using FetchNodeUserLatestActionCounterCallbackFunc = std::function<void(const DataView userPublicKey, u64 latestActionCounter)>;
    
    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<bool, std::shared_ptr<OwnedMemory>> getNodeDecryptionKey(const Hash &nodeHash);
        void setNodeDecryptionKey(const Hash &nodeHash, const DataView &decryptionKey);
        
        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();
        bool decryptNodeData(const Hash &nodeHash, const std::shared_ptr<OwnedMemory> decryptionKey);
        bool decryptNodeData(const Hash &nodeHash, const std::shared_ptr<OwnedMemory> 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<OwnedMemory> 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<OwnedMemory> 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;
        u8 passwordSalt[PASSWORD_SALT_LEN];
        std::pair<std::shared_ptr<dht::crypto::PrivateKey>, std::shared_ptr<dht::crypto::Certificate>> identity;
    };
}