aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_cryptobox.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rspamd.com>2024-12-20 17:19:12 +0600
committerGitHub <noreply@github.com>2024-12-20 17:19:12 +0600
commitbc674074a56e77061c3d97d12c2784e0b8d96231 (patch)
tree2a98a8eb558f27278fce6694bd7a6ac406e9d035 /src/lua/lua_cryptobox.c
parentd35385f951ee38dfdd0bedc77eb7e2d1e5809e40 (diff)
parent223d286c5434de74b7ed05c0ace2381174185452 (diff)
downloadrspamd-bc674074a56e77061c3d97d12c2784e0b8d96231.tar.gz
rspamd-bc674074a56e77061c3d97d12c2784e0b8d96231.zip
Merge pull request #5266 from rspamd/vstakhov-universal-hashing-lua
[Feature] Allow to hash any Lua types
Diffstat (limited to 'src/lua/lua_cryptobox.c')
-rw-r--r--src/lua/lua_cryptobox.c116
1 files changed, 84 insertions, 32 deletions
diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
index 9600a4732..b562c4778 100644
--- a/src/lua/lua_cryptobox.c
+++ b/src/lua/lua_cryptobox.c
@@ -1362,57 +1362,110 @@ lua_cryptobox_hash_create_specific_keyed(lua_State *L)
return 1;
}
-/***
- * @method cryptobox_hash:update(data)
- * Updates hash with the specified data (hash should not be finalized using `hex` or `bin` methods)
- * @param {string} data data to hash
- */
-static int
-lua_cryptobox_hash_update(lua_State *L)
+static void
+lua_cryptobox_update_pos(lua_State *L, struct rspamd_lua_cryptobox_hash *h, int pos)
{
- LUA_TRACE_POINT;
- struct rspamd_lua_cryptobox_hash *h = lua_check_cryptobox_hash(L, 1), **ph;
const char *data;
struct rspamd_lua_text *t;
gsize len;
- if (lua_isuserdata(L, 2)) {
- t = lua_check_text(L, 2);
+ /* Inverse pos if it is relative to the top of the stack */
+ if (pos < 0) {
+ pos = lua_gettop(L) + pos + 1;
+ }
- if (!t) {
- return luaL_error(L, "invalid arguments");
+ switch (lua_type(L, pos)) {
+ case LUA_TSTRING:
+ data = lua_tolstring(L, pos, &len);
+ rspamd_lua_hash_update(h, data, len);
+ break;
+
+ case LUA_TNUMBER: {
+ lua_Number n = lua_tonumber(L, pos);
+ if (n == (lua_Number) (lua_Integer) n) {
+ lua_Integer i = lua_tointeger(L, pos);
+ rspamd_lua_hash_update(h, (void *) &i, sizeof(i));
}
+ else {
- data = t->start;
- len = t->len;
+ rspamd_lua_hash_update(h, (void *) &n, sizeof(n));
+ }
+
+ break;
}
- else {
- data = luaL_checklstring(L, 2, &len);
+
+ case LUA_TBOOLEAN: {
+ char b = lua_toboolean(L, pos);
+ rspamd_lua_hash_update(h, &b, sizeof(b));
+ break;
}
- if (lua_isnumber(L, 3)) {
- gsize nlen = lua_tonumber(L, 3);
+ case LUA_TTABLE: {
- if (nlen > len) {
- return luaL_error(L, "invalid length: %d while %d is available",
- (int) nlen, (int) len);
+ /* Hash array part */
+ gsize alen;
+#if LUA_VERSION_NUM >= 502
+ alen = lua_rawlen(L, 2);
+#else
+ alen = lua_objlen(L, pos);
+#endif
+
+ for (gsize i = 1; i <= alen; i++) {
+ lua_rawgeti(L, pos, i);
+ lua_cryptobox_update_pos(L, h, -1); /* Recurse */
+ lua_pop(L, 1);
}
- len = nlen;
- }
+ /* Hash key-value pairs */
+ lua_pushnil(L);
+ while (lua_next(L, pos) != 0) {
+ /* Hash key */
+ lua_pushvalue(L, -2);
+ lua_cryptobox_update_pos(L, h, -1);
+ lua_pop(L, 1);
- if (h && data) {
- if (!h->is_finished) {
- rspamd_lua_hash_update(h, data, len);
+ /* Hash value */
+ lua_cryptobox_update_pos(L, h, -1);
+ lua_pop(L, 1);
}
- else {
- return luaL_error(L, "hash is already finalized");
+
+ break;
+ }
+
+ case LUA_TUSERDATA:
+ t = lua_check_text(L, 2);
+ if (t) {
+ rspamd_lua_hash_update(h, t->start, t->len);
}
+ break;
+
+ case LUA_TFUNCTION:
+ case LUA_TTHREAD:
+ case LUA_TNIL:
+ default:
+ /* Skip these types */
+ break;
}
- else {
- return luaL_error(L, "invalid arguments");
+}
+
+/***
+ * @method cryptobox_hash:update(data)
+ * Updates hash with the specified data (hash should not be finalized using `hex` or `bin` methods)
+ * @param {string} data data to hash
+ */
+static int
+lua_cryptobox_hash_update(lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_lua_cryptobox_hash *h = lua_check_cryptobox_hash(L, 1), **ph;
+
+
+ if (h == NULL || h->is_finished) {
+ return luaL_error(L, "invalid arguments or hash is already finalized");
}
+ lua_cryptobox_update_pos(L, h, 2);
+
ph = lua_newuserdata(L, sizeof(void *));
*ph = h;
REF_RETAIN(h);
@@ -1420,7 +1473,6 @@ lua_cryptobox_hash_update(lua_State *L)
return 1;
}
-
/***
* @method cryptobox_hash:reset()
* Resets hash to the initial state