使用 libsecret 我无法获得解锁项目的标签

Posted

技术标签:

【中文标题】使用 libsecret 我无法获得解锁项目的标签【英文标题】:Using libsecret I can't get to the label of an unlocked item 【发布时间】:2016-02-08 03:15:35 【问题描述】:

我正在开发一个使用 libsecret 的小程序。这个程序应该可以创建一个 Secret.Service...

from gi.repository import Secret
service = Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS)

...从该服务中获取特定的集合...

# 2 is the index of a custom collection I created, not the default one.
collection = service.get_collections()[2]

...然后列出该集合中的所有项目,只需打印它们的标签即可。

# I'm just printing a single label here for testing, I'd need all of course.
print(collection.get_items()[0].get_label())

一个重要的细节是 Collection 最初可能被锁定,因此我需要包含检查这种可能性的代码,并尝试解锁 Collection。

# The unlock method returns a tuple (number_of_objs_unlocked, [list_of_objs])
collection = service.unlock_sync([collection])[1][0]

这很重要,因为我目前拥有的代码可以在集合最初解锁时完成我需要的所有操作。但是,如果集合最初被锁定,即使在我解锁它之后,我也无法从里面的项目中获取标签。我能做的是断开()服务,再次重新创建服务,获取现在解锁的集合,这样我就可以读取每个项目上的标签。另一个有趣的细节是,标签被读取一次后,我不再需要服务重新连接来访问它们。这似乎很不优雅,所以我开始寻找不同的解决方案。

我意识到 Collection 继承自 Gio.DBusProxy 并且这个类缓存了它访问的对象的数据。所以我假设这对我来说是个问题,我没有更新缓存。这很奇怪,因为文档指出 Gio.DBusProxy 应该能够检测到原始对象上的更改,但这并没有发生。

现在我不知道如何更新该类的缓存。我查看了一些 seahorse(另一个使用 libsecret 的应用程序)vala 代码,我无法完全破译,我无法对 vala 进行编码,但是提到了 Object.emit() 方法,我是仍然不确定如何使用该方法来实现我的目标。从文档(https://lazka.github.io/pgi-docs/Secret-1/#)中,我发现了另一种很有前途的方法,Object.notify(),它似乎能够发送启用缓存更新的更改通知,但我还不能正确使用它。

我还在 gnome-keyring 邮件列表上发布了关于此的信息...

https://mail.gnome.org/archives/gnome-keyring-list/2015-November/msg00000.html

...到目前为止没有答案,并在 gnome.org 上找到了一个 bugzilla 报告,其中提到了这个问题...

https://bugzilla.gnome.org/show_bug.cgi?id=747359

...到目前为止(7个月)也没有解决方案。

因此,如果有人能对这个问题有所了解,那就太好了。否则不幸的是,一些不雅的代码会进入我的小程序。


编辑-0:

这是一些在 Python3 中复制问题的代码。 此 sn-p 创建一个集合“test_col”,其中包含一个项目“test_item”,并锁定该集合。注意 libsecret 将提示您输入此新集合所需的密码:

#!/usr/bin/env python3

from gi import require_version
require_version('Secret', '1')
from gi.repository import Secret

# Create schema
args = ['com.idlecore.test.schema']
args += [Secret.SchemaFlags.NONE]
args += ['service': Secret.SchemaAttributeType.STRING,
          'username': Secret.SchemaAttributeType.STRING]
schema = Secret.Schema.new(*args)

# Create 'test_col' collection
flags = Secret.CollectionCreateFlags.COLLECTION_CREATE_NONE
collection = Secret.Collection.create_sync(None, 'test_col', None, flags, None)

# Create item 'test_item' inside collection 'test_col'
attributes = 'service': '***', 'username': 'xor'
password = 'password123'
value = Secret.Value(password, len(password), 'text/plain')
flags = Secret.ItemCreateFlags.NONE
Secret.Item.create_sync(collection, schema, attributes,
                        'test_item', value, flags, None)

# Lock collection
service = collection.get_service()
service.lock_sync([collection])

然后我们需要重启 gnome-keyring-daemon,你可以直接注销再登录或者使用命令行:

gnome-keyrin-daemon --replace

这将设置您的密钥环,以便我们可以尝试打开一个最初被锁定的集合。我们可以用这段代码 sn-p 做到这一点。请注意,系统将再次提示您输入之前设置的密码:

#!/usr/bin/env python3

from gi import require_version
require_version('Secret', '1')
from gi.repository import Secret

# Get the service
service = Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS)

# Find the correct collection
for c in service.get_collections():
    if c.get_label() == 'test_col':
        collection = c
        break

# Unlock the collection and show the item label, note that it's empty.
collection = service.unlock_sync([collection])[1][0]
print('Item Label:', collection.get_items()[0].get_label())

# Do the same thing again, and it works.
# It's necessary to disconnect the service to clear the cache,
# Otherwise we keep getting the same empty label.
service.disconnect()

# Get the service
service = Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS)

# Find the correct collection
for c in service.get_collections():
    if c.get_label() == 'test_col':
        collection = c
        break

# No need to unlock again, just show the item label
print('Item Label:', collection.get_items()[0].get_label())

此代码尝试读取项目标签两次。一种失败的正常方式,您应该看到一个空字符串,然后使用解决方法断开服务并重新连接。

【问题讨论】:

【参考方案1】:

我在尝试更新用于从笔记本电脑上的桌面检索密码的脚本时遇到了这个问题,反之亦然。

线索在the documentation for Secret.ServiceFlags——有两个:

OPEN_SESSION = 2

在初始化 Secret.Service 时建立用于传输秘密的会话

LOAD_COLLECTIONS = 4

在初始化 Secret.Service 时加载集合

我认为对于Service both 加载集合 并且 允许从这些集合中传输机密(包括项目标签),我们需要使用这两个标志。

以下代码(类似于your mailing list post,但没有设置用于调试的临时集合)似乎可以工作。它给了我一个项目的标签:

from gi.repository import Secret
service = Secret.Service.get_sync(Secret.ServiceFlags.OPEN_SESSION |
                                  Secret.ServiceFlags.LOAD_COLLECTIONS)
collections = service.get_collections()
unlocked_collection = service.unlock_sync([collections[0]], None)[1][0]
unlocked_collection.get_items()[0].get_label()

【讨论】:

我得到了和以前一样的行为。我会注意到这种行为只发生在第一次解锁时。要正确测试这一点,我需要首先使用“gnome-keyring-daemon --replace”重新启动 gnome-keyring-daemon。【参考方案2】:

我一直在这样做

print(collection.get_locked())
if collection.get_locked():
  service.unlock_sync(collection)

不知道它是否会起作用,因为我从来没有遇到过我的东西被锁定的情况。如果您有一段示例代码,我可以在其中创建集合的锁定实例,那么也许我可以提供帮助

【讨论】:

我编辑了我的原始帖子,在底部包含了几个可以帮助复制问题的 python3 文件。

以上是关于使用 libsecret 我无法获得解锁项目的标签的主要内容,如果未能解决你的问题,请参考以下文章

正在等待缓存锁:无法获得锁 /var/lib/dpkg/lock-frontend。锁正由进程 12836(unattended-upgr)持有

正在等待缓存锁:无法获得锁 /var/lib/dpkg/lock-frontend。锁正由进程 12836(unattended-upgr)持有

即使管理员也无法解锁 AEM 中的页面

Steam 成就 API - 如何获得成就解锁日期?

无法获得 Inception-ResNet-v2 模型的可读类标签

Swift:在 sizetofit 之后无法获得标题单元格标签的正确高度