LCOV - code coverage report
Current view: top level - test/unitTest/conversation - conversationcommon.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 135 168 80.4 %
Date: 2024-12-21 08:56:24 Functions: 8 28 28.6 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  This program is free software: you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation, either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include <cppunit/TestAssert.h>
      19             : #include <cppunit/TestFixture.h>
      20             : #include <cppunit/extensions/HelperMacros.h>
      21             : 
      22             : #include <yaml-cpp/yaml.h>
      23             : #include <filesystem>
      24             : 
      25             : #include "common.h"
      26             : 
      27             : /* Jami */
      28             : #include "account_const.h"
      29             : #include "base64.h"
      30             : #include "jami.h"
      31             : #include "fileutils.h"
      32             : #include "manager.h"
      33             : #include "jamidht/conversation.h"
      34             : #include "jamidht/conversationrepository.h"
      35             : #include "conversation/conversationcommon.h"
      36             : 
      37             : using namespace std::string_literals;
      38             : 
      39             : /* Make GCC quiet about unused functions */
      40             : #pragma GCC diagnostic push
      41             : #pragma GCC diagnostic ignored "-Wunused-function"
      42             : 
      43             : namespace jami {
      44             : 
      45             : void
      46           1 : addVote(std::shared_ptr<JamiAccount> account,
      47             :         const std::string& convId,
      48             :         const std::string& votedUri,
      49             :         const std::string& content)
      50             : {
      51           1 :     ConversationRepository::DISABLE_RESET = true;
      52           2 :     auto repoPath = fileutils::get_data_dir() / account->getAccountID()
      53           4 :                     / "conversations" / convId;
      54           2 :     auto voteDirectory = repoPath / "votes" / "members";
      55           1 :     auto voteFile = voteDirectory / votedUri;
      56           1 :     if (!dhtnet::fileutils::recursive_mkdir(voteDirectory, 0700)) {
      57           0 :         return;
      58             :     }
      59             : 
      60           1 :     std::ofstream file(voteFile);
      61           1 :     if (file.is_open()) {
      62           1 :         file << content;
      63           1 :         file.close();
      64             :     }
      65             : 
      66           1 :     Json::Value json;
      67           1 :     json["uri"] = votedUri;
      68           1 :     json["type"] = "vote";
      69           1 :     Json::StreamWriterBuilder wbuilder;
      70           1 :     wbuilder["commentStyle"] = "None";
      71           1 :     wbuilder["indentation"] = "";
      72           1 :     ConversationRepository cr(account, convId);
      73           1 :     cr.commitMessage(Json::writeString(wbuilder, json), false);
      74           1 : }
      75             : 
      76             : void
      77           3 : simulateRemoval(std::shared_ptr<JamiAccount> account,
      78             :                 const std::string& convId,
      79             :                 const std::string& votedUri)
      80             : {
      81           3 :     ConversationRepository::DISABLE_RESET = true;
      82           6 :     auto repoPath = fileutils::get_data_dir() / account->getAccountID()
      83          12 :                     / "conversations" / convId;
      84           6 :     auto memberFile = repoPath / "members" / (votedUri + ".crt");
      85           6 :     auto bannedFile = repoPath / "banned" / "members"
      86           9 :                       / (votedUri + ".crt");
      87           3 :     std::rename(memberFile.c_str(), bannedFile.c_str());
      88             : 
      89           3 :     git_repository* repo = nullptr;
      90           3 :     if (git_repository_open(&repo, repoPath.c_str()) != 0)
      91           0 :         return;
      92           3 :     GitRepository rep = {std::move(repo), git_repository_free};
      93             : 
      94             :     // git add -A
      95           3 :     git_index* index_ptr = nullptr;
      96           3 :     if (git_repository_index(&index_ptr, repo) < 0)
      97           0 :         return;
      98           3 :     GitIndex index {index_ptr, git_index_free};
      99           3 :     git_strarray array = {nullptr, 0};
     100           3 :     git_index_add_all(index.get(), &array, 0, nullptr, nullptr);
     101           3 :     git_index_write(index.get());
     102           3 :     git_strarray_dispose(&array);
     103             : 
     104           3 :     ConversationRepository cr(account, convId);
     105             : 
     106           3 :     Json::Value json;
     107           3 :     json["action"] = "ban";
     108           3 :     json["uri"] = votedUri;
     109           3 :     json["type"] = "member";
     110           3 :     Json::StreamWriterBuilder wbuilder;
     111           3 :     wbuilder["commentStyle"] = "None";
     112           3 :     wbuilder["indentation"] = "";
     113           3 :     cr.commitMessage(Json::writeString(wbuilder, json));
     114             : 
     115           9 :     libjami::sendMessage(account->getAccountID(),
     116             :                        convId,
     117           6 :                        "trigger the fake history to be pulled"s,
     118             :                        "");
     119           3 : }
     120             : 
     121             : void
     122           8 : addFile(std::shared_ptr<JamiAccount> account,
     123             :         const std::string& convId,
     124             :         const std::string& relativePath,
     125             :         const std::string& content)
     126             : {
     127           8 :     ConversationRepository::DISABLE_RESET = true;
     128          16 :     auto repoPath = fileutils::get_data_dir() / account->getAccountID()
     129          32 :                     / "conversations" / convId;
     130             :     // Add file
     131           8 :     auto p = std::filesystem::path(fileutils::getFullPath(repoPath, relativePath));
     132           8 :     dhtnet::fileutils::recursive_mkdir(p.parent_path());
     133           8 :     std::ofstream file(p);
     134           8 :     if (file.is_open()) {
     135           8 :         file << content;
     136           8 :         file.close();
     137             :     }
     138             : 
     139           8 :     git_repository* repo = nullptr;
     140           8 :     if (git_repository_open(&repo, repoPath.c_str()) != 0)
     141           0 :         return;
     142           8 :     GitRepository rep = {std::move(repo), git_repository_free};
     143             : 
     144             :     // git add -A
     145           8 :     git_index* index_ptr = nullptr;
     146           8 :     if (git_repository_index(&index_ptr, repo) < 0)
     147           0 :         return;
     148           8 :     GitIndex index {index_ptr, git_index_free};
     149           8 :     git_strarray array = {nullptr, 0};
     150           8 :     git_index_add_all(index.get(), &array, 0, nullptr, nullptr);
     151           8 :     git_index_write(index.get());
     152           8 :     git_strarray_dispose(&array);
     153           8 : }
     154             : 
     155             : void
     156           7 : addAll(std::shared_ptr<JamiAccount> account, const std::string& convId)
     157             : {
     158           7 :     ConversationRepository::DISABLE_RESET = true;
     159          14 :     auto repoPath = fileutils::get_data_dir() / account->getAccountID()
     160          28 :                     / "conversations" / convId;
     161             : 
     162           7 :     git_repository* repo = nullptr;
     163           7 :     if (git_repository_open(&repo, repoPath.c_str()) != 0)
     164           0 :         return;
     165           7 :     GitRepository rep = {std::move(repo), git_repository_free};
     166             : 
     167             :     // git add -A
     168           7 :     git_index* index_ptr = nullptr;
     169           7 :     if (git_repository_index(&index_ptr, repo) < 0)
     170           0 :         return;
     171           7 :     GitIndex index {index_ptr, git_index_free};
     172           7 :     git_strarray array = {nullptr, 0};
     173           7 :     git_index_add_all(index.get(), &array, 0, nullptr, nullptr);
     174           7 :     git_index_write(index.get());
     175           7 :     git_strarray_dispose(&array);
     176           7 : }
     177             : 
     178             : void
     179           5 : commit(std::shared_ptr<JamiAccount> account, const std::string& convId, Json::Value& message)
     180             : {
     181           5 :     ConversationRepository::DISABLE_RESET = true;
     182           5 :     ConversationRepository cr(account, convId);
     183             : 
     184           5 :     Json::StreamWriterBuilder wbuilder;
     185           5 :     wbuilder["commentStyle"] = "None";
     186           5 :     wbuilder["indentation"] = "";
     187           5 :     cr.commitMessage(Json::writeString(wbuilder, message));
     188           5 : }
     189             : 
     190             : std::string
     191           3 : commitInRepo(const std::string& path, std::shared_ptr<JamiAccount> account, const std::string& msg)
     192             : {
     193           3 :     ConversationRepository::DISABLE_RESET = true;
     194           3 :     auto deviceId = std::string(account->currentDeviceId());
     195           3 :     auto name = account->getDisplayName();
     196           3 :     if (name.empty())
     197           0 :         name = deviceId;
     198             : 
     199           3 :     git_signature* sig_ptr = nullptr;
     200             :     // Sign commit's buffer
     201           3 :     if (git_signature_new(&sig_ptr, name.c_str(), deviceId.c_str(), std::time(nullptr), 0) < 0) {
     202           0 :         JAMI_ERROR("Unable to create a commit signature.");
     203           0 :         return {};
     204             :     }
     205           3 :     GitSignature sig {sig_ptr, git_signature_free};
     206             : 
     207             :     // Retrieve current index
     208           3 :     git_index* index_ptr = nullptr;
     209           3 :     git_repository* repo = nullptr;
     210             :     // TODO share this repo with GitServer
     211           3 :     if (git_repository_open(&repo, path.c_str()) != 0) {
     212           0 :         JAMI_ERROR("Unable to open repository");
     213           0 :         return {};
     214             :     }
     215             : 
     216           3 :     if (git_repository_index(&index_ptr, repo) < 0) {
     217           0 :         JAMI_ERROR("Unable to open repository index");
     218           0 :         return {};
     219             :     }
     220           3 :     GitIndex index {index_ptr, git_index_free};
     221             : 
     222             :     git_oid tree_id;
     223           3 :     if (git_index_write_tree(&tree_id, index.get()) < 0) {
     224           0 :         JAMI_ERROR("Unable to write initial tree from index");
     225           0 :         return {};
     226             :     }
     227             : 
     228           3 :     git_tree* tree_ptr = nullptr;
     229           3 :     if (git_tree_lookup(&tree_ptr, repo, &tree_id) < 0) {
     230           0 :         JAMI_ERROR("Unable to look up initial tree");
     231           0 :         return {};
     232             :     }
     233           3 :     GitTree tree = {tree_ptr, git_tree_free};
     234             : 
     235             :     git_oid commit_id;
     236           3 :     if (git_reference_name_to_id(&commit_id, repo, "HEAD") < 0) {
     237           0 :         JAMI_ERROR("Unable to get reference for HEAD");
     238           0 :         return {};
     239             :     }
     240             : 
     241           3 :     git_commit* head_ptr = nullptr;
     242           3 :     if (git_commit_lookup(&head_ptr, repo, &commit_id) < 0) {
     243           0 :         JAMI_ERROR("Unable to look up HEAD commit");
     244           0 :         return {};
     245             :     }
     246           3 :     GitCommit head_commit {head_ptr, git_commit_free};
     247             : 
     248           3 :     git_buf to_sign = {};
     249             : #if( LIBGIT2_VER_MAJOR > 1 ) || ( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR >= 8 )
     250             :     // For libgit2 version 1.8.0 and above
     251           3 :     git_commit* const head_ref[1] = {head_commit.get()};
     252             : #else
     253             :     // For libgit2 versions older than 1.8.0
     254             :     const git_commit* head_ref[1] = {head_commit.get()};
     255             : #endif
     256           6 :     if (git_commit_create_buffer(
     257           6 :             &to_sign, repo, sig.get(), sig.get(), nullptr, msg.c_str(), tree.get(), 1, &head_ref[0])
     258           3 :         < 0) {
     259           0 :         JAMI_ERROR("Unable to create commit buffer");
     260           0 :         return {};
     261             :     }
     262             : 
     263             :     // git commit -S
     264           3 :     auto to_sign_vec = std::vector<uint8_t>(to_sign.ptr, to_sign.ptr + to_sign.size);
     265           3 :     auto signed_buf = account->identity().first->sign(to_sign_vec);
     266           3 :     std::string signed_str = base64::encode(signed_buf);
     267           3 :     if (git_commit_create_with_signature(&commit_id,
     268             :                                          repo,
     269           3 :                                          to_sign.ptr,
     270             :                                          signed_str.c_str(),
     271             :                                          "signature")
     272           3 :         < 0) {
     273           0 :         const git_error* err = giterr_last();
     274           0 :         if (err)
     275           0 :             JAMI_ERROR("Unable to sign commit: {}", err->message);
     276           0 :         return {};
     277             :     }
     278             : 
     279             :     // Move commit to main branch
     280           3 :     git_reference* ref_ptr = nullptr;
     281           3 :     if (git_reference_create(&ref_ptr, repo, "refs/heads/main", &commit_id, true, nullptr) < 0) {
     282           0 :         const git_error* err = giterr_last();
     283           0 :         if (err)
     284           0 :             JAMI_ERROR("Unable to move commit to main: {}", err->message);
     285           0 :         return {};
     286             :     }
     287           3 :     git_reference_free(ref_ptr);
     288           3 :     git_repository_free(repo);
     289             : 
     290           3 :     auto commit_str = git_oid_tostr_s(&commit_id);
     291           3 :     if (commit_str) {
     292           9 :         JAMI_LOG("New message added with id: {}", commit_str);
     293           3 :         return commit_str;
     294             :     }
     295             : 
     296           0 :     return {};
     297           3 : }
     298             : 
     299             : } // namespace jami
     300             : 
     301             : #pragma GCC diagnostic pop

Generated by: LCOV version 1.14