Я пытаюсь получить пароль от связки ключей для сеанса потрясающе-wm (используя DBus через библиотеку lgi).
Я могу найти путь входа в связку ключей, открыть сеанс связи и разблокировать запись.
Затем я вызываю метод 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
?
secret:get_data_as_bytes():get_data()
выгружает структуру в виде байтового массива; secret:print()
возвращает отформатированную строку структуры. Интересно, есть ли способ лучше.
тип переменной 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"}}})
@cyclaminist оказывается, что secret
является объектом типа GLib.Variant
. Теперь мне нужно разобраться, как получить из него value
.
(Обратите внимание, что я не устанавливал этот менеджер паролей и не пробовал ничего из этого вообще)
В прошлый раз, когда я спросил автора LGI о такой проблеме, я ответил:
I have submitted fix to Variant which restores this functionality. So an example of use will be:
local function called_from_C(userdata)
local variant = GLib.Variant(userdata)
print(variant)
endif you have to support older (well, released :) lgi versions, you can use undocumented way:
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].
Наконец, если вопрос больше о том, как распаковать "рабочие" значения GVariant после того, как они правильно потребляются LGI, посмотрите мой код для этого здесь 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 в основном с точки зрения распространения кода. Я добавил небольшой фрагмент кода для воссоздания объекта требуемого типа. Может, вы могли бы взглянуть на это?
Наконец-то я нашел решение. Для распаковки значения сложного типа, например (a{o(oayays)})
, следует использовать функцию get_child_value
.
secret:get_child_value(0):get_child_value(0):get_child_value(1):get_child_value(2).value
Пояснение: индексный кортеж; индексный массив; index dict; индексный кортеж
Вы можете проверить, есть ли в пользовательских данных метатаблица с метаметодом
__index
для доступа к полям структуры.