【问题标题】:Lua LGI unpack GLib.Variant objectLua LGI 解压 GLib.Variant 对象
【发布时间】:2018-11-21 00:41:53
【问题描述】:

我正在尝试从 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 是一个对象。如何从GLib.Variant 对象中检索value 字段?

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

【问题讨论】:

  • 你可以检查用户数据是否有一个带有__index元方法的元表来访问结构的字段。
  • @cyclaminist 证明secretGLib.Variant 类型的对象。现在我需要弄清楚如何从中获取value

标签: lua dbus awesome-wm lgi


【解决方案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

【讨论】:

  • 我不想在C中添加代码,主要是从代码分发的角度来看。我添加了一小段代码来重新创建所需类型的对象。也许你可以看看它?
【解决方案2】:

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

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

解释:索引元组;索引数组;索引字典;索引元组

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2017-03-30
    • 2019-11-17
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多