aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/dchat/Process.hpp8
-rw-r--r--include/dchat/Room.hpp18
-rw-r--r--src/Cache.cpp5
-rw-r--r--src/Process.cpp33
-rw-r--r--src/Room.cpp68
5 files changed, 106 insertions, 26 deletions
diff --git a/include/dchat/Process.hpp b/include/dchat/Process.hpp
new file mode 100644
index 0000000..18aa2d9
--- /dev/null
+++ b/include/dchat/Process.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <string>
+
+namespace dchat
+{
+ std::string escapeCommand(const std::string &cmd);
+} \ No newline at end of file
diff --git a/include/dchat/Room.hpp b/include/dchat/Room.hpp
index 56b60e5..6681cdc 100644
--- a/include/dchat/Room.hpp
+++ b/include/dchat/Room.hpp
@@ -31,16 +31,16 @@ namespace dchat
Room(Rooms *rooms, std::shared_ptr<odhtdb::Hash> id);
// Throws exception on failure if we are not allowed to add the user to the group
void addUser(const odhtdb::Signature::PublicKey &userPublicKey, std::shared_ptr<Group> group);
- // Returns null if the user already exists in the room
- std::shared_ptr<User> addUserLocally(const odhtdb::Signature::PublicKey &userPublicKey, std::shared_ptr<Group> group);
- // Returns null if the group already exists in the room
- std::shared_ptr<Group> addGroupLocally(const odhtdb::DataView groupId);
+
// Returns null if user doesn't exist in room
std::shared_ptr<User> getUserByPublicKey(const odhtdb::Signature::PublicKey &userPublicKey);
+
// Returns null if group doesn't exist in room
std::shared_ptr<Group> getGroupById(const odhtdb::DataView groupId);
+
void setAvatarUrl(const std::string &url);
- void setNickname(const std::string &nickname);
+ void setUserNickname(const std::string &nickname);
+ bool setName(const std::string &name);
void publishMessage(const std::string &msg);
const odhtdb::Signature::MapPublicKey<std::shared_ptr<User>>& getUsers() const { return userByPublicKey; }
@@ -57,6 +57,10 @@ namespace dchat
// TODO: Move to private when we have proper support for groups
std::vector<std::shared_ptr<Group>> groups;
private:
+ // Returns null if the user already exists in the room
+ std::shared_ptr<User> addUserLocally(const odhtdb::Signature::PublicKey &userPublicKey, std::shared_ptr<Group> group);
+ // Returns null if the group already exists in the room
+ std::shared_ptr<Group> addGroupLocally(const odhtdb::DataView groupId);
void setLocalUser(std::shared_ptr<User> user, std::shared_ptr<odhtdb::Signature::KeyPair> keyPair);
private:
odhtdb::Signature::MapPublicKey<std::shared_ptr<User>> userByPublicKey;
@@ -116,6 +120,7 @@ namespace dchat
uint32_t timestampSeconds;
bool loadedFromCache;
bool isLocalUser;
+ bool waitedToJoin;
};
// if connection failed then @rooms is null and errMsg contains the error
@@ -153,7 +158,8 @@ namespace dchat
void registerUser(const std::string &username, const std::string &password);
// Throws on failure
std::shared_ptr<Room> createRoom(const std::string &name);
- void requestJoinRoom(const std::string &inviteKey, const std::string &message);
+ // Throws on failure, returns true on success, returns false on expected failures (such as already being a member of the room)
+ bool requestJoinRoom(const std::string &inviteKey, const std::string &message);
std::shared_ptr<odhtdb::Database> database;
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 82f31b9..bb87857 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -3,6 +3,7 @@
#include "../include/dchat/FileUtil.hpp"
#include "../include/dchat/Gif.hpp"
#include "../include/dchat/Storage.hpp"
+#include "../include/dchat/Process.hpp"
#include <boost/filesystem/convenience.hpp>
#include <process.hpp>
#include <odhtdb/Hash.hpp>
@@ -351,8 +352,8 @@ namespace dchat
string downloadLimitBytesStr = to_string(downloadLimitBytes);
std::string cmdUtf8 = "curl -L --silent -o '";
- cmdUtf8 += filepath.string();
- cmdUtf8 += "' --max-filesize " + downloadLimitBytesStr + " --range 0-" + downloadLimitBytesStr + " --url '" + url + "'";
+ cmdUtf8 += escapeCommand(filepath.string());
+ cmdUtf8 += "' --max-filesize " + downloadLimitBytesStr + " --range 0-" + downloadLimitBytesStr + " --url '" + escapeCommand(url) + "'";
Process::string_type cmd = toNativeString(cmdUtf8);
// TODO: Use this instead of curl on windows: certutil.exe -urlcache -split -f "https://url/to/file" path/and/name/to/save/as/file
Process *process = new Process(cmd, toNativeString(""), nullptr, nullptr, false);
diff --git a/src/Process.cpp b/src/Process.cpp
new file mode 100644
index 0000000..d82da42
--- /dev/null
+++ b/src/Process.cpp
@@ -0,0 +1,33 @@
+#include "../include/dchat/Process.hpp"
+
+namespace dchat
+{
+ std::string escapeCommand(const std::string &cmd)
+ {
+ std::string result;
+ result.reserve(cmd.size());
+ bool escape = false;
+
+ for(char c : cmd)
+ {
+ if(c == '\\')
+ escape = !escape;
+ else
+ {
+ if(escape)
+ result += "\\";
+
+ if(c == '"')
+ result += "\\\""; // \"
+ else if(c == '\'')
+ result += "\\'"; // \'
+ else
+ result += c;
+
+ escape = false;
+ }
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/Room.cpp b/src/Room.cpp
index b558f87..bc87c05 100644
--- a/src/Room.cpp
+++ b/src/Room.cpp
@@ -105,7 +105,9 @@ namespace dchat
inviteKey = id->toString() + odhtdb::bin2hex((const char*)encryptionKey->data, encryptionKey->size);
inviteKey += getInviteKeyChecksum(inviteKey);
odhtdb::InfoHash inviteInfoHash = odhtdb::InfoHash::generateHash((const u8*)inviteKey.data(), inviteKey.size());
- // TODO: Use database instead of custom message. Then both parties dont have to be online to add user to room
+ // TODO: Use database instead of custom message. Then both parties dont have to be online to add user to room.
+ // TODO: Only listen for invite request if we have the right to add users to the room.
+ // TODO: Make this optional (should be possible to turn off from gui/settings)
rooms->database->receiveCustomMessage(inviteInfoHash, [this](const void *data, usize size)
{
sibs::SafeSerializer serializer;
@@ -160,37 +162,62 @@ namespace dchat
assert(localUser);
assert(publicKeyToKeyPairMap.find(localUser->publicKey) != publicKeyToKeyPairMap.end());
assert(encryptionKey);
+
sibs::SafeSerializer serializer;
serializer.add(RoomDataType::CHANGE_AVATAR);
serializer.add((u16)url.size());
- serializer.add((const u8*)url.data(), url.size());
+ serializer.add(url.data(), url.size());
auto keyPair = publicKeyToKeyPairMap[localUser->publicKey];
odhtdb::DatabaseNode roomNode(encryptionKey, id);
rooms->database->addData(roomNode, *keyPair, { serializer.getBuffer().data(), serializer.getSize() });
}
- void Room::setNickname(const std::string &nickname)
+ void Room::setUserNickname(const std::string &nickname)
{
assert(localUser);
assert(publicKeyToKeyPairMap.find(localUser->publicKey) != publicKeyToKeyPairMap.end());
assert(encryptionKey);
+
sibs::SafeSerializer serializer;
serializer.add(RoomDataType::NICKNAME_CHANGE);
serializer.add((u8)nickname.size());
- serializer.add((const u8*)nickname.data(), nickname.size());
+ serializer.add(nickname.data(), nickname.size());
auto keyPair = publicKeyToKeyPairMap[localUser->publicKey];
odhtdb::DatabaseNode roomNode(encryptionKey, id);
rooms->database->addData(roomNode, *keyPair, { serializer.getBuffer().data(), serializer.getSize() });
}
+ bool Room::setName(const std::string &name)
+ {
+ assert(localUser);
+ assert(encryptionKey);
+
+ int userPermissionLevel = rooms->database->getUserLowestPermissionLevel(*id, localUser->publicKey);
+ if(userPermissionLevel != odhtdb::PERMISSION_LEVEL_ADMIN)
+ {
+ odhtdb::Log::debug("Room change name: attempted by user %s who is not an admin (permission level: %d)\n", localUser->publicKey.toString().c_str(), userPermissionLevel);
+ return false;
+ }
+
+ sibs::SafeSerializer serializer;
+ serializer.add(RoomDataType::CHANGE_ROOM_NAME);
+ serializer.add((u16)name.size());
+ serializer.add(name.data(), name.size());
+ auto keyPair = publicKeyToKeyPairMap[localUser->publicKey];
+ odhtdb::DatabaseNode roomNode(encryptionKey, id);
+ rooms->database->addData(roomNode, *keyPair, { serializer.getBuffer().data(), serializer.getSize() });
+ return true;
+ }
+
void Room::publishMessage(const std::string &msg)
{
assert(localUser);
assert(publicKeyToKeyPairMap.find(localUser->publicKey) != publicKeyToKeyPairMap.end());
assert(encryptionKey);
+
sibs::SafeSerializer serializer;
serializer.add(RoomDataType::ADD_MESSAGE);
- serializer.add((const u8*)msg.data(), msg.size());
+ serializer.add(msg.data(), msg.size());
auto keyPair = publicKeyToKeyPairMap[localUser->publicKey];
odhtdb::DatabaseNode roomNode(encryptionKey, id);
rooms->database->addData(roomNode, *keyPair, { serializer.getBuffer().data(), serializer.getSize() });
@@ -248,6 +275,7 @@ namespace dchat
callbackRequest.timestampSeconds = ntp::NtpTimestamp::fromCombined(request.timestamp).seconds;
callbackRequest.loadedFromCache = request.loadedFromCache;
callbackRequest.isLocalUser = isLocalUser;
+ callbackRequest.waitedToJoin = false;
callbackFuncs.addUserCallbackFunc(callbackRequest);
}
}
@@ -415,6 +443,7 @@ namespace dchat
auto user = room->addUserLocally(*request.userToAddPublicKey, group);
bool isLocalUser = false;
+ bool waitedToJoin = false;
if(!room->localUser)
{
std::lock_guard<std::recursive_mutex> waitingToJoinRoomLock(waitingToJoinRoomMutex);
@@ -424,6 +453,7 @@ namespace dchat
room->setLocalUser(user, waitingToJoinRoomIt->second);
waitingToJoinRoom.erase(waitingToJoinRoomIt);
isLocalUser = true;
+ waitedToJoin = true;
}
else
{
@@ -445,6 +475,7 @@ namespace dchat
callbackRequest.timestampSeconds = ntp::NtpTimestamp::fromCombined(request.timestamp).seconds;
callbackRequest.loadedFromCache = request.loadedFromCache;
callbackRequest.isLocalUser = isLocalUser;
+ callbackRequest.waitedToJoin = waitedToJoin;
callbackFuncs.addUserCallbackFunc(callbackRequest);
}
}
@@ -523,20 +554,23 @@ namespace dchat
odhtdb::DatabaseNode nodeInfo(newNode->getNodeEncryptionKey(), newNode->getRequestHash());
database->storeNodeInfoForUserEncrypted(nodeInfo, currentUsername, currentUserPassword, *newNode->getNodeAdminKeyPair());
- sibs::SafeSerializer serializer;
- serializer.add(RoomDataType::CHANGE_ROOM_NAME);
- serializer.add((u16)name.size());
- serializer.add(name.data(), name.size());
- database->addData(nodeInfo, *newNode->getNodeAdminKeyPair(), { serializer.getBuffer().data(), serializer.getSize() });
+ roomIt->second->setName(name);
return roomIt->second;
}
- void Rooms::requestJoinRoom(const std::string &inviteKey, const std::string &message)
+ bool Rooms::requestJoinRoom(const std::string &inviteKey, const std::string &message)
{
if(!loggedIn)
throw std::runtime_error("You need to be logged in to join a room");
- assert(inviteKey.size() == 130);
+ if(inviteKey.size() != 130)
+ {
+ std::string errMsg = "Invalid invite key length. Expected to be 130 bytes, was ";
+ errMsg += std::to_string(inviteKey.size());
+ errMsg += " byte(s)";
+ throw std::runtime_error(errMsg);
+ }
+
std::lock_guard<std::recursive_mutex> waitingToJoinRoomLock(waitingToJoinRoomMutex);
std::string roomIdHex = inviteKey.substr(0, 64);
std::string roomIdBin = odhtdb::hex2bin(roomIdHex.c_str(), roomIdHex.size());
@@ -545,12 +579,12 @@ namespace dchat
if(waitingToJoinRoom.find(*roomId) != waitingToJoinRoom.end())
{
fprintf(stderr, "You have already requested to join room %s\n", roomIdHex.c_str());
- return;
+ return false;
}
if(roomById.find(*roomId) != roomById.end())
{
fprintf(stderr, "You are already a member of the room %s\n", roomIdHex.c_str());
- return;
+ return false;
}
std::string roomEncryptionKeyHex = inviteKey.substr(64, 64);
std::string roomEncryptionKeyStr = odhtdb::hex2bin(roomEncryptionKeyHex.c_str(), roomEncryptionKeyHex.size());
@@ -558,10 +592,7 @@ namespace dchat
memcpy(newEncryptionKey->data, roomEncryptionKeyStr.data(), roomEncryptionKeyStr.size());
std::string inviteKeyChecksum = inviteKey.substr(128, 2);
if(inviteKeyChecksum != getInviteKeyChecksum(inviteKey.substr(0, 128)))
- {
- fprintf(stderr, "Invalid invite key, checksum is incorrect. Did you type the invite key incorrectly?\n");
- return;
- }
+ throw std::runtime_error("Invalid invite key, checksum is incorrect. Did you type the invite key incorrectly?");
auto ourNewUser = std::make_shared<odhtdb::Signature::KeyPair>();
sibs::SafeSerializer serializer;
@@ -582,5 +613,6 @@ namespace dchat
odhtdb::DatabaseNode roomNode(newEncryptionKey, roomId);
database->seed(roomNode);
database->storeNodeInfoForUserEncrypted(roomNode, currentUsername, currentUserPassword, *ourNewUser);
+ return true;
}
}