LCOV - code coverage report
Current view: top level - foo/src/plugin - jamipluginmanager.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 12 303 4.0 %
Date: 2025-12-18 10:07:43 Functions: 2 34 5.9 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2025 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 "jamipluginmanager.h"
      19             : #include "pluginsutils.h"
      20             : #include "fileutils.h"
      21             : #include "archiver.h"
      22             : #include "logger.h"
      23             : #include "manager.h"
      24             : #include "jami/plugin_manager_interface.h"
      25             : #include "store_ca_crt.cpp"
      26             : 
      27             : #include <fstream>
      28             : #include <stdexcept>
      29             : #include <msgpack.hpp>
      30             : 
      31             : #define FAILURE                         -1
      32             : #define SUCCESS                         0
      33             : #define PLUGIN_ALREADY_INSTALLED        100 /* Plugin already installed with the same version */
      34             : #define PLUGIN_OLD_VERSION              200 /* Plugin already installed with a newer version */
      35             : #define SIGNATURE_VERIFICATION_FAILED   300
      36             : #define CERTIFICATE_VERIFICATION_FAILED 400
      37             : #define INVALID_PLUGIN                  500
      38             : 
      39             : #ifdef WIN32
      40             : #define LIB_TYPE   ".dll"
      41             : #define LIB_PREFIX ""
      42             : #else
      43             : #ifdef __APPLE__
      44             : #define LIB_TYPE   ".dylib"
      45             : #define LIB_PREFIX "lib"
      46             : #else
      47             : #define LIB_TYPE   ".so"
      48             : #define LIB_PREFIX "lib"
      49             : #endif
      50             : #endif
      51             : 
      52             : namespace jami {
      53             : 
      54          32 : JamiPluginManager::JamiPluginManager()
      55          32 :     : callsm_ {pm_}
      56          32 :     , chatsm_ {pm_}
      57          32 :     , webviewsm_ {pm_}
      58          64 :     , preferencesm_ {pm_}
      59             : {
      60          32 :     registerServices();
      61          32 : }
      62             : 
      63             : std::string
      64           0 : JamiPluginManager::getPluginAuthor(const std::string& rootPath, const std::string& pluginId)
      65             : {
      66           0 :     auto cert = PluginUtils::readPluginCertificate(rootPath, pluginId);
      67           0 :     if (!cert) {
      68           0 :         JAMI_ERROR("Unable to read plugin certificate");
      69           0 :         return {};
      70             :     }
      71           0 :     return cert->getIssuerName();
      72           0 : }
      73             : 
      74             : std::map<std::string, std::string>
      75           0 : JamiPluginManager::getPluginDetails(const std::string& rootPath, bool reset)
      76             : {
      77           0 :     auto detailsIt = pluginDetailsMap_.find(rootPath);
      78           0 :     if (detailsIt != pluginDetailsMap_.end()) {
      79           0 :         if (!reset)
      80           0 :             return detailsIt->second;
      81           0 :         pluginDetailsMap_.erase(detailsIt);
      82             :     }
      83             : 
      84           0 :     std::map<std::string, std::string> details = PluginUtils::parseManifestFile(PluginUtils::manifestPath(rootPath),
      85           0 :                                                                                 rootPath);
      86           0 :     if (!details.empty()) {
      87           0 :         auto itIcon = details.find("iconPath");
      88           0 :         itIcon->second.insert(0, rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH);
      89             : 
      90           0 :         auto itImage = details.find("backgroundPath");
      91           0 :         itImage->second.insert(0, rootPath + DIR_SEPARATOR_CH + "data" + DIR_SEPARATOR_CH);
      92             : 
      93           0 :         details["soPath"] = rootPath + DIR_SEPARATOR_CH + LIB_PREFIX + details["id"] + LIB_TYPE;
      94           0 :         details["author"] = getPluginAuthor(rootPath, details["id"]);
      95           0 :         detailsIt = pluginDetailsMap_.emplace(rootPath, std::move(details)).first;
      96           0 :         return detailsIt->second;
      97             :     }
      98           0 :     return {};
      99           0 : }
     100             : 
     101             : std::vector<std::string>
     102           0 : JamiPluginManager::getInstalledPlugins()
     103             : {
     104             :     // Gets all plugins in standard path
     105           0 :     auto pluginsPath = fileutils::get_data_dir() / "plugins";
     106           0 :     std::vector<std::string> pluginsPaths;
     107           0 :     std::error_code ec;
     108           0 :     for (const auto& entry : std::filesystem::directory_iterator(pluginsPath, ec)) {
     109           0 :         const auto& p = entry.path();
     110           0 :         if (PluginUtils::checkPluginValidity(p))
     111           0 :             pluginsPaths.emplace_back(p.string());
     112           0 :     }
     113             : 
     114             :     // Gets plugins installed in non standard path
     115           0 :     std::vector<std::string> nonStandardInstalls = jami::Manager::instance().pluginPreferences.getInstalledPlugins();
     116           0 :     for (auto& path : nonStandardInstalls) {
     117           0 :         if (PluginUtils::checkPluginValidity(path))
     118           0 :             pluginsPaths.emplace_back(path);
     119             :     }
     120             : 
     121           0 :     return pluginsPaths;
     122           0 : }
     123             : 
     124             : bool
     125           0 : JamiPluginManager::checkPluginCertificatePublicKey(const std::string& oldJplPath, const std::string& newJplPath)
     126             : {
     127           0 :     std::map<std::string, std::string> oldDetails = PluginUtils::parseManifestFile(PluginUtils::manifestPath(oldJplPath),
     128           0 :                                                                                    oldJplPath);
     129           0 :     std::error_code ec;
     130           0 :     if (oldDetails.empty()
     131           0 :         || !std::filesystem::is_regular_file(oldJplPath + DIR_SEPARATOR_CH + oldDetails["id"] + ".crt", ec)
     132           0 :         || !std::filesystem::is_regular_file(newJplPath, ec))
     133           0 :         return false;
     134             :     try {
     135           0 :         auto oldCert = PluginUtils::readPluginCertificate(oldJplPath, oldDetails["id"]);
     136           0 :         auto newCert = PluginUtils::readPluginCertificateFromArchive(newJplPath);
     137           0 :         if (!oldCert || !newCert) {
     138           0 :             return false;
     139             :         }
     140           0 :         return oldCert->getPublicKey() == newCert->getPublicKey();
     141           0 :     } catch (const std::exception& e) {
     142           0 :         JAMI_ERR() << e.what();
     143           0 :         return false;
     144           0 :     }
     145             :     return true;
     146           0 : }
     147             : 
     148             : bool
     149           0 : JamiPluginManager::checkPluginCertificateValidity(dht::crypto::Certificate* cert)
     150             : {
     151           0 :     if (!cert || !*cert)
     152           0 :         return false;
     153           0 :     trust_.add(crypto::Certificate(store_ca_crt, sizeof(store_ca_crt)));
     154           0 :     auto result = trust_.verify(*cert);
     155           0 :     if (!result) {
     156           0 :         JAMI_ERROR("Certificate verification failed: {}", result.toString());
     157             :     }
     158           0 :     return (bool) result;
     159             : }
     160             : 
     161             : std::map<std::string, std::string>
     162           0 : JamiPluginManager::getPlatformInfo()
     163             : {
     164           0 :     return PluginUtils::getPlatformInfo();
     165             : }
     166             : 
     167             : bool
     168           0 : JamiPluginManager::checkPluginSignatureFile(const std::string& jplPath)
     169             : {
     170             :     // check if the file exists
     171           0 :     std::error_code ec;
     172           0 :     if (!std::filesystem::is_regular_file(jplPath, ec)) {
     173           0 :         return false;
     174             :     }
     175             :     try {
     176           0 :         auto signatures = PluginUtils::readPluginSignatureFromArchive(jplPath);
     177           0 :         auto manifest = PluginUtils::readPluginManifestFromArchive(jplPath);
     178           0 :         const std::string& name = manifest["id"];
     179           0 :         auto filesPath = archiver::listFilesFromArchive(jplPath);
     180           0 :         for (const auto& file : filesPath) {
     181             :             // we skip the signatures and signatures.sig file
     182           0 :             if (file == "signatures" || file == "signatures.sig")
     183           0 :                 continue;
     184             :             // we also skip the plugin certificate
     185           0 :             if (file == name + ".crt")
     186           0 :                 continue;
     187             : 
     188           0 :             if (signatures.count(file) == 0) {
     189           0 :                 return false;
     190             :             }
     191             :         }
     192           0 :     } catch (const std::exception& e) {
     193           0 :         return false;
     194           0 :     }
     195           0 :     return true;
     196             : }
     197             : 
     198             : bool
     199           0 : JamiPluginManager::checkPluginSignatureValidity(const std::string& jplPath, dht::crypto::Certificate* cert)
     200             : {
     201           0 :     if (!std::filesystem::is_regular_file(jplPath))
     202           0 :         return false;
     203             :     try {
     204           0 :         const auto& pk = cert->getPublicKey();
     205           0 :         auto signaturesData = archiver::readFileFromArchive(jplPath, "signatures");
     206           0 :         auto signatureFile = PluginUtils::readSignatureFileFromArchive(jplPath);
     207           0 :         if (!pk.checkSignature(signaturesData, signatureFile))
     208           0 :             return false;
     209           0 :         auto signatures = PluginUtils::readPluginSignatureFromArchive(jplPath);
     210           0 :         for (const auto& signature : signatures) {
     211           0 :             auto file = archiver::readFileFromArchive(jplPath, signature.first);
     212           0 :             if (!pk.checkSignature(file, signature.second)) {
     213           0 :                 JAMI_ERROR("{} not correctly signed", signature.first);
     214           0 :                 return false;
     215             :             }
     216           0 :         }
     217           0 :     } catch (const std::exception& e) {
     218           0 :         return false;
     219           0 :     }
     220             : 
     221           0 :     return true;
     222             : }
     223             : 
     224             : bool
     225           0 : JamiPluginManager::checkPluginSignature(const std::string& jplPath, dht::crypto::Certificate* cert)
     226             : {
     227           0 :     if (!std::filesystem::is_regular_file(jplPath) || !cert || !*cert)
     228           0 :         return false;
     229             :     try {
     230           0 :         return checkPluginSignatureValidity(jplPath, cert) && checkPluginSignatureFile(jplPath);
     231           0 :     } catch (const std::exception& e) {
     232           0 :         return false;
     233           0 :     }
     234             : }
     235             : 
     236             : std::unique_ptr<dht::crypto::Certificate>
     237           0 : JamiPluginManager::checkPluginCertificate(const std::string& jplPath, bool force)
     238             : {
     239           0 :     if (!std::filesystem::is_regular_file(jplPath))
     240           0 :         return {};
     241             :     try {
     242           0 :         auto cert = PluginUtils::readPluginCertificateFromArchive(jplPath);
     243           0 :         if (checkPluginCertificateValidity(cert.get()) || force) {
     244           0 :             return cert;
     245             :         }
     246           0 :         return {};
     247           0 :     } catch (const std::exception& e) {
     248           0 :         return {};
     249           0 :     }
     250             : }
     251             : 
     252             : int
     253           0 : JamiPluginManager::installPlugin(const std::string& jplPath, bool force)
     254             : {
     255           0 :     int r {SUCCESS};
     256           0 :     std::error_code ec;
     257           0 :     if (std::filesystem::is_regular_file(jplPath, ec)) {
     258             :         try {
     259           0 :             auto manifestMap = PluginUtils::readPluginManifestFromArchive(jplPath);
     260           0 :             const std::string& name = manifestMap["id"];
     261           0 :             if (name.empty())
     262           0 :                 return INVALID_PLUGIN;
     263           0 :             auto cert = checkPluginCertificate(jplPath, force);
     264           0 :             if (!cert)
     265           0 :                 return CERTIFICATE_VERIFICATION_FAILED;
     266           0 :             if (!checkPluginSignature(jplPath, cert.get()))
     267           0 :                 return SIGNATURE_VERIFICATION_FAILED;
     268           0 :             const std::string& version = manifestMap["version"];
     269           0 :             auto destinationDir = (fileutils::get_data_dir() / "plugins" / name).string();
     270             :             // Find if there is an existing version of this plugin
     271           0 :             const auto alreadyInstalledManifestMap = PluginUtils::parseManifestFile(PluginUtils::manifestPath(
     272             :                                                                                         destinationDir),
     273           0 :                                                                                     destinationDir);
     274             : 
     275           0 :             if (!alreadyInstalledManifestMap.empty()) {
     276           0 :                 if (force) {
     277           0 :                     r = uninstallPlugin(destinationDir);
     278           0 :                     if (r == SUCCESS) {
     279           0 :                         archiver::uncompressArchive(jplPath, destinationDir, PluginUtils::uncompressJplFunction);
     280             :                     }
     281             :                 } else {
     282           0 :                     std::string installedVersion = alreadyInstalledManifestMap.at("version");
     283           0 :                     if (version > installedVersion) {
     284           0 :                         if (!checkPluginCertificatePublicKey(destinationDir, jplPath))
     285           0 :                             return CERTIFICATE_VERIFICATION_FAILED;
     286           0 :                         r = uninstallPlugin(destinationDir);
     287           0 :                         if (r == SUCCESS) {
     288           0 :                             archiver::uncompressArchive(jplPath, destinationDir, PluginUtils::uncompressJplFunction);
     289             :                         }
     290           0 :                     } else if (version == installedVersion) {
     291           0 :                         r = PLUGIN_ALREADY_INSTALLED;
     292             :                     } else {
     293           0 :                         r = PLUGIN_OLD_VERSION;
     294             :                     }
     295           0 :                 }
     296             :             } else {
     297           0 :                 archiver::uncompressArchive(jplPath, destinationDir, PluginUtils::uncompressJplFunction);
     298             :             }
     299           0 :             if (!libjami::getPluginsEnabled()) {
     300           0 :                 libjami::setPluginsEnabled(true);
     301           0 :                 Manager::instance().saveConfig();
     302           0 :                 loadPlugins();
     303           0 :                 return r;
     304             :             }
     305           0 :             libjami::loadPlugin(destinationDir);
     306           0 :         } catch (const std::exception& e) {
     307           0 :             JAMI_ERR() << e.what();
     308           0 :         }
     309             :     }
     310           0 :     return r;
     311             : }
     312             : 
     313             : int
     314           0 : JamiPluginManager::uninstallPlugin(const std::string& rootPath)
     315             : {
     316           0 :     std::error_code ec;
     317           0 :     if (PluginUtils::checkPluginValidity(rootPath)) {
     318           0 :         auto detailsIt = pluginDetailsMap_.find(rootPath);
     319           0 :         if (detailsIt != pluginDetailsMap_.end()) {
     320           0 :             bool loaded = pm_.checkLoadedPlugin(rootPath);
     321           0 :             if (loaded) {
     322           0 :                 JAMI_INFO() << "PLUGIN: unloading before uninstall.";
     323           0 :                 bool status = libjami::unloadPlugin(rootPath);
     324           0 :                 if (!status) {
     325           0 :                     JAMI_INFO() << "PLUGIN: unable to unload, not performing uninstall.";
     326           0 :                     return FAILURE;
     327             :                 }
     328             :             }
     329           0 :             for (const auto& accId : jami::Manager::instance().getAccountList())
     330           0 :                 std::filesystem::remove_all(fileutils::get_data_dir() / accId / "plugins" / detailsIt->second.at("id"),
     331           0 :                                             ec);
     332           0 :             pluginDetailsMap_.erase(detailsIt);
     333             :         }
     334           0 :         return std::filesystem::remove_all(rootPath, ec) ? SUCCESS : FAILURE;
     335             :     } else {
     336           0 :         JAMI_INFO() << "PLUGIN: not installed.";
     337           0 :         return FAILURE;
     338             :     }
     339             : }
     340             : 
     341             : bool
     342           0 : JamiPluginManager::loadPlugin(const std::string& rootPath)
     343             : {
     344             : #ifdef ENABLE_PLUGIN
     345             :     try {
     346           0 :         bool status = pm_.load(getPluginDetails(rootPath).at("soPath"));
     347           0 :         JAMI_INFO() << "PLUGIN: load status - " << status;
     348             : 
     349           0 :         return status;
     350             : 
     351           0 :     } catch (const std::exception& e) {
     352           0 :         JAMI_ERR() << e.what();
     353           0 :         return false;
     354           0 :     }
     355             : #endif
     356             :     return false;
     357             : }
     358             : 
     359             : bool
     360           0 : JamiPluginManager::loadPlugins()
     361             : {
     362             : #ifdef ENABLE_PLUGIN
     363           0 :     bool status = true;
     364           0 :     auto loadedPlugins = jami::Manager::instance().pluginPreferences.getLoadedPlugins();
     365           0 :     for (const auto& pluginPath : loadedPlugins) {
     366           0 :         status &= loadPlugin(pluginPath);
     367             :     }
     368           0 :     return status;
     369             : #endif
     370             :     return false;
     371           0 : }
     372             : 
     373             : bool
     374           0 : JamiPluginManager::unloadPlugin(const std::string& rootPath)
     375             : {
     376             : #ifdef ENABLE_PLUGIN
     377             :     try {
     378           0 :         bool status = pm_.unload(getPluginDetails(rootPath).at("soPath"));
     379           0 :         JAMI_INFO() << "PLUGIN: unload status - " << status;
     380             : 
     381           0 :         return status;
     382           0 :     } catch (const std::exception& e) {
     383           0 :         JAMI_ERR() << e.what();
     384           0 :         return false;
     385           0 :     }
     386             : #endif
     387             :     return false;
     388             : }
     389             : 
     390             : std::vector<std::string>
     391           0 : JamiPluginManager::getLoadedPlugins() const
     392             : {
     393           0 :     std::vector<std::string> loadedSoPlugins = pm_.getLoadedPlugins();
     394           0 :     std::vector<std::string> loadedPlugins {};
     395           0 :     loadedPlugins.reserve(loadedSoPlugins.size());
     396           0 :     std::transform(loadedSoPlugins.begin(),
     397             :                    loadedSoPlugins.end(),
     398             :                    std::back_inserter(loadedPlugins),
     399           0 :                    [](const std::string& soPath) { return PluginUtils::getRootPathFromSoPath(soPath).string(); });
     400           0 :     return loadedPlugins;
     401           0 : }
     402             : 
     403             : std::vector<std::map<std::string, std::string>>
     404           0 : JamiPluginManager::getPluginPreferences(const std::string& rootPath, const std::string& accountId)
     405             : {
     406           0 :     return PluginPreferencesUtils::getPreferences(rootPath, accountId);
     407             : }
     408             : 
     409             : bool
     410           0 : JamiPluginManager::setPluginPreference(const std::filesystem::path& rootPath,
     411             :                                        const std::string& accountId,
     412             :                                        const std::string& key,
     413             :                                        const std::string& value)
     414             : {
     415           0 :     std::string acc = accountId;
     416             : 
     417             :     // If we try to change a preference value linked to an account
     418             :     // but that preference is global, we must ignore accountId and
     419             :     // change the preference for every account
     420           0 :     if (!accountId.empty()) {
     421             :         // Get global preferences
     422           0 :         auto preferences = PluginPreferencesUtils::getPreferences(rootPath, "");
     423             :         // Check if the preference we want to change is global
     424           0 :         auto it = std::find_if(preferences.cbegin(),
     425             :                                preferences.cend(),
     426           0 :                                [key](const std::map<std::string, std::string>& preference) {
     427           0 :                                    return preference.at("key") == key;
     428             :                                });
     429             :         // Ignore accountId if global preference
     430           0 :         if (it != preferences.cend())
     431           0 :             acc.clear();
     432           0 :     }
     433             : 
     434             :     std::map<std::string, std::string> pluginUserPreferencesMap
     435           0 :         = PluginPreferencesUtils::getUserPreferencesValuesMap(rootPath, acc);
     436             :     std::map<std::string, std::string> pluginPreferencesMap = PluginPreferencesUtils::getPreferencesValuesMap(rootPath,
     437           0 :                                                                                                               acc);
     438             : 
     439             :     // If any plugin handler is active we may have to reload it
     440           0 :     bool force {pm_.checkLoadedPlugin(rootPath.string())};
     441             : 
     442             :     // We check if the preference is modified without having to reload plugin
     443           0 :     force &= preferencesm_.setPreference(key, value, rootPath.string(), acc);
     444           0 :     force &= callsm_.setPreference(key, value, rootPath.string());
     445           0 :     force &= chatsm_.setPreference(key, value, rootPath.string());
     446             : 
     447           0 :     if (force)
     448           0 :         unloadPlugin(rootPath.string());
     449             : 
     450             :     // Save preferences.msgpack with modified preferences values
     451           0 :     auto find = pluginPreferencesMap.find(key);
     452           0 :     if (find != pluginPreferencesMap.end()) {
     453           0 :         pluginUserPreferencesMap[key] = value;
     454           0 :         auto preferencesValuesFilePath = PluginPreferencesUtils::valuesFilePath(rootPath, acc);
     455           0 :         std::lock_guard guard(dhtnet::fileutils::getFileLock(preferencesValuesFilePath));
     456           0 :         std::ofstream fs(preferencesValuesFilePath, std::ios::binary);
     457           0 :         if (!fs.good()) {
     458           0 :             if (force) {
     459           0 :                 loadPlugin(rootPath.string());
     460             :             }
     461           0 :             return false;
     462             :         }
     463             :         try {
     464           0 :             msgpack::pack(fs, pluginUserPreferencesMap);
     465           0 :         } catch (const std::exception& e) {
     466           0 :             JAMI_ERR() << e.what();
     467           0 :             if (force) {
     468           0 :                 loadPlugin(rootPath.string());
     469             :             }
     470           0 :             return false;
     471           0 :         }
     472           0 :     }
     473           0 :     if (force) {
     474           0 :         loadPlugin(rootPath.string());
     475             :     }
     476           0 :     return true;
     477           0 : }
     478             : 
     479             : std::map<std::string, std::string>
     480           0 : JamiPluginManager::getPluginPreferencesValuesMap(const std::string& rootPath, const std::string& accountId)
     481             : {
     482           0 :     return PluginPreferencesUtils::getPreferencesValuesMap(rootPath, accountId);
     483             : }
     484             : 
     485             : bool
     486           0 : JamiPluginManager::resetPluginPreferencesValuesMap(const std::string& rootPath, const std::string& accountId)
     487             : {
     488           0 :     bool acc {accountId.empty()};
     489           0 :     bool loaded {pm_.checkLoadedPlugin(rootPath)};
     490           0 :     if (loaded && acc)
     491           0 :         unloadPlugin(rootPath);
     492           0 :     auto status = PluginPreferencesUtils::resetPreferencesValuesMap(rootPath, accountId);
     493           0 :     preferencesm_.resetPreferences(rootPath, accountId);
     494           0 :     if (loaded && acc) {
     495           0 :         loadPlugin(rootPath);
     496             :     }
     497           0 :     return status;
     498             : }
     499             : 
     500             : void
     501          32 : JamiPluginManager::registerServices()
     502             : {
     503             :     // Register getPluginPreferences so that plugin's can receive it's preferences
     504          32 :     pm_.registerService("getPluginPreferences", [](const DLPlugin* plugin, void* data) {
     505           0 :         auto ppp = static_cast<std::map<std::string, std::string>*>(data);
     506           0 :         *ppp = PluginPreferencesUtils::getPreferencesValuesMap(PluginUtils::getRootPathFromSoPath(plugin->getPath()));
     507           0 :         return SUCCESS;
     508             :     });
     509             : 
     510             :     // Register getPluginDataPath so that plugin's can receive the path to it's data folder
     511          32 :     pm_.registerService("getPluginDataPath", [](const DLPlugin* plugin, void* data) {
     512           0 :         auto dataPath = static_cast<std::string*>(data);
     513           0 :         dataPath->assign(PluginUtils::dataPath(plugin->getPath()).string());
     514           0 :         return SUCCESS;
     515             :     });
     516             : 
     517             :     // getPluginAccPreferences is a service that allows plugins to load saved per account preferences.
     518           0 :     auto getPluginAccPreferences = [](const DLPlugin* plugin, void* data) {
     519           0 :         const auto path = PluginUtils::getRootPathFromSoPath(plugin->getPath());
     520           0 :         auto preferencesPtr {(static_cast<PreferencesMap*>(data))};
     521           0 :         if (!preferencesPtr)
     522           0 :             return FAILURE;
     523             : 
     524           0 :         preferencesPtr->emplace("default", PluginPreferencesUtils::getPreferencesValuesMap(path, "default"));
     525             : 
     526           0 :         for (const auto& accId : jami::Manager::instance().getAccountList())
     527           0 :             preferencesPtr->emplace(accId, PluginPreferencesUtils::getPreferencesValuesMap(path, accId));
     528           0 :         return SUCCESS;
     529           0 :     };
     530             : 
     531          32 :     pm_.registerService("getPluginAccPreferences", getPluginAccPreferences);
     532          32 : }
     533             : 
     534             : #ifdef LIBJAMI_TEST
     535             : void
     536           0 : JamiPluginManager::addPluginAuthority(const dht::crypto::Certificate& cert)
     537             : {
     538           0 :     trust_.add(cert);
     539           0 : }
     540             : #endif
     541             : 
     542             : } // namespace jami

Generated by: LCOV version 1.14