diff options
author | Philipp Kerling <pkerling@casix.org> | 2018-03-17 21:25:47 +0100 |
---|---|---|
committer | Philipp Kerling <pkerling@casix.org> | 2018-04-05 11:39:45 +0200 |
commit | 1ba0b4c431f8285e193867c77d19d81bfe3adb1c (patch) | |
tree | c2362a7a3c994b40cfebc33bb6048768351dc4a6 | |
parent | e7ec1be2e52538096dd70bfa715321f52b1129cd (diff) |
[addons] Validate addons.xml against provided hash
-rw-r--r-- | addons/repository.xbmc.org/addon.xml | 2 | ||||
-rw-r--r-- | xbmc/addons/Repository.cpp | 27 | ||||
-rw-r--r-- | xbmc/addons/Repository.h | 4 |
3 files changed, 28 insertions, 5 deletions
diff --git a/addons/repository.xbmc.org/addon.xml b/addons/repository.xbmc.org/addon.xml index 185ddd348f..4d6552c757 100644 --- a/addons/repository.xbmc.org/addon.xml +++ b/addons/repository.xbmc.org/addon.xml @@ -8,7 +8,7 @@ </requires> <extension point="xbmc.addon.repository"> <info>http://mirrors.kodi.tv/addons/leia/addons.xml.gz</info> - <checksum>http://mirrors.kodi.tv/addons/leia/addons.xml.gz?sha256</checksum> + <checksum verify="sha256">http://mirrors.kodi.tv/addons/leia/addons.xml.gz?sha256</checksum> <datadir>https://mirrors.kodi.tv/addons/leia</datadir> <artdir>http://mirrors.kodi.tv/addons/leia</artdir> <hashes>sha256</hashes> diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp index 9f28c27fd0..ffd2ea7128 100644 --- a/xbmc/addons/Repository.cpp +++ b/xbmc/addons/Repository.cpp @@ -21,6 +21,7 @@ #include "Repository.h" #include <iterator> +#include <tuple> #include <utility> #include "ServiceBroker.h" @@ -42,6 +43,7 @@ #include "TextureDatabase.h" #include "URL.h" #include "utils/Base64.h" +#include "utils/Digest.h" #include "utils/JobManager.h" #include "utils/log.h" #include "utils/Mime.h" @@ -53,6 +55,7 @@ using namespace XFILE; using namespace ADDON; using namespace KODI::MESSAGING; +using KODI::UTILITY::CDigest; using KODI::MESSAGING::HELPERS::DialogResponse; @@ -119,6 +122,12 @@ CRepository::DirInfo CRepository::ParseDirConfiguration(cp_cfg_element_t* config auto const& mgr = CServiceBroker::GetAddonMgr(); DirInfo dir; dir.checksum = mgr.GetExtValue(configuration, "checksum"); + std::string checksumStr = mgr.GetExtValue(configuration, "checksum@verify"); + if (!checksumStr.empty()) + { + dir.verifyChecksum = true; + dir.checksumType = CDigest::TypeFromString(checksumStr); + } dir.info = mgr.GetExtValue(configuration, "info"); dir.datadir = mgr.GetExtValue(configuration, "datadir"); dir.artdir = mgr.GetExtValue(configuration, "artdir"); @@ -210,7 +219,7 @@ bool CRepository::FetchChecksum(const std::string& url, std::string& checksum) n return true; } -bool CRepository::FetchIndex(const DirInfo& repo, VECADDONS& addons) noexcept +bool CRepository::FetchIndex(const DirInfo& repo, std::string const& digest, VECADDONS& addons) noexcept { XFILE::CCurlFile http; http.SetAcceptEncoding("gzip"); @@ -222,6 +231,16 @@ bool CRepository::FetchIndex(const DirInfo& repo, VECADDONS& addons) noexcept return false; } + if (repo.verifyChecksum) + { + std::string actualDigest = CDigest::Calculate(repo.checksumType, response); + if (!StringUtils::EqualsNoCase(digest, actualDigest)) + { + CLog::Log(LOGERROR, "CRepository: {} index has wrong digest {}, expected: {}", repo.info, actualDigest, digest); + return false; + } + } + if (URIUtils::HasExtension(repo.info, ".gz") || CMime::GetFileTypeFromMime(http.GetProperty(XFILE::FILE_PROPERTY_MIME_TYPE)) == CMime::EFileType::FileTypeGZip) { @@ -242,6 +261,7 @@ CRepository::FetchStatus CRepository::FetchIfChanged(const std::string& oldCheck std::string& checksum, VECADDONS& addons) const { checksum = ""; + std::vector<std::tuple<DirInfo const&, std::string>> dirChecksums; for (const auto& dir : m_dirs) { if (!dir.checksum.empty()) @@ -252,6 +272,7 @@ CRepository::FetchStatus CRepository::FetchIfChanged(const std::string& oldCheck CLog::Log(LOGERROR, "CRepository: failed read '%s'", dir.checksum.c_str()); return STATUS_ERROR; } + dirChecksums.emplace_back(dir, part); checksum += part; } } @@ -259,10 +280,10 @@ CRepository::FetchStatus CRepository::FetchIfChanged(const std::string& oldCheck if (oldChecksum == checksum && !oldChecksum.empty()) return STATUS_NOT_MODIFIED; - for (const auto& dir : m_dirs) + for (const auto& dirTuple : dirChecksums) { VECADDONS tmp; - if (!FetchIndex(dir, tmp)) + if (!FetchIndex(std::get<0>(dirTuple), std::get<1>(dirTuple), tmp)) return STATUS_ERROR; addons.insert(addons.end(), tmp.begin(), tmp.end()); } diff --git a/xbmc/addons/Repository.h b/xbmc/addons/Repository.h index 63515d49d1..654a8b5300 100644 --- a/xbmc/addons/Repository.h +++ b/xbmc/addons/Repository.h @@ -40,6 +40,8 @@ namespace ADDON AddonVersion version{""}; std::string info; std::string checksum; + bool verifyChecksum{false}; + KODI::UTILITY::CDigest::Type checksumType; std::string datadir; std::string artdir; bool hashes{false}; @@ -77,7 +79,7 @@ namespace ADDON private: static bool FetchChecksum(const std::string& url, std::string& checksum) noexcept; - static bool FetchIndex(const DirInfo& repo, VECADDONS& addons) noexcept; + static bool FetchIndex(const DirInfo& repo, std::string const& digest, VECADDONS& addons) noexcept; static DirInfo ParseDirConfiguration(cp_cfg_element_t* configuration); |