aboutsummaryrefslogtreecommitdiff
path: root/include/odhtdb/DatabaseStorage.hpp
blob: f3c3087d4062e99da65b9934760afe85fef088c6 (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
#pragma once

#include "types.hpp"
#include "Hash.hpp"
#include "DataView.hpp"
#include "Signature.hpp"
#include "Encryption.hpp"
#include "Group.hpp"
#include "LocalUser.hpp"
#include "LocalUserEncrypted.hpp"
#include <vector>
#include <stdexcept>
#include <boost/filesystem/path.hpp>
#include <sibs/SafeDeserializer.hpp>
#include <opendht/crypto.h>

namespace odhtdb
{
    struct DatabaseStorageObject
    {
        DataView data;
        u64 createdTimestamp; // In microseconds
        Signature::PublicKey creatorPublicKey;
        
        DatabaseStorageObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey);
    };
    
    struct DatabaseStorageObjectList
    {
        DataView data;
        u64 createdTimestamp; // In microseconds
        std::vector<Group*> groups;
        std::vector<DatabaseStorageObject*> objects;
    };
    
    struct DatabaseStorageQuarantineObject
    {
        DataView data;
        u64 createdTimestamp; // In microseconds
        u64 storedTimestamp; // In microseconds
        Signature::PublicKey creatorPublicKey;
        
        DatabaseStorageQuarantineObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey);
    };
    
    class DatabaseStorageAlreadyExists : public std::runtime_error
    {
    public:
        DatabaseStorageAlreadyExists(const std::string &errMsg) : std::runtime_error(errMsg) {}
    };
    
    class DatabaseStorageNotFound : public std::runtime_error
    {
    public:
        DatabaseStorageNotFound(const std::string &errMsg) : std::runtime_error(errMsg) {}
    };
    
    class DatabaseStorageCorrupt : public std::runtime_error
    {
    public:
        DatabaseStorageCorrupt(const std::string &errMsg) : std::runtime_error(errMsg) {}
    };
    
    using DatabaseStorageMap = MapHash<DatabaseStorageObjectList*>;
    using DatabaseStorageQuarantineMap = Signature::MapPublicKey<std::vector<DatabaseStorageQuarantineObject*>>;
    
    const int PASSWORD_SALT_LEN = 16;
    const int HASHED_PASSWORD_LEN = 32;
    
    class DatabaseStorage
    {
    public:
        // Throws DatabaseStorageCorrupt if storage is corrupted
        DatabaseStorage(const boost::filesystem::path &storagePath);
        
        // Throws DatabaseStorageAlreadyExists if data with hash already exists
        void createStorage(const Hash &hash, Group *creatorGroup, u64 timestamp, const u8 *data, usize dataSize);
        
        // 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, const User *creatorUser, u64 timestamp, const u8 *data, usize dataSize);
        
        // Throws DatabaseStorageAlreadyExists if same data has been added before (hash of @data, in @dataHash)
        void addToQuarantine(const Hash &dataHash, const Signature::PublicKey &creatorPublicKey, u64 timestamp, const u8 *data, usize dataSize);
        
        // Return false if group with id already exists, otherwise return true
        bool addGroup(const Hash &nodeHash, Group *group);
        
        // Return false if user public key already exists, otherwise return true
        bool addUser(const Hash &nodeHash, User *user);
        
        // Returns nullptr if no storage with provided hash exists
        const DatabaseStorageObjectList* getStorage(const Hash &hash) const;
        
        // Returns nullptr if a group with id @groupId doesn't exist in node @nodeHash or if no node with id @nodeHash exists
        Group* getGroupById(const Hash &nodeHash, uint8_t groupId[GROUP_ID_LENGTH]) const;
        
        // Returns nullptr if a user with public key @publicKey doesn't exist in node @nodeHash or if no node with id @nodeHash exists
        User* getUserByPublicKey(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const;
        
        // Username, public key and private key has to be unique
        bool storeLocalUser(const std::string &username, const Signature::PublicKey &publicKey, const Signature::PrivateKey &privateKey, const std::string &password);
        
        const dht::crypto::Identity& getIdentity() const;
        
        // Update storage state (remove quarantine objects if they are too old, etc)
        void update();
    private:
        void loadGroupsFromFile();
        void loadUsersFromFile();
        void loadDataFromFile();
        void loadLocalUsersFromFile();
        void loadMetadataFromFile();
        void loadStorageCreate(sibs::SafeDeserializer &deserializer);
        void loadStorageAppend(sibs::SafeDeserializer &deserializer);
    private:
        DatabaseStorageMap storageMap;
        DatabaseStorageQuarantineMap quarantineStorageMap;
        SetHash storedDataHash; // Prevent duplicate data from being added
        MapHash<Signature::MapPublicKey<User*>*> nodePublicKeyUserDataMap;
        MapHash<DataViewMap<Group*>*> nodeGroupByIdMap;
        std::unordered_map<std::string, LocalUserEncrypted*> nameLocalUsersMap;
        boost::filesystem::path groupsFilePath;
        boost::filesystem::path usersFilePath;
        boost::filesystem::path dataFilePath;
        boost::filesystem::path metadataFilePath;
        boost::filesystem::path localUsersFilePath;
        u8 passwordSalt[PASSWORD_SALT_LEN];
        std::pair<std::shared_ptr<dht::crypto::PrivateKey>, std::shared_ptr<dht::crypto::Certificate>> identity;
    };
}