Hash verification works for torrents with a single file
This commit is contained in:
parent
6ef11e3256
commit
365a888511
2 changed files with 76 additions and 39 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
||||||
tags
|
tags
|
||||||
subprojects/libstriezel/
|
subprojects/libstriezel
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
|
93
src/main.cpp
93
src/main.cpp
|
@ -10,9 +10,11 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <climits>
|
||||||
#include <boost/variant/apply_visitor.hpp>
|
#include <boost/variant/apply_visitor.hpp>
|
||||||
#include <sha1/sha1.hpp>
|
#include <sha1/sha1.hpp>
|
||||||
#include <sha1/FileSource.hpp>
|
#include <sha1/BufferSource.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::string load_file (const std::string& path) {
|
std::string load_file (const std::string& path) {
|
||||||
|
@ -107,8 +109,9 @@ struct PrintVisitor {
|
||||||
bool skip_first;
|
bool skip_first;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FindStringVisitor : boost::static_visitor<std::string_view> {
|
template <typename T>
|
||||||
FindStringVisitor (std::string_view search_path) {
|
struct FindTVisitor : boost::static_visitor<T> {
|
||||||
|
FindTVisitor (std::string_view search_path) {
|
||||||
auto split = dincore::split(search_path, '/', true, true);
|
auto split = dincore::split(search_path, '/', true, true);
|
||||||
search.reserve(split.size());
|
search.reserve(split.size());
|
||||||
for (const auto& itm : split) {
|
for (const auto& itm : split) {
|
||||||
|
@ -116,28 +119,41 @@ struct FindStringVisitor : boost::static_visitor<std::string_view> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
search_error = false;
|
||||||
|
search_match_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_path_found() const {
|
bool is_path_found() const {
|
||||||
return search.size() == search_match_count;
|
return search.size() == search_match_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view operator() (long long value) {
|
T operator() (long long value) {
|
||||||
|
if constexpr (std::is_same<long long, T>::value)
|
||||||
|
return value;
|
||||||
|
search_error = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view operator() (const duck::TorrentStringType& value) {
|
T operator() (const duck::TorrentStringType& value) {
|
||||||
|
if constexpr (std::is_same<duck::TorrentStringType, T>::value) {
|
||||||
if (is_path_found())
|
if (is_path_found())
|
||||||
return value;
|
return value;
|
||||||
else
|
}
|
||||||
|
search_error = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view operator() (const std::vector<duck::TorrentValue>&) {
|
T operator() (const std::vector<duck::TorrentValue>&) {
|
||||||
|
search_error = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view operator() (const std::map<duck::TorrentStringType, duck::TorrentValue>& value) {
|
T operator() (const std::map<duck::TorrentStringType, duck::TorrentValue>& value) {
|
||||||
if (is_path_found())
|
if (is_path_found()) {
|
||||||
|
search_error = true;
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
auto it_found = value.find(search[search_match_count]);
|
auto it_found = value.find(search[search_match_count]);
|
||||||
if (value.end() == it_found)
|
if (value.end() == it_found)
|
||||||
|
@ -149,6 +165,7 @@ struct FindStringVisitor : boost::static_visitor<std::string_view> {
|
||||||
|
|
||||||
std::vector<std::string> search;
|
std::vector<std::string> search;
|
||||||
std::size_t search_match_count{0};
|
std::size_t search_match_count{0};
|
||||||
|
bool search_error{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::array<std::uint32_t, 5>> collect_hashes (std::string_view hashes) {
|
std::vector<std::array<std::uint32_t, 5>> collect_hashes (std::string_view hashes) {
|
||||||
|
@ -178,19 +195,28 @@ std::vector<std::array<std::uint32_t, 5>> collect_hashes (std::string_view hashe
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view find_item(std::string_view path, const std::vector<duck::TorrentValue>& values) {
|
template <typename T>
|
||||||
FindStringVisitor visitor(path);
|
T find_item(std::string_view path, const std::vector<duck::TorrentValue>& values) {
|
||||||
|
FindTVisitor<T> visitor(path);
|
||||||
for (const auto& value : values) {
|
for (const auto& value : values) {
|
||||||
std::string_view found = boost::apply_visitor(visitor, value);
|
visitor.reset();
|
||||||
if (not found.empty())
|
T found = boost::apply_visitor(visitor, value);
|
||||||
|
if (not visitor.search_error)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHA1::MessageDigest to_hash160_digest (const std::array<std::uint32_t, 5>& arr) {
|
||||||
|
SHA1::MessageDigest hash_found;
|
||||||
|
std::copy_n(arr.begin(), 5, hash_found.hash);
|
||||||
|
return hash_found;
|
||||||
|
}
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
using duck::parse_torrent;
|
using duck::parse_torrent;
|
||||||
|
typedef duck::TorrentStringType torrent_string;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
std::cerr << "Wrong number of parameters. Usage:\n"
|
std::cerr << "Wrong number of parameters. Usage:\n"
|
||||||
|
@ -207,27 +233,38 @@ int main(int argc, const char* argv[]) {
|
||||||
boost::apply_visitor(visitor, value);
|
boost::apply_visitor(visitor, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
auto source_hashes = find_item<torrent_string>("/info/pieces", values);
|
||||||
auto source_hashes = find_item("/info/pieces", values);
|
|
||||||
std::cout << "Got source_hashes with size " << source_hashes.size() << '\n';
|
std::cout << "Got source_hashes with size " << source_hashes.size() << '\n';
|
||||||
auto hashes = collect_hashes(source_hashes);
|
auto hashes = collect_hashes(source_hashes);
|
||||||
std::cout << "Got " << hashes.size() << " hashes\n";
|
std::cout << "Got " << hashes.size() << " hashes\n";
|
||||||
|
|
||||||
if (not hashes.empty()) {
|
std::string file_name = std::string{find_item<torrent_string>("/info/name", values)};
|
||||||
SHA1::MessageDigest hash_found;
|
|
||||||
std::copy_n(hashes.front().begin(), 5, hash_found.hash);
|
|
||||||
std::cout << hash_found.toHexString() << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view file_name = find_item("/info/name", values);
|
|
||||||
std::cout << "Found file name \"" << file_name << "\"\n";
|
std::cout << "Found file name \"" << file_name << "\"\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
SHA1::MessageDigest hash160;
|
const auto piece_length = find_item<long long int>("/info/piece length", values);
|
||||||
SHA1::FileSource file_source;
|
std::ifstream istream(file_name, std::ios::in|std::ios::binary);
|
||||||
file_source.open(std::string{file_name});
|
|
||||||
hash160 = SHA1::computeFromSource(file_source);
|
if (istream.is_open()) {
|
||||||
std::cout << hash160.toHexString() << " " << file_name << '\n';
|
std::vector<std::uint8_t> buff(piece_length);
|
||||||
|
std::size_t hash_index = 0;
|
||||||
|
std::size_t match_count = 0;
|
||||||
|
|
||||||
|
while (istream.read(reinterpret_cast<char*>(buff.data()), piece_length).gcount() > 0) {
|
||||||
|
SHA1::BufferSource buff_source(buff.data(), istream.gcount() * CHAR_BIT);
|
||||||
|
SHA1::MessageDigest calculated_hash = SHA1::computeFromSource(buff_source);
|
||||||
|
SHA1::MessageDigest stored_hash = to_hash160_digest(hashes[hash_index]);
|
||||||
|
std::cout << stored_hash.toHexString() << " " <<
|
||||||
|
calculated_hash.toHexString() << " " << file_name << '\n';
|
||||||
|
++hash_index;
|
||||||
|
if (stored_hash == calculated_hash)
|
||||||
|
++match_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Hash verified " << match_count << '/' << hashes.size() << '\n';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "Error: opening \"" << file_name << "\" failed\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue