Line data Source code
1 : /*
2 : * Copyright (C) 2021-2024 Savoir-faire Linux Inc.
3 : * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
4 : *
5 : * This program is free software; you can redistribute it and/or modify
6 : * it under the terms of the GNU General Public License as published by
7 : * the Free Software Foundation; either version 3 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 : */
18 :
19 : #include "manager.h"
20 : #include "jamidht/conversationrepository.h"
21 : #include "jamidht/gitserver.h"
22 : #include "jamidht/jamiaccount.h"
23 : #include "../../test_runner.h"
24 : #include "archiver.h"
25 : #include "base64.h"
26 : #include "jami.h"
27 : #include "fileutils.h"
28 : #include "account_const.h"
29 : #include "account_schema.h"
30 : #include "common.h"
31 :
32 : #include <dhtnet/connectionmanager.h>
33 :
34 : #include <cppunit/TestAssert.h>
35 : #include <cppunit/TestFixture.h>
36 : #include <cppunit/extensions/HelperMacros.h>
37 :
38 : #include <git2.h>
39 : #include <condition_variable>
40 : #include <string>
41 : #include <fstream>
42 : #include <streambuf>
43 : #include <filesystem>
44 :
45 : using namespace std::string_literals;
46 : using namespace std::literals::chrono_literals;
47 : using namespace libjami::Account;
48 :
49 : namespace jami {
50 : namespace test {
51 :
52 : class AccountArchiveTest : public CppUnit::TestFixture
53 : {
54 : public:
55 8 : AccountArchiveTest()
56 8 : {
57 : // Init daemon
58 8 : libjami::init(libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
59 8 : if (not Manager::instance().initialized)
60 1 : CPPUNIT_ASSERT(libjami::start("dring-sample.yml"));
61 8 : }
62 16 : ~AccountArchiveTest() { libjami::fini(); }
63 2 : static std::string name() { return "AccountArchive"; }
64 : void setUp();
65 : void tearDown();
66 :
67 : std::string aliceId;
68 : std::string bobId;
69 : std::string bob2Id;
70 :
71 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
72 : std::mutex mtx;
73 : std::unique_lock<std::mutex> lk {mtx};
74 : std::condition_variable cv;
75 : bool aliceReady = false;
76 :
77 : private:
78 : void testExportImportNoPassword();
79 : void testExportImportNoPasswordDoubleGunzip();
80 : void testExportImportPassword();
81 : void testExportImportPasswordDoubleGunzip();
82 : void testExportDht();
83 : void testExportDhtWrongPassword();
84 : void testChangePassword();
85 : void testChangeDhtPort();
86 :
87 2 : CPPUNIT_TEST_SUITE(AccountArchiveTest);
88 1 : CPPUNIT_TEST(testExportImportNoPassword);
89 1 : CPPUNIT_TEST(testExportImportNoPasswordDoubleGunzip);
90 1 : CPPUNIT_TEST(testExportImportPassword);
91 1 : CPPUNIT_TEST(testExportImportPasswordDoubleGunzip);
92 1 : CPPUNIT_TEST(testExportDht);
93 1 : CPPUNIT_TEST(testExportDhtWrongPassword);
94 1 : CPPUNIT_TEST(testChangePassword);
95 1 : CPPUNIT_TEST(testChangeDhtPort);
96 4 : CPPUNIT_TEST_SUITE_END();
97 : };
98 :
99 : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AccountArchiveTest, AccountArchiveTest::name());
100 :
101 : void
102 8 : AccountArchiveTest::setUp()
103 : {
104 16 : auto actors = load_actors_and_wait_for_announcement("actors/alice-bob-password.yml");
105 8 : aliceId = actors["alice"];
106 8 : bobId = actors["bob"];
107 :
108 :
109 8 : confHandlers.insert(
110 16 : libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>(
111 13 : [&](const std::string& accountId,
112 : const std::map<std::string, std::string>& details) {
113 13 : if (accountId != aliceId) {
114 5 : return;
115 : }
116 : try {
117 16 : aliceReady |= accountId == aliceId
118 16 : && details.at(jami::Conf::CONFIG_ACCOUNT_REGISTRATION_STATUS) == "REGISTERED"
119 16 : && details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) == "true";
120 0 : } catch (const std::out_of_range&) {}
121 8 : cv.notify_one();
122 : }));
123 8 : libjami::registerSignalHandlers(confHandlers);
124 8 : }
125 :
126 : void
127 8 : AccountArchiveTest::tearDown()
128 : {
129 8 : if (!bob2Id.empty())
130 4 : wait_for_removal_of({aliceId, bob2Id, bobId});
131 : else
132 21 : wait_for_removal_of({aliceId, bobId});
133 8 : }
134 :
135 : void
136 1 : AccountArchiveTest::testExportImportNoPassword()
137 : {
138 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
139 :
140 1 : CPPUNIT_ASSERT(aliceAccount->exportArchive("test.gz"));
141 :
142 2 : std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
143 1 : details[ConfProperties::ARCHIVE_PATH] = "test.gz";
144 :
145 1 : auto accountId = jami::Manager::instance().addAccount(details);
146 1 : wait_for_announcement_of(accountId);
147 1 : auto alice2Account = Manager::instance().getAccount<JamiAccount>(accountId);
148 1 : CPPUNIT_ASSERT(alice2Account->getUsername() == aliceAccount->getUsername());
149 1 : std::remove("test.gz");
150 1 : wait_for_removal_of(accountId);
151 1 : }
152 :
153 : void
154 1 : AccountArchiveTest::testExportImportNoPasswordDoubleGunzip()
155 : {
156 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
157 :
158 1 : CPPUNIT_ASSERT(aliceAccount->exportArchive("test.gz"));
159 2 : auto dat = fileutils::loadFile("test.gz");
160 1 : archiver::compressGzip(dat, "test.gz");
161 :
162 2 : std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
163 1 : details[ConfProperties::ARCHIVE_PATH] = "test.gz";
164 :
165 1 : auto accountId = jami::Manager::instance().addAccount(details);
166 1 : wait_for_announcement_of(accountId);
167 1 : auto alice2Account = Manager::instance().getAccount<JamiAccount>(accountId);
168 1 : CPPUNIT_ASSERT(alice2Account->getUsername() == aliceAccount->getUsername());
169 1 : std::remove("test.gz");
170 1 : wait_for_removal_of(accountId);
171 1 : }
172 :
173 : void
174 1 : AccountArchiveTest::testExportImportPassword()
175 : {
176 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
177 :
178 1 : CPPUNIT_ASSERT(bobAccount->exportArchive("test.gz", "password", "test"));
179 :
180 2 : std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
181 1 : details[ConfProperties::ARCHIVE_PATH] = "test.gz";
182 1 : details[ConfProperties::ARCHIVE_PASSWORD] = "test";
183 :
184 1 : auto accountId = jami::Manager::instance().addAccount(details);
185 1 : wait_for_announcement_of(accountId);
186 1 : auto bob2Account = Manager::instance().getAccount<JamiAccount>(accountId);
187 1 : CPPUNIT_ASSERT(bob2Account->getUsername() == bobAccount->getUsername());
188 1 : std::remove("test.gz");
189 1 : wait_for_removal_of(accountId);
190 1 : }
191 :
192 : void
193 1 : AccountArchiveTest::testExportImportPasswordDoubleGunzip()
194 : {
195 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
196 :
197 1 : CPPUNIT_ASSERT(bobAccount->exportArchive("test.gz", "password", "test"));
198 2 : auto dat = fileutils::loadFile("test.gz");
199 1 : archiver::compressGzip(dat, "test.gz");
200 :
201 2 : std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
202 1 : details[ConfProperties::ARCHIVE_PATH] = "test.gz";
203 1 : details[ConfProperties::ARCHIVE_PASSWORD] = "test";
204 :
205 1 : auto accountId = jami::Manager::instance().addAccount(details);
206 1 : wait_for_announcement_of(accountId);
207 1 : auto bob2Account = Manager::instance().getAccount<JamiAccount>(accountId);
208 1 : CPPUNIT_ASSERT(bob2Account->getUsername() == bobAccount->getUsername());
209 1 : std::remove("test.gz");
210 1 : wait_for_removal_of(accountId);
211 1 : }
212 :
213 : void
214 1 : AccountArchiveTest::testExportDht()
215 : {
216 1 : std::mutex mtx;
217 1 : std::unique_lock lk {mtx};
218 1 : std::condition_variable cv;
219 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
220 1 : std::string pin;
221 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ExportOnRingEnded>(
222 1 : [&](const std::string& accountId, int status, const std::string& p) {
223 1 : if (accountId == bobId && status == 0)
224 1 : pin = p;
225 1 : cv.notify_one();
226 1 : }));
227 1 : libjami::registerSignalHandlers(confHandlers);
228 1 : CPPUNIT_ASSERT(libjami::exportOnRing(bobId, "test"));
229 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !pin.empty(); }));
230 :
231 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
232 :
233 2 : std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
234 1 : details[ConfProperties::ARCHIVE_PIN] = pin;
235 1 : details[ConfProperties::ARCHIVE_PASSWORD] = "test";
236 :
237 1 : bob2Id = jami::Manager::instance().addAccount(details);
238 1 : wait_for_announcement_of(bob2Id);
239 1 : auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id);
240 1 : CPPUNIT_ASSERT(bob2Account->getUsername() == bobAccount->getUsername());
241 1 : }
242 :
243 : void
244 1 : AccountArchiveTest::testExportDhtWrongPassword()
245 : {
246 1 : std::mutex mtx;
247 1 : std::unique_lock lk {mtx};
248 1 : std::condition_variable cv;
249 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
250 : int status;
251 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ExportOnRingEnded>(
252 1 : [&](const std::string& accountId, int s, const std::string&) {
253 1 : if (accountId == bobId)
254 1 : status = s;
255 1 : cv.notify_one();
256 1 : }));
257 1 : libjami::registerSignalHandlers(confHandlers);
258 1 : CPPUNIT_ASSERT(libjami::exportOnRing(bobId, "wrong"));
259 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return status == 1; }));
260 1 : }
261 :
262 : void
263 1 : AccountArchiveTest::testChangePassword()
264 : {
265 : // Test wrong password, should fail
266 1 : CPPUNIT_ASSERT(!libjami::changeAccountPassword(aliceId, "wrong", "new"));
267 : // Test correct password, should succeed
268 1 : CPPUNIT_ASSERT(libjami::changeAccountPassword(aliceId, "", "new"));
269 : // Now it should fail
270 1 : CPPUNIT_ASSERT(!libjami::changeAccountPassword(aliceId, "", "new"));
271 : // Remove password again (should succeed)
272 1 : CPPUNIT_ASSERT(libjami::changeAccountPassword(aliceId, "new", ""));
273 1 : }
274 :
275 : void
276 1 : AccountArchiveTest::testChangeDhtPort()
277 : {
278 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
279 :
280 1 : std::map<std::string, std::string> newDetails;
281 1 : newDetails[libjami::Account::ConfProperties::DHT_PORT] = "1412";
282 1 : aliceReady = false;
283 1 : libjami::setAccountDetails(aliceId, newDetails);
284 4 : cv.wait_for(lk, 20s, [&] { return aliceReady; });
285 :
286 1 : CPPUNIT_ASSERT(aliceAccount->dht()->getBoundPort() == 1412);
287 :
288 1 : newDetails[libjami::Account::ConfProperties::DHT_PORT] = "1413";
289 1 : aliceReady = false;
290 1 : libjami::setAccountDetails(aliceId, newDetails);
291 4 : cv.wait_for(lk, 20s, [&] { return aliceReady; });
292 :
293 1 : CPPUNIT_ASSERT(aliceAccount->dht()->getBoundPort() == 1413);
294 1 : }
295 :
296 : } // namespace test
297 : } // namespace jami
298 :
299 1 : RING_TEST_RUNNER(jami::test::AccountArchiveTest::name())
|