#include <array>
#include <cstddef>
#include <cstdint>
#include <string_view>
#include "cow_string.hpp"
#include "transformer/base64_decode.hpp"
#include "utils.hpp"
namespace ddwaf::transformer {
namespace {
bool decode_common(cow_string &str, const std::array<char, 256> &b64Reverse)
{
size_t read = 0;
size_t write = 0;
while (read < str.length()) {
std::array<char, 4> quartet{0, 0, 0, 0};
size_t pos = 0;
for (; pos < 4 && read < str.length(); ++read) {
auto idx = str.at<uint8_t>(read);
auto c = b64Reverse[idx];
if ((c & 0x40) == 0) {
quartet[pos++] = c;
}
}
auto value = quartet[0] << 18 | quartet[1] << 12 | quartet[2] << 6 | quartet[3];
std::array<char, 3> bytes{static_cast<char>(value >> 16),
static_cast<char>((value >> 8) & 0xff), static_cast<char>(value & 0xff)};
if (pos == 4) {
str[write++] = bytes[0];
str[write++] = bytes[1];
str[write++] = bytes[2];
} else if (pos != 0) {
str[write++] = bytes[0];
if (pos > 1 && ((bytes[1] != 0) || (bytes[2] != 0))) {
str[write++] = bytes[1];
}
if (pos > 2 && bytes[2] != 0) {
str[write++] = bytes[2];
}
}
}
str.truncate(write);
return true;
}
}
bool base64_decode::needs_transform(std::string_view str)
{
std::size_t pos = 0;
for (; pos < str.length(); ++pos) {
if (!ddwaf::isalnum(str[pos]) && str[pos] != '+' && str[pos] != '/') {
break;
}
}
auto expected_padding = 4 - (pos % 4);
auto remaining = str.length() - pos;
if (remaining > 0 && (expected_padding == 3 || remaining > expected_padding)) {
return false;
}
for (; pos < str.length(); ++pos) {
if (str[pos] != '=') {
return false;
}
}
return true;
}
bool base64_decode::transform_impl(cow_string &str)
{
static constexpr std::array<char, 256> b64Reverse{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, -1, -1, -1, 64, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
return decode_common(str, b64Reverse);
}
bool base64url_decode::needs_transform(std::string_view str)
{
std::size_t pos = 0;
for (; pos < str.length(); ++pos) {
if (!ddwaf::isalnum(str[pos]) && str[pos] != '-' && str[pos] != '_') {
break;
}
}
auto expected_padding = 4 - (pos % 4);
auto remaining = str.length() - pos;
if (remaining > 0 && (expected_padding == 3 || remaining > expected_padding)) {
return false;
}
for (; pos < str.length(); ++pos) {
if (str[pos] != '=') {
return false;
}
}
return true;
}
bool base64url_decode::transform_impl(cow_string &str)
{
static constexpr std::array<char, 256> b64Reverse{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, -1, -1, -1, 64, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
return decode_common(str, b64Reverse);
}
}