Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: normalize slashes of stored vpk paths #9

Merged
merged 2 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.24)

project( verifier
DESCRIPTION "A tool used to verify a game's install."
VERSION 0.3.0
VERSION 0.3.1
)
set( CMAKE_CXX_STANDARD 20 )
set( CMAKE_CXX_STANDARD_REQUIRED ON )
Expand Down
35 changes: 18 additions & 17 deletions src/create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ auto createFromRoot( std::string_view root_, std::string_view indexLocation, boo
}

// relative path
const auto pathRel{ std::filesystem::relative( path, root ).string() };
auto pathRel{ std::filesystem::relative( path, root ).string() };
sourcepp::string::normalizeSlashes( pathRel );

auto breaker{ false };
for ( const auto& exclusion : exclusionREs ) {
Expand Down Expand Up @@ -120,31 +121,31 @@ auto createFromRoot( std::string_view root_, std::string_view indexLocation, boo
const auto size{ std::ftell( file ) };
std::fseek( file, 0, 0 );

// sha256/crc32
CryptoPP::SHA256 sha256er{};
// sha1/crc32
CryptoPP::SHA1 sha1er{};
CryptoPP::CRC32 crc32er{};

unsigned char buffer[2048];
while ( auto bufCount = std::fread( buffer, 1, sizeof( buffer ), file ) ) {
sha256er.Update( buffer, bufCount );
sha1er.Update( buffer, bufCount );
crc32er.Update( buffer, bufCount );
}
std::fclose( file );

std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> sha256Hash{};
sha256er.Final( sha256Hash.data() );
std::array<CryptoPP::byte, CryptoPP::SHA1::DIGESTSIZE> sha1Hash{};
sha1er.Final( sha1Hash.data() );
std::array<CryptoPP::byte, CryptoPP::CRC32::DIGESTSIZE> crc32Hash{};
crc32er.Final( crc32Hash.data() );

std::string sha256HashStr;
std::string sha1HashStr;
std::string crc32HashStr;
{
CryptoPP::StringSource sha256HashStrSink{ sha256Hash.data(), sha256Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha256HashStr } } };
CryptoPP::StringSource sha1HashStrSink{ sha1Hash.data(), sha1Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha1HashStr } } };
CryptoPP::StringSource crc32HashStrSink{ crc32Hash.data(), crc32Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ crc32HashStr } } };
}

// write out entry
writer << fmt::format( ".\xFF{}\xFF{}\xFF{}\xFF{}\xFF\xFD", pathRel, size, sha256HashStr, crc32HashStr );
writer << fmt::format( ".\xFF{}\xFF{}\xFF{}\xFF{}\xFF\xFD", pathRel, size, sha1HashStr, crc32HashStr );
Log_Info( "Processed file `{}`", path );
count += 1;
}
Expand Down Expand Up @@ -192,21 +193,21 @@ static auto enterVPK( std::ofstream& writer, std::string_view vpkPath, std::stri
continue;
}

// sha256 (crc32 is already computed)
CryptoPP::SHA256 sha256er{};
sha256er.Update( reinterpret_cast<const CryptoPP::byte*>( entryData->data() ), entryData->size() );
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> sha256Hash{};
sha256er.Final( sha256Hash.data() );
// sha1 (crc32 is already computed)
CryptoPP::SHA1 sha1er{};
sha1er.Update( reinterpret_cast<const CryptoPP::byte*>( entryData->data() ), entryData->size() );
std::array<CryptoPP::byte, CryptoPP::SHA1::DIGESTSIZE> sha1Hash{};
sha1er.Final( sha1Hash.data() );

std::string sha256HashStr;
std::string sha1HashStr;
std::string crc32HashStr;
{
CryptoPP::StringSource sha256HashStrSink{ sha256Hash.data(), sha256Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha256HashStr } } };
CryptoPP::StringSource sha1HashStrSink{ sha1Hash.data(), sha1Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha1HashStr } } };
CryptoPP::StringSource crc32HashStrSink{ reinterpret_cast<const CryptoPP::byte*>( &entry.crc32 ), sizeof( entry.crc32 ), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ crc32HashStr } } };
}

// write out entry
writer << fmt::format( "{}\xFF{}\xFF{}\xFF{}\xFF{}\xFF\xFD", vpkPathRel, entry.path, entryData->size(), sha256HashStr, crc32HashStr );
writer << fmt::format( "{}\xFF{}\xFF{}\xFF{}\xFF{}\xFF\xFD", vpkPathRel, entry.path, entryData->size(), sha1HashStr, crc32HashStr );
Log_Info( "Processed file `{}/{}`", vpkPath, entry.path );
}
}
Expand Down
44 changes: 22 additions & 22 deletions src/verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "log.hpp"

static auto verifyArchivedFile( const std::string& archivePath, const std::string& entryPath, std::uint64_t expectedSize, std::string_view expectedSha256, std::string_view expectedCrc32, unsigned int& entries, unsigned int& errors ) -> void;
static auto verifyArchivedFile( const std::string& archivePath, const std::string& entryPath, std::uint64_t expectedSize, std::string_view expectedSha1, std::string_view expectedCrc32, unsigned int& entries, unsigned int& errors ) -> void;

static auto splitString( const std::string& string, const std::string& delim ) -> std::vector<std::string>;

Expand Down Expand Up @@ -59,7 +59,7 @@ auto verify( std::string_view root_, std::string_view indexLocation ) -> int {
const auto& archive{ split[ 0 ] };
const auto& pathRel{ split[ 1 ] };
const auto expectedSize{ std::stoull( split[ 2 ] ) };
const auto& expectedSha256{ split[ 3 ] };
const auto& expectedSha1{ split[ 3 ] };
const auto& expectedCrc32{ split[ 4 ] };

// verify it
Expand All @@ -73,7 +73,7 @@ auto verify( std::string_view root_, std::string_view indexLocation ) -> int {
}

if ( insideArchive ) {
verifyArchivedFile( path.string(), pathRel, expectedSize, expectedSha256, expectedCrc32, entries, errors );
verifyArchivedFile( path.string(), pathRel, expectedSize, expectedSha1, expectedCrc32, entries, errors );
continue;
}

Expand Down Expand Up @@ -103,30 +103,30 @@ auto verify( std::string_view root_, std::string_view indexLocation ) -> int {
}
std::fseek( file, 0, 0 );

// sha256/crc32
CryptoPP::SHA256 sha256er{};
// sha1/crc32
CryptoPP::SHA1 sha1er{};
CryptoPP::CRC32 crc32er{};

unsigned char buffer[2048];
while ( auto count = std::fread( buffer, 1, sizeof( buffer ), file ) ) {
sha256er.Update( buffer, count );
sha1er.Update( buffer, count );
crc32er.Update( buffer, count );
}

std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> sha256Hash{};
sha256er.Final( sha256Hash.data() );
std::array<CryptoPP::byte, CryptoPP::SHA1::DIGESTSIZE> sha1Hash{};
sha1er.Final( sha1Hash.data() );
std::array<CryptoPP::byte, CryptoPP::CRC32::DIGESTSIZE> crc32Hash{};
crc32er.Final( crc32Hash.data() );

std::string sha256HashStr;
std::string sha1HashStr;
std::string crc32HashStr;
{
CryptoPP::StringSource sha256HashStrSink{ sha256Hash.data(), sha256Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha256HashStr } } };
CryptoPP::StringSource sha1HashStrSink{ sha1Hash.data(), sha1Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha1HashStr } } };
CryptoPP::StringSource crc32HashStrSink{ crc32Hash.data(), crc32Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ crc32HashStr } } };
}

if ( sha256HashStr != expectedSha256 ) {
Log_Report( pathRel, "Content sha256 doesn't match.", sha256HashStr, expectedSha256 );
if ( sha1HashStr != expectedSha1 ) {
Log_Report( pathRel, "Content sha1 doesn't match.", sha1HashStr, expectedSha1 );
errors += 1;
}

Expand All @@ -146,7 +146,7 @@ auto verify( std::string_view root_, std::string_view indexLocation ) -> int {
return 0;
}

static auto verifyArchivedFile( const std::string& archivePath, const std::string& entryPath, std::uint64_t expectedSize, std::string_view expectedSha256, std::string_view expectedCrc32, unsigned int& entries, unsigned int& errors ) -> void {
static auto verifyArchivedFile( const std::string& archivePath, const std::string& entryPath, std::uint64_t expectedSize, std::string_view expectedSha1, std::string_view expectedCrc32, unsigned int& entries, unsigned int& errors ) -> void {
using namespace vpkpp;

static std::unordered_map<std::string, std::unique_ptr<PackFile>> loadedVPKs{};
Expand Down Expand Up @@ -181,21 +181,21 @@ static auto verifyArchivedFile( const std::string& archivePath, const std::strin
return;
}

// sha256 (crc32 is already computed)
CryptoPP::SHA256 sha256er{};
sha256er.Update( reinterpret_cast<const CryptoPP::byte*>( entryData->data() ), entryData->size() );
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> sha256Hash{};
sha256er.Final( sha256Hash.data() );
// sha1 (crc32 is already computed)
CryptoPP::SHA1 sha1er{};
sha1er.Update( reinterpret_cast<const CryptoPP::byte*>( entryData->data() ), entryData->size() );
std::array<CryptoPP::byte, CryptoPP::SHA1::DIGESTSIZE> sha1Hash{};
sha1er.Final( sha1Hash.data() );

std::string sha256HashStr;
std::string sha1HashStr;
std::string crc32HashStr;
{
CryptoPP::StringSource sha256HashStrSink{ sha256Hash.data(), sha256Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha256HashStr } } };
CryptoPP::StringSource sha1HashStrSink{ sha1Hash.data(), sha1Hash.size(), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ sha1HashStr } } };
CryptoPP::StringSource crc32HashStrSink{ reinterpret_cast<const CryptoPP::byte*>( &entry->crc32 ), sizeof( entry->crc32 ), true, new CryptoPP::HexEncoder{ new CryptoPP::StringSink{ crc32HashStr } } };
}

if ( sha256HashStr != expectedSha256 ) {
Log_Report( fullPath, "Content sha256 doesn't match.", sha256HashStr, expectedSha256 );
if ( sha1HashStr != expectedSha1 ) {
Log_Report( fullPath, "Content sha1 doesn't match.", sha1HashStr, expectedSha1 );
errors += 1;
}

Expand Down