首页 > 解决方案 > Lua LGI 解压 GLib.Variant 对象

问题描述

我正在尝试从密钥环中获取awesome-wm会话的密码(通过lgi库使用 DBus)。

我能够找到密钥环入口路径、打开通信会话并解锁入口。然后我调用GetSecrets方法并将结果存储到secret变量中。根据文档,它应该是struct Secret。似乎lgi无法处理这种类型并将其作为userdata类型传递(至少我无法让它访问结构字段)。有没有办法在struct Secret value不编写自定义 C 处理程序的情况下获取字段内容?

这是代码:

local bus = Gio.bus_get_sync(Gio.BusType.SESSION, nil)

local attr = {}
attr[1] = {attribute = "value"} -- attribute-value pair to search for

-- search for secret path
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "SearchItems"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(a{ss})", attr))

local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)
local location
for _, l in result:get_body():pairs() do
   if #l > 0 then location = l[1] end
end
print(location) -- returns "/org/freedesktop/secrets/collection/Default/1"

-- open session
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "OpenSession"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(sv)", {"plain", GLib.Variant("s", "")}))

local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)
local session = result:get_body()[2]
print(session) -- returns "/org/freedesktop/secrets/session/s4"

-- unlock key
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "Unlock"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(ao)", {{location}}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)
-- at this point key property "Locked" if false. tested using d-feet

-- get secret
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "GetSecrets"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(aoo)", {{location},session}))

local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)
local secret = result:get_body()
print(#secret) -- returns "1"
print(secret)  -- returns table address
print(type(secret))  -- returns "userdata"

-- lock key
local name = "org.freedesktop.secrets"
local object = "/org/freedesktop/secrets"
local interface = "org.freedesktop.Secret.Service"
local method = "Lock"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
message:set_body(GLib.Variant("(ao)", {{location}}))
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)

-- close session
local name = "org.freedesktop.secrets"
local object = location
local interface = "org.freedesktop.Secret.Session"
local method = "Close"
local message = Gio.DBusMessage.new_method_call(name, object, interface, method)
local result, err = bus:send_message_with_reply_sync(message, Gio.DBusSendMessageFlags.NONE,
                                                     -1, nil)

编辑

当我这样做时print(secret)lgi.rec 0x7f57d0014960:GLib.Variant返回。所以,secret是一个对象。如何从对象中检索value字段?GLib.Variant

编辑 2

secret:get_data_as_bytes():get_data()以字节数组形式转储结构;secret:print()返回结构的格式化字符串。我想知道是否有更好的方法。

编辑 3

secret变量类型是(a{o(oayays)}) 重新创建该类型对象的代码:

local lgi       = require     'lgi'
local Gio       = lgi.require 'Gio'
local GLib      = lgi.require 'GLib'

local var = GLib.Variant("(a{o(oayays)})", {{["/path/to/object"]={"/path/to/session","parameters","value","content_type"}}})

标签: luadbusawesome-wmlgi

解决方案


(请注意,我根本没有安装此密码管理器或尝试其中任何一个)

上次我问LGI的作者关于这个问题,答案是:

我已向 Variant 提交了修复此功能的修复程序。所以一个使用的例子是:

local function called_from_C(userdata)
local variant = GLib.Variant(userdata)
print(variant)
end

如果您必须支持较旧的(好吧,已发布:) lgi 版本,您可以使用未记录的方式:

local core = require 'lgi.core'
local function called_from_C(userdata)
local variant = core.record.new(GLib.Variant, userdata)
print(variant)
end

请注意,还有其他方法。为了解决另一个这样的错误,我还创建了一个 C Lua 插件,并只是用 C 编写了该代码。这实际上对于 Lua [2] 来说是相当微不足道的。

如果你使用 LuaJIT,另一种方法是使用内置的 FFI 将结构定义即时编译成 Lua 对象 [1]。

最后,如果问题更多是关于如何在 LGI 正确使用“工作”GVariant 值后解压缩它们,请在此处查看我的代码https://github.com/Elv13/wirefu/blob/master/proxy.lua

[1] http://luajit.org/ext_ffi_api.html

[2] https://github.com/Elv13/lua_async_binding/blob/master/src/luabridge.c#L407


推荐阅读