Lua LGI解压缩GLib.Variant对象

时间:2018-11-17 17:34:25

标签: lua dbus awesome-wm lgi

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

我能够找到钥匙圈输入路径,打开通信会话并解锁输入。 然后,我调用GetSecrets方法并将结果存储到secret变量中。 根据文档,它应该是struct Secret。似乎lgi无法处理此类型,而将其作为userdata类型传递(至少我无法使它能够访问结构字段)。是否有一种无需编写自定义C处理程序即可获取struct Secret value字段内容的方法?

代码如下:

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()返回格式化的struct字符串。我想知道是否有更好的方法。

编辑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"}}})

2 个答案:

答案 0 :(得分:1)

(请注意,我没有安装此密码管理器,也没有尝试使用任何密码管理器)

上次我问LGI的作者有关此类问题的答案是:

  

我已提交对Variant的修复,该修复可以恢复此功能。所以   一个使用示例是:

     

称为_from_C(userdata)的本地函数
    本地变体= GLib.Variant(userdata)
    打印(变体)
  结束

     

如果您必须支持较旧的(以及已发布的:)lgi版本,则可以   使用未公开的方式:

     

本地核心=要求'lgi.core'
     名为_from_C(userdata)的局部函数
       本地变体= core.record.new(GLib.Variant,userdata)
       打印(变体)
     结束

请注意,还有其他方法。为了解决另一个此类错误,我还创建了一个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

答案 1 :(得分:0)

最后我找到了解决方案。要解压复杂类型的值(例如(a{o(oayays)})),应使用get_child_value函数。

secret:get_child_value(0):get_child_value(0):get_child_value(1):get_child_value(2).value

说明:索引元组;索引数组索引字典索引元组