diff options
author | Sadie Powell <sadie@witchery.services> | 2025-05-05 16:51:47 +0100 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2025-05-05 16:53:03 +0100 |
commit | c5ad774ce5dd51ea2e6e09374901f583b9857d7f (patch) | |
tree | cf5b03ab195e427f637216ad68aeb6c0ce106e31 | |
parent | 1321f4f0711b8d0fc799f3d0ea114984083a2c11 (diff) |
Add a workaround for JavaScript truncating integers in RPC.
-rw-r--r-- | data/modules.example.conf | 19 | ||||
-rw-r--r-- | modules/rpc/jsonrpc.cpp | 32 |
2 files changed, 46 insertions, 5 deletions
diff --git a/data/modules.example.conf b/data/modules.example.conf index c317cd6cf..93aa0df54 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -810,6 +810,19 @@ module { name = "jsonrpc" + /* + * The maximum number of bits an integer can be have in its native type. + * + * By default Anope will emit integers as their native JSON type. If you are + * using JavaScript (which has 56 bit integers) or another language with + * native integer types smaller than 64 bits you may need to limit the size + * of integers emitted by Anope. + * + * If this is enabled a string will be used for values outside of the range + * supported by the native data type. + */ + #integer_bits = 56 + /* Web service to use. Requires httpd. */ server = "httpd/main" @@ -852,9 +865,6 @@ module { name = "xmlrpc" - /* Web service to use. Requires httpd. */ - server = "httpd/main" - /* * Whether to enable the use of XML-RPC extensions. * @@ -869,6 +879,9 @@ module #enable_i8 = no #enable_nil = no + /* Web service to use. Requires httpd. */ + server = "httpd/main" + /* * You can also specify one or more authorization tokens to protect access * to the XML-RPC interface. These tokens should be sent using the Bearer diff --git a/modules/rpc/jsonrpc.cpp b/modules/rpc/jsonrpc.cpp index 163658495..189e2b3a8 100644 --- a/modules/rpc/jsonrpc.cpp +++ b/modules/rpc/jsonrpc.cpp @@ -86,6 +86,9 @@ private: } public: + // The number of bits that can be represented using the native integer type. + static unsigned integer_bits; + JSONRPCServiceInterface(Module *creator) : RPC::ServiceInterface(creator) , HTTPPage("/jsonrpc", "application/json") @@ -236,16 +239,39 @@ yyjson_mut_val *JSONRPCServiceInterface::SerializeElement(yyjson_mut_doc *doc, c }, [&doc, &elem](int64_t i) { - elem = yyjson_mut_int(doc, i); + auto bits = std::floor(std::log2(abs(i))) + 1; + if (bits <= integer_bits) + { + // We can fit this into an integer. + elem = yyjson_mut_int(doc, i); + } + else + { + // We need to convert this to a string. + auto s = Anope::ToString(i); + elem = yyjson_mut_strncpy(doc, s.c_str(), s.length()); + } }, [&doc, &elem](uint64_t u) { - elem = yyjson_mut_uint(doc, u); + auto bits = std::floor(std::log2(u)) + 1; + if (bits <= integer_bits) + { + // We can fit this into an integer. + elem = yyjson_mut_uint(doc, u); + } + else + { + // We need to convert this to a string. + auto s = Anope::ToString(u); + elem = yyjson_mut_strncpy(doc, s.c_str(), s.length()); + } }, }, value.Get()); return elem; } +unsigned JSONRPCServiceInterface::integer_bits = 64; class ModuleJSONRPC final : public Module @@ -273,6 +299,8 @@ public: httpref->UnregisterPage(&jsonrpcinterface); const auto &modconf = conf.GetModule(this); + JSONRPCServiceInterface::integer_bits = modconf.Get<unsigned>("integer_bits", "64"); + this->httpref = ServiceReference<HTTPProvider>("HTTPProvider", modconf.Get<const Anope::string>("server", "httpd/main")); if (!httpref) throw ConfigException("Unable to find http reference, is httpd loaded?"); |