#include "../include/Channel.hpp" #include "../include/ChannelSidePanel.hpp" #include "../include/UsersSidePanel.hpp" #include "../include/ChannelTopPanel.hpp" #include "../include/Cache.hpp" #include "../include/ResourceCache.hpp" #include "../include/Video.hpp" #include "../include/Command.hpp" #include "../include/Settings.hpp" #include "../include/ColorScheme.hpp" #include #include #include #include #include #include #include #include #include using namespace std; using namespace dchat; using namespace TinyProcessLib; string createChannelJoinKey(const unique_ptr &databaseCreateResponse) { string result; result += databaseCreateResponse->getRequestHash()->toString(); result += "&"; result += odhtdb::bin2hex((const char*)databaseCreateResponse->getNodeEncryptionKey()->data, databaseCreateResponse->getNodeEncryptionKey()->size); return result; } odhtdb::DatabaseNode createDatabaseNodeFromJoinKey(const string &joinKey) { odhtdb::DatabaseNode result; string nodeHashStr = odhtdb::hex2bin(joinKey.c_str(), 64); memcpy(result.getRequestHash()->getData(), nodeHashStr.data(), nodeHashStr.size()); string nodeEncryptionKeyStr = odhtdb::hex2bin(joinKey.c_str() + 65, 64); char *nodeEncryptionKeyRaw = new char[nodeEncryptionKeyStr.size()]; result.getNodeEncryptionKey()->data = nodeEncryptionKeyRaw; result.getNodeEncryptionKey()->size = nodeEncryptionKeyStr.size(); return result; } void channelAddStoredMessages(Channel *channel, const odhtdb::DatabaseStorageObjectList *nodeStorage) { printf("Load %u messages in channel %s\n", nodeStorage->objects.size(), channel->getName().c_str()); for(auto nodeStorageAddedObject : nodeStorage->objects) { if(nodeStorageAddedObject->decryptedObject.operation == odhtdb::DatabaseOperation::ADD_DATA) { User *user = channel->getUserByPublicKey(nodeStorageAddedObject->creatorPublicKey); if(!user) { fprintf(stderr, "Missing user? %s\n", nodeStorageAddedObject->creatorPublicKey.toString().c_str()); continue; } string msg((const char*)nodeStorageAddedObject->decryptedObject.data.data, nodeStorageAddedObject->decryptedObject.data.size); channel->addLocalMessage(msg, user); } } } int main(int argc, char **argv) { /* boost::filesystem::path programPath(argv[0]); auto parentPath = programPath.parent_path(); printf("parent path: %s\n", parentPath.string().c_str()); boost::filesystem::current_path(parentPath); // Ensures loading of resources works no matter which path we run this executable from */ XInitThreads(); sf::RenderWindow window(sf::VideoMode(1920, 1080), "dchat"); window.setVerticalSyncEnabled(false); window.setFramerateLimit(60); odhtdb::Database database("bootstrap.ring.cx", 4222, Cache::getDchatDir()); database.setOnCreateNodeCallback([](const odhtdb::DatabaseCreateNodeRequest &request) { }); database.setOnAddNodeCallback([](const odhtdb::DatabaseAddNodeRequest &request) { }); database.setOnAddUserCallback([](const odhtdb::DatabaseAddUserRequest &request) { }); //Video video(500, 500, "https://www.youtube.com/watch?v=bs0-EX9mJmg"); Cache cache; Channel offlineChannel("Offline"); ChannelSidePanel::addChannel(&offlineChannel); Channel::setCurrent(&offlineChannel); vector channels; odhtdb::Signature::KeyPair *currentUserKeyPair = nullptr; vector localNodeUsers; string currentUserName; string currentUserPassword; Command::add("login", [¤tUserKeyPair, ¤tUserName, ¤tUserPassword, &localNodeUsers, &database, &channels](const vector &args) { if(args.size() != 2) { fprintf(stderr, "Expected 2 arguments for command login (username and password), got %u argument(s)\n", args.size()); return; } try { odhtdb::Signature::KeyPair keyPair = database.getStorage().decryptLocalEncryptedUser(args[0], args[1]); localNodeUsers = database.getStorage().getLocalNodeUsers(keyPair); ChannelSidePanel::removeAllChannels(); for(Channel *channel : channels) { delete channel; } channels.clear(); 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->addUser(newRemoteUser); } } ChannelSidePanel::addChannel(channel); channels.push_back(channel); Channel::setCurrent(channel); channelAddStoredMessages(channel, nodeStorage); } 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]; } catch(odhtdb::DatabaseStorageException &e) { fprintf(stderr, "Failed to login, reason: %s\n", e.what()); } }); Command::add("register", [¤tUserKeyPair, ¤tUserName, ¤tUserPassword, &localNodeUsers, &database](const vector &args) { if(args.size() != 2) { fprintf(stderr, "Expected 2 arguments for command register (username and password), got %u argument(s)\n", args.size()); return; } if(currentUserKeyPair) { fprintf(stderr, "You can't register a new account when you are logged in, please logout first\n"); return; } odhtdb::Signature::KeyPair keyPair; if(!database.getStorage().storeLocalUser(args[0], keyPair, args[1])) { 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()); if(currentUserKeyPair) delete currentUserKeyPair; currentUserKeyPair = new odhtdb::Signature::KeyPair(keyPair); localNodeUsers.clear(); currentUserName = args[0]; currentUserPassword = args[1]; }); Command::add("cc", [¤tUserKeyPair, ¤tUserName, &database, &channels](const vector &args) { if(args.size() != 1) { fprintf(stderr, "Expected 1 argument for command cc (channel name), got %u argument(s)\n", args.size()); return; } if(!currentUserKeyPair) { 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(); printf("Created database '%s', join key: '%s'\n", args[0].c_str(), createChannelJoinKey(createResponse).c_str()); User *newLocalUser = new OnlineUser(createResponse->getNodeAdminUser()); odhtdb::DatabaseNode databaseNode(createResponse->getNodeEncryptionKey(), createResponse->getRequestHash()); Channel *channel = new Channel(args[0], databaseNode, newLocalUser, &database); ChannelSidePanel::addChannel(channel); channels.push_back(channel); Channel::setCurrent(channel); }); Command::add("jc", [¤tUserKeyPair, &database, &localNodeUsers](const vector &args) { if(args.size() != 1) { fprintf(stderr, "Expected 1 argument for command jc (channel join key), got %u argument(s)\n", args.size()); return; } if(args[0].size() != 129) { fprintf(stderr, "Expected join key to be 129 characters, was %u character(s)\n", args[0].size()); return; } if(!currentUserKeyPair) { 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) { if(*databaseNode.getRequestHash() == localNodeUser.nodeHash) { fprintf(stderr, "You have already joined the channel %s\n", databaseNode.getRequestHash()->toString().c_str()); return; } } #if 0 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->addUser(newRemoteUser); } } ChannelSidePanel::addChannel(channel); channels.push_back(channel); Channel::setCurrent(channel); channelAddStoredMessages(channel, nodeStorage); #endif }); Command::add("scale", [](const vector &args) { if(args.size() != 1) { fprintf(stderr, "Expected 1 argument for command scale, got %u argument(s)\n", args.size()); return; } float scaling = stof(args[0]); Settings::setScaling(scaling); printf("UI scaling set to %f\n", scaling); }); sf::Event event; while (window.isOpen()) { while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); else if(event.type == sf::Event::Resized) { sf::FloatRect viewRect(0.0f, 0.0f, event.size.width, event.size.height); const int minWidth = 800; if(event.size.width < minWidth) { viewRect.width = minWidth; window.setSize(sf::Vector2u(minWidth, event.size.height)); } sf::View view(viewRect); window.setView(view); } Channel::getCurrent()->processEvent(event); } window.clear(ColorScheme::getBackgroundColor()); ChannelSidePanel::draw(window); Channel::getCurrent()->draw(window, cache); UsersSidePanel::draw(window); ChannelTopPanel::draw(window); //video.draw(window); window.display(); } return 0; }