Lua LGI распаковать объект GLib.Variant

Я пытаюсь получить пароль от связки ключей для сеанса потрясающе-wm (используя DBus через библиотеку lgi).

Я могу найти путь входа в связку ключей, открыть сеанс связи и разблокировать запись. Затем я вызываю метод GetSecrets и сохраняю результат в переменной secret. Согласно документации это должен быть struct Secret. Похоже, что lgi не может обрабатывать этот тип и передает его как тип userdata (по крайней мере, мне не удалось заставить его предоставлять доступ к полям структуры). Есть ли способ получить содержимое поля struct Secretvalue без написания собственного обработчика 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"}}})

Вы можете проверить, есть ли в пользовательских данных метатаблица с метаметодом __index для доступа к полям структуры.

cyclaminist 17.11.2018 20:35

@cyclaminist оказывается, что secret является объектом типа GLib.Variant. Теперь мне нужно разобраться, как получить из него value.

Sergey 17.11.2018 21:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
252
2

Ответы 2

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

В прошлый раз, когда я спросил автора 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)
end

if 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 в основном с точки зрения распространения кода. Я добавил небольшой фрагмент кода для воссоздания объекта требуемого типа. Может, вы могли бы взглянуть на это?

Sergey 20.11.2018 14:06

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

Другие вопросы по теме