aboutsummaryrefslogtreecommitdiff
path: root/src/Database.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Database.cpp')
-rw-r--r--src/Database.cpp254
1 files changed, 60 insertions, 194 deletions
diff --git a/src/Database.cpp b/src/Database.cpp
index 41d3798..88ac8e4 100644
--- a/src/Database.cpp
+++ b/src/Database.cpp
@@ -61,7 +61,7 @@ namespace odhtdb
return DataView(result, allocationSize);
}
- DatabaseCreateResponse::DatabaseCreateResponse(LocalUser *_nodeAdminUser, const shared_ptr<OwnedMemory> &_key, const shared_ptr<Hash> &_hash) :
+ DatabaseCreateResponse::DatabaseCreateResponse(LocalUser *_nodeAdminUser, shared_ptr<OwnedMemory> _key, shared_ptr<Hash> _hash) :
nodeAdminUser(_nodeAdminUser),
key(_key),
hash(_hash)
@@ -84,10 +84,10 @@ namespace odhtdb
return hash;
}
- Database::Database(const char *bootstrapNodeAddr, u16 port, const boost::filesystem::path &storageDir) :
- onCreateNodeCallbackFunc(nullptr),
- onAddNodeCallbackFunc(nullptr),
- onAddUserCallbackFunc(nullptr),
+ Database::Database(const char *bootstrapNodeAddr, u16 port, const boost::filesystem::path &storageDir, DatabaseCallbackFuncs callbackFuncs) :
+ onCreateNodeCallbackFunc(callbackFuncs.createNodeCallbackFunc),
+ onAddNodeCallbackFunc(callbackFuncs.addNodeCallbackFunc),
+ onAddUserCallbackFunc(callbackFuncs.addUserCallbackFunc),
databaseStorage(this, storageDir)
{
node.run(port , {
@@ -218,38 +218,35 @@ namespace odhtdb
u64 dataStartTimestamp = deserializer.extract<u64>();
u8 requestResponseKey[OPENDHT_INFOHASH_LEN];
deserializer.extract(requestResponseKey, OPENDHT_INFOHASH_LEN);
-
- auto requestedData = databaseStorage.getStorage(*nodeToSeed.getRequestHash());
- if(!requestedData)
- {
- Log::debug("No data found for hash %s, unable to serve peer", nodeToSeed.getRequestHash()->toString().c_str());
- return true;
- }
-
InfoHash requestResponseInfoHash(requestResponseKey, OPENDHT_INFOHASH_LEN);
if(dataStartTimestamp == 0)
{
- Log::debug("Request: Sent create packet to requesting peer");
- node.put(requestResponseInfoHash, Value((u8*)requestedData->data.data, requestedData->data.size), [](bool ok)
+ databaseStorage.fetchNodeRaw(*nodeToSeed.getRequestHash(), [this, requestResponseInfoHash](const DataView rawData)
{
- if(!ok)
- Log::error("Failed to put response for old data for 'create' data");
+ Log::debug("Request: Sent create packet to requesting peer");
+ Value value((u8*)rawData.data, rawData.size);
+ node.put(requestResponseInfoHash, move(value), [](bool ok)
+ {
+ if(!ok)
+ Log::error("Failed to put response for old data for 'create' data");
+ });
});
}
- for(auto requestedObject : requestedData->objects)
+ databaseStorage.fetchNodeAddDataRaw(*nodeToSeed.getRequestHash(), [this, requestResponseInfoHash](const DataView rawData)
{
- node.put(requestResponseInfoHash, Value((u8*)requestedObject->data.data, requestedObject->data.size), [](bool ok)
+ Value value((u8*)rawData.data, rawData.size);
+ node.put(requestResponseInfoHash, move(value), [](bool ok)
{
if(!ok)
Log::error("Failed to put response for old data for 'add' data");
});
- }
+ });
}
- catch (sibs::DeserializeException &e)
+ catch (std::exception &e)
{
- Log::warn("Failed to deserialize 'get old data' request: %s", e.what());
+ Log::warn("Failed while serving peer, error: %s", e.what());
}
return true;
});
@@ -283,19 +280,25 @@ namespace odhtdb
seedInfoMap.erase(seedInfoIt);
}
}
+
+ void Database::loadNode(const Hash &nodeHash)
+ {
+ databaseStorage.loadNode(nodeHash);
+ }
- unique_ptr<DatabaseCreateResponse> Database::create(const string &ownerName, const string &nodeName)
+ unique_ptr<DatabaseCreateResponse> Database::create()
{
- return create(ownerName, Signature::KeyPair(), nodeName);
+ return create(Signature::KeyPair());
}
- unique_ptr<DatabaseCreateResponse> Database::create(const string &ownerName, const Signature::KeyPair &keyPair, const string &nodeName)
+ unique_ptr<DatabaseCreateResponse> Database::create(const Signature::KeyPair &creatorKeyPair)
{
// TODO: Should this be declared static? is there any difference in behavior/performance?
boost::uuids::random_generator uuidGen;
auto adminGroupId = uuidGen();
- auto adminGroup = new Group("administrator", adminGroupId.data, ADMIN_PERMISSION);
- LocalUser *nodeAdminUser = LocalUser::create(keyPair, ownerName, adminGroup);
+ assert(adminGroupId.size() == GROUP_ID_LENGTH);
+ auto adminGroup = new Group(adminGroupId.data, ADMIN_PERMISSION);
+ LocalUser *nodeAdminUser = LocalUser::create(creatorKeyPair, adminGroup);
// Header
sibs::SafeSerializer serializer;
@@ -305,30 +308,18 @@ namespace odhtdb
serializer.add((u8*)nodeAdminUser->getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES);
serializer.add(adminGroupId.data, adminGroupId.size());
- // Encrypted body
- sibs::SafeSerializer encryptedSerializer;
- assert(nodeAdminUser->getName().size() <= 255);
- encryptedSerializer.add((u8)nodeAdminUser->getName().size());
- encryptedSerializer.add((u8*)nodeAdminUser->getName().data(), nodeAdminUser->getName().size());
- assert(nodeName.size() <= 255);
- encryptedSerializer.add((u8)nodeName.size());
- encryptedSerializer.add((u8*)nodeName.data(), nodeName.size());
-
try
{
- Encryption encryptedBody(DataView(encryptedSerializer.getBuffer().data(), encryptedSerializer.getBuffer().size()));
- DataView requestData = combine(serializer, encryptedBody);
- shared_ptr<Hash> hashRequestKey = make_shared<Hash>(requestData.data, requestData.size);
- databaseStorage.setNodeDecryptionKey(*hashRequestKey, DataView(encryptedBody.getKey().data, encryptedBody.getKey().size));
- databaseStorage.createStorage(*hashRequestKey, adminGroup, timestampCombined, (const u8*)requestData.data, requestData.size, serializer.getBuffer().size());
+ unsigned char *encryptionKeyRaw = new unsigned char[ENCRYPTION_KEY_BYTE_SIZE];
+ Encryption::generateKey(encryptionKeyRaw);
+ shared_ptr<OwnedMemory> encryptionKey = make_shared<OwnedMemory>(encryptionKeyRaw, ENCRYPTION_KEY_BYTE_SIZE);
+ shared_ptr<Hash> hashRequestKey = make_shared<Hash>(serializer.getBuffer().data(), serializer.getBuffer().size());
- assert(encryptedBody.getKey().size == ENCRYPTION_KEY_BYTE_SIZE);
- auto key = make_shared<OwnedMemory>(new char[encryptedBody.getKey().size], encryptedBody.getKey().size);
- memcpy(key->data, encryptedBody.getKey().data, encryptedBody.getKey().size);
+ databaseStorage.setNodeDecryptionKey(*hashRequestKey, DataView(encryptionKey->data, encryptionKey->size));
+ databaseStorage.createStorage(*hashRequestKey, adminGroup, timestampCombined, (const u8*)serializer.getBuffer().data(), serializer.getBuffer().size());
DhtKey dhtKey(*hashRequestKey);
- Value createDataValue((u8*)requestData.data, requestData.size);
- delete[] (char*)requestData.data;
+ Value createDataValue(move(serializer.getBuffer()));
node.put(dhtKey.getNewDataListenerKey(), move(createDataValue), [](bool ok)
{
// TODO: Handle failure to put data
@@ -336,7 +327,7 @@ namespace odhtdb
Log::warn("Failed to put: %s, what to do?", "Database::create");
});
- return make_unique<DatabaseCreateResponse>(nodeAdminUser, move(key), hashRequestKey);
+ return make_unique<DatabaseCreateResponse>(nodeAdminUser, encryptionKey, hashRequestKey);
}
catch (EncryptionException &e)
{
@@ -354,7 +345,7 @@ namespace odhtdb
// and remote peers would accept our request to perform operation if they haven't received the operation that removes the user from the group.
// How to handle this?
string errMsg = "User ";
- errMsg += userToPerformActionWith->getName();
+ errMsg += userToPerformActionWith->getPublicKey().toString();
errMsg += " is not allowed to perform the operation: ADD_USER";
throw PermissionDeniedException(errMsg);
}
@@ -372,7 +363,7 @@ namespace odhtdb
DataView stagedAddObject = combine(userToPerformActionWith->getPublicKey(), signedRequestData);
Hash requestDataHash(stagedAddObject.data, stagedAddObject.size);
DataView encryptedDataView((char*)requestData.data + serializer.getBuffer().size(), requestData.size - serializer.getBuffer().size());
- databaseStorage.appendStorage(*nodeInfo.getRequestHash(), requestDataHash, DatabaseOperation::ADD_DATA, userToPerformActionWith, timestampCombined, (u8*)stagedAddObject.data, stagedAddObject.size, encryptedDataView);
+ databaseStorage.appendStorage(*nodeInfo.getRequestHash(), requestDataHash, DatabaseOperation::ADD_DATA, userToPerformActionWith->getPublicKey(), timestampCombined, (u8*)stagedAddObject.data, stagedAddObject.size, encryptedDataView);
delete[] (char*)requestData.data;
DhtKey dhtKey(requestDataHash);
@@ -391,7 +382,7 @@ namespace odhtdb
for(auto group : groups)
{
const auto &groupPermission = group->getPermission();
- if(groupPermission.getFlag(PermissionType::ADD_USER_LOWER_LEVEL) && groupPermission.getPermissionLevel() < groupToAddUserTo->getPermission().getPermissionLevel())
+ if(groupPermission.getFlag(PermissionType::ADD_USER_HIGHER_LEVEL) && groupPermission.getPermissionLevel() < groupToAddUserTo->getPermission().getPermissionLevel())
{
return group;
}
@@ -403,15 +394,15 @@ namespace odhtdb
return nullptr;
}
- void Database::addUser(const DatabaseNode &nodeInfo, const LocalUser *userToPerformActionWith, const string &userToAddName, const Signature::PublicKey &userToAddPublicKey, Group *groupToAddUserTo)
+ void Database::addUser(const DatabaseNode &nodeInfo, const LocalUser *userToPerformActionWith, const Signature::PublicKey &userToAddPublicKey, Group *groupToAddUserTo)
{
auto groupWithAddUserRights = getGroupWithRightsToAddUserToGroup(userToPerformActionWith->getGroups(), groupToAddUserTo);
if(!groupWithAddUserRights)
{
string errMsg = "The user ";
- errMsg += userToPerformActionWith->getName();
+ errMsg += userToPerformActionWith->getPublicKey().toString();
errMsg += " does not belong to any group that is allowed to add an user to the group ";
- errMsg += groupToAddUserTo->getName();
+ errMsg += bin2hex((const char*)groupToAddUserTo->getId().data, groupToAddUserTo->getId().size).c_str();
throw PermissionDeniedException(errMsg);
}
@@ -420,27 +411,22 @@ namespace odhtdb
u64 timestampCombined = getSyncedTimestampUtc().getCombined();
serializer.add(timestampCombined);
serializer.add(DatabaseOperation::ADD_USER);
-
- assert(userToAddName.size() <= 255);
- usize serializedEncryptedDataOffset = serializer.getBuffer().size();
- serializer.add((u8)userToAddName.size());
- DataView encryptionKey(nodeInfo.getNodeEncryptionKey()->data, ENCRYPTION_KEY_BYTE_SIZE);
- Encryption encryptedUserName(DataView((void*)userToAddName.data(), userToAddName.size()), DataView(), encryptionKey);
- serializer.add((u8*)encryptedUserName.getNonce().data, ENCRYPTION_NONCE_BYTE_SIZE);
- assert(encryptedUserName.getCipherText().size == ENCRYPTION_CHECKSUM_BYTE_SIZE + userToAddName.size());
- serializer.add((u8*)encryptedUserName.getCipherText().data, ENCRYPTION_CHECKSUM_BYTE_SIZE + userToAddName.size());
- usize serializedEncryptedDataSize = serializer.getBuffer().size() - serializedEncryptedDataOffset;
+ usize additionalDataOffset = serializer.getBuffer().size();
serializer.add((u8*)userToAddPublicKey.getData(), PUBLIC_KEY_NUM_BYTES);
serializer.add((uint8_t*)groupToAddUserTo->getId().data, groupToAddUserTo->getId().size);
+ // TODO: Should this be declared static? is there any difference in behavior/performance?
+ boost::uuids::random_generator uuidGen;
+ auto padding = uuidGen();
+ assert(padding.size() == 16);
+ serializer.add(padding.data, padding.size());
+
DataView requestData { serializer.getBuffer().data(), serializer.getBuffer().size() };
string signedRequestData = userToPerformActionWith->getPrivateKey().sign(requestData);
DataView stagedAddObject = combine(userToPerformActionWith->getPublicKey(), signedRequestData);
Hash requestDataHash(stagedAddObject.data, stagedAddObject.size);
- DataView encryptedDataView(nullptr, 0);
- auto userToAdd = RemoteUser::create(userToAddPublicKey, userToAddName, groupToAddUserTo);
- databaseStorage.addUser(*nodeInfo.getRequestHash(), userToAdd);
- databaseStorage.appendStorage(*nodeInfo.getRequestHash(), requestDataHash, DatabaseOperation::ADD_USER, userToPerformActionWith, timestampCombined, (u8*)stagedAddObject.data, stagedAddObject.size, encryptedDataView);
+ DataView additionalDataView((void*)(static_cast<const char*>(requestData.data) + additionalDataOffset), requestData.size - additionalDataOffset);
+ databaseStorage.appendStorage(*nodeInfo.getRequestHash(), requestDataHash, DatabaseOperation::ADD_USER, userToPerformActionWith->getPublicKey(), timestampCombined, (u8*)stagedAddObject.data, stagedAddObject.size, additionalDataView);
DhtKey dhtKey(requestDataHash);
Value addDataValue((u8*)stagedAddObject.data, stagedAddObject.size);
@@ -506,10 +492,10 @@ namespace odhtdb
if(deserializer.getSize() < ENCRYPTION_NONCE_BYTE_SIZE)
throw sibs::DeserializeException("Unsigned encrypted body is too small (unable to extract nonce)");
- auto adminGroup = new Group("administrator", adminGroupId, ADMIN_PERMISSION);
+ auto adminGroup = new Group(adminGroupId, ADMIN_PERMISSION);
// TODO: Username is encrypted, we dont know it... unless we have encryption key, in which case we should modify the user name and set it
- auto creatorUser = RemoteUser::create(userPublicKey, "ENCRYPTED USER NAME", adminGroup);
- databaseStorage.createStorage(hash, adminGroup, creationDate, value->data.data(), value->data.size(), value->data.size() - deserializer.getSize());
+ auto creatorUser = RemoteUser::create(userPublicKey, adminGroup);
+ databaseStorage.createStorage(hash, adminGroup, creationDate, value->data.data(), value->data.size());
}
void Database::deserializeAddRequest(const shared_ptr<dht::Value> &value, const Hash &requestDataHash, const std::shared_ptr<Hash> &nodeHash, const shared_ptr<OwnedMemory> encryptionKey)
@@ -548,108 +534,8 @@ namespace odhtdb
*/
DatabaseOperation operation = deserializerUnsigned.extract<DatabaseOperation>();
-#if 0
- const Hash *node = databaseStorage.getNodeByUserPublicKey(creatorPublicKey);
- if(!node)
- {
- // The user (public key) could belong to a node but we might not have retrieved the node info yet since data may
- // not be retrieved in order.
- // Data in quarantine is processed when 'create' packet is received or removed after 60 seconds
- databaseStorage.addToQuarantine(requestDataHash, creatorPublicKey, creationDate, value->data.data(), value->data.size());
- throw RequestQuarantineException();
- }
-#endif
- auto creatorUser = databaseStorage.getUserByPublicKey(*nodeHash, creatorPublicKey);
- if(!creatorUser)
- {
- // TODO: Add to quarantine
- string errMsg = "User with public key ";
- errMsg += creatorPublicKey.toString();
- errMsg += " does not exist in code ";
- errMsg += nodeHash->toString();
- throw sibs::DeserializeException(errMsg);
- }
-
- DataView encryptedDataView((void*)deserializerUnsigned.getBuffer(), deserializerUnsigned.getSize());
-
- if(operation == DatabaseOperation::ADD_DATA)
- {
- if(deserializerUnsigned.getSize() < ENCRYPTION_NONCE_BYTE_SIZE)
- throw sibs::DeserializeException("Unsigned encrypted body is too small (unable to extract nonce)");
-
- if(!creatorUser->isAllowedToPerformAction(PermissionType::ADD_DATA))
- {
- // TODO: User might have permission to perform operation, but we haven't got the packet that adds user to the group with the permission,
- // or we haven't received the packet that modifies group with the permission to perform the operation.
- // This also means that an user can be in a group that has permission to perform the operation and then later be removed from it,
- // and remote peers would accept our request to perform operation if they haven't received the operation that removes the user from the group.
- // How to handle this?
- string errMsg = "User ";
- errMsg += creatorUser->getName();
- errMsg += " is not allowed to add data to node ";
- errMsg += nodeHash->toString();
- throw PermissionDeniedException(errMsg);
- }
-
- // TODO: Verify there isn't already data with same timestamp for this node. Same for quarantine.
- // TODO: We might receive 'add' data packet before 'create'. If that happens, we should put it in quarantine and process it later.
- databaseStorage.appendStorage(*nodeHash, requestDataHash, operation, creatorUser, creationDate, value->data.data(), value->data.size(), encryptedDataView);
- }
- else if(operation == DatabaseOperation::ADD_USER)
- {
- u8 nameLength = deserializerUnsigned.extract<u8>();
-
- u8 nonce[ENCRYPTION_NONCE_BYTE_SIZE];
- deserializerUnsigned.extract(nonce, ENCRYPTION_NONCE_BYTE_SIZE);
- DataView dataToDecrypt((void*)deserializerUnsigned.getBuffer(), ENCRYPTION_CHECKSUM_BYTE_SIZE + nameLength);
-
- sibs::SafeDeserializer deserializerSkippedEncryptedData(deserializerUnsigned.getBuffer() + ENCRYPTION_CHECKSUM_BYTE_SIZE + nameLength, PUBLIC_KEY_NUM_BYTES + GROUP_ID_LENGTH);
-
- char userToAddPublicKeyRaw[PUBLIC_KEY_NUM_BYTES];
- deserializerSkippedEncryptedData.extract((u8*)userToAddPublicKeyRaw, PUBLIC_KEY_NUM_BYTES);
- Signature::PublicKey userToAddPublicKey(userToAddPublicKeyRaw, PUBLIC_KEY_NUM_BYTES);
-
- uint8_t groupId[GROUP_ID_LENGTH];
- deserializerSkippedEncryptedData.extract(groupId, GROUP_ID_LENGTH);
-
- auto group = databaseStorage.getGroupById(*nodeHash, groupId);
- if(group)
- {
- auto user = RemoteUser::create(userToAddPublicKey, "ENCRYPTED USER NAME", group);
- // TODO: What if we receive packets in wrong order? (maliciously or non-maliciously). You would be able to register a user to a group with given name
- // and further registration would be dropped (even if that is the correct one)
- if(!databaseStorage.addUser(*nodeHash, user)) return;
-
- auto creatorUserGroupWithRights = getGroupWithRightsToAddUserToGroup(creatorUser->getGroups(), group);
- if(!creatorUserGroupWithRights)
- {
- // TODO: User might have permission to perform operation, but we haven't got the packet that adds user to the group with the permission,
- // or we haven't received the packet that modifies group with the permission to perform the operation.
- // This also means that an user can be in a group that has permission to perform the operation and then later be removed from it,
- // and remote peers would accept our request to perform operation if they haven't received the operation that removes the user from the group.
- // How to handle this?
- string errMsg = "User ";
- errMsg += creatorUser->getName();
- errMsg += " is not allowed to perform the operation: ";
- errMsg += to_string((u8)operation);
- throw PermissionDeniedException(errMsg);
- }
-
- // TODO: Verify there isn't already data with same timestamp for this node. Same for quarantine.
- // TODO: We might receive 'add' data packet before 'create'. If that happens, we should put it in quarantine and process it later.
- databaseStorage.appendStorage(*nodeHash, requestDataHash, operation, creatorUser, creationDate, value->data.data(), value->data.size(), encryptedDataView);
- }
- else
- {
- throw sibs::DeserializeException("TODO: Add to quarantine? You can receive ADD_USER packet before you receive ADD_GROUP");
- }
- }
- else
- {
- string errMsg = "Got unexpected operation: ";
- errMsg += to_string((u8)operation);
- throw sibs::DeserializeException(errMsg);
- }
+ DataView additionalDataView((void*)deserializerUnsigned.getBuffer(), deserializerUnsigned.getSize());
+ databaseStorage.appendStorage(*nodeHash, requestDataHash, operation, creatorPublicKey, creationDate, value->data.data(), value->data.size(), additionalDataView);
}
bool Database::listenCreateData(shared_ptr<dht::Value> value, const Hash &hash, const shared_ptr<OwnedMemory> encryptionKey)
@@ -657,7 +543,7 @@ namespace odhtdb
Log::debug("Got create data");
try
{
- if(databaseStorage.getStorage(hash))
+ if(databaseStorage.doesNodeExist(hash))
throw DatabaseStorageAlreadyExists("Create request hash is equal to hash already in storage (duplicate data?)");
deserializeCreateRequest(value, hash, encryptionKey);
}
@@ -673,7 +559,7 @@ namespace odhtdb
Log::debug("Got add data");
try
{
- if(databaseStorage.getDataById(requestDataHash))
+ if(databaseStorage.doesDataExist(requestDataHash))
throw DatabaseStorageAlreadyExists("Add data request hash is equal to hash already in storage (duplicate data?)");
deserializeAddRequest(value, requestDataHash, nodeHash, encryptionKey);
//Log::debug("Got add object, timestamp: %zu", addObject.timestamp);
@@ -688,24 +574,4 @@ namespace odhtdb
}
return true;
}
-
- void Database::setOnCreateNodeCallback(function<void(const DatabaseCreateNodeRequest&)> callbackFunc)
- {
- onCreateNodeCallbackFunc = callbackFunc;
- }
-
- void Database::setOnAddNodeCallback(function<void(const DatabaseAddNodeRequest&)> callbackFunc)
- {
- onAddNodeCallbackFunc = callbackFunc;
- }
-
- void Database::setOnAddUserCallback(function<void(const DatabaseAddUserRequest&)> callbackFunc)
- {
- onAddUserCallbackFunc = callbackFunc;
- }
-
- DatabaseStorage& Database::getStorage()
- {
- return databaseStorage;
- }
}