Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1035 from advancedtelematic/feat/altualizr_repo_m…
Browse files Browse the repository at this point in the history
…ore_improvements

Add image without actual file
  • Loading branch information
lbonn authored Jan 8, 2019
2 parents 951808a + e79fa6f commit 45d8053
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 10 deletions.
19 changes: 19 additions & 0 deletions src/aktualizr_repo/director_repo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,23 @@ void DirectorRepo::signTargets() {
Utils::writeFile(path_ / "repo/director/targets.json",
Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Targets(), targets_unsigned)));
boost::filesystem::remove(path_ / "repo/director/staging/targets.json");
}
void DirectorRepo::emptyTargets() {
const boost::filesystem::path staging = path_ / "repo/director/staging/targets.json";
Json::Value targets_unsigned;
targets_unsigned = Utils::parseJSONFile(staging);
targets_unsigned["targets"].clear();
Utils::writeFile(staging, Utils::jsonToCanonicalStr(targets_unsigned));
}

void DirectorRepo::oldTargets() {
const boost::filesystem::path current = path_ / "repo/director/targets.json";
const boost::filesystem::path staging = path_ / "repo/director/staging/targets.json";

if (!boost::filesystem::exists(current)) {
throw std::runtime_error(std::string("targets.json not found at ") + current.c_str() + "!");
}
Json::Value targets_current = Utils::parseJSONFile(current);
Json::Value targets_unsigned = targets_current["signed"];
Utils::writeFile(staging, Utils::jsonToCanonicalStr(targets_unsigned));
}
2 changes: 2 additions & 0 deletions src/aktualizr_repo/director_repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class DirectorRepo : public Repo {
void addTarget(const std::string &target_name, const Json::Value &target, const std::string &hardware_id,
const std::string &ecu_serial);
void signTargets();
void emptyTargets();
void oldTargets();
};

#endif // DIRECTOR_REPO_H_
29 changes: 23 additions & 6 deletions src/aktualizr_repo/image_repo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ void ImageRepo::addImage(const boost::filesystem::path &image_path) {
}
std::string image = Utils::readFile(image_path);

Json::Value targets = Utils::parseJSONFile(repo_dir / "targets.json")["signed"];
std::string target_name = image_path.filename().string();
targets["targets"][target_name]["length"] = Json::UInt64(image.size());
targets["targets"][target_name]["hashes"]["sha256"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(image)));
targets["targets"][target_name]["hashes"]["sha512"] =
boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(image)));
Json::Value target;
target["length"] = Json::UInt64(image.size());
target["hashes"]["sha256"] = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha256digest(image)));
target["hashes"]["sha512"] = boost::algorithm::to_lower_copy(boost::algorithm::hex(Crypto::sha512digest(image)));
addImage(target_name, target);
}

void ImageRepo::addImage(const std::string &name, const Json::Value &target) {
boost::filesystem::path repo_dir(path_ / "repo/image");

Json::Value targets = Utils::parseJSONFile(repo_dir / "targets.json")["signed"];
targets["targets"][name] = target;
targets["version"] = (targets["version"].asUInt()) + 1;

std::string signed_targets = Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Targets(), targets));
Expand All @@ -44,4 +50,15 @@ void ImageRepo::addImage(const boost::filesystem::path &image_path) {
timestamp["meta"]["snapshot.json"]["version"] = snapshot["version"].asUInt();
Utils::writeFile(repo_dir / "timestamp.json",
Utils::jsonToCanonicalStr(signTuf(Uptane::Role::Timestamp(), timestamp)));
}

void ImageRepo::addCustomImage(const std::string &name, const Uptane::Hash &hash, const uint64_t length) {
Json::Value target;
target["length"] = Json::UInt(length);
if (hash.type() == Uptane::Hash::Type::kSha256) {
target["hashes"]["sha256"] = hash.HashString();
} else if (hash.type() == Uptane::Hash::Type::kSha512) {
target["hashes"]["sha512"] = hash.HashString();
}
addImage(name, target);
}
4 changes: 4 additions & 0 deletions src/aktualizr_repo/image_repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ class ImageRepo : public Repo {
ImageRepo(boost::filesystem::path path, const std::string &expires, std::string correlation_id)
: Repo(Uptane::RepositoryType::Image(), std::move(path), expires, std::move(correlation_id)) {}
void addImage(const boost::filesystem::path &image_path);
void addCustomImage(const std::string &name, const Uptane::Hash &hash, uint64_t length);

private:
void addImage(const std::string &name, const Json::Value &target);
};

#endif // IMAGE_REPO_H_
29 changes: 26 additions & 3 deletions src/aktualizr_repo/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ int main(int argc, char **argv) {
// clang-format off
desc.add_options()
("help,h", "print usage")
("command", po::value<std::string>(), "generate|sign|image|addtarget|signtargets")
("command", po::value<std::string>(), "generate|sign|image|addtarget|emptytargets|oldtargets|signtargets")
("path", po::value<boost::filesystem::path>(), "path to the repository")
("filename", po::value<std::string>(), "path to the image")
("hwid", po::value<std::string>(), "target hardware identifier")
Expand All @@ -24,7 +24,11 @@ int main(int argc, char **argv) {
("keyname", po::value<std::string>(), "name of key's role")
("repotype", po::value<std::string>(), "director|image")
("correlationid", po::value<std::string>()->default_value(""), "correlation id")
("keytype", po::value<std::string>()->default_value("RSA2048"), "UPTANE key type");
("keytype", po::value<std::string>()->default_value("RSA2048"), "UPTANE key type")
("targetname", po::value<std::string>(), "target's name (for adding metadata without an actual file)")
("targetsha256", po::value<std::string>(), "target's SHA256 hash (for adding metadata without an actual file)")
("targetsha512", po::value<std::string>(), "target's SHA512 hash (for adding metadata without an actual file)")
("targetlength", po::value<uint64_t>(), "target's length (for adding metadata without an actual file)");
// clang-format on

po::positional_options_description positionalOptions;
Expand Down Expand Up @@ -63,11 +67,30 @@ int main(int argc, char **argv) {
key_type_str >> key_type;
repo.generateRepo(key_type);
} else if (command == "image") {
repo.addImage(vm["filename"].as<std::string>());
if (vm.count("filename") > 0) {
repo.addImage(vm["filename"].as<std::string>());
} else if (vm.count("targetname") > 0 && (vm.count("targetsha256") > 0 || vm.count("targetsha512") > 0) &&
vm.count("targetlength") > 0) {
std::unique_ptr<Uptane::Hash> hash;
if (vm.count("targetsha256") > 0) {
hash = std_::make_unique<Uptane::Hash>(Uptane::Hash::Type::kSha256, vm["targetsha256"].as<std::string>());
} else {
hash = std_::make_unique<Uptane::Hash>(Uptane::Hash::Type::kSha512, vm["targetsha512"].as<std::string>());
}
repo.addCustomImage(vm["targetname"].as<std::string>(), *hash, vm["targetlength"].as<uint64_t>());
} else {
std::cerr
<< "You shoud provide --filename or --targetname, --targetsha256 or --targetsha512, and --targetlength\n";
exit(EXIT_FAILURE);
}
} else if (command == "addtarget") {
repo.addTarget(vm["filename"].as<std::string>(), vm["hwid"].as<std::string>(), vm["serial"].as<std::string>());
} else if (command == "signtargets") {
repo.signTargets();
} else if (command == "emptytargets") {
repo.emptyTargets();
} else if (command == "oldtargets") {
repo.oldTargets();
} else if (command == "sign") {
if (vm.count("repotype") == 0 || vm.count("keyname") == 0) {
std::cerr << "--repotype or --keyname is missing\n";
Expand Down
107 changes: 107 additions & 0 deletions src/aktualizr_repo/repo_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,113 @@ TEST(aktualizr_repo, sign) {
EXPECT_NO_THROW(root.UnpackSignedObject(Uptane::RepositoryType::Director(), json));
}

TEST(aktualizr_repo, image_custom) {
TemporaryDirectory temp_dir;
std::ostringstream keytype_stream;
keytype_stream << key_type;
std::string cmd = generate_repo_exec + " generate " + temp_dir.Path().string() + " --keytype " + keytype_stream.str();
std::string output;
int retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n";
}
cmd = generate_repo_exec + " image " + temp_dir.Path().string();
cmd +=
" --targetname target1 --targetsha256 8ab755c16de6ee9b6224169b36cbf0f2a545f859be385501ad82cdccc240d0a6 "
"--targetlength 123";
retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n";
}

Json::Value image_targets = Utils::parseJSONFile(temp_dir.Path() / "repo/image/targets.json");
EXPECT_EQ(image_targets["signed"]["targets"].size(), 1);
EXPECT_EQ(image_targets["signed"]["targets"]["target1"]["length"].asUInt(), 123);
}

TEST(aktualizr_repo, emptytargets) {
TemporaryDirectory temp_dir;
std::ostringstream keytype_stream;
keytype_stream << key_type;
std::string cmd = generate_repo_exec + " generate " + temp_dir.Path().string() + " --keytype " + keytype_stream.str();
std::string output;
int retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n";
}
cmd = generate_repo_exec + " image " + temp_dir.Path().string();
cmd +=
" --targetname target1 --targetsha256 8ab755c16de6ee9b6224169b36cbf0f2a545f859be385501ad82cdccc240d0a6 "
"--targetlength 123";
retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n";
}

cmd = generate_repo_exec + " addtarget " + temp_dir.Path().string();
cmd += " --filename target1 --hwid hwid123 --serial serial123";
retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n";
}

Json::Value targets = Utils::parseJSONFile(temp_dir.Path() / "repo/director/staging/targets.json");
EXPECT_EQ(targets["targets"].size(), 1);
EXPECT_EQ(targets["targets"]["target1"]["length"].asUInt(), 123);
EXPECT_EQ(targets["targets"]["target1"]["hashes"]["sha256"].asString(),
"8AB755C16DE6EE9B6224169B36CBF0F2A545F859BE385501AD82CDCCC240D0A6");

cmd = generate_repo_exec + " emptytargets " + temp_dir.Path().string();
retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n"
<< "output: " << output;
}

Json::Value empty_targets = Utils::parseJSONFile(temp_dir.Path() / "repo/director/staging/targets.json");
EXPECT_EQ(empty_targets["targets"].size(), 0);
}

TEST(aktualizr_repo, oldtargets) {
TemporaryDirectory temp_dir;
UptaneRepo repo(temp_dir.Path(), "", "");
repo.generateRepo(key_type);
Uptane::Hash hash(Uptane::Hash::Type::kSha256, "8ab755c16de6ee9b6224169b36cbf0f2a545f859be385501ad82cdccc240d0a6");
repo.addCustomImage("target1", hash, 123);
repo.addCustomImage("target2", hash, 321);
repo.addTarget("target1", "test-hw", "test-serial");
repo.signTargets();
repo.addTarget("target2", "test-hw", "test-serial");

Json::Value targets = Utils::parseJSONFile(temp_dir.Path() / "repo/director/staging/targets.json");
EXPECT_EQ(targets["targets"].size(), 2);
EXPECT_EQ(targets["targets"]["target1"]["length"].asUInt(), 123);
EXPECT_EQ(targets["targets"]["target1"]["hashes"]["sha256"].asString(),
"8AB755C16DE6EE9B6224169B36CBF0F2A545F859BE385501AD82CDCCC240D0A6");
EXPECT_EQ(targets["targets"]["target2"]["length"].asUInt(), 321);
EXPECT_EQ(targets["targets"]["target2"]["hashes"]["sha256"].asString(),
"8AB755C16DE6EE9B6224169B36CBF0F2A545F859BE385501AD82CDCCC240D0A6");

Json::Value targets_current = Utils::parseJSONFile(temp_dir.Path() / "repo/director/targets.json");
EXPECT_EQ(targets_current["signed"]["targets"].size(), 1);
EXPECT_EQ(targets_current["signed"]["targets"]["target1"]["length"].asUInt(), 123);
EXPECT_EQ(targets_current["signed"]["targets"]["target1"]["hashes"]["sha256"].asString(),
"8AB755C16DE6EE9B6224169B36CBF0F2A545F859BE385501AD82CDCCC240D0A6");

std::string cmd = generate_repo_exec + " oldtargets " + temp_dir.Path().string();
std::string output;
int retval = Utils::shell(cmd, &output);
if (retval) {
FAIL() << "'" << cmd << "' exited with error code\n"
<< "output: " << output;
}
targets = Utils::parseJSONFile(temp_dir.Path() / "repo/director/staging/targets.json");
EXPECT_EQ(targets["targets"].size(), 1);
EXPECT_EQ(targets["targets"]["target1"]["length"].asUInt(), 123);
EXPECT_EQ(targets["targets"]["target1"]["hashes"]["sha256"].asString(),
"8AB755C16DE6EE9B6224169B36CBF0F2A545F859BE385501AD82CDCCC240D0A6");
}

#ifndef __NO_MAIN__
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
Expand Down
10 changes: 9 additions & 1 deletion src/aktualizr_repo/uptane_repo.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

#include "uptane_repo.h"

UptaneRepo::UptaneRepo(const boost::filesystem::path &path, const std::string &expires,
Expand All @@ -17,4 +18,11 @@ void UptaneRepo::addTarget(const std::string &target_name, const std::string &ha
director_repo_.addTarget(target_name, target, hardware_id, ecu_serial);
}
void UptaneRepo::addImage(const boost::filesystem::path &image_path) { image_repo_.addImage(image_path); }
void UptaneRepo::signTargets() { director_repo_.signTargets(); }
void UptaneRepo::addCustomImage(const std::string &name, const Uptane::Hash &hash, uint64_t length) {
image_repo_.addCustomImage(name, hash, length);
}

void UptaneRepo::signTargets() { director_repo_.signTargets(); }

void UptaneRepo::emptyTargets() { director_repo_.emptyTargets(); }
void UptaneRepo::oldTargets() { director_repo_.oldTargets(); }
3 changes: 3 additions & 0 deletions src/aktualizr_repo/uptane_repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ class UptaneRepo {
void generateRepo(KeyType key_type = KeyType::kRSA2048);
void addTarget(const std::string &target_name, const std::string &hardware_id, const std::string &ecu_serial);
void addImage(const boost::filesystem::path &image_path);
void addCustomImage(const std::string &name, const Uptane::Hash &hash, uint64_t length);
void signTargets();
void emptyTargets();
void oldTargets();

private:
DirectorRepo director_repo_;
Expand Down

0 comments on commit 45d8053

Please sign in to comment.