aries: Implement DecodeBinaryTagData

Not the prettiest implementation, but it seems to work.
This commit is contained in:
Lily Tsuru 2024-03-23 07:24:19 -04:00
parent a5bf226d11
commit 8e78492728
3 changed files with 61 additions and 27 deletions

View File

@ -1,8 +1,9 @@
#include <aries/Tags.hpp> #include <aries/Tags.hpp>
#include <string_view>
namespace ls::aries { namespace ls::aries {
bool ParseTagFieldsToMap(const std::string_view tagFieldData, TagMap& outMap) { bool ParseTagFieldsToMap(const std::string_view tagFieldData, TagMap& outMap) {
// Nothing to parse, // Nothing to parse,
// which isn't exclusively a failure condition. // which isn't exclusively a failure condition.
if(tagFieldData.empty()) if(tagFieldData.empty())
@ -83,35 +84,62 @@ namespace ls::aries {
} }
void SerializeTagFields(const TagMap& map, std::string& outStr) { void SerializeTagFields(const TagMap& map, std::string& outStr) {
std::string tagFieldBuffer{}; std::string tagFieldBuffer {};
// Reserve a sane amount, to avoid allocations when serializing // Reserve a sane amount, to avoid allocations when serializing
// (in most cases; larger tag count MIGHT still cause some allocation pressure). // (in most cases; larger tag count MIGHT still cause some allocation pressure).
tagFieldBuffer.reserve(512); tagFieldBuffer.reserve(512);
// Serialize the tag fields // Serialize the tag fields
for(auto [key, value] : map) for(auto [key, value] : map)
tagFieldBuffer += std::format("{}={}\n", key, value); tagFieldBuffer += std::format("{}={}\n", key, value);
// Null terminate it. (TODO: We shouldn't have to do this anymore, std::string does this on its own)
//tagFieldBuffer.push_back('\0');
outStr = std::move(tagFieldBuffer); outStr = std::move(tagFieldBuffer);
} }
std::vector<u8> DecodeBinaryTagData(std::string_view tagData) { namespace impl {
static constexpr std::byte HexCharToByte(char nibble1, char nibble2) {
// mmm so sexy
constexpr auto convertOneNibble = [](char nibbleChar) -> char {
if(nibbleChar >= '0' && nibbleChar <= '9') {
return nibbleChar - '0';
} else if(nibbleChar >= 'A' && nibbleChar <= 'F') {
return nibbleChar - 'A' + 10;
} else if(nibbleChar >= 'a' && nibbleChar <= 'f') {
return nibbleChar - 'a' + 10;
} else {
return 0;
}
};
return static_cast<std::byte>((convertOneNibble(nibble1) << 4) | (convertOneNibble(nibble2)));
}
} // namespace impl
std::vector<std::byte> DecodeBinaryTagData(std::string_view tagData) {
// This could be more ergonomic as an optional or something. // This could be more ergonomic as an optional or something.
std::vector<std::byte> res;
if(tagData.empty()) if(tagData.empty())
return {}; return res;
// Marker for binary data // Aries tagfield's marker for binary data is the $ character.
// If this isn't at the start of a binary payload, it's probably invalid.
if(tagData[0] != '$') if(tagData[0] != '$')
return {}; return res;
// TODO: Implement me fully! // remove the '$' marker from consideration
const auto hexPointLength = tagData.length() - 1;
const auto byteSize = hexPointLength / 2;
return {}; res.resize(byteSize);
const auto dataView = std::string_view(tagData.data() + 1, hexPointLength);
for(auto i = 0; i < byteSize; ++i) {
res[i] = impl::HexCharToByte(dataView[i * 2], dataView[i * 2 + 1]);
}
return res;
} }
} // namespace ls::aries } // namespace ls::aries

View File

@ -4,21 +4,21 @@
namespace ls::aries { namespace ls::aries {
using TagMap = std::unordered_map<std::string, std::string>; /// A map of tag fields and their values.
using TagMap = std::unordered_map<std::string, std::string>;
/// Parses tag field data to a TagMap. /// Parses tag field data to a TagMap.
/// # Returns /// # Returns
/// True on success; false otherwise (TODO: Move to exceptions or error_category) /// True on success; false otherwise (TODO: Move to exceptions or error_category)
bool ParseTagFieldsToMap(const std::string_view tagFieldData, TagMap& outMap); bool ParseTagFieldsToMap(const std::string_view tagFieldData, TagMap& outMap);
/// Serializes a TagMap to a string. /// Serializes a TagMap to a string.
void SerializeTagFields(const TagMap& map, std::string& outStr); void SerializeTagFields(const TagMap& map, std::string& outStr);
/// Decodes a binary tag to binary data. /// Decodes a binary tag to binary data.
std::vector<u8> DecodeBinaryTagData(std::string_view tagData); std::vector<std::byte> DecodeBinaryTagData(std::string_view tagData);
// TODO: Maybe also a in-Aries implementation of "CryptoSSC2"/other dirtysock crypto primitives so that we can rehash
// passwords to an actually sane password hash (e.g: argon2di).
// TODO: Maybe also a in-Aries implementation of "CryptoSSC2"/other dirtysock crypto primitives so that we can rehash } // namespace ls::aries
// passwords to an actually sane password hash (e.g: argon2di).
}

View File

@ -28,7 +28,13 @@ TEST_CASE("Aries tag field serde functions as expected", "[Aries] [TagFields]")
TEST_CASE("DecodeBinaryTagData() works", "[Aries] [TagFields] [DecodeBinarytagData]") { TEST_CASE("DecodeBinaryTagData() works", "[Aries] [TagFields] [DecodeBinarytagData]") {
// should decode to [ 0x12, 0x34, 0x56, 0x78 ] // should decode to [ 0x12, 0x34, 0x56, 0x78 ]
std::string testCorpus = "$12345678"; std::string testCorpus = "$12345678";
const static std::vector<u8> expectedOutput = { 0x12, 0x34, 0x56, 0x78 }; const static std::vector<std::byte> expectedOutput = { static_cast<std::byte>(0x12), static_cast<std::byte>(0x34), static_cast<std::byte>(0x56), static_cast<std::byte>(0x78) };
REQUIRE(aries::DecodeBinaryTagData(testCorpus) == expectedOutput); std::string testCorpus2 = "$feffffeeffffffff";
const static std::vector<std::byte> expectedOutput2 = { static_cast<std::byte>(0xfe), static_cast<std::byte>(0xff), static_cast<std::byte>(0xff), static_cast<std::byte>(0xee), static_cast<std::byte>(0xff), static_cast<std::byte>(0xff), static_cast<std::byte>(0xff), static_cast<std::byte>(0xff) };
REQUIRE(aries::DecodeBinaryTagData(testCorpus) == expectedOutput);
REQUIRE(aries::DecodeBinaryTagData(testCorpus2) == expectedOutput2);
REQUIRE(aries::DecodeBinaryTagData("invalid").empty());
} }