我正在开发一个使用 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())
此代码尝试读取项目标签两次。一种失败的正常方式,您应该看到一个空字符串,然后使用解决方法,断开服务并重新连接。