저는 다양한 애플리케이션의 비밀번호 저장 백엔드로 Gnome Keyring을 사용합니다. 많은 항목은 서로 다른 방법을 통해 액세스되는 동일한 계정에 로그인하는 다양한 방법에 대한 것입니다. 이 계정의 비밀번호를 변경했으며 이제 키링의 모든 항목을 업데이트하고 싶습니다.
저는 보통 Seahorse를 사용하여 키링을 편집하지만 약간 어색한 키 입력이나 마우스 클릭을 통해서만 개별 항목을 편집할 수 있습니다. 변경해야 할 비밀번호가 많기 때문에 이는 지루한 작업입니다.
Gnome Keyring의 많은 항목에 대한 비밀번호를 효율적으로 업데이트하는 방법, 즉 비밀번호를 반복해서 입력할 필요 없이 어떻게 해야 합니까?
답변1
다음과 같은흠 제안특정 기준(예: 특정 사용자 이름 및 서버 이름)과 일치하는 모든 항목의 비밀번호를 변경하는 Python 스크립트를 작성했습니다. 스크립트는 온전한 확인을 위해 이전 비밀번호를 요청하고 지정된 이전 비밀번호가 있는 항목만 변경합니다. 사용 예:
keyring-change-passwords 'user|username_value=^gilles$' 'action_url|server=acme\.example\.com'
경고: 코드가 한 번 만족스럽게 실행되었습니다. 이것이 내 테스트의 범위입니다.
참고: API는 시간이 지남에 따라 변경됩니다. 아래 코드는 Ubuntu 20.04용입니다. 하나이 답변의 이전 버전Ubuntu 14.04에서 실행되는 코드가 있습니다.
#!/usr/bin/env python3
"""Change multiple entries in the Gnome Keyring login keyring.
Prompt for the old and new password. Only entries for which the old password
matches are modified.
Condition syntax:
ATTRIBUTE[,ATTRIBUTE...]=REGEX
e.g.
bar,baz=^foo
Only match if the "bar" attribute starts with "foo". If there's no "bar"
attribute, use "baz" instead.
"""
import argparse
import getpass
import os
import re
import sys
import time
import keyring
def print_info():
cfg = keyring.util.platform_.config_root() + '/keyringrc.cfg'
print("Using keyring configuration file:", cfg)
if os.path.exists(cfg):
print(re.sub(r'^', r' ', re.M), open(cfg).read())
print("Any data files are in:", keyring.util.platform_.data_root())
kr = keyring.get_keyring()
print("Backend name:", kr.name)
if hasattr(kr, 'backends'):
print("Backends:")
for b in kr.backends:
print('{}; priority={}, viable={}'
.format(b.name, b.priority, b.viable))
def getpass2(prompt):
input1 = getpass.getpass(prompt)
input2 = getpass.getpass("Repeat " + prompt)
if input1 != input2:
raise ValueError("password mismatch")
return input1
def format_date(seconds):
return time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(seconds))
def maybe_add_attribute(item, attributes, name, method_name=None, formatter=None):
if name in attributes:
return
if method_name is None:
method_name = 'get_' + name
if not hasattr(item, method_name):
return
method = getattr(item, method_name)
value = method()
attributes[name] = formatter(value) if formatter else value
def get_extended_attributes(item):
attributes = item.get_attributes()
maybe_add_attribute(item, attributes, 'label')
maybe_add_attribute(item, attributes, 'secret_content_type')
maybe_add_attribute(item, attributes, 'created', formatter=format_date)
maybe_add_attribute(item, attributes, 'modified', formatter=format_date)
return attributes
def check_conditions(conditions, attributes):
for (names, regexp) in conditions:
value = ''
for name in names:
if name in attributes:
value = attributes[name]
break
if not re.search(regexp, value): return False
return True
def parse_condition_string(arg):
eq = arg.index('=')
return re.split(r'[|,]+', arg[:eq]), re.compile(arg[eq+1:])
def all_keyring_items():
kr = keyring.get_keyring()
if isinstance(kr, keyring.backends.chainer.ChainerBackend):
for b in kr.backends:
if hasattr(b, 'get_preferred_collection'):
yield from b.get_preferred_collection().get_all_items()
else:
yield from kr.get_preferred_collection().get_all_items()
def keyring_items(conditions):
for item in all_keyring_items():
attributes = get_extended_attributes(item)
if check_conditions(conditions, attributes):
yield item, attributes
def change_passwords(conditions, old_password, new_password, verbosity=1):
"""Change the password in many Gnome Keyring entries to new_password.
Iterate over the keyring keyring_name. Only items matching conditions and where
the current password is old_password are considered. The argument conditions
is a list of elements of the form (names, regexp) where names is a list of
attribute names. An item matches the condition if the value of the first
attribute in names that is present on the item contains a match for regexp.
"""
for item, attributes in keyring_items(conditions):
label = attributes['label']
secret_bytes = item.get_secret()
if secret_bytes == old_password or \
secret_bytes == bytes(old_password, 'utf-8'):
if verbosity >= 1:
print('Changing:' if new_password is not None else 'Would change:',
label)
if new_password is not None:
item.set_secret(new_password)
else:
if verbosity >= 2:
print('Has different password, skipping:', label)
def change_password_ui(condition_strings, no_act, verbosity):
conditions = [parse_condition_string(s) for s in condition_strings]
old_password = getpass.getpass("Old password: ")
if no_act:
new_password = None
else:
new_password = getpass2("New password: ")
change_passwords(conditions, old_password, new_password, verbosity)
def main(args):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--info', action='store_true',
help='Print system information and exit')
parser.add_argument('--no-act', '-n', action='store_true',
help='Don\'t actually change passwords, just list entries with a matching password')
parser.add_argument('--quiet', '-q', action='store_true',
help='Print less information')
parser.add_argument('--verbose', '-v', action='store_true',
help='Print more information')
parser.add_argument('conditions', nargs='*', metavar='CONDITION',
help='Only act on entries matching this condition')
options = parser.parse_args(args)
if options.info:
print_info()
return
change_password_ui(options.conditions,
no_act=options.no_act,
verbosity=1 + options.verbose - options.quiet)
if __name__ == '__main__':
main(sys.argv[1:])
답변2
하나 있다파이썬gnome 키링 API용 패키지입니다. 따라할 수 있는 몇 가지 튜토리얼이 있습니다.그놈 키링을 파이썬으로 구부리기비밀번호 검색 및 설정에 대한 몇 가지 예가 있습니다.
secret-tool
패키지에는 libsecret
gnome-keyring에서 비밀번호를 가져오거나 설정하는 명령도 있습니다.