Python 使用libsecret我可以';t到达未锁定物品的标签

Python 使用libsecret我可以';t到达未锁定物品的标签,python,gnome,dbus,gio,Python,Gnome,Dbus,Gio,我正在开发一个使用libsecret的小程序。这个程序应该可以创建一个秘密服务 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_collect

我正在开发一个使用libsecret的小程序。这个程序应该可以创建一个秘密服务

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]
。。。从该服务获取特定集合

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())
一个重要的细节是,集合最初可能被锁定,因此我需要包含检查这种可能性的代码,并尝试解锁集合

# The unlock method returns a tuple (number_of_objs_unlocked, [list_of_objs])
collection = service.unlock_sync([collection])[1][0]
这一点很重要,因为当集合最初解锁时,我当前拥有的代码可以完成我所需的所有工作。但是,如果集合最初被锁定,即使在我解锁它之后,我也无法从里面的项目中获取标签。我能做的是断开()服务的连接,重新创建服务,获取现在已解锁的集合,这样我就能够读取每个项目上的标签。另一个有趣的细节是,在标签读取一次之后,我不再需要重新连接服务来访问它们。这似乎很不雅观,所以我开始寻找不同的解决方案

我意识到集合继承自Gio.DBusProxy,这个类缓存它访问的对象的数据。所以我假设这是我的问题,我没有更新缓存。但这很奇怪,因为文档说明Gio.DBusProxy应该能够检测原始对象上的更改,但事实并非如此

现在我不知道如何更新该类上的缓存。我看了一些seahorse(另一个使用libsecret的应用程序)的vala代码,我无法完全破译,我无法编写vala,但提到了Object.emit()方法,我仍然不确定如何使用该方法来实现我的目标。从documentation()中,我发现了另一个很有前途的方法Object.notify(),它似乎能够发送更改通知,从而启用缓存更新,但我还不能正确使用它

我也在gnome钥匙圈邮件列表上发布了关于这个

。。。到目前为止还没有答案,在gnome.org上找到了一份提到这个问题的bugzilla报告

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

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


编辑-0:

下面是一些代码来复制Python3中的问题。 此代码段创建一个集合“test\u col”,其中包含一个项“test\u 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守护程序,您只需注销并返回或使用命令行:

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

我一直在这样做

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

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

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

线索就在这里——有两条:

开放式会话=2

在初始化机密服务时建立用于传输机密的会话

加载集合=4

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

我认为对于一个
服务
,既可以加载集合,又可以从集合中传输机密(包括项目标签),我们需要同时使用这两个标志

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

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()

我编辑了我的原始文章,在底部包含了几个python3文件,这些文件可以帮助复制这个问题。我会注意到,这种行为只发生在第一次解锁时。为了正确地测试这一点,我需要首先用“gnomekeyring守护程序--replace”重新启动gnomekeyring守护程序。