#include "UserScript.h"
|
|
#include <algorithm>
|
|
#include <span>
|
|
#include <utility>
|
|
#include "UserScriptWizardry.h"
|
|
#include "UserScriptRequire.h"
|
|
|
|
using interpreter = decltype(scripting::prepare_interpreter({}));
|
|
using namespace scripting;
|
|
|
|
namespace bad_cryptography {
|
|
|
|
struct encode_n_parameters {
|
|
uint8_t spin;
|
|
uint8_t clash;
|
|
uint8_t maim;
|
|
};
|
|
|
|
static constexpr uint8_t encode_n_1(uint8_t value, const encode_n_parameters ¶ms) {
|
|
value += 42;
|
|
value ^= 0b01010101;
|
|
value += params.clash;
|
|
value = std::rotl(value, params.spin);
|
|
value ^= 0b10101010;
|
|
value ^= params.maim;
|
|
return value;
|
|
}
|
|
|
|
static constexpr uint8_t decode_n_1(uint8_t value, const encode_n_parameters ¶ms) {
|
|
value ^= params.maim;
|
|
value ^= 0b10101010;
|
|
value = std::rotl(value, -params.spin);
|
|
value -= params.clash;
|
|
value ^= 0b01010101;
|
|
value -= 42;
|
|
return value;
|
|
}
|
|
|
|
namespace eliminated_001 {
|
|
constexpr encode_n_parameters params{.spin = 3, .clash = 17, .maim = 54};
|
|
static_assert(0 == decode_n_1(encode_n_1(0, params), params));
|
|
static_assert(10 == decode_n_1(encode_n_1(10, params), params));
|
|
static_assert(100 == decode_n_1(encode_n_1(100, params), params));
|
|
static_assert(20 == decode_n_1(encode_n_1(20, params), params));
|
|
static_assert(200 == decode_n_1(encode_n_1(200, params), params));
|
|
static_assert(117 == decode_n_1(encode_n_1(117, params), params));
|
|
static_assert(42 == decode_n_1(encode_n_1(42, params), params));
|
|
};
|
|
|
|
namespace eliminated_002 {
|
|
constexpr encode_n_parameters params{.spin = 7, .clash = 97, .maim = 154};
|
|
static_assert(0 == decode_n_1(encode_n_1(0, params), params));
|
|
static_assert(10 == decode_n_1(encode_n_1(10, params), params));
|
|
static_assert(100 == decode_n_1(encode_n_1(100, params), params));
|
|
static_assert(20 == decode_n_1(encode_n_1(20, params), params));
|
|
static_assert(200 == decode_n_1(encode_n_1(200, params), params));
|
|
static_assert(117 == decode_n_1(encode_n_1(117, params), params));
|
|
static_assert(42 == decode_n_1(encode_n_1(42, params), params));
|
|
};
|
|
}
|
|
|
|
namespace scripting {
|
|
struct fn_string_to_binary final : public scripting::function_impl {
|
|
int32_t array_size_limit;
|
|
explicit fn_string_to_binary(int32_t _array_size_limit)
|
|
: array_size_limit(_array_size_limit)
|
|
{}
|
|
|
|
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
|
|
if(n.size() != 1) {
|
|
error = script_error{
|
|
.message = "/string_to_binary takes exactly 1 argument of type string"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto& arg = n.front();
|
|
script_value target;
|
|
|
|
if(std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
if(not std::holds_alternative<std::string>(target)) {
|
|
error = script_error{
|
|
.message = "/string_to_binary takes exactly 1 argument of type string"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto& str = std::get<std::string>(target);
|
|
|
|
array result;
|
|
|
|
std::transform(str.begin(), str.end(), std::back_inserter(result.value), [&](char value) -> script_value {
|
|
return (int32_t)value;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
~fn_string_to_binary() final = default;
|
|
};
|
|
|
|
struct fn_binary_to_string final : public scripting::function_impl {
|
|
int32_t string_size_limit;
|
|
explicit fn_binary_to_string(int32_t _string_size_limit)
|
|
: string_size_limit(_string_size_limit) {}
|
|
|
|
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
|
|
if(n.size() != 1) {
|
|
error = script_error{
|
|
.message = "/binary_to_string takes exactly 1 argument of type array"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto& arg = n.front();
|
|
script_value target;
|
|
|
|
if(std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
if(not std::holds_alternative<array>(target)) {
|
|
error = script_error{
|
|
.message = "/binary_to_string takes exactly 1 argument of type array"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto& ary = std::get<array>(target);
|
|
|
|
if(ary.value.size() > string_size_limit) {
|
|
error = script_error{
|
|
.message = "/binary_to_string: array is too bit to fit string type"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::string result;
|
|
|
|
const bool valid = std::any_of(ary.value.begin(), ary.value.end(), [](auto val) {
|
|
return std::visit(
|
|
wizardry::overloaded{
|
|
[](int32_t v) { return 0 <= v && v <= 255; },
|
|
[](auto v) { return false; }
|
|
},
|
|
val
|
|
);
|
|
});
|
|
|
|
if(not valid) {
|
|
error = script_error{
|
|
.message = "/binary_to_string takes exactly 1 argument of type array of which contents must be numbers between 0 and 255 included"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
constexpr auto byte_convert = [](int32_t v) -> char {
|
|
const uint32_t v2 = v;
|
|
const uint8_t v3 = v2 & 0b1111'1111;
|
|
return char(v3);
|
|
};
|
|
|
|
std::transform(ary.value.begin(), ary.value.end(), std::back_inserter(result), [&](const script_value& value) -> char {
|
|
return std::visit(
|
|
wizardry::overloaded{
|
|
byte_convert,
|
|
[](auto v) { return '\0'; }
|
|
},
|
|
value
|
|
);
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
~fn_binary_to_string() final = default;
|
|
};
|
|
|
|
struct fn_encode_n final : public scripting::function_impl {
|
|
int32_t string_size_limit;
|
|
explicit fn_encode_n(int32_t _string_size_limit)
|
|
: string_size_limit(_string_size_limit) {}
|
|
|
|
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
|
|
using verifier = Verify<
|
|
details::SizeEquals<4>,
|
|
details::TypeVerifier<0, int32_t>,
|
|
details::TypeVerifier<1, int32_t>,
|
|
details::TypeVerifier<2, int32_t>,
|
|
details::OctetArrayVerifier<3>
|
|
>;
|
|
|
|
if(not verifier{}.verify(self, n)) {
|
|
error = script_error{
|
|
.message = "/encode_n takes exactly 3 arguments of type integer and an argument of type array"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
auto& arg = n.front();
|
|
script_value target;
|
|
|
|
if(std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
bad_cryptography::encode_n_parameters params;
|
|
|
|
{
|
|
auto& arg = n[3];
|
|
script_value target;
|
|
|
|
if (std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
params.spin = std::get<int32_t>(target);
|
|
}
|
|
|
|
{
|
|
auto& arg = n[2];
|
|
script_value target;
|
|
|
|
if (std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
params.clash = std::get<int32_t>(target);
|
|
}
|
|
|
|
{
|
|
auto& arg = n[1];
|
|
script_value target;
|
|
|
|
if (std::holds_alternative<scripting::script_value>(arg)) {
|
|
target = std::get<scripting::script_value>(arg);
|
|
} else {
|
|
target = self->resolve(std::get<scripting::script_variable>(arg).name);
|
|
}
|
|
|
|
params.maim = std::get<int32_t>(target);
|
|
}
|
|
|
|
auto ary = std::get<array>(target);
|
|
|
|
if(ary.value.size() > string_size_limit) {
|
|
error = script_error{
|
|
.message = "/encode_n: array is too bit to fit string type"
|
|
};
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::transform(ary.value.begin(), ary.value.end(), ary.value.begin(), [&](const script_value& value) {
|
|
return std::visit(
|
|
wizardry::overloaded{
|
|
[&](int32_t v) -> script_value { return script_value{bad_cryptography::encode_n_1(v, params)};},
|
|
[](auto v) -> script_value { return null{}; }
|
|
},
|
|
value
|
|
);
|
|
});
|
|
|
|
return ary;
|
|
}
|
|
|
|
~fn_encode_n() final = default;
|
|
};
|
|
|
|
interpreter register_crypto_lib(interpreter target, int32_t array_size_limit, int32_t string_size_limit) {
|
|
target->registerFunction("string_to_binary", std::make_unique<fn_string_to_binary>(array_size_limit));
|
|
target->registerFunction("binary_to_string", std::make_unique<fn_binary_to_string>(string_size_limit));
|
|
target->registerFunction("encode_n", std::make_unique<fn_encode_n>(string_size_limit));
|
|
return std::move(target);
|
|
}
|
|
}
|