swarm: allow admin to kick invited members

/invited was not checked for kicking member, add this directory
and cleanup the function for resolving votes too.

Documentation is updated:
https://git.jami.net/savoirfairelinux/jami-project/-/wikis/technical/\
2.3.-Swarm#remove-a-device-from-a-conversation

https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/340

Change-Id: I18882066e3e42ced8ed656da3b1d2ed0a19929cf
This commit is contained in:
Sébastien Blin
2022-02-14 16:58:19 -05:00
committed by Adrien Béraud
parent 3db5a90828
commit 4ddf1c6f2e
2 changed files with 208 additions and 144 deletions

View File

@ -855,7 +855,7 @@ ConversationRepository::Impl::checkVote(const std::string& userDevice,
std::string votedFile = "";
for (const auto& changedFile : changedFiles) {
// NOTE: libgit2 return a diff with /, not DIR_SEPARATOR_DIR
if (changedFile == std::string("devices") + "/" + userDevice + ".crt") {
if (changedFile == fmt::format("devices/{}.crt", userDevice)) {
deviceFile = changedFile;
} else if (changedFile.find("votes") == 0) {
votedFile = changedFile;
@ -931,13 +931,13 @@ ConversationRepository::Impl::checkVote(const std::string& userDevice,
// Check that peer voted is only other device or other member
if (type == "members") {
// Voted uri = not self
if (votedUri == userUri) {
JAMI_ERR("Detected vote for self: %s", votedUri.c_str());
return false;
}
// file in members or admin
if (!memberCertificate(votedUri, treeOld)) {
// file in members or admin or invited
auto invitedFile = fmt::format("invited/{}", votedUri);
if (!memberCertificate(votedUri, treeOld) && !fileAtTree(invitedFile, treeOld)) {
JAMI_ERR("No member file found for vote: %s", votedUri.c_str());
return false;
}
@ -948,7 +948,7 @@ ConversationRepository::Impl::checkVote(const std::string& userDevice,
return false;
}
// File in devices
deviceFile = std::string("devices") + "/" + votedUri + ".crt";
deviceFile = fmt::format("devices/{}.crt", votedUri);
if (!fileAtTree(deviceFile, treeOld)) {
JAMI_ERR("No device file found for vote: %s", votedUri.c_str());
return false;
@ -1126,10 +1126,11 @@ ConversationRepository::Impl::checkValidRemove(const std::string& userDevice,
auto changedFiles = ConversationRepository::changedFiles(diffStats(commitId, parentId));
// NOTE: libgit2 return a diff with /, not DIR_SEPARATOR_DIR
std::string deviceFile = std::string("devices") + "/" + userDevice + ".crt";
std::string adminFile = std::string("admins") + "/" + uriMember + ".crt";
std::string memberFile = std::string("members") + "/" + uriMember + ".crt";
std::string crlFile = std::string("CRLs") + "/" + uriMember;
std::string deviceFile = fmt::format("devices/{}.crt", userDevice);
std::string adminFile = fmt::format("admins/{}.crt", uriMember);
std::string memberFile = fmt::format("members/{}.crt", uriMember);
std::string crlFile = fmt::format("CRLs/{}", uriMember);
std::string invitedFile = fmt::format("invited/{}", uriMember);
std::vector<std::string> voters;
std::vector<std::string> devicesRemoved;
std::vector<std::string> bannedFiles;
@ -1140,8 +1141,9 @@ ConversationRepository::Impl::checkValidRemove(const std::string& userDevice,
const std::regex regex_banned("banned.(members|devices).(\\w+)\\.crt");
std::smatch base_match;
for (const auto& f : changedFiles) {
if (f == deviceFile || f == adminFile || f == memberFile || f == crlFile) {
if (f == deviceFile || f == adminFile || f == memberFile || f == crlFile || f == invitedFile) {
// Ignore
continue;
} else if (std::regex_match(f, base_match, regex_votes)) {
if (base_match.size() != 4 or base_match[2] != uriMember) {
JAMI_ERR("Invalid vote file detected: %s", f.c_str());
@ -1170,7 +1172,7 @@ ConversationRepository::Impl::checkValidRemove(const std::string& userDevice,
// Check that removed devices are for removed member (or directly uriMember)
for (const auto& deviceUri : devicesRemoved) {
deviceFile = std::string("devices") + "/" + deviceUri + ".crt";
deviceFile = fmt::format("devices/{}.crt", deviceUri);
if (!fileAtTree(deviceFile, treeOld)) {
JAMI_ERR("device not found added (%s)", deviceFile.c_str());
return false;
@ -3072,18 +3074,17 @@ ConversationRepository::resolveVote(const std::string& uri, bool isDevice)
return {};
std::string repoPath = git_repository_workdir(repo.get());
std::string adminsPath = repoPath + "admins";
std::string invitedPath = repoPath + "invited";
std::string membersPath = repoPath + "members";
std::string devicesPath = repoPath + "devices";
std::string bannedPath = repoPath + "banned";
auto isAdmin = fileutils::isFile(fileutils::getFullPath(adminsPath, uri + ".crt"));
std::string type = "members";
if (isDevice)
type = "devices";
else if (isAdmin)
type = "admins";
auto isInvited = fileutils::isFile(fileutils::getFullPath(invitedPath, uri));
auto voteDirectory = repoPath + DIR_SEPARATOR_STR + "votes" + DIR_SEPARATOR_STR
+ (isDevice ? "devices" : "members") + DIR_SEPARATOR_STR + uri;
auto voteDirectory = fmt::format("{}/votes/{}/{}",
repoPath,
(isDevice ? "devices" : "members"),
uri);
for (const auto& certificate : fileutils::readDirectory(adminsPath)) {
if (certificate.find(".crt") == std::string::npos) {
JAMI_WARN("Incorrect file found: %s/%s", adminsPath.c_str(), certificate.c_str());
@ -3102,14 +3103,16 @@ ConversationRepository::resolveVote(const std::string& uri, bool isDevice)
fileutils::removeAll(voteDirectory, true);
// Move from device or members file into banned
std::string originFilePath = membersPath;
std::string originFilePath = fmt::format("{}/{}.crt", membersPath, uri);
if (isDevice)
originFilePath = devicesPath;
originFilePath = fmt::format("{}/{}.crt", devicesPath, uri);
else if (isAdmin)
originFilePath = adminsPath;
originFilePath += DIR_SEPARATOR_STR + uri + ".crt";
originFilePath = fmt::format("{}/{}.crt", adminsPath, uri);
else if (isInvited)
originFilePath = fmt::format("{}/{}", invitedPath, uri);
auto destPath = bannedPath + DIR_SEPARATOR_STR + (isDevice ? "devices" : "members");
auto destFilePath = destPath + DIR_SEPARATOR_STR + uri + ".crt";
auto destFilePath = fmt::format("{}/{}.crt", destPath, uri);
if (!fileutils::recursive_mkdir(destPath, 0700)) {
JAMI_ERR("Error when creating %s. Abort resolving vote", destPath.c_str());
return {};

View File

@ -38,6 +38,7 @@
#include "conversation/conversationcommon.h"
using namespace std::string_literals;
using namespace std::literals::chrono_literals;
using namespace DRing::Account;
namespace jami {
@ -61,6 +62,7 @@ public:
void testAddOfflineMemberThenConnects();
void testGetMembers();
void testRemoveMember();
void testRemoveInvitedMember();
void testMemberBanNoBadFile();
void testMemberTryToRemoveAdmin();
void testBannedMemberCannotSendMessage();
@ -92,6 +94,7 @@ private:
CPPUNIT_TEST(testAddOfflineMemberThenConnects);
CPPUNIT_TEST(testGetMembers);
CPPUNIT_TEST(testRemoveMember);
CPPUNIT_TEST(testRemoveInvitedMember);
CPPUNIT_TEST(testMemberBanNoBadFile);
CPPUNIT_TEST(testMemberTryToRemoveAdmin);
CPPUNIT_TEST(testBannedMemberCannotSendMessage);
@ -212,7 +215,7 @@ ConversationMembersEventTest::testRemoveConversationNoMember()
// Start conversation
auto convId = DRing::startConversation(aliceId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
@ -280,8 +283,7 @@ ConversationMembersEventTest::testRemoveConversationWithMember()
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
@ -291,23 +293,22 @@ ConversationMembersEventTest::testRemoveConversationWithMember()
auto bobInvitedFile = repoPath + DIR_SEPARATOR_STR + "invited" + DIR_SEPARATOR_STR + bobUri;
CPPUNIT_ASSERT(fileutils::isFile(bobInvitedFile));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
auto clonedPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + bobAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(clonedPath));
bobInvitedFile = clonedPath + DIR_SEPARATOR_STR + "invited" + DIR_SEPARATOR_STR + bobUri;
CPPUNIT_ASSERT(!fileutils::isFile(bobInvitedFile));
// Remove conversation from alice once member confirmed
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
bobSeeAliceRemoved = false;
DRing::removeConversation(aliceId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return bobSeeAliceRemoved; }));
std::this_thread::sleep_for(std::chrono::seconds(3));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobSeeAliceRemoved; }));
std::this_thread::sleep_for(3s);
CPPUNIT_ASSERT(!fileutils::isDirectory(repoPath));
}
@ -349,8 +350,7 @@ ConversationMembersEventTest::testAddMember()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
@ -358,9 +358,9 @@ ConversationMembersEventTest::testAddMember()
// Check created files
auto bobInvited = repoPath + DIR_SEPARATOR_STR + "invited" + DIR_SEPARATOR_STR + bobUri;
CPPUNIT_ASSERT(fileutils::isFile(bobInvited));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
auto clonedPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + bobAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(clonedPath));
@ -414,10 +414,10 @@ ConversationMembersEventTest::testMemberAddedNoBadFile()
aliceAccount->sendTextMessage(bobUri,
{{"application/invite+json",
"{\"conversationId\":\"" + convId + "\"}"}});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
errorDetected = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -454,10 +454,10 @@ ConversationMembersEventTest::testAddOfflineMemberThenConnects()
DRing::addConversationMember(aliceId, convId, carlaUri);
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return requestReceived; }));
DRing::acceptConversationRequest(carlaId, convId);
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; });
cv.wait_for(lk, 30s, [&]() { return conversationReady; });
auto clonedPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + carlaAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(clonedPath));
@ -508,7 +508,7 @@ ConversationMembersEventTest::testGetMembers()
messageReceived = false;
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&]() { return messageReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return messageReceived; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
@ -522,13 +522,13 @@ ConversationMembersEventTest::testGetMembers()
CPPUNIT_ASSERT(members[1]["uri"] == bobUri);
CPPUNIT_ASSERT(members[1]["role"] == "invited");
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
messageReceived = false;
DRing::acceptConversationRequest(bobId, convId);
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; });
cv.wait_for(lk, 30s, [&]() { return conversationReady; });
members = DRing::getConversationMembers(bobId, convId);
CPPUNIT_ASSERT(members.size() == 2);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&]() { return messageReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return messageReceived; }));
members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 2);
CPPUNIT_ASSERT(members[0]["uri"] == aliceAccount->getUsername());
@ -582,19 +582,17 @@ ConversationMembersEventTest::testRemoveMember()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Now check that alice, has the only admin, can remove bob
memberMessageGenerated = false;
voteMessageGenerated = false;
DRing::removeConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && voteMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; }));
auto members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 1);
CPPUNIT_ASSERT(members[0]["uri"] == aliceAccount->getUsername());
@ -602,6 +600,96 @@ ConversationMembersEventTest::testRemoveMember()
DRing::unregisterSignalHandlers();
}
void
ConversationMembersEventTest::testRemoveInvitedMember()
{
auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId);
auto aliceUri = aliceAccount->getUsername();
auto bobUri = bobAccount->getUsername();
auto carlaUri = carlaAccount->getUsername();
auto convId = DRing::startConversation(aliceId);
std::mutex mtx;
std::unique_lock<std::mutex> lk {mtx};
std::condition_variable cv;
std::map<std::string, std::shared_ptr<DRing::CallbackWrapperBase>> confHandlers;
bool conversationReady = false, requestReceived = false;
confHandlers.insert(
DRing::exportable_callback<DRing::ConversationSignal::ConversationRequestReceived>(
[&](const std::string& /*accountId*/,
const std::string& /* conversationId */,
std::map<std::string, std::string> /*metadatas*/) {
requestReceived = true;
cv.notify_one();
}));
bool carlaConnected = false;
confHandlers.insert(
DRing::exportable_callback<DRing::ConfigurationSignal::VolatileDetailsChanged>(
[&](const std::string&, const std::map<std::string, std::string>&) {
auto details = carlaAccount->getVolatileAccountDetails();
auto deviceAnnounced = details[DRing::Account::VolatileProperties::DEVICE_ANNOUNCED];
if (deviceAnnounced == "true") {
carlaConnected = true;
cv.notify_one();
}
}));
confHandlers.insert(DRing::exportable_callback<DRing::ConversationSignal::ConversationReady>(
[&](const std::string& accountId, const std::string& conversationId) {
if (accountId == bobId && conversationId == convId) {
conversationReady = true;
cv.notify_one();
}
}));
bool voteMessageGenerated = false, memberMessageGenerated = false, carlaMessageReceived;
confHandlers.insert(
DRing::exportable_callback<DRing::ConversationSignal::MessageReceived>(
[&](const std::string& accountId,
const std::string& conversationId,
std::map<std::string, std::string> message) {
if (accountId == aliceId && conversationId == convId && message["type"] == "vote")
voteMessageGenerated = true;
else if (accountId == aliceId && conversationId == convId
&& message["type"] == "member")
memberMessageGenerated = true;
else if (accountId == carlaId && message["type"] == "text/plain" && message["body"] == "hi")
carlaMessageReceived = true;
cv.notify_one();
}));
DRing::registerSignalHandlers(confHandlers);
// Add carla
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaConnected; }));
DRing::addConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(carlaId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Invite Alice
requestReceived = false;
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
auto members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 3);
// Now check that alice, has the only admin, can remove bob
memberMessageGenerated = false;
voteMessageGenerated = false;
DRing::removeConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; }));
members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 2);
// Check that Carla is still able to sync
DRing::sendMessage(aliceId, convId, "hi"s, "");
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaMessageReceived; }));
DRing::unregisterSignalHandlers();
}
void
ConversationMembersEventTest::testMemberBanNoBadFile()
{
@ -671,32 +759,28 @@ ConversationMembersEventTest::testMemberBanNoBadFile()
}));
DRing::registerSignalHandlers(confHandlers);
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; }));
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
requestReceived = false;
DRing::addConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
messageBobReceived = false;
DRing::acceptConversationRequest(carlaId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && messageBobReceived;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; }));
memberMessageGenerated = false;
voteMessageGenerated = false;
addFile(aliceAccount, convId, "BADFILE");
DRing::removeConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -738,13 +822,11 @@ ConversationMembersEventTest::testMemberTryToRemoveAdmin()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Now check that alice, has the only admin, can remove bob
memberMessageGenerated = false;
@ -800,28 +882,24 @@ ConversationMembersEventTest::testBannedMemberCannotSendMessage()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
memberMessageGenerated = false;
voteMessageGenerated = false;
DRing::removeConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && voteMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; }));
auto members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 1);
// Now check that alice doesn't receive a message from Bob
aliceMessageReceived = false;
DRing::sendMessage(bobId, convId, "hi"s, "");
CPPUNIT_ASSERT(
!cv.wait_for(lk, std::chrono::seconds(30), [&]() { return aliceMessageReceived; }));
CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return aliceMessageReceived; }));
DRing::unregisterSignalHandlers();
}
@ -869,27 +947,23 @@ ConversationMembersEventTest::testAddBannedMember()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
// Now check that alice, has the only admin, can remove bob
memberMessageGenerated = false;
voteMessageGenerated = false;
DRing::removeConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && voteMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; }));
// Then check that bobUri cannot be re-added
memberMessageGenerated = false;
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(
!cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
DRing::unregisterSignalHandlers();
}
@ -960,37 +1034,33 @@ ConversationMembersEventTest::testMemberCannotBanOther()
}));
DRing::registerSignalHandlers(confHandlers);
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; }));
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
requestReceived = false;
memberMessageGenerated = false;
DRing::addConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
messageBobReceived = false;
DRing::acceptConversationRequest(carlaId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && messageBobReceived;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; }));
// Now Carla remove Bob as a member
errorDetected = false;
messageBobReceived = false;
// remove from member & add into banned without voting for the ban
simulateRemoval(carlaAccount, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
DRing::sendMessage(aliceId, convId, "hi"s, "");
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return messageBobReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageBobReceived; }));
}
void
@ -1062,31 +1132,27 @@ ConversationMembersEventTest::testCheckAdminFakeAVoteIsDetected()
}));
DRing::registerSignalHandlers(confHandlers);
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; }));
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; }));
requestReceived = false;
DRing::addConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return requestReceived && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; }));
memberMessageGenerated = false;
messageBobReceived = false;
DRing::acceptConversationRequest(carlaId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return memberMessageGenerated && messageBobReceived;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; }));
// Now Alice remove Carla without a vote. Bob will not receive the message
errorDetected = false;
simulateRemoval(aliceAccount, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
}
void
@ -1195,18 +1261,17 @@ ConversationMembersEventTest::testCommitUnauthorizedUser()
auto convId = DRing::startConversation(aliceId);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + bobAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(repoPath));
// Wait that alice sees Bob
CPPUNIT_ASSERT(
cv.wait_for(lk, std::chrono::seconds(30), [&]() { return messageAliceReceived == 2; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; }));
// Add commit from invalid user
Json::Value root;
@ -1220,7 +1285,7 @@ ConversationMembersEventTest::testCommitUnauthorizedUser()
errorDetected = false;
DRing::sendMessage(bobId, convId, "hi"s, "");
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -1277,7 +1342,7 @@ ConversationMembersEventTest::testMemberJoinsNoBadFile()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->convModule()->addConversationMember(convId, carlaUri, false);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(5), [&] { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; }));
// Cp conversations & convInfo
auto repoPathAlice = fileutils::get_data_dir() + DIR_SEPARATOR_STR
@ -1299,12 +1364,12 @@ ConversationMembersEventTest::testMemberJoinsNoBadFile()
// Start Carla, should merge and all messages should be there
carlaAccount->convModule()->loadConversations(); // Because of the copy
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; }));
errorDetected = false;
DRing::sendMessage(carlaId, convId, "hi"s, "");
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -1361,7 +1426,7 @@ ConversationMembersEventTest::testMemberAddedNoCertificate()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->convModule()->addConversationMember(convId, carlaUri, false);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(5), [&] { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; }));
// Cp conversations & convInfo
auto repoPathAlice = fileutils::get_data_dir() + DIR_SEPARATOR_STR
@ -1393,12 +1458,12 @@ ConversationMembersEventTest::testMemberAddedNoCertificate()
// Start Carla, should merge and all messages should be there
carlaAccount->convModule()->loadConversations(); // Because of the copy
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; }));
DRing::sendMessage(carlaId, convId, "hi"s, "");
errorDetected = false;
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -1455,7 +1520,7 @@ ConversationMembersEventTest::testMemberJoinsInviteRemoved()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->convModule()->addConversationMember(convId, carlaUri, false);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(5), [&] { return memberMessageGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; }));
// Cp conversations & convInfo
auto repoPathAlice = fileutils::get_data_dir() + DIR_SEPARATOR_STR
@ -1492,12 +1557,12 @@ ConversationMembersEventTest::testMemberJoinsInviteRemoved()
// Start Carla, should merge and all messages should be there
carlaAccount->convModule()->loadConversations(); // Because of the copy
Manager::instance().sendRegister(carlaId, true);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&] { return carlaConnected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; }));
DRing::sendMessage(carlaId, convId, "hi"s, "");
errorDetected = false;
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; }));
DRing::unregisterSignalHandlers();
}
@ -1547,11 +1612,10 @@ ConversationMembersEventTest::testFailAddMemberInOneToOne()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->addContact(bobUri);
aliceAccount->sendTrustRequest(bobUri, {});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(5), [&]() { return !convId.empty(); }));
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !convId.empty(); }));
memberMessageGenerated = false;
DRing::addConversationMember(aliceId, convId, carlaUri);
CPPUNIT_ASSERT(
!cv.wait_for(lk, std::chrono::seconds(5), [&]() { return memberMessageGenerated; }));
CPPUNIT_ASSERT(!cv.wait_for(lk, 5s, [&]() { return memberMessageGenerated; }));
}
void
@ -1613,18 +1677,15 @@ ConversationMembersEventTest::testOneToOneFetchWithNewMemberRefused()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->addContact(bobUri);
aliceAccount->sendTrustRequest(bobUri, {});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return !convId.empty() && requestReceived;
}));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; }));
CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri));
memberMessageGenerated = false;
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() {
return conversationReady && memberMessageGenerated;
}));
CPPUNIT_ASSERT(
cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; }));
errorDetected = false;
generateFakeInvite(aliceAccount, convId, carlaUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return errorDetected; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; }));
}
void
@ -1668,7 +1729,7 @@ ConversationMembersEventTest::testConversationMemberEvent()
}));
DRing::registerSignalHandlers(confHandlers);
DRing::addConversationMember(aliceId, convId, bobUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return memberAddGenerated; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberAddGenerated; }));
// Assert that repository exists
auto repoPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + aliceAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
@ -1676,9 +1737,9 @@ ConversationMembersEventTest::testConversationMemberEvent()
// Check created files
auto bobInvited = repoPath + DIR_SEPARATOR_STR + "invited" + DIR_SEPARATOR_STR + bobUri;
CPPUNIT_ASSERT(fileutils::isFile(bobInvited));
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
DRing::acceptConversationRequest(bobId, convId);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return conversationReady; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; }));
auto clonedPath = fileutils::get_data_dir() + DIR_SEPARATOR_STR + bobAccount->getAccountID()
+ DIR_SEPARATOR_STR + "conversations" + DIR_SEPARATOR_STR + convId;
CPPUNIT_ASSERT(fileutils::isDirectory(clonedPath));
@ -1724,7 +1785,7 @@ ConversationMembersEventTest::testGetConversationsMembersWhileSyncing()
DRing::registerSignalHandlers(confHandlers);
aliceAccount->addContact(bobUri);
aliceAccount->sendTrustRequest(bobUri, {});
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(30), [&]() { return requestReceived; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; }));
Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately
CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri));
@ -1758,7 +1819,7 @@ ConversationMembersEventTest::testGetConversationMembersWithSelfOneOne()
}));
DRing::registerSignalHandlers(confHandlers);
aliceAccount->addContact(aliceUri);
CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(5), [&]() { return !convId.empty(); }));
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !convId.empty(); }));
auto members = DRing::getConversationMembers(aliceId, convId);
CPPUNIT_ASSERT(members.size() == 1);