2

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

我意识到 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 中复制问题的代码。此代码段创建一个集合“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': 'stackoverflow', '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

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

#!/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())

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

4

2 回答 2

1

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

线索在文档中Secret.ServiceFlags——有两个:

开放会话 = 2

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

加载集合 = 4

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

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

以下代码(类似于您的邮件列表 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()
于 2016-08-11T17:57:56.357 回答
0

我一直在这样做

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

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

于 2015-11-12T10:51:30.300 回答