Lua LGI распаковать GLib.Variant объект - PullRequest
0 голосов
/ 17 ноября 2018

Я пытаюсь получить пароль от набора ключей для сеанса awesome-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 объекта?

редактировать 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"}}})

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Наконец-то я нашел решение.Чтобы распаковать значение сложного типа, например (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 tuple;индексный массив;индекс dict;индексный кортеж

0 голосов
/ 20 ноября 2018

(обратите внимание, что я не устанавливал этот менеджер паролей или вообще не пробовал что-либо из этого)

В прошлый раз, когда я спрашивал автора LGI о такой проблеме, ответ был:

Я отправил исправление в Variant, которое восстанавливает эту функциональность. Так пример использования будет:

локальная функция named_from_C (userdata)
локальный вариант = GLib.Variant (userdata)
печать (вариант) * +1010 * конец

если вам нужно поддерживать более старые (ну, выпущенные :) версии lgi, вы можете использовать недокументированный способ:

локальное ядро ​​= требуется 'lgi.core'
локальная функция named_from_C (userdata)
локальный вариант = core.record.new (GLib.Variant, userdata)
печать (вариант)
конец

Обратите внимание, что есть и другие способы. Чтобы обойти другие подобные ошибки, я также однажды создал плагин 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

...