aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Kerling <pkerling@casix.org>2018-03-17 21:25:47 +0100
committerPhilipp Kerling <pkerling@casix.org>2018-04-05 11:39:45 +0200
commit1ba0b4c431f8285e193867c77d19d81bfe3adb1c (patch)
treec2362a7a3c994b40cfebc33bb6048768351dc4a6
parente7ec1be2e52538096dd70bfa715321f52b1129cd (diff)
[addons] Validate addons.xml against provided hash
-rw-r--r--addons/repository.xbmc.org/addon.xml2
-rw-r--r--xbmc/addons/Repository.cpp27
-rw-r--r--xbmc/addons/Repository.h4
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);