You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
8.4 KiB

  1. #include "UserScript.h"
  2. #include <algorithm>
  3. #include <span>
  4. #include <utility>
  5. #include "UserScriptWizardry.h"
  6. #include "UserScriptRequire.h"
  7. using interpreter = decltype(scripting::prepare_interpreter({}));
  8. using namespace scripting;
  9. namespace bad_cryptography {
  10. struct encode_n_parameters {
  11. uint8_t spin;
  12. uint8_t clash;
  13. uint8_t maim;
  14. };
  15. static constexpr uint8_t encode_n_1(uint8_t value, const encode_n_parameters &params) {
  16. value += 42;
  17. value ^= 0b01010101;
  18. value += params.clash;
  19. value = std::rotl(value, params.spin);
  20. value ^= 0b10101010;
  21. value ^= params.maim;
  22. return value;
  23. }
  24. static constexpr uint8_t decode_n_1(uint8_t value, const encode_n_parameters &params) {
  25. value ^= params.maim;
  26. value ^= 0b10101010;
  27. value = std::rotl(value, -params.spin);
  28. value -= params.clash;
  29. value ^= 0b01010101;
  30. value -= 42;
  31. return value;
  32. }
  33. namespace eliminated_001 {
  34. constexpr encode_n_parameters params{.spin = 3, .clash = 17, .maim = 54};
  35. static_assert(0 == decode_n_1(encode_n_1(0, params), params));
  36. static_assert(10 == decode_n_1(encode_n_1(10, params), params));
  37. static_assert(100 == decode_n_1(encode_n_1(100, params), params));
  38. static_assert(20 == decode_n_1(encode_n_1(20, params), params));
  39. static_assert(200 == decode_n_1(encode_n_1(200, params), params));
  40. static_assert(117 == decode_n_1(encode_n_1(117, params), params));
  41. static_assert(42 == decode_n_1(encode_n_1(42, params), params));
  42. };
  43. namespace eliminated_002 {
  44. constexpr encode_n_parameters params{.spin = 7, .clash = 97, .maim = 154};
  45. static_assert(0 == decode_n_1(encode_n_1(0, params), params));
  46. static_assert(10 == decode_n_1(encode_n_1(10, params), params));
  47. static_assert(100 == decode_n_1(encode_n_1(100, params), params));
  48. static_assert(20 == decode_n_1(encode_n_1(20, params), params));
  49. static_assert(200 == decode_n_1(encode_n_1(200, params), params));
  50. static_assert(117 == decode_n_1(encode_n_1(117, params), params));
  51. static_assert(42 == decode_n_1(encode_n_1(42, params), params));
  52. };
  53. }
  54. namespace scripting {
  55. struct fn_string_to_binary final : public scripting::function_impl {
  56. int32_t array_size_limit;
  57. explicit fn_string_to_binary(int32_t _array_size_limit)
  58. : array_size_limit(_array_size_limit)
  59. {}
  60. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  61. if(n.size() != 1) {
  62. error = script_error{
  63. .message = "/string_to_binary takes exactly 1 argument of type string"
  64. };
  65. return std::nullopt;
  66. }
  67. auto& arg = n.front();
  68. script_value target;
  69. if(std::holds_alternative<scripting::script_value>(arg)) {
  70. target = std::get<scripting::script_value>(arg);
  71. } else {
  72. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  73. }
  74. if(not std::holds_alternative<std::string>(target)) {
  75. error = script_error{
  76. .message = "/string_to_binary takes exactly 1 argument of type string"
  77. };
  78. return std::nullopt;
  79. }
  80. auto& str = std::get<std::string>(target);
  81. array result;
  82. std::transform(str.begin(), str.end(), std::back_inserter(result.value), [&](char value) -> script_value {
  83. return (int32_t)value;
  84. });
  85. return result;
  86. }
  87. ~fn_string_to_binary() final = default;
  88. };
  89. struct fn_binary_to_string final : public scripting::function_impl {
  90. int32_t string_size_limit;
  91. explicit fn_binary_to_string(int32_t _string_size_limit)
  92. : string_size_limit(_string_size_limit) {}
  93. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  94. if(n.size() != 1) {
  95. error = script_error{
  96. .message = "/binary_to_string takes exactly 1 argument of type array"
  97. };
  98. return std::nullopt;
  99. }
  100. auto& arg = n.front();
  101. script_value target;
  102. if(std::holds_alternative<scripting::script_value>(arg)) {
  103. target = std::get<scripting::script_value>(arg);
  104. } else {
  105. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  106. }
  107. if(not std::holds_alternative<array>(target)) {
  108. error = script_error{
  109. .message = "/binary_to_string takes exactly 1 argument of type array"
  110. };
  111. return std::nullopt;
  112. }
  113. auto& ary = std::get<array>(target);
  114. if(ary.value.size() > string_size_limit) {
  115. error = script_error{
  116. .message = "/binary_to_string: array is too bit to fit string type"
  117. };
  118. return std::nullopt;
  119. }
  120. std::string result;
  121. const bool valid = std::any_of(ary.value.begin(), ary.value.end(), [](auto val) {
  122. return std::visit(
  123. wizardry::overloaded{
  124. [](int32_t v) { return 0 <= v && v <= 255; },
  125. [](auto v) { return false; }
  126. },
  127. val
  128. );
  129. });
  130. if(not valid) {
  131. error = script_error{
  132. .message = "/binary_to_string takes exactly 1 argument of type array of which contents must be numbers between 0 and 255 included"
  133. };
  134. return std::nullopt;
  135. }
  136. constexpr auto byte_convert = [](int32_t v) -> char {
  137. const uint32_t v2 = v;
  138. const uint8_t v3 = v2 & 0b1111'1111;
  139. return char(v3);
  140. };
  141. std::transform(ary.value.begin(), ary.value.end(), std::back_inserter(result), [&](const script_value& value) -> char {
  142. return std::visit(
  143. wizardry::overloaded{
  144. byte_convert,
  145. [](auto v) { return '\0'; }
  146. },
  147. value
  148. );
  149. });
  150. return result;
  151. }
  152. ~fn_binary_to_string() final = default;
  153. };
  154. struct fn_encode_n final : public scripting::function_impl {
  155. int32_t string_size_limit;
  156. explicit fn_encode_n(int32_t _string_size_limit)
  157. : string_size_limit(_string_size_limit) {}
  158. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  159. using verifier = Verify<
  160. details::SizeEquals<4>,
  161. details::TypeVerifier<0, int32_t>,
  162. details::TypeVerifier<1, int32_t>,
  163. details::TypeVerifier<2, int32_t>,
  164. details::OctetArrayVerifier<3>
  165. >;
  166. if(not verifier{}.verify(self, n)) {
  167. error = script_error{
  168. .message = "/encode_n takes exactly 3 arguments of type integer and an argument of type array"
  169. };
  170. return std::nullopt;
  171. }
  172. auto& arg = n.front();
  173. script_value target;
  174. if(std::holds_alternative<scripting::script_value>(arg)) {
  175. target = std::get<scripting::script_value>(arg);
  176. } else {
  177. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  178. }
  179. bad_cryptography::encode_n_parameters params;
  180. {
  181. auto& arg = n[3];
  182. script_value target;
  183. if (std::holds_alternative<scripting::script_value>(arg)) {
  184. target = std::get<scripting::script_value>(arg);
  185. } else {
  186. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  187. }
  188. params.spin = std::get<int32_t>(target);
  189. }
  190. {
  191. auto& arg = n[2];
  192. script_value target;
  193. if (std::holds_alternative<scripting::script_value>(arg)) {
  194. target = std::get<scripting::script_value>(arg);
  195. } else {
  196. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  197. }
  198. params.clash = std::get<int32_t>(target);
  199. }
  200. {
  201. auto& arg = n[1];
  202. script_value target;
  203. if (std::holds_alternative<scripting::script_value>(arg)) {
  204. target = std::get<scripting::script_value>(arg);
  205. } else {
  206. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  207. }
  208. params.maim = std::get<int32_t>(target);
  209. }
  210. auto ary = std::get<array>(target);
  211. if(ary.value.size() > string_size_limit) {
  212. error = script_error{
  213. .message = "/encode_n: array is too bit to fit string type"
  214. };
  215. return std::nullopt;
  216. }
  217. std::transform(ary.value.begin(), ary.value.end(), ary.value.begin(), [&](const script_value& value) {
  218. return std::visit(
  219. wizardry::overloaded{
  220. [&](int32_t v) -> script_value { return script_value{bad_cryptography::encode_n_1(v, params)};},
  221. [](auto v) -> script_value { return null{}; }
  222. },
  223. value
  224. );
  225. });
  226. return ary;
  227. }
  228. ~fn_encode_n() final = default;
  229. };
  230. interpreter register_crypto_lib(interpreter target, int32_t array_size_limit, int32_t string_size_limit) {
  231. target->registerFunction("string_to_binary", std::make_unique<fn_string_to_binary>(array_size_limit));
  232. target->registerFunction("binary_to_string", std::make_unique<fn_binary_to_string>(string_size_limit));
  233. target->registerFunction("encode_n", std::make_unique<fn_encode_n>(string_size_limit));
  234. return std::move(target);
  235. }
  236. }