{
LUA_TRACE_POINT;
luaL_checktype(L, 1, LUA_TTABLE);
- const char *password = luaL_checkstring(L, 2);
+ const char *password = NULL;
+ if (lua_gettop(L) >= 2 && !lua_isnil(L, 2)) {
+ if (lua_type(L, 2) == LUA_TSTRING) {
+ password = lua_tostring(L, 2);
+ }
+ else {
+ return luaL_error(L, "invalid password (string expected)");
+ }
+ }
GArray *specs = g_array_sized_new(FALSE, FALSE, sizeof(struct rspamd_zip_file_spec), 8);
GError *err = NULL;
}
/***
- * @function archive.unpack(data[, format])
+ * @function archive.unpack(data[, format][, password])
* Unpacks an archive from a Lua string (or rspamd_text) using libarchive.
* @param {string|text} data archive contents
* @param {string} format optional format name to restrict autodetection (e.g. "zip")
+ * @param {string} password optional password for encrypted archives (e.g. ZIP AES)
* @return {table} array of files: { name = string, content = text } (non-regular entries are skipped)
*/
static int
LUA_TRACE_POINT;
struct rspamd_lua_text *t = NULL;
const char *format = NULL;
+ const char *password = NULL;
struct archive *a = NULL;
t = lua_check_text_or_string(L, 1);
if (lua_type(L, 2) == LUA_TSTRING) {
format = lua_tostring(L, 2);
}
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ password = lua_tostring(L, 3);
+ }
a = archive_read_new();
if (a == NULL) {
archive_read_support_format_all(a);
}
+ if (password && *password) {
+ /* supply passphrase for encrypted archives (e.g. zip AES) */
+ int pr = archive_read_add_passphrase(a, password);
+ if (pr != ARCHIVE_OK) {
+ const char *aerr = archive_error_string(a);
+ lua_pushfstring(L, "cannot set passphrase: %s", aerr ? aerr : "unknown error");
+ archive_read_free(a);
+ return lua_error(L);
+ }
+ }
+
int r = archive_read_open_memory(a, t->start, t->len);
if (r != ARCHIVE_OK) {
const char *aerr = archive_error_string(a);
local blob = archive.zip_encrypt(files, pwd)
assert_equal(type(blob), "userdata")
-- libarchive can read AE-2, so unpack should succeed and yield the same files
- local out = archive.unpack(blob, "zip")
+ local out = archive.unpack(blob, "zip", pwd)
assert_equal(#out, 2)
local names = {}
for _, f in ipairs(out) do names[f.name] = f.content end
assert_rspamd_eq({ actual = names["y.bin"], expect = rspamd_text.fromstring("\001\002\003") })
end)
+ test("zip_encrypt with wrong password fails to unpack", function()
+ local files = {
+ { name = "secret.txt", content = "topsecret" },
+ }
+ local pwd = "goodpass"
+ local blob = archive.zip_encrypt(files, pwd)
+ assert_equal(type(blob), "userdata")
+ local ok, err = pcall(function()
+ archive.unpack(blob, "zip", "badpass")
+ end)
+ assert_equal(ok, false)
+ end)
+
test("tar/untar helpers roundtrip (no compression)", function()
local files = {
{ name = "x.txt", content = "X" },