summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadie Powell <sadie@witchery.services>2025-05-05 16:51:47 +0100
committerSadie Powell <sadie@witchery.services>2025-05-05 16:53:03 +0100
commitc5ad774ce5dd51ea2e6e09374901f583b9857d7f (patch)
treecf5b03ab195e427f637216ad68aeb6c0ce106e31
parent1321f4f0711b8d0fc799f3d0ea114984083a2c11 (diff)
Add a workaround for JavaScript truncating integers in RPC.
-rw-r--r--data/modules.example.conf19
-rw-r--r--modules/rpc/jsonrpc.cpp32
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?");