From e6331c04af99d7deeb9b15be02dd30665c3c41ce Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 16 May 2018 10:24:22 +0200 Subject: Rewrite code to work with new backend Redesigned join channel system, read README.md for more information --- src/Channel.cpp | 61 ++++---- src/Command.cpp | 2 +- src/MessageBoard.cpp | 19 ++- src/User.cpp | 35 ++++- src/main.cpp | 397 ++++++++++++++++++++++++++++++--------------------- 5 files changed, 296 insertions(+), 218 deletions(-) (limited to 'src') diff --git a/src/Channel.cpp b/src/Channel.cpp index ed037a4..a63fcc4 100644 --- a/src/Channel.cpp +++ b/src/Channel.cpp @@ -1,5 +1,4 @@ #include "../include/Channel.hpp" -#include #include #include #include @@ -95,17 +94,15 @@ namespace dchat void Channel::addMessage(const std::string &msg) { - if(database && localUser->type == User::Type::ONLINE) + if(database && localUser->type == User::Type::ONLINE_LOCAL_USER) { - auto localOnlineUser = static_cast(localUser); - assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL); + auto onlineLocalUser = static_cast(localUser); sibs::SafeSerializer serializer; serializer.add(ChannelDataType::ADD_MESSAGE); serializer.add((const u8*)msg.data(), msg.size()); - database->addData(databaseNodeInfo, static_cast(localOnlineUser->databaseUser), odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); - database->commit(); + database->addData(databaseNodeInfo, onlineLocalUser->keyPair, odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); } else addLocalMessage(msg, localUser, 0, odhtdb::Hash()); @@ -118,17 +115,15 @@ namespace dchat void Channel::deleteMessage(const odhtdb::Hash &id, const odhtdb::Signature::PublicKey &requestedByUser) { - if(database && localUser->type == User::Type::ONLINE) + if(database && localUser->type == User::Type::ONLINE_LOCAL_USER) { - auto localOnlineUser = static_cast(localUser); - assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL); + auto onlineLocalUser = static_cast(localUser); sibs::SafeSerializer serializer; serializer.add(ChannelDataType::DELETE_MESSAGE); serializer.add((const u8*)id.getData(), odhtdb::HASH_BYTE_SIZE); - database->addData(databaseNodeInfo, static_cast(localOnlineUser->databaseUser), odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); - database->commit(); + database->addData(databaseNodeInfo, onlineLocalUser->keyPair, odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); } else deleteLocalMessage(id, requestedByUser); @@ -137,41 +132,39 @@ namespace dchat void Channel::addUserLocally(User *user) { users.push_back(user); - if(user->type == User::Type::ONLINE) + if(user->isOnlineUser()) { auto onlineUser = static_cast(user); - publicKeyOnlineUsersMap[onlineUser->databaseUser->getPublicKey()] = onlineUser; + publicKeyOnlineUsersMap[onlineUser->getPublicKey()] = onlineUser; } } - bool Channel::addUser(const odhtdb::Signature::PublicKey &userId, const string &groupId) + bool Channel::addUser(const odhtdb::Signature::PublicKey &userId, const odhtdb::DataView &groupId) { assert(database); - if(!database || localUser->type != User::Type::ONLINE) + if(!database || localUser->type != User::Type::ONLINE_LOCAL_USER) return false; - if(groupId.size() != odhtdb::GROUP_ID_LENGTH) + if(groupId.size != odhtdb::GROUP_ID_LENGTH) { - fprintf(stderr, "Group id is wrong size. Expected to be %u bytes, was %u byte(s)\n", odhtdb::GROUP_ID_LENGTH, groupId.size()); + fprintf(stderr, "Group id is wrong size. Expected to be %u bytes, was %u byte(s)\n", odhtdb::GROUP_ID_LENGTH, groupId.size); return false; } - auto localOnlineUser = static_cast(localUser); - assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL); - - uint8_t groupIdRaw[odhtdb::GROUP_ID_LENGTH]; - memcpy(groupIdRaw, groupId.data(), groupId.size()); - auto groupToAddUserTo = database->getStorage().getGroupById(*databaseNodeInfo.getRequestHash(), groupIdRaw); - if(!groupToAddUserTo) + auto onlineLocalUser = static_cast(localUser); + try + { + database->addUser(databaseNodeInfo, onlineLocalUser->keyPair, userId, groupId); + return true; + } + catch(std::exception &e) { - fprintf(stderr, "Group with id %s does not exist in channel %s\n", odhtdb::bin2hex(groupId.c_str(), groupId.size()).c_str(), databaseNodeInfo.getRequestHash()->toString().c_str()); + fprintf(stderr, "Group with id %s does not exist in channel %s or you do not have permission to add user to that group\nError: %s\n", odhtdb::bin2hex((const char*)groupId.data, groupId.size).c_str(), databaseNodeInfo.getRequestHash()->toString().c_str(), e.what()); return false; } - database->addUser(databaseNodeInfo, static_cast(localOnlineUser->databaseUser), "noname", userId, groupToAddUserTo); - return true; } - void Channel::replaceLocalUser(User *newLocalUser) + void Channel::replaceLocalUser(OnlineLocalUser *newOnlineLocalUser) { for(vector::iterator it = users.begin(); it != users.end(); ++it) { @@ -183,24 +176,22 @@ namespace dchat } } - localUser = newLocalUser; - addUserLocally(newLocalUser); + localUser = newOnlineLocalUser; + addUserLocally(newOnlineLocalUser); } void Channel::changeNick(const std::string &newNick) { - if(database && localUser->type == User::Type::ONLINE) + if(database && localUser->type == User::Type::ONLINE_LOCAL_USER) { - auto localOnlineUser = static_cast(localUser); - assert(localOnlineUser->databaseUser->getType() == odhtdb::User::Type::LOCAL); + auto onlineLocalUser = static_cast(localUser); sibs::SafeSerializer serializer; serializer.add(ChannelDataType::NICKNAME_CHANGE); serializer.add((u8)newNick.size()); serializer.add((const u8*)newNick.data(), newNick.size()); - database->addData(databaseNodeInfo, static_cast(localOnlineUser->databaseUser), odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); - database->commit(); + database->addData(databaseNodeInfo, onlineLocalUser->keyPair, odhtdb::DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); } } diff --git a/src/Command.cpp b/src/Command.cpp index a074930..a28cd42 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -5,7 +5,7 @@ using namespace std; namespace dchat { - unordered_map commandHandlerFuncs; + static unordered_map commandHandlerFuncs; bool Command::add(const string &cmd, CommandHandlerFunc handlerFunc) { diff --git a/src/MessageBoard.cpp b/src/MessageBoard.cpp index 46b9d28..b1f8b0b 100644 --- a/src/MessageBoard.cpp +++ b/src/MessageBoard.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include using namespace std; @@ -82,12 +81,12 @@ namespace dchat lock_guard lock(messageProcessMutex); auto it = messageIdMap.find(id); if(it == messageIdMap.end()) return; - if(it->second->user->type == User::Type::ONLINE) + if(it->second->user->isOnlineUser()) { auto onlineUser = static_cast(it->second->user); - if(onlineUser->databaseUser->getPublicKey() != requestedByUser) + if(onlineUser->getPublicKey() != requestedByUser) { - fprintf(stderr, "Warning: user %s requested to delete a message owned by user %s, ignoring request\n", requestedByUser.toString().c_str(), onlineUser->databaseUser->getPublicKey().toString().c_str()); + fprintf(stderr, "Warning: user %s requested to delete a message owned by user %s, ignoring request\n", requestedByUser.toString().c_str(), onlineUser->getPublicKey().toString().c_str()); return; } } @@ -292,11 +291,11 @@ namespace dchat message->text.processEvent(event); } - OnlineUser *localOnlineUser = nullptr; - if(channel->getLocalUser()->type == User::Type::ONLINE) - localOnlineUser = static_cast(channel->getLocalUser()); + OnlineLocalUser *onlineLocalUser = nullptr; + if(channel->getLocalUser()->type == User::Type::ONLINE_LOCAL_USER) + onlineLocalUser = static_cast(channel->getLocalUser()); - if(localOnlineUser && event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Button::Right) + if(onlineLocalUser && event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Button::Right) { for(auto it : messageIdMap) { @@ -307,9 +306,9 @@ namespace dchat auto contextMenu = GlobalContextMenu::getEditMessageContextMenu(); contextMenu->setPosition(sf::Vector2f(event.mouseButton.x, event.mouseButton.y)); contextMenu->setVisible(true); - GlobalContextMenu::setClickDeleteMessageCallbackFunc([this, it, localOnlineUser](ContextMenuItem *menuItem) + GlobalContextMenu::setClickDeleteMessageCallbackFunc([this, it, onlineLocalUser](ContextMenuItem *menuItem) { - channel->deleteMessage(it.first, localOnlineUser->databaseUser->getPublicKey()); + channel->deleteMessage(it.first, onlineLocalUser->getPublicKey()); GlobalContextMenu::setClickDeleteMessageCallbackFunc(nullptr); }); return; diff --git a/src/User.cpp b/src/User.cpp index 16b3648..986380c 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -1,6 +1,4 @@ #include "../include/User.hpp" -#include -#include namespace dchat { @@ -12,18 +10,41 @@ namespace dchat } - OnlineUser::OnlineUser(const odhtdb::User *_databaseUser) : - User(Type::ONLINE), - name("randomUser69"), - databaseUser(_databaseUser) + OnlineUser::OnlineUser(const std::string &_name, Type type) : + User(type), + name(_name) { - assert(databaseUser); + } const std::string& OnlineUser::getName() const { return name; } + + OnlineRemoteUser::OnlineRemoteUser(const std::string &name, const odhtdb::Signature::PublicKey &_publicKey) : + OnlineUser(name, Type::ONLINE_REMOTE_USER), + publicKey(_publicKey) + { + + } + + const odhtdb::Signature::PublicKey& OnlineRemoteUser::getPublicKey() const + { + return publicKey; + } + + OnlineLocalUser::OnlineLocalUser(const std::string &name, const odhtdb::Signature::KeyPair &_keyPair) : + OnlineUser(name, Type::ONLINE_LOCAL_USER), + keyPair(_keyPair) + { + + } + + const odhtdb::Signature::PublicKey& OnlineLocalUser::getPublicKey() const + { + return keyPair.getPublicKey(); + } OfflineUser::OfflineUser(const std::string &_name) : User(Type::OFFLINE), diff --git a/src/main.cpp b/src/main.cpp index 18f10fe..249c5d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include using namespace std; @@ -128,19 +129,6 @@ void channelAddStoredMessage(Channel *channel, const odhtdb::Hash &requestHash, } } -void channelAddStoredMessages(Channel *channel, const odhtdb::DatabaseStorageObjectList *nodeStorage) -{ - printf("Load %u message(s) in channel %s\n", nodeStorage->objects.size(), channel->getName().c_str()); - for(auto nodeStorageAddedObject : nodeStorage->objects) - { - if(nodeStorageAddedObject->decryptedObject.operation == odhtdb::DatabaseOperation::ADD_DATA) - { - StringView decryptedObject((const char*)nodeStorageAddedObject->decryptedObject.data.data, nodeStorageAddedObject->decryptedObject.data.size); - channelAddStoredMessage(channel, nodeStorageAddedObject->requestHash, nodeStorageAddedObject->creatorPublicKey, decryptedObject, nodeStorageAddedObject->createdTimestamp); - } - } -} - int main(int argc, char **argv) { /* @@ -158,8 +146,6 @@ int main(int argc, char **argv) window.setVerticalSyncEnabled(false); window.setFramerateLimit(FRAMERATE_FOCUSED); - odhtdb::Database database("bootstrap.ring.cx", 4222, Cache::getDchatDir()); - //Video video(500, 500, "https://www.youtube.com/watch?v=bs0-EX9mJmg"); Cache cache; @@ -171,51 +157,69 @@ int main(int argc, char **argv) vector channels; - odhtdb::Signature::KeyPair *currentUserKeyPair = nullptr; - vector localNodeUsers; vector waitingToJoinChannels; - string currentUserName; - string currentUserPassword; + odhtdb::MapHash localNodeUsers; + string currentUsername; + string currentPassword; recursive_mutex channelMessageMutex; bool waitingToJoin = false; + bool loggedIn = false; + + odhtdb::Database *database = nullptr; + odhtdb::DatabaseCallbackFuncs callbackFuncs; - database.setOnCreateNodeCallback([&waitingToJoinChannels, &database, &channels, &channelMessageMutex, &waitingToJoin](const odhtdb::DatabaseCreateNodeRequest &request) + callbackFuncs.createNodeCallbackFunc = [&waitingToJoinChannels, &database, &channels, &channelMessageMutex, &waitingToJoin, &localNodeUsers](const odhtdb::DatabaseCreateNodeRequest &request) { lock_guard lock(channelMessageMutex); + + auto nodeUserData = localNodeUsers.find(*request.nodeHash); + if(nodeUserData == localNodeUsers.end()) return; + + User *localUser; + if(nodeUserData->second.userKeyPair->getPublicKey() == *request.creatorPublicKey) + localUser = new OnlineLocalUser("NoName", *nodeUserData->second.userKeyPair); + else + localUser = new OfflineUser("You"); + + shared_ptr databaseNodeHash = make_shared(); + memcpy(databaseNodeHash->getData(), request.nodeHash->getData(), odhtdb::HASH_BYTE_SIZE); + odhtdb::DatabaseNode databaseNode(nodeUserData->second.nodeEncryptionKey, databaseNodeHash); + Channel *channel = new Channel("NoChannelName", databaseNode, localUser, database); + ChannelSidePanel::addChannel(channel); + channels.push_back(channel); + Channel::setCurrent(channel); + + if(localUser->type == User::Type::OFFLINE) + { + User *nodeCreatorUser = new OnlineRemoteUser("NoName", *request.creatorPublicKey); + channel->addUserLocally(nodeCreatorUser); + } + for(vector::iterator it = waitingToJoinChannels.begin(); it != waitingToJoinChannels.end(); ++it) { if(*request.nodeHash == *it->getRequestHash()) { - User *localUser = new OfflineUser("You"); - Channel *channel = new Channel(request.name, *it, localUser, &database); - ChannelSidePanel::addChannel(channel); - channels.push_back(channel); - Channel::setCurrent(channel); - - User *nodeCreatorUser = new OnlineUser(request.creatorUser); - channel->addUserLocally(nodeCreatorUser); waitingToJoin = true; - waitingToJoinChannels.erase(it); return; } } - }); + }; - database.setOnAddNodeCallback([&channels, &channelMessageMutex](const odhtdb::DatabaseAddNodeRequest &request) + callbackFuncs.addNodeCallbackFunc = [&channels, &channelMessageMutex](const odhtdb::DatabaseAddNodeRequest &request) { lock_guard lock(channelMessageMutex); for(Channel *channel : channels) { if(*request.nodeHash == *channel->getNodeInfo().getRequestHash()) { - channelAddStoredMessage(channel, *request.requestHash, request.creatorUser->getPublicKey(), StringView((const char*)request.decryptedData.data, request.decryptedData.size), request.timestamp); + channelAddStoredMessage(channel, *request.requestHash, *request.creatorPublicKey, StringView((const char*)request.decryptedData.data, request.decryptedData.size), request.timestamp); return; } } - }); + }; - database.setOnAddUserCallback([¤tUserKeyPair, &channels, &channelMessageMutex, &waitingToJoin, &database](const odhtdb::DatabaseAddUserRequest &request) + callbackFuncs.addUserCallbackFunc = [&channels, &channelMessageMutex, &waitingToJoin, &localNodeUsers](const odhtdb::DatabaseAddUserRequest &request) { lock_guard lock(channelMessageMutex); printf("Add user callback. Channel to add user to: %s\n", request.nodeHash->toString().c_str()); @@ -225,34 +229,35 @@ int main(int argc, char **argv) if(*request.nodeHash == *channel->getNodeInfo().getRequestHash()) { printf("Add user to one of my channels\n"); - if(currentUserKeyPair && request.userToAdd->getPublicKey() == currentUserKeyPair->getPublicKey() && channel->getLocalUser()->type != User::Type::ONLINE) + auto nodeUserData = localNodeUsers.find(*request.nodeHash); + + User *userToAdd = channel->getUserByPublicKey(*request.userToAddPublicKey); + if(userToAdd) { - // Replace remote user with local user, if we are the remote user - database.getStorage().getLocalNodeUsers(*currentUserKeyPair); - auto userToAdd = database.getStorage().getUserByPublicKey(*request.nodeHash, currentUserKeyPair->getPublicKey()); - printf("You were added to channel %s by %s\n", request.nodeHash->toString().c_str(), request.creatorUser->getName().c_str()); - channel->replaceLocalUser(new OnlineUser(userToAdd)); - waitingToJoin = false; + fprintf(stderr, "User %s already exists in channel\n", request.userToAddPublicKey->toString().c_str()); return; } - User *userToAdd = channel->getUserByPublicKey(request.userToAdd->getPublicKey()); - if(userToAdd) + if(*request.userToAddPublicKey == nodeUserData->second.userKeyPair->getPublicKey()) { - fprintf(stderr, "User %s already exists in channel\n", request.userToAdd->getPublicKey().toString().c_str()); + printf("You were added to channel %s by %s\n", request.nodeHash->toString().c_str(), request.creatorPublicKey->toString().c_str()); + channel->replaceLocalUser(new OnlineLocalUser("NoName", *nodeUserData->second.userKeyPair)); + waitingToJoin = false; return; } - User *newRemoteUser = new OnlineUser(request.userToAdd); + User *newRemoteUser = new OnlineRemoteUser("NoName", *request.userToAddPublicKey); channel->addUserLocally(newRemoteUser); return; } } - }); + }; + database = new odhtdb::Database("bootstrap.ring.cx", 4222, Cache::getDchatDir(), callbackFuncs); // Login to account - Command::add("login", [¤tUserKeyPair, ¤tUserName, ¤tUserPassword, &localNodeUsers, &database, &channels, &channelMessageMutex](const vector &args) + Command::add("login", [&localNodeUsers, &database, &channels, &loggedIn, &channelMessageMutex, ¤tUsername, ¤tPassword](const vector &args) { + lock_guard lock(channelMessageMutex); if(args.size() != 2) { fprintf(stderr, "Expected 2 arguments for command login (username and password), got %u argument(s)\n", args.size()); @@ -261,8 +266,7 @@ int main(int argc, char **argv) try { - odhtdb::Signature::KeyPair keyPair = database.getStorage().decryptLocalEncryptedUser(args[0], args[1]); - localNodeUsers = database.getStorage().getLocalNodeUsers(keyPair); + localNodeUsers = database->getStoredNodeUserInfoDecrypted(args[0], args[1]); ChannelSidePanel::removeAllChannels(); for(Channel *channel : channels) @@ -271,51 +275,25 @@ int main(int argc, char **argv) } channels.clear(); - lock_guard lock(channelMessageMutex); - for(auto localNodeUser : localNodeUsers) + printf("Loading %u channel(s) for user\n", localNodeUsers.size()); + for(auto &localNodeUser : localNodeUsers) { - auto nodeStorage = database.getStorage().getStorage(localNodeUser.nodeHash); - if(!nodeStorage) continue; - - auto nodeDecryptionKeyResult = database.getStorage().getNodeDecryptionKey(localNodeUser.nodeHash); - if(!nodeDecryptionKeyResult.first) continue; - - User *newLocalUser = new OnlineUser(localNodeUser.localUser); - odhtdb::DatabaseNode databaseNode(nodeDecryptionKeyResult.second, make_shared(localNodeUser.nodeHash)); - Channel *channel = new Channel(nodeStorage->nodeName, databaseNode, newLocalUser, &database); - - auto nodeUserMapByPublicKey = database.getStorage().getNodeUsers(localNodeUser.nodeHash); - for(auto nodeUserIt : *nodeUserMapByPublicKey) - { - if(nodeUserIt.second != localNodeUser.localUser) - { - User *newRemoteUser = new OnlineUser(nodeUserIt.second); - channel->addUserLocally(newRemoteUser); - } - } - - ChannelSidePanel::addChannel(channel); - channels.push_back(channel); - Channel::setCurrent(channel); - channelAddStoredMessages(channel, nodeStorage); + database->loadNode(localNodeUser.first); } printf("Successfully logged into user %s\n", args[0].c_str()); - if(currentUserKeyPair) - delete currentUserKeyPair; - currentUserKeyPair = new odhtdb::Signature::KeyPair(keyPair); - - currentUserName = args[0]; - currentUserPassword = args[1]; + currentUsername = args[0]; + currentPassword = args[1]; + loggedIn = true; } - catch(odhtdb::DatabaseStorageException &e) + catch(std::exception &e) { fprintf(stderr, "Failed to login, reason: %s\n", e.what()); } }); // Register account - Command::add("register", [¤tUserKeyPair, ¤tUserName, ¤tUserPassword, &localNodeUsers, &database, &channelMessageMutex](const vector &args) + Command::add("register", [&localNodeUsers, &database, &channels, &loggedIn, &channelMessageMutex, ¤tUsername, ¤tPassword](const vector &args) { lock_guard lock(channelMessageMutex); if(args.size() != 2) @@ -324,33 +302,34 @@ int main(int argc, char **argv) return; } - if(currentUserKeyPair) + try { - fprintf(stderr, "You can't register a new account when you are logged in, please logout first\n"); - return; + database->storeUserWithoutNodes(args[0], args[1]); } - - odhtdb::Signature::KeyPair keyPair; - if(!database.getStorage().storeLocalUser(args[0], keyPair, args[1])) + catch(odhtdb::SqlExecException &e) { fprintf(stderr, "User with name %s already exists in storage\n", args[0].c_str()); return; } - printf("Registered user %s, public key: %s, private key: %s\n", args[0].c_str(), keyPair.getPublicKey().toString().c_str(), keyPair.getPrivateKey().toString().c_str()); - printf("Successfully logged into user %s\n", args[0].c_str()); + printf("Registered user %s\n", args[0].c_str()); - if(currentUserKeyPair) - delete currentUserKeyPair; - currentUserKeyPair = new odhtdb::Signature::KeyPair(keyPair); + ChannelSidePanel::removeAllChannels(); + for(Channel *channel : channels) + { + delete channel; + } + channels.clear(); localNodeUsers.clear(); - currentUserName = args[0]; - currentUserPassword = args[1]; + printf("Successfully logged into user %s\n", args[0].c_str()); + currentUsername = args[0]; + currentPassword = args[1]; + loggedIn = true; }); // Create channel - Command::add("cc", [¤tUserKeyPair, ¤tUserName, &database, &channels, &channelMessageMutex](const vector &args) + Command::add("cc", [&database, &channels, &channelMessageMutex, &loggedIn, &localNodeUsers, ¤tUsername, ¤tPassword](const vector &args) { lock_guard lock(channelMessageMutex); if(args.size() != 1) @@ -359,69 +338,113 @@ int main(int argc, char **argv) return; } - if(!currentUserKeyPair) + if(!loggedIn) { fprintf(stderr, "You are not logged in. Please login before creating a channel\n"); return; } - auto createResponse = database.create(currentUserName, *currentUserKeyPair, args[0]); - database.commit(); + auto createResponse = database->create(); printf("Created database '%s', join key: '%s'\n", args[0].c_str(), createChannelJoinKey(createResponse).c_str()); - User *newLocalUser = new OnlineUser(createResponse->getNodeAdminUser()); + User *newLocalUser = new OnlineLocalUser("NoName", *createResponse->getNodeAdminKeyPair()); odhtdb::DatabaseNode databaseNode(createResponse->getNodeEncryptionKey(), createResponse->getRequestHash()); - Channel *channel = new Channel(args[0], databaseNode, newLocalUser, &database); + Channel *channel = new Channel(args[0], databaseNode, newLocalUser, database); ChannelSidePanel::addChannel(channel); channels.push_back(channel); Channel::setCurrent(channel); + + localNodeUsers[*createResponse->getRequestHash()] = { createResponse->getNodeEncryptionKey(), createResponse->getNodeAdminKeyPair() }; + database->storeNodeInfoForUserEncrypted(databaseNode, currentUsername, currentPassword, *createResponse->getNodeAdminKeyPair()); + Channel::getCurrent()->addLocalMessage("Channel created and stored in database", Channel::getCurrent()->getSystemUser()); }); - // Add user - Command::add("au", [&offlineChannel, &channelMessageMutex](const vector &args) + // Create invite key + Command::add("invite", [&channelMessageMutex, &offlineChannel, &database](const vector &args) { lock_guard lock(channelMessageMutex); - if(args.size() != 2) - { - fprintf(stderr, "Expected 2 arguments for command au (user id, group id), got %u argument(s)\n", args.size()); - return; - } - - if(args[0].size() != odhtdb::PUBLIC_KEY_NUM_BYTES * 2) - { - fprintf(stderr, "User id is wrong size. Expected to be %u characters, was %u character(s)\n", odhtdb::PUBLIC_KEY_NUM_BYTES * 2, args[0].size()); - return; - } - - if(args[1].size() != odhtdb::GROUP_ID_LENGTH * 2) + if(args.size() != 0) { - fprintf(stderr, "Group id is wrong size. Expected to be %u characters, was %u character(s)\n", odhtdb::GROUP_ID_LENGTH * 2, args[1].size()); + fprintf(stderr, "Expected 0 arguments for command invite, got %u argument(s)\n", args.size()); return; } Channel *currentChannel = Channel::getCurrent(); if(currentChannel == &offlineChannel) { - Channel::getCurrent()->addLocalMessage("You need to be in a channel to add user to the channel", Channel::getCurrent()->getSystemUser()); + Channel::getCurrent()->addLocalMessage("You need to be in a channel to create an invite key", Channel::getCurrent()->getSystemUser()); return; } - auto userIdRaw = odhtdb::hex2bin(args[0].c_str(), args[0].size()); - odhtdb::Signature::PublicKey userPublicKey(userIdRaw.data(), userIdRaw.size()); + // TODO: Verify user has permission to add users before generating invite key, otherwise invite will fail and the users attempting to join will wait in futile - auto groupIdRaw = odhtdb::hex2bin(args[1].c_str(), args[1].size()); - bool userAddResult = currentChannel->addUser(userPublicKey, groupIdRaw); - if(userAddResult) - { - printf("Added user to your channel!\n"); - } - else + auto channelNodeHash = currentChannel->getNodeInfo().getRequestHash(); + auto channelEncryptionKey = currentChannel->getNodeInfo().getNodeEncryptionKey(); + shared_ptr encryptionKey = make_shared(new u8[odhtdb::ENCRYPTION_KEY_BYTE_SIZE], odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + odhtdb::Encryption::generateKey((unsigned char*)encryptionKey->data); + + string inviteKey = odhtdb::bin2hex((const char*)channelNodeHash->getData(), channelNodeHash->getSize()); + inviteKey += '&'; + inviteKey += odhtdb::bin2hex((const char*)encryptionKey->data, odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + + string msg = "You are now listening for users to join the channel using the key: "; + msg += inviteKey; + + Channel::getCurrent()->addLocalMessage(msg, Channel::getCurrent()->getSystemUser()); + printf("%s\n", msg.c_str()); + + sibs::SafeSerializer keySerializer; + keySerializer.add((const u8*)channelNodeHash->getData(), channelNodeHash->getSize()); + keySerializer.add((const u8*)encryptionKey->data, odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + dht::InfoHash key = odhtdb::Database::getInfoHash(keySerializer.getBuffer().data(), keySerializer.getBuffer().size()); + database->receiveCustomMessage(key, [&channelMessageMutex, encryptionKey, channelEncryptionKey, currentChannel, &database](const void *data, usize size) { - fprintf(stderr, "Failed to add user to your channel!\n"); - } + // TODO: User can remove channel @currentChannel before we get here, meaning @currentChannel is deleted and would be invalid; causing the program to crash + try + { + sibs::SafeDeserializer deserializer((const u8*)data, size); + u8 userToAddPublicKeyRaw[odhtdb::PUBLIC_KEY_NUM_BYTES]; + deserializer.extract(userToAddPublicKeyRaw, odhtdb::PUBLIC_KEY_NUM_BYTES); + odhtdb::Signature::PublicKey userToAddPublicKey((const char*)userToAddPublicKeyRaw, odhtdb::PUBLIC_KEY_NUM_BYTES); + string unsignedEncryptedMsg = userToAddPublicKey.unsign(odhtdb::DataView((void*)deserializer.getBuffer(), deserializer.getSize())); + + sibs::SafeDeserializer encryptedDataDeserializer((const u8*)unsignedEncryptedMsg.data(), unsignedEncryptedMsg.size()); + u8 nonce[odhtdb::ENCRYPTION_NONCE_BYTE_SIZE]; + encryptedDataDeserializer.extract(nonce, odhtdb::ENCRYPTION_NONCE_BYTE_SIZE); + odhtdb::Decryption decryptedMsg(odhtdb::DataView((void*)encryptedDataDeserializer.getBuffer(), encryptedDataDeserializer.getSize()), + odhtdb::DataView(nonce, odhtdb::ENCRYPTION_NONCE_BYTE_SIZE), + encryptionKey->getView()); + + // TODO: Create GUI for accepting users into channel instead of accepting ALL users + sibs::SafeSerializer encryptedDataSerializer; + encryptedDataSerializer.add((const u8*)channelEncryptionKey->data, channelEncryptionKey->size); + encryptedDataSerializer.add((const u8*)userToAddPublicKey.getData(), userToAddPublicKey.getSize()); + odhtdb::Encryption encryptedChannelKey(odhtdb::DataView((void*)encryptedDataSerializer.getBuffer().data(), encryptedDataSerializer.getBuffer().size()), encryptionKey->getView()); + + sibs::SafeSerializer serializer; + serializer.add((const u8*)encryptedChannelKey.getNonce().data, encryptedChannelKey.getNonce().size); + serializer.add((const u8*)encryptedChannelKey.getCipherText().data, encryptedChannelKey.getCipherText().size); + const auto &localUserPublicKey = static_cast(currentChannel->getLocalUser())->getPublicKey(); + auto localUserGroups = database->getUserGroups(*currentChannel->getNodeInfo().getRequestHash(), localUserPublicKey); + if(!localUserGroups.empty()) + { + fprintf(stderr, "No group to add user to...\n"); + return sibs::SafeSerializer(); + } + lock_guard lock(channelMessageMutex); + currentChannel->addUser(localUserPublicKey, localUserGroups[0].getView()); + return serializer; + } + catch(std::exception &e) + { + fprintf(stderr, "Failed while parsing user data to add to channel, reason: %s\n", e.what()); + } + return sibs::SafeSerializer(); + }); }); - Command::add("jc", [¤tUserKeyPair, &database, &localNodeUsers, &channelMessageMutex, &waitingToJoin, &waitingToJoinChannels](const vector &args) + // Join channel using invite key + Command::add("jc", [&loggedIn, &database, &localNodeUsers, &channelMessageMutex, &waitingToJoin, &waitingToJoinChannels, ¤tUsername, ¤tPassword](const vector &args) { lock_guard lock(channelMessageMutex); if(args.size() != 1) @@ -436,29 +459,90 @@ int main(int argc, char **argv) return; } - if(!currentUserKeyPair) + if(!loggedIn) { fprintf(stderr, "You are not logged in. Please login before joining a channel\n"); return; } - odhtdb::DatabaseNode databaseNode = createDatabaseNodeFromJoinKey(args[0]); - for(auto localNodeUser : localNodeUsers) + string nodeHashBinRaw = odhtdb::hex2bin(args[0].c_str(), 64); + shared_ptr nodeHash = make_shared(); + memcpy(nodeHash->getData(), nodeHashBinRaw.data(), nodeHashBinRaw.size()); + auto nodeUserIt = localNodeUsers.find(*nodeHash); + if(nodeUserIt != localNodeUsers.end()) { - if(*databaseNode.getRequestHash() == localNodeUser.nodeHash) - { - fprintf(stderr, "You have already joined the channel %s\n", databaseNode.getRequestHash()->toString().c_str()); - return; - } + fprintf(stderr, "You have already joined the channel %s\n", args[0].c_str()); + return; } - database.seed(databaseNode); - waitingToJoinChannels.push_back(databaseNode); + string encryptionKeyBinRaw = odhtdb::hex2bin(args[0].c_str() + 65, 64); + shared_ptr encryptionKey = make_shared(new u8[odhtdb::ENCRYPTION_KEY_BYTE_SIZE], odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + memcpy(encryptionKey->data, encryptionKeyBinRaw.data(), encryptionKeyBinRaw.size()); + + shared_ptr keyPair = make_shared(); + sibs::SafeSerializer serializer; + serializer.add((const u8*)keyPair->getPublicKey().getData(), keyPair->getPublicKey().getSize()); + + localNodeUsers[*nodeHash] = { encryptionKey, keyPair }; + + const char *msg = "please let me join"; + odhtdb::Encryption encryptedJoinMsg(odhtdb::DataView((void*)msg, strlen(msg)), encryptionKey->getView()); + sibs::SafeSerializer encryptedDataSerializer; + encryptedDataSerializer.add((const u8*)encryptedJoinMsg.getNonce().data, encryptedJoinMsg.getNonce().size); + encryptedDataSerializer.add((const u8*)encryptedJoinMsg.getCipherText().data, encryptedJoinMsg.getCipherText().size); + string signedEncryptedMsg = keyPair->getPrivateKey().sign(odhtdb::DataView(encryptedDataSerializer.getBuffer().data(), encryptedDataSerializer.getBuffer().size())); + serializer.add((const u8*)signedEncryptedMsg.data(), signedEncryptedMsg.size()); + + sibs::SafeSerializer keySerializer; + keySerializer.add((const u8*)nodeHash->getData(), nodeHash->getSize()); + keySerializer.add((const u8*)encryptionKeyBinRaw.data(), odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + dht::InfoHash key = odhtdb::Database::getInfoHash(keySerializer.getBuffer().data(), keySerializer.getBuffer().size()); + database->sendCustomMessage(key, move(serializer.getBuffer()), [&database, nodeHash, encryptionKey, &waitingToJoinChannels, &channelMessageMutex, keyPair, ¤tUsername, ¤tPassword, &localNodeUsers](bool gotResponse, const void *data, usize size) + { + if(!gotResponse) + { + printf("We didn't get a response from anybody in the channel. Is there nobody that can add us (nobody with the permission required to do so or no online users) or is the node hash invalid?\n"); + return false; + } + + try + { + sibs::SafeDeserializer deserializer((const u8*)data, size); + u8 nonce[odhtdb::ENCRYPTION_NONCE_BYTE_SIZE]; + deserializer.extract(nonce, odhtdb::ENCRYPTION_NONCE_BYTE_SIZE); + odhtdb::Decryption decryptedMsg(odhtdb::DataView((void*)deserializer.getBuffer(), deserializer.getSize()), + odhtdb::DataView(nonce, odhtdb::ENCRYPTION_NONCE_BYTE_SIZE), + encryptionKey->getView()); + if(decryptedMsg.getDecryptedText().size != odhtdb::ENCRYPTION_KEY_BYTE_SIZE + odhtdb::PUBLIC_KEY_NUM_BYTES) + { + fprintf(stderr, "Invite response was of unexpected size, maybe it wasn't mean for us?\n"); + return true; + } + + odhtdb::DataView channelEncryptionKey(decryptedMsg.getDecryptedText().data, odhtdb::ENCRYPTION_KEY_BYTE_SIZE); + odhtdb::DataView invitedUserPublicKey((u8*)decryptedMsg.getDecryptedText().data + odhtdb::ENCRYPTION_KEY_BYTE_SIZE, odhtdb::PUBLIC_KEY_NUM_BYTES); + if(memcmp(keyPair->getPublicKey().getData(), invitedUserPublicKey.data, odhtdb::PUBLIC_KEY_NUM_BYTES) != 0) + { + fprintf(stderr, "Invite response was not meant for us\n"); + return true; + } + + odhtdb::DatabaseNode databaseNode(encryptionKey, nodeHash); + database->storeNodeInfoForUserEncrypted(databaseNode, currentUsername, currentPassword, *keyPair); + printf("Got a response from a person in the channel, we might get added...\n"); + waitingToJoinChannels.push_back(databaseNode); + lock_guard lock(channelMessageMutex); + database->seed(databaseNode); + return false; + } + catch(std::exception &e) + { + fprintf(stderr, "Failed while parsing join response for invite link, reason: %s\n", e.what()); + } + return true; + + }); waitingToJoin = true; - // TODO: Add the channel to join to a pending join list in a file and remove from it when we have joined the channel. - // The reason for doing that is so if we crash or lose internet connection before we have got `create node` request from remote peers, - // then we need to start seeding again when we login. Once we have `create node` request, then it's added to local cache and when you login, - // it will be used to seed the channel. }); // Scale UI @@ -556,25 +640,8 @@ int main(int argc, char **argv) Channel::getCurrent()->addLocalMessage(msg, Channel::getCurrent()->getSystemUser()); }); - // Get username and id (public key) - Command::add("whoami", [¤tUserKeyPair, ¤tUserName](const vector &args) - { - if(!currentUserKeyPair) - { - Channel::getCurrent()->addLocalMessage("You are not logged in", Channel::getCurrent()->getSystemUser()); - return; - } - - string response = "Username: "; - response += currentUserName; - response += ", id: "; - response += currentUserKeyPair->getPublicKey().toString(); - printf("%s\n", response.c_str()); - Channel::getCurrent()->addLocalMessage(response, Channel::getCurrent()->getSystemUser()); - }); - // Change nick of current user in current channel - Command::add("nick", [¤tUserKeyPair, &offlineChannel](const vector &args) + Command::add("nick", [&loggedIn, &offlineChannel](const vector &args) { if(args.size() != 1) { @@ -585,7 +652,7 @@ int main(int argc, char **argv) return; } - if(!currentUserKeyPair) + if(!loggedIn) { Channel::getCurrent()->addLocalMessage("You need to be logged in to change your nickname", Channel::getCurrent()->getSystemUser()); return; @@ -610,7 +677,7 @@ int main(int argc, char **argv) }); // Get channel join key - Command::add("joinkey", [¤tUserKeyPair, ¤tUserName, &offlineChannel](const vector &args) + Command::add("joinkey", [&offlineChannel](const vector &args) { Channel *currentChannel = Channel::getCurrent(); if(!currentChannel || currentChannel == &offlineChannel) -- cgit v1.2.3