lua - 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"}}})
解决方案
(请注意,我根本没有安装此密码管理器或尝试其中任何一个)
上次我问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
推荐阅读
- python - 如何计算姿势图优化器(slam)?
- c++ - 有没有办法合并两个(或多个)for循环以降低整体时间复杂度?
- kubernetes - PodDisruptionBudgets 是否优先于 HorizontalPodAutoscaler?
- python-3.x - 为什么我的列表在使用 for 循环追加后不断变化?
- regex - 正则表达式使字符串的最后一部分是可选的,如果它是可选的,则捕获所有内容
- java - 在 AWS 上导入密钥对之前,如何通过 Java 验证 OpenSSH 公钥格式?
- azure - for-each 在 azure 数据工厂中一次传递所有文件
- python - 使用 python IndentationError 编码的 Discord bot:unindent 不匹配任何外部缩进级别
- python - Discord Py 'NoneType' 对象没有属性 'voice_channel'
- java - 无法从 .jar 文件创建的 Android 模块中找到类