-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tuf: Create a new API to encapsulate TUF operations
The API alows a better isolation between aktualizr-lite and libaktualizr, and also allows the use of multiple sources for a same TUF repository. Signed-off-by: Andre Detsch <[email protected]>
- Loading branch information
Showing
12 changed files
with
581 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
cmake_minimum_required (VERSION 3.5) | ||
|
||
set(TARGET tufctl) | ||
project(${TARGET}) | ||
|
||
set(SRC main.cpp) | ||
# set(HEADERS cmds.h) | ||
|
||
add_executable(${TARGET} ${SRC}) | ||
add_dependencies(aktualizr-lite ${TARGET}) | ||
set_property(TARGET ${TARGET} PROPERTY CXX_STANDARD 17) | ||
|
||
set(INCS | ||
${AKLITE_DIR}/include/ | ||
${AKLITE_DIR}/src/ | ||
${AKTUALIZR_DIR}/src/libaktualizr | ||
${AKTUALIZR_DIR}/include | ||
${AKTUALIZR_DIR}/third_party/jsoncpp/include | ||
# odd dependency of libaktualizr/http/httpclient.h | ||
${AKTUALIZR_DIR}/third_party/googletest/googletest/include | ||
${LIBOSTREE_INCLUDE_DIRS} | ||
) | ||
|
||
target_include_directories(${TARGET} PRIVATE ${INCS}) | ||
|
||
target_link_libraries(${TARGET} aktualizr_lite ${AKLITE_OFFLINE_LIB}) | ||
|
||
install(TARGETS ${TARGET} RUNTIME DESTINATION bin) | ||
|
||
# enable creating clang-tidy targets for each source file (see aktualizr/CMakeLists.txt for details) | ||
aktualizr_source_file_checks(${SRC} ${HEADERS}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
#include <boost/property_tree/ini_parser.hpp> | ||
#include <boost/property_tree/json_parser.hpp> | ||
#include <boost/property_tree/ptree.hpp> | ||
#include <boost/property_tree/ptree_fwd.hpp> | ||
#include "aktualizr-lite/tuf/tuf.h" | ||
#include "tuf/akhttpsreposource.h" | ||
#include "tuf/akrepo.h" | ||
#include "tuf/localreposource.h" | ||
|
||
// Strip leading and trailing quotes | ||
std::string strip_quotes(const std::string& value) { | ||
std::string res = value; | ||
res.erase(std::remove(res.begin(), res.end(), '\"'), res.end()); | ||
return res; | ||
} | ||
|
||
int main(int argc, char** argv) { | ||
if (argc < 2) { | ||
std::cerr << "Usage example: " << argv[0] << " repo_sources.toml" << std::endl; | ||
exit(1); | ||
} | ||
|
||
boost::filesystem::path storage_path; | ||
|
||
std::vector<std::shared_ptr<aklite::tuf::RepoSource>> sources; | ||
// Set up | ||
{ | ||
boost::property_tree::ptree pt; | ||
boost::property_tree::ini_parser::read_ini(argv[1], pt); | ||
|
||
std::ostringstream oss; | ||
boost::property_tree::write_json(oss, pt); | ||
std::cout << oss.str(); | ||
|
||
for (boost::property_tree::ptree::iterator pos = pt.begin(); pos != pt.end();) { | ||
std::cout << pos->first << std::endl; | ||
|
||
if (pos->first.rfind("source ") == 0) { | ||
std::cout << "got repo " << pos->first.substr(7) << std::endl; | ||
std::string uri = pos->second.get<std::string>("uri"); | ||
std::cout << "uri " << uri << " " << uri.rfind("\"file://", 0) << std::endl; | ||
|
||
std::shared_ptr<aklite::tuf::RepoSource> source; | ||
if (uri.rfind("\"file://", 0) == 0) { | ||
auto local_path = Utils::stripQuotes(uri).erase(0, strlen("file://")); | ||
source = std::make_shared<aklite::tuf::LocalRepoSource>(pos->first, local_path); | ||
} else { | ||
source = std::make_shared<aklite::tuf::AkHttpsRepoSource>(pos->first, pos->second); | ||
} | ||
sources.push_back(source); | ||
} | ||
|
||
if (pos->first == "storage") { | ||
storage_path = strip_quotes(pos->second.get<std::string>("path")); | ||
} | ||
|
||
++pos; | ||
} | ||
} | ||
|
||
// Try individual fetch operations. sota.toml is not used | ||
{ | ||
for (auto const& source : sources) { | ||
Json::StreamWriterBuilder builder; | ||
builder["indentation"] = " "; | ||
try { | ||
auto json = source->fetchRoot(1); | ||
std::cout << json << std::endl; | ||
} catch (std::runtime_error e) { | ||
std::cout << e.what() << std::endl; | ||
} | ||
try { | ||
auto json = source->fetchTimestamp(); | ||
std::cout << json << std::endl; | ||
} catch (std::runtime_error e) { | ||
std::cout << e.what() << std::endl; | ||
} | ||
|
||
try { | ||
auto json = source->fetchSnapshot(); | ||
std::cout << json << std::endl; | ||
} catch (std::runtime_error e) { | ||
std::cout << e.what() << std::endl; | ||
} | ||
try { | ||
auto json = source->fetchTargets(); | ||
// std::cout << json << std::endl; | ||
} catch (std::runtime_error e) { | ||
std::cout << e.what() << std::endl; | ||
} | ||
} | ||
} | ||
|
||
// Perform TUF refresh for each repo source, using libaktualizr implementation of Repo | ||
{ | ||
aklite::tuf::AkRepo repo(storage_path); | ||
for (auto const& source : sources) { | ||
repo.updateMeta(source); | ||
} | ||
|
||
auto targets = repo.GetTargets(); | ||
for (auto const& target : targets) { | ||
std::cout << target.Name() << " " << target.Sha256Hash() << std::endl; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright (c) 2023 Foundries.io | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#ifndef AKLITE_TUF_TUF_H_ | ||
#define AKLITE_TUF_TUF_H_ | ||
|
||
#include <string> | ||
|
||
#include "json/json.h" | ||
|
||
/** | ||
* This header contains the definition of an EXPERIMENTAL API for accessing TUF | ||
* functionality. It allows for better isolation between Aktualizr-lite and | ||
* libaktualizr, and better handling of multiple metadata sources for a same | ||
* TUF repository (for example, mirrors or pre-fetched metadata files). | ||
*/ | ||
|
||
namespace aklite::tuf { | ||
|
||
/** | ||
* Interface for a TUF repository metadata source. | ||
*/ | ||
class RepoSource { | ||
public: | ||
virtual ~RepoSource() = default; | ||
RepoSource(const RepoSource&) = delete; | ||
RepoSource(const RepoSource&&) = delete; | ||
RepoSource& operator=(const RepoSource&) = delete; | ||
RepoSource& operator=(const RepoSource&&) = delete; | ||
|
||
virtual std::string fetchRoot(int version) = 0; | ||
virtual std::string fetchTimestamp() = 0; | ||
virtual std::string fetchSnapshot() = 0; | ||
virtual std::string fetchTargets() = 0; | ||
|
||
protected: | ||
RepoSource() = default; | ||
}; | ||
|
||
/** | ||
* A high-level representation of a TUF Target in terms applicable to a | ||
* FoundriesFactory. | ||
*/ | ||
class TufTarget { | ||
public: | ||
explicit TufTarget() : name_{"unknown"} {} | ||
TufTarget(std::string name, std::string sha256, int version, Json::Value custom) | ||
: name_(std::move(name)), sha256_(std::move(sha256)), version_(version), custom_(std::move(custom)) {} | ||
|
||
/** | ||
* Return the TUF Target name. This is the key in the targets.json key/value | ||
* singed.metadata dictionary. | ||
*/ | ||
const std::string& Name() const { return name_; } | ||
/** | ||
* Return the sha256 OStree hash of the Target. | ||
*/ | ||
const std::string& Sha256Hash() const { return sha256_; } | ||
/** | ||
* Return the FoundriesFactory CI build number or in TUF, custom.version. | ||
*/ | ||
int Version() const { return version_; } | ||
|
||
/** | ||
* Return TUF custom data for a Target. | ||
*/ | ||
const Json::Value& Custom() const { return custom_; } | ||
|
||
/** | ||
* Is this a known target in the Tuf manifest? There are two common causes | ||
* to this situation: | ||
* 1) A device has been re-registered (sql.db got wiped out) and the | ||
* /var/sota/installed_versions file is missing. The device might | ||
* running the correct target but the system isn't sure. | ||
* 2) A device might be running a Target from a different tag it's not | ||
* configured for. This means the Target isn't present in the targets.json | ||
* this device is getting from the device-gateway. | ||
*/ | ||
bool IsUnknown() const { return name_ == "unknown"; } | ||
|
||
/** | ||
* @brief Compares the given target with the other target | ||
* @param other - the other target to compare with | ||
* @return true if the targets match, otherwise false | ||
*/ | ||
bool operator==(const TufTarget& other) const { | ||
return other.name_ == name_ && other.sha256_ == sha256_ && other.version_ == version_; | ||
} | ||
|
||
private: | ||
std::string name_; | ||
std::string sha256_; | ||
int version_{-1}; | ||
Json::Value custom_; | ||
}; | ||
|
||
/** | ||
* Interface for a TUF specification engine, handling a single repository, | ||
* fed through one or more consistent RepoSource instances. | ||
*/ | ||
class Repo { | ||
public: | ||
virtual ~Repo() = default; | ||
Repo(const Repo&) = delete; | ||
Repo(const Repo&&) = delete; | ||
Repo& operator=(const Repo&) = delete; | ||
Repo& operator=(const Repo&&) = delete; | ||
|
||
virtual std::vector<TufTarget> GetTargets() = 0; | ||
virtual void updateMeta(std::shared_ptr<RepoSource> repo_src) = 0; | ||
|
||
protected: | ||
Repo() = default; | ||
}; | ||
|
||
} // namespace aklite::tuf | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.