New upstream version 10.5.0
Dmitry Shachnev
6 years ago
2 | 2 | brew install python3 |
3 | 3 | rm /usr/local/bin/python |
4 | 4 | ln -s python3 /usr/local/bin/python |
5 | python -m pip install --upgrade tox |
0 | 0 | language: python |
1 | python: | |
2 | - 2.7 | |
3 | - 3.3 | |
4 | - 3.4 | |
5 | - 3.5 | |
6 | - 3.6 | |
7 | matrix: | |
1 | ||
2 | jobs: | |
3 | fast_finish: true | |
8 | 4 | include: |
5 | - python: 2.7 | |
6 | - python: 3.3 | |
7 | - python: &latest_py3 3.6 | |
9 | 8 | - os: osx |
10 | 9 | language: generic |
10 | - stage: deploy | |
11 | if: tag IS present | |
12 | python: *latest_py3 | |
13 | install: skip | |
14 | script: skip | |
15 | deploy: | |
16 | provider: pypi | |
17 | on: | |
18 | tags: true | |
19 | all_branches: true | |
20 | user: jaraco | |
21 | password: | |
22 | secure: aDqlVdm6FZ8pqLkoDRR2LH3TEz7pBvKH2HhOlSy7OEmopN/36ncql/KvfE0ccpaOES9Xm31a51bUfNjcwb1HVKjfW544C+IoSHctkG1rI5bp3q4rW+4RbQcBZVHUUKR9yQf9ZyikEmoYXi3g+JKcOf9rj+v/32PAfUDzSpFbWik= | |
23 | distributions: dists | |
24 | skip_cleanup: true | |
25 | skip_upload_docs: true | |
26 | ||
27 | cache: pip | |
11 | 28 | |
12 | 29 | before_install: |
13 | 30 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source .travis-osx; fi |
14 | 31 | |
15 | 32 | install: |
16 | - python -m pip install tox "setuptools>=28.2" | |
17 | script: | |
18 | - tox -- -rs -v | |
19 | branches: | |
20 | except: | |
21 | - skeleton | |
22 | deploy: | |
23 | provider: pypi | |
24 | server: https://upload.pypi.org/legacy/ | |
25 | on: | |
26 | tags: true | |
27 | all_branches: true | |
28 | python: 3.6 | |
29 | user: jaraco | |
30 | password: | |
31 | secure: aDqlVdm6FZ8pqLkoDRR2LH3TEz7pBvKH2HhOlSy7OEmopN/36ncql/KvfE0ccpaOES9Xm31a51bUfNjcwb1HVKjfW544C+IoSHctkG1rI5bp3q4rW+4RbQcBZVHUUKR9yQf9ZyikEmoYXi3g+JKcOf9rj+v/32PAfUDzSpFbWik= | |
32 | distributions: dists | |
33 | skip_upload_docs: true | |
33 | - pip install tox | |
34 | ||
35 | script: tox |
0 | 10.5.0 | |
1 | ------ | |
2 | ||
3 | * #287: Added ``--list-backends`` option to | |
4 | command-line interface. | |
5 | ||
6 | * Removed ``logger`` from ``keyring``. See #291 for related | |
7 | request. | |
8 | ||
9 | * #292: Set the appid for SecretService & KWallet to | |
10 | something meaningful. | |
11 | ||
0 | 12 | 10.4.0 |
1 | 13 | ------ |
2 | 14 | |
486 | 498 | |
487 | 499 | * Removed support for Python 2.5. |
488 | 500 | * Removed names in ``keyring.backend`` moved in 1.1 and previously retained |
489 | for compatibilty. | |
501 | for compatibility. | |
490 | 502 | |
491 | 503 | 2.1.1 |
492 | 504 | ----- |
788 | 800 | location or make assumptions about the storage location will need to take |
789 | 801 | this change into consideration. Additionally, after upgrading to 0.8, |
790 | 802 | it is not possible to downgrade to 0.7 without manually moving |
791 | configuration files. In 1.0, the backward compatibilty | |
803 | configuration files. In 1.0, the backward compatibility | |
792 | 804 | will be removed. |
793 | 805 | |
794 | 806 | 0.7.1 |
0 | Copyright Jason R. Coombs | |
1 | ||
2 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
3 | ||
4 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
5 | ||
6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
0 | Metadata-Version: 1.1 | |
0 | Metadata-Version: 1.2 | |
1 | 1 | Name: keyring |
2 | Version: 10.4.0 | |
2 | Version: 10.5.0 | |
3 | 3 | Summary: Store and access your passwords safely. |
4 | 4 | Home-page: https://github.com/jaraco/keyring |
5 | 5 | Author: Jason R. Coombs |
6 | 6 | Author-email: jaraco@jaraco.com |
7 | 7 | License: UNKNOWN |
8 | Description-Content-Type: UNKNOWN | |
8 | 9 | Description: .. image:: https://img.shields.io/pypi/v/keyring.svg |
9 | 10 | :target: https://pypi.org/project/keyring |
10 | 11 | |
11 | 12 | .. image:: https://img.shields.io/pypi/pyversions/keyring.svg |
12 | 13 | |
13 | .. image:: https://img.shields.io/pypi/dm/keyring.svg | |
14 | ||
15 | 14 | .. image:: https://img.shields.io/travis/jaraco/keyring/master.svg |
16 | 15 | :target: http://travis-ci.org/jaraco/keyring |
17 | 16 | |
17 | .. image:: https://readthedocs.org/projects/keyring/badge/?version=latest | |
18 | :target: http://keyring.readthedocs.io/en/latest/?badge=latest | |
18 | 19 | |
19 | 20 | ======================================= |
20 | 21 | Installing and Using Python Keyring Lib |
26 | 27 | What is Python keyring lib? |
27 | 28 | --------------------------- |
28 | 29 | |
29 | The Python keyring lib provides a easy way to access the system keyring service | |
30 | The Python keyring lib provides an easy way to access the system keyring service | |
30 | 31 | from python. It can be used in any application that needs safe password storage. |
31 | 32 | |
32 | 33 | The keyring library is licensed under both the `MIT license |
41 | 42 | `secretstorage <https://pypi.python.org/pypi/secretstorage>`_) |
42 | 43 | * `KWallet <https://en.wikipedia.org/wiki/KWallet>`_ |
43 | 44 | (requires `dbus <https://pypi.python.org/pypi/dbus-python>`_) |
44 | * `Windows Credential Vault | |
45 | <http://windows.microsoft.com/en-us/windows7/what-is-credential-manager>`_ | |
45 | * `Windows Credential Locker | |
46 | <https://docs.microsoft.com/en-us/windows/uwp/security/credential-locker>`_ | |
46 | 47 | |
47 | 48 | Other keyring implementations are provided in the `keyrings.alt package`_. |
48 | 49 | |
219 | 220 | # invoke the keyring lib |
220 | 221 | try: |
221 | 222 | keyring.set_password("demo-service", "tarek", "passexample") |
222 | print("password stored sucessfully") | |
223 | print("password stored successfully") | |
223 | 224 | except keyring.errors.PasswordSetError: |
224 | 225 | print("failed to store password") |
225 | 226 | print("password", keyring.get_password("demo-service", "tarek")) |
361 | 362 | Classifier: Programming Language :: Python :: 3.4 |
362 | 363 | Classifier: Programming Language :: Python :: 3.5 |
363 | 364 | Classifier: Programming Language :: Python :: 3.6 |
365 | Requires-Python: >=2.7 |
2 | 2 | |
3 | 3 | .. image:: https://img.shields.io/pypi/pyversions/keyring.svg |
4 | 4 | |
5 | .. image:: https://img.shields.io/pypi/dm/keyring.svg | |
6 | ||
7 | 5 | .. image:: https://img.shields.io/travis/jaraco/keyring/master.svg |
8 | 6 | :target: http://travis-ci.org/jaraco/keyring |
9 | 7 | |
8 | .. image:: https://readthedocs.org/projects/keyring/badge/?version=latest | |
9 | :target: http://keyring.readthedocs.io/en/latest/?badge=latest | |
10 | 10 | |
11 | 11 | ======================================= |
12 | 12 | Installing and Using Python Keyring Lib |
18 | 18 | What is Python keyring lib? |
19 | 19 | --------------------------- |
20 | 20 | |
21 | The Python keyring lib provides a easy way to access the system keyring service | |
21 | The Python keyring lib provides an easy way to access the system keyring service | |
22 | 22 | from python. It can be used in any application that needs safe password storage. |
23 | 23 | |
24 | 24 | The keyring library is licensed under both the `MIT license |
33 | 33 | `secretstorage <https://pypi.python.org/pypi/secretstorage>`_) |
34 | 34 | * `KWallet <https://en.wikipedia.org/wiki/KWallet>`_ |
35 | 35 | (requires `dbus <https://pypi.python.org/pypi/dbus-python>`_) |
36 | * `Windows Credential Vault | |
37 | <http://windows.microsoft.com/en-us/windows7/what-is-credential-manager>`_ | |
36 | * `Windows Credential Locker | |
37 | <https://docs.microsoft.com/en-us/windows/uwp/security/credential-locker>`_ | |
38 | 38 | |
39 | 39 | Other keyring implementations are provided in the `keyrings.alt package`_. |
40 | 40 | |
211 | 211 | # invoke the keyring lib |
212 | 212 | try: |
213 | 213 | keyring.set_password("demo-service", "tarek", "passexample") |
214 | print("password stored sucessfully") | |
214 | print("password stored successfully") | |
215 | 215 | except keyring.errors.PasswordSetError: |
216 | 216 | print("failed to store password") |
217 | 217 | print("password", keyring.get_password("demo-service", "tarek")) |
15 | 15 | |
16 | 16 | test_script: |
17 | 17 | - "python -m pip install tox" |
18 | - "tox -- -rs -v" | |
18 | - "tox" | |
19 | 19 | |
20 | branches: | |
21 | except: | |
22 | - skeleton | |
20 | version: '{build}' |
4 | 4 | ] |
5 | 5 | |
6 | 6 | if platform.system() != 'Darwin': |
7 | collect_ignore.append('keyring/backends/_OS_X_API.py') | |
7 | collect_ignore.append('keyring/backends/_OS_X_API.py') | |
8 | 8 | |
9 | 9 | collect_ignore.append('keyring/devpi_client.py') |
10 | 10 | import pkg_resources |
11 | 11 | |
12 | 12 | hiddenimports.extend( |
13 | ep.module_name | |
14 | for ep in pkg_resources.iter_entry_points('keyring.backends') | |
13 | ep.module_name | |
14 | for ep in pkg_resources.iter_entry_points('keyring.backends') | |
15 | 15 | ) |
0 | 0 | from __future__ import absolute_import |
1 | 1 | |
2 | import logging | |
3 | logger = logging.getLogger('keyring') | |
4 | ||
5 | 2 | from .core import (set_keyring, get_keyring, set_password, get_password, |
6 | delete_password) | |
3 | delete_password) | |
7 | 4 | from .getpassbackend import get_password as get_pass_get_password |
8 | 5 | |
9 | 6 | try: |
10 | import pkg_resources | |
11 | __version__ = pkg_resources.require('keyring')[0].version | |
7 | import pkg_resources | |
8 | __version__ = pkg_resources.get_distribution('keyring').version | |
12 | 9 | except Exception: |
13 | __version__ = 'unknown' | |
10 | __version__ = 'unknown' | |
11 | ||
12 | __all__ = ( | |
13 | 'set_keyring', 'get_keyring', 'set_password', 'get_password', | |
14 | 'delete_password', 'get_pass_get_password', | |
15 | ) |
97 | 97 | """ |
98 | 98 | raise errors.PasswordDeleteError("reason") |
99 | 99 | |
100 | ||
100 | 101 | class Crypter(object): |
101 | 102 | """Base class providing encryption and decryption |
102 | 103 | """ |
113 | 114 | """ |
114 | 115 | pass |
115 | 116 | |
117 | ||
116 | 118 | class NullCrypter(Crypter): |
117 | 119 | """A crypter that does nothing |
118 | 120 | """ |
127 | 129 | def _load_backend(name): |
128 | 130 | "Load a backend by name" |
129 | 131 | package = backends.__package__ or backends.__name__ |
130 | mod = importlib.import_module('.'+name, package) | |
132 | mod = importlib.import_module('.' + name, package) | |
131 | 133 | # invoke __name__ on each module to ensure it's loaded in demand-import |
132 | 134 | # environments |
133 | 135 | mod.__name__ |
136 | ||
134 | 137 | |
135 | 138 | def _load_backends(): |
136 | 139 | "ensure that native keyring backends are loaded" |
137 | 140 | backends = 'kwallet', 'OS_X', 'SecretService', 'Windows' |
138 | 141 | list(map(_load_backend, backends)) |
139 | 142 | _load_plugins() |
143 | ||
140 | 144 | |
141 | 145 | def _load_plugins(): |
142 | 146 | """ |
169 | 173 | except Exception: |
170 | 174 | log.exception("Error initializing plugin %s." % ep) |
171 | 175 | |
176 | ||
172 | 177 | @util.once |
173 | 178 | def get_all_keyring(): |
174 | 179 | """ |
187 | 192 | all_classes = KeyringBackend._classes |
188 | 193 | viable_classes = filter(is_class_viable, all_classes) |
189 | 194 | return list(util.suppress_exceptions(viable_classes, |
190 | exceptions=TypeError)) | |
195 | exceptions=TypeError)) |
31 | 31 | username = '' |
32 | 32 | |
33 | 33 | try: |
34 | api.set_generic_password(self.keychain, service, username, password) | |
34 | api.set_generic_password( | |
35 | self.keychain, service, username, password) | |
35 | 36 | except api.Error: |
36 | 37 | raise PasswordSetError("Can't store password on keychain") |
37 | 38 | |
49 | 50 | username = '' |
50 | 51 | |
51 | 52 | try: |
52 | return api.delete_generic_password(self.keychain, service, username) | |
53 | return api.delete_generic_password( | |
54 | self.keychain, service, username) | |
53 | 55 | except api.Error: |
54 | 56 | raise PasswordDeleteError("Can't delete password in keychain") |
0 | 0 | import logging |
1 | ||
2 | import sys | |
3 | import os | |
1 | 4 | |
2 | 5 | from ..util import properties |
3 | 6 | from ..backend import KeyringBackend |
4 | 7 | from ..errors import (InitError, PasswordDeleteError, |
5 | ExceptionRaisedContext) | |
8 | ExceptionRaisedContext) | |
6 | 9 | |
7 | 10 | try: |
8 | 11 | import secretstorage |
12 | 15 | |
13 | 16 | log = logging.getLogger(__name__) |
14 | 17 | |
18 | ||
15 | 19 | class Keyring(KeyringBackend): |
16 | 20 | """Secret Service Keyring""" |
17 | appid = "python-keyring" | |
21 | appid = os.path.basename(sys.argv[0]) or 'Python keyring library' | |
18 | 22 | |
19 | 23 | @properties.ClassProperty |
20 | 24 | @classmethod |
40 | 44 | bus = secretstorage.dbus_init() |
41 | 45 | try: |
42 | 46 | if hasattr(self, 'preferred_collection'): |
43 | collection = secretstorage.Collection(bus, self.preferred_collection) | |
47 | collection = secretstorage.Collection( | |
48 | bus, self.preferred_collection) | |
44 | 49 | else: |
45 | 50 | collection = secretstorage.get_default_collection(bus) |
46 | 51 | except exceptions.SecretStorageException as e: |
47 | 52 | raise InitError("Failed to create the collection: %s." % e) |
48 | 53 | if collection.is_locked(): |
49 | 54 | collection.unlock() |
50 | if collection.is_locked(): # User dismissed the prompt | |
55 | if collection.is_locked(): # User dismissed the prompt | |
51 | 56 | raise InitError("Failed to unlock the collection!") |
52 | 57 | return collection |
53 | 58 | |
71 | 76 | "application": self.appid, |
72 | 77 | "service": service, |
73 | 78 | "username": username |
74 | } | |
79 | } | |
75 | 80 | label = "Password for '%s' on '%s'" % (username, service) |
76 | 81 | collection.create_item(label, attributes, password, replace=True) |
77 | 82 |
19 | 19 | import win32cred |
20 | 20 | except ImportError: |
21 | 21 | pass |
22 | ||
22 | 23 | |
23 | 24 | def has_pywin32(): |
24 | 25 | """ |
82 | 83 | ) |
83 | 84 | except pywintypes.error as e: |
84 | 85 | e = OldPywinError.wrap(e) |
85 | if e.winerror == 1168 and e.funcname == 'CredRead': # not found | |
86 | if e.winerror == 1168 and e.funcname == 'CredRead': # not found | |
86 | 87 | return None |
87 | 88 | raise |
88 | 89 | return res |
94 | 95 | existing_username = existing_pw['UserName'] |
95 | 96 | target = self._compound_name(existing_username, service) |
96 | 97 | self._set_password(target, existing_username, |
97 | existing_pw['CredentialBlob'].decode('utf-16')) | |
98 | existing_pw['CredentialBlob'].decode('utf-16')) | |
98 | 99 | self._set_password(service, username, text_type(password)) |
99 | 100 | |
100 | 101 | def _set_password(self, target, username, password): |
129 | 130 | A compatibility wrapper for old PyWin32 errors, such as reported in |
130 | 131 | https://bitbucket.org/kang/python-keyring-lib/issue/140/ |
131 | 132 | """ |
133 | ||
132 | 134 | def __init__(self, orig): |
133 | 135 | self.orig = orig |
134 | 136 |
8 | 8 | sec_keychain_ref = sec_keychain_item_ref = c_void_p |
9 | 9 | OS_status = c_int32 |
10 | 10 | |
11 | ||
11 | 12 | class error: |
12 | 13 | item_not_found = -25300 |
14 | ||
13 | 15 | |
14 | 16 | fw = '/System/Library/Frameworks/{name}.framework/Versions/A/{name}'.format |
15 | 17 | _sec = ctypes.CDLL(fw(name='Security')) |
22 | 24 | POINTER(sec_keychain_ref), |
23 | 25 | ) |
24 | 26 | SecKeychainOpen.restype = OS_status |
25 | ||
26 | 27 | |
27 | 28 | |
28 | 29 | SecKeychainCopyDefault = _sec.SecKeychainCopyDefault |
61 | 62 | finally: |
62 | 63 | _core.CFRelease(ref) |
63 | 64 | |
65 | ||
64 | 66 | SecKeychainFindGenericPassword = _sec.SecKeychainFindGenericPassword |
65 | 67 | SecKeychainFindGenericPassword.argtypes = ( |
66 | 68 | sec_keychain_ref, |
74 | 76 | ) |
75 | 77 | SecKeychainFindGenericPassword.restype = OS_status |
76 | 78 | |
79 | ||
77 | 80 | def find_generic_password(kc_name, service, username): |
78 | username = username.encode('utf-8') | |
79 | service = service.encode('utf-8') | |
80 | with open(kc_name) as keychain: | |
81 | length = c_uint32() | |
82 | data = c_void_p() | |
83 | status = SecKeychainFindGenericPassword( | |
84 | keychain, | |
85 | len(service), | |
86 | service, | |
87 | len(username), | |
88 | username, | |
89 | length, | |
90 | data, | |
91 | None, | |
92 | ) | |
93 | ||
94 | msg = "Can't fetch password from system" | |
95 | NotFound.raise_for_status(status, msg) | |
96 | ||
97 | password = ctypes.create_string_buffer(length.value) | |
98 | ctypes.memmove(password, data.value, length.value) | |
99 | SecKeychainItemFreeContent(None, data) | |
100 | return password.raw.decode('utf-8') | |
81 | username = username.encode('utf-8') | |
82 | service = service.encode('utf-8') | |
83 | with open(kc_name) as keychain: | |
84 | length = c_uint32() | |
85 | data = c_void_p() | |
86 | status = SecKeychainFindGenericPassword( | |
87 | keychain, | |
88 | len(service), | |
89 | service, | |
90 | len(username), | |
91 | username, | |
92 | length, | |
93 | data, | |
94 | None, | |
95 | ) | |
96 | ||
97 | msg = "Can't fetch password from system" | |
98 | NotFound.raise_for_status(status, msg) | |
99 | ||
100 | password = ctypes.create_string_buffer(length.value) | |
101 | ctypes.memmove(password, data.value, length.value) | |
102 | SecKeychainItemFreeContent(None, data) | |
103 | return password.raw.decode('utf-8') | |
101 | 104 | |
102 | 105 | |
103 | 106 | SecKeychainFindInternetPassword = _sec.SecKeychainFindInternetPassword |
104 | 107 | SecKeychainFindInternetPassword.argtypes = ( |
105 | sec_keychain_ref, # keychainOrArray | |
108 | sec_keychain_ref, # keychainOrArray | |
106 | 109 | c_uint32, # serverNameLength |
107 | 110 | c_char_p, # serverName |
108 | 111 | c_uint32, # securityDomainLength |
169 | 172 | |
170 | 173 | |
171 | 174 | def find_internet_password(kc_name, service, username): |
172 | username = username.encode('utf-8') | |
173 | domain = None | |
174 | service = service.encode('utf-8') | |
175 | path = None | |
176 | port = 0 | |
177 | ||
178 | with open(kc_name) as keychain: | |
179 | length = c_uint32() | |
180 | data = c_void_p() | |
181 | status = SecKeychainFindInternetPassword( | |
182 | keychain, | |
183 | len(service), service, | |
184 | 0, domain, | |
185 | len(username), username, | |
186 | 0, path, | |
187 | port, | |
188 | SecProtocolType.kSecProtocolTypeHTTPS, | |
189 | SecAuthenticationType.kSecAuthenticationTypeAny, | |
190 | length, | |
191 | data, | |
192 | None, | |
193 | ) | |
194 | ||
195 | msg = "Can't fetch password from system" | |
196 | NotFound.raise_for_status(status, msg) | |
197 | ||
198 | password = ctypes.create_string_buffer(length.value) | |
199 | ctypes.memmove(password, data.value, length.value) | |
200 | SecKeychainItemFreeContent(None, data) | |
201 | return password.raw.decode('utf-8') | |
175 | username = username.encode('utf-8') | |
176 | domain = None | |
177 | service = service.encode('utf-8') | |
178 | path = None | |
179 | port = 0 | |
180 | ||
181 | with open(kc_name) as keychain: | |
182 | length = c_uint32() | |
183 | data = c_void_p() | |
184 | status = SecKeychainFindInternetPassword( | |
185 | keychain, | |
186 | len(service), service, | |
187 | 0, domain, | |
188 | len(username), username, | |
189 | 0, path, | |
190 | port, | |
191 | SecProtocolType.kSecProtocolTypeHTTPS, | |
192 | SecAuthenticationType.kSecAuthenticationTypeAny, | |
193 | length, | |
194 | data, | |
195 | None, | |
196 | ) | |
197 | ||
198 | msg = "Can't fetch password from system" | |
199 | NotFound.raise_for_status(status, msg) | |
200 | ||
201 | password = ctypes.create_string_buffer(length.value) | |
202 | ctypes.memmove(password, data.value, length.value) | |
203 | SecKeychainItemFreeContent(None, data) | |
204 | return password.raw.decode('utf-8') | |
202 | 205 | |
203 | 206 | |
204 | 207 | SecKeychainAddGenericPassword = _sec.SecKeychainAddGenericPassword |
243 | 246 | |
244 | 247 | SecKeychainAddInternetPassword = _sec.SecKeychainAddInternetPassword |
245 | 248 | SecKeychainAddInternetPassword.argtypes = ( |
246 | sec_keychain_ref, # keychainOrArray | |
249 | sec_keychain_ref, # keychainOrArray | |
247 | 250 | c_uint32, # serverNameLength |
248 | 251 | c_char_p, # serverName |
249 | 252 | c_uint32, # securityDomainLength |
0 | 0 | from __future__ import absolute_import |
1 | ||
2 | import sys | |
3 | import os | |
1 | 4 | |
2 | 5 | from ..backend import KeyringBackend |
3 | 6 | from ..errors import PasswordDeleteError |
16 | 19 | KDE KWallet 5 via D-Bus |
17 | 20 | """ |
18 | 21 | |
19 | appid = 'Python program' | |
22 | appid = os.path.basename(sys.argv[0]) or 'Python keyring library' | |
20 | 23 | wallet = None |
21 | 24 | bus_name = 'org.kde.kwalletd5' |
22 | 25 | object_path = '/modules/kwalletd5' |
47 | 50 | entry_list = [] |
48 | 51 | if self.iface.hasFolder(self.handle, old_folder, self.appid): |
49 | 52 | entry_list = self.iface.readPasswordList( |
50 | self.handle, old_folder, '*@*', self.appid) | |
53 | self.handle, old_folder, '*@*', self.appid) | |
51 | 54 | |
52 | 55 | for entry in entry_list.items(): |
53 | 56 | key = entry[0] |
55 | 58 | |
56 | 59 | username, service = key.rsplit('@', 1) |
57 | 60 | ret = self.iface.writePassword( |
58 | self.handle, service, username, password, self.appid) | |
61 | self.handle, service, username, password, self.appid) | |
59 | 62 | if ret == 0: |
60 | self.iface.removeEntry(self.handle, old_folder, key, self.appid) | |
63 | self.iface.removeEntry( | |
64 | self.handle, old_folder, key, self.appid) | |
61 | 65 | |
62 | 66 | entry_list = self.iface.readPasswordList( |
63 | self.handle, old_folder, '*', self.appid) | |
67 | self.handle, old_folder, '*', self.appid) | |
64 | 68 | if not entry_list: |
65 | 69 | self.iface.removeFolder(self.handle, old_folder, self.appid) |
66 | 70 | |
73 | 77 | remote_obj = bus.get_object(self.bus_name, self.object_path) |
74 | 78 | self.iface = dbus.Interface(remote_obj, 'org.kde.KWallet') |
75 | 79 | self.handle = self.iface.open( |
76 | self.iface.networkWallet(), wId, self.appid) | |
80 | self.iface.networkWallet(), wId, self.appid) | |
77 | 81 | except dbus.DBusException: |
78 | 82 | self.handle = -1 |
79 | 83 | if self.handle < 0: |
6 | 6 | from optparse import OptionParser |
7 | 7 | import sys |
8 | 8 | |
9 | from . import core | |
10 | from . import backend | |
9 | 11 | from . import get_keyring, set_keyring, get_password, set_password, delete_password |
10 | from . import core | |
11 | 12 | |
12 | 13 | |
13 | 14 | class CommandLineTool(object): |
14 | 15 | def __init__(self): |
15 | 16 | self.parser = OptionParser( |
16 | usage="%prog [get|set|del] SERVICE USERNAME") | |
17 | usage="%prog [get|set|del] SERVICE USERNAME") | |
17 | 18 | self.parser.add_option("-p", "--keyring-path", |
18 | 19 | dest="keyring_path", default=None, |
19 | 20 | help="Path to the keyring backend") |
20 | 21 | self.parser.add_option("-b", "--keyring-backend", |
21 | 22 | dest="keyring_backend", default=None, |
22 | 23 | help="Name of the keyring backend") |
24 | self.parser.add_option("--list-backends", | |
25 | action="store_true", | |
26 | help="List keyring backends and exit") | |
23 | 27 | |
24 | 28 | def run(self, argv): |
25 | 29 | opts, args = self.parser.parse_args(argv) |
30 | ||
31 | if opts.list_backends: | |
32 | for k in backend.get_all_keyring(): | |
33 | print(k) | |
34 | return | |
26 | 35 | |
27 | 36 | try: |
28 | 37 | kind, service, username = args |
38 | 47 | try: |
39 | 48 | if opts.keyring_path: |
40 | 49 | sys.path.insert(0, opts.keyring_path) |
41 | backend = core.load_keyring(opts.keyring_backend) | |
42 | set_keyring(backend) | |
50 | set_keyring(core.load_keyring(opts.keyring_backend)) | |
43 | 51 | except (Exception,): |
44 | 52 | # Tons of things can go wrong here: |
45 | 53 | # ImportError when using "fjkljfljkl" |
65 | 73 | |
66 | 74 | elif kind == 'del': |
67 | 75 | password = self.input_password("Deleting password for '%s' in '%s': " % |
68 | (username, service)) | |
76 | (username, service)) | |
69 | 77 | delete_password(service, username) |
70 | 78 | return 0 |
71 | 79 |
9 | 9 | from .py27compat import configparser, filter |
10 | 10 | from .py33compat import max |
11 | 11 | |
12 | from . import logger | |
13 | 12 | from . import backend |
14 | 13 | from .util import platform_ as platform |
15 | 14 | from .backends import fail |
18 | 17 | log = logging.getLogger(__name__) |
19 | 18 | |
20 | 19 | _keyring_backend = None |
20 | ||
21 | 21 | |
22 | 22 | def set_keyring(keyring): |
23 | 23 | """Set current keyring backend. |
52 | 52 | _keyring_backend.delete_password(service_name, username) |
53 | 53 | |
54 | 54 | |
55 | recommended = lambda backend: backend.priority >= 1 | |
55 | def recommended(backend): return backend.priority >= 1 | |
56 | ||
57 | ||
56 | 58 | by_priority = operator.attrgetter('priority') |
57 | 59 | |
58 | 60 | |
129 | 131 | raise configparser.NoOptionError('backend', 'default-keyring') |
130 | 132 | |
131 | 133 | except (configparser.NoOptionError, ImportError): |
134 | logger = logging.getLogger('keyring') | |
132 | 135 | logger.warning("Keyring config file contains incorrect values.\n" + |
133 | 136 | "Config file: %s" % keyring_cfg) |
134 | 137 | return |
135 | 138 | |
136 | 139 | return load_keyring(keyring_name) |
140 | ||
137 | 141 | |
138 | 142 | def _load_keyring_path(config): |
139 | 143 | "load the keyring-path option (if present)" |
143 | 147 | except (configparser.NoOptionError, configparser.NoSectionError): |
144 | 148 | pass |
145 | 149 | |
150 | ||
146 | 151 | # init the _keyring_backend |
147 | 152 | init_backend() |
1 | 1 | import abc |
2 | 2 | |
3 | 3 | from .py27compat import add_metaclass |
4 | ||
4 | 5 | |
5 | 6 | @add_metaclass(abc.ABCMeta) |
6 | 7 | class Credential(object): |
14 | 15 | @abc.abstractproperty |
15 | 16 | def password(self): |
16 | 17 | return None |
18 | ||
17 | 19 | |
18 | 20 | class SimpleCredential(Credential): |
19 | 21 | """Simple credentials implementation |
31 | 33 | def password(self): |
32 | 34 | return self._password |
33 | 35 | |
36 | ||
34 | 37 | class EnvironCredential(Credential): |
35 | 38 | """Source credentials from environment variables. |
36 | 39 | Actual sourcing is deferred until requested. |
45 | 48 | """ |
46 | 49 | value = os.environ.get(env_var) |
47 | 50 | if not value: |
48 | raise ValueError('Missing environment variable:%s' %env_var) | |
51 | raise ValueError('Missing environment variable:%s' % env_var) | |
49 | 52 | return value |
50 | 53 | |
51 | 54 | @property |
4 | 4 | |
5 | 5 | hookimpl = HookimplMarker("devpiclient") |
6 | 6 | |
7 | ||
7 | 8 | @hookimpl() |
8 | 9 | def devpiclient_get_password(url, username): |
9 | return keyring.get_password(url, username) | |
10 | return keyring.get_password(url, username) |
0 | 0 | import sys |
1 | ||
1 | 2 | |
2 | 3 | class PasswordSetError(Exception): |
3 | 4 | """Raised when the password can't be set. |
4 | 5 | """ |
5 | 6 | |
7 | ||
6 | 8 | class PasswordDeleteError(Exception): |
7 | 9 | """Raised when the password can't be deleted. |
8 | 10 | """ |
9 | 11 | |
12 | ||
10 | 13 | class InitError(Exception): |
11 | 14 | """Raised when the keyring could not be initialised |
12 | 15 | """ |
16 | ||
13 | 17 | |
14 | 18 | class ExceptionRaisedContext(object): |
15 | 19 | """ |
16 | 20 | An exception-trapping context that indicates whether an exception was |
17 | 21 | raised. |
18 | 22 | """ |
23 | ||
19 | 24 | def __init__(self, ExpectedException=Exception): |
20 | 25 | self.ExpectedException = ExpectedException |
21 | 26 | self.exc_info = None |
28 | 33 | self.exc_info.__init__(*exc_info) |
29 | 34 | return self.exc_info.type and issubclass( |
30 | 35 | self.exc_info.type, self.ExpectedException) |
36 | ||
31 | 37 | |
32 | 38 | class ExceptionInfo(object): |
33 | 39 | def __init__(self, *info): |
14 | 14 | import getpass |
15 | 15 | |
16 | 16 | from . import get_password, delete_password, set_password |
17 | ||
17 | 18 | |
18 | 19 | class PasswordMgr(object): |
19 | 20 | def get_username(self, realm, authuri): |
29 | 29 | filter = filter |
30 | 30 | |
31 | 31 | # Taken from six.py |
32 | ||
33 | ||
32 | 34 | def add_metaclass(metaclass): |
33 | 35 | """Class decorator for creating a class with a metaclass.""" |
34 | 36 | def wrapper(cls): |
40 | 42 | return metaclass(cls.__name__, cls.__bases__, orig_vars) |
41 | 43 | return wrapper |
42 | 44 | |
45 | ||
43 | 46 | try: |
44 | 47 | import builtins |
45 | 48 | except ImportError: |
3 | 3 | from ..test_backend import BackendBasicTests |
4 | 4 | from keyring.backends import OS_X |
5 | 5 | |
6 | ||
6 | 7 | def is_osx_keychain_supported(): |
7 | return sys.platform in ('mac','darwin') | |
8 | return sys.platform in ('mac', 'darwin') | |
9 | ||
8 | 10 | |
9 | 11 | @unittest.skipUnless(is_osx_keychain_supported(), |
10 | 12 | "Need OS X") |
3 | 3 | from keyring.backends import SecretService |
4 | 4 | from .. import util |
5 | 5 | |
6 | ||
6 | 7 | @unittest.skipUnless(SecretService.Keyring.viable, |
7 | "SecretStorage package is needed for SecretServiceKeyring") | |
8 | "SecretStorage package is needed for SecretServiceKeyring") | |
8 | 9 | class SecretServiceKeyringTestCase(BackendBasicTests, unittest.TestCase): |
9 | 10 | __test__ = True |
10 | 11 | |
11 | 12 | def init_keyring(self): |
12 | 13 | print("Testing SecretServiceKeyring; the following " |
13 | "password prompts are for this keyring") | |
14 | "password prompts are for this keyring") | |
14 | 15 | keyring = SecretService.Keyring() |
15 | 16 | keyring.preferred_collection = '/org/freedesktop/secrets/collection/session' |
16 | 17 | return keyring |
18 | ||
17 | 19 | |
18 | 20 | class SecretServiceKeyringUnitTests(unittest.TestCase): |
19 | 21 | def test_supported_no_secretstorage(self): |
9 | 9 | |
10 | 10 | |
11 | 11 | @unittest.skipUnless(keyring.backends.Windows.WinVaultKeyring.viable, |
12 | "Needs Windows") | |
12 | "Needs Windows") | |
13 | 13 | class WinVaultKeyringTestCase(BackendBasicTests, unittest.TestCase): |
14 | 14 | def tearDown(self): |
15 | 15 | # clean up any credentials created |
15 | 15 | |
16 | 16 | def tearDown(self): |
17 | 17 | for item in self.credentials_created: |
18 | # Suppress errors, as only one pre/post migration item will be present | |
18 | # Suppress errors, as only one pre/post migration item will be | |
19 | # present | |
19 | 20 | try: |
20 | 21 | self.keyring.delete_password(*item) |
21 | except: | |
22 | except BaseException: | |
22 | 23 | pass |
23 | 24 | |
24 | 25 | # TODO Remove empty folders created during tests |
29 | 30 | self.credentials_created.add((service, username)) |
30 | 31 | |
31 | 32 | if old_format: |
32 | username = username+'@'+service | |
33 | username = username + '@' + service | |
33 | 34 | service = 'Python' |
34 | 35 | |
35 | super(DBusKWalletTestCase, self).set_password(service, username, password) | |
36 | super( | |
37 | DBusKWalletTestCase, | |
38 | self).set_password( | |
39 | service, | |
40 | username, | |
41 | password) | |
36 | 42 | |
37 | 43 | def check_set_get(self, service, username, password): |
38 | 44 | keyring = self.keyring |
46 | 52 | self.keyring = keyring = self.init_keyring() |
47 | 53 | ret_password = keyring.get_password(service, username) |
48 | 54 | self.assertEqual( |
49 | ret_password, password, | |
50 | "Incorrect password for username: '%s' on service: '%s'. '%s' != '%s'" | |
51 | % (service, username, ret_password, password)) | |
55 | ret_password, password, | |
56 | "Incorrect password for username: '%s' on service: '%s'. '%s' != '%s'" | |
57 | % (service, username, ret_password, password)) | |
52 | 58 | |
53 | 59 | # for the empty password |
54 | 60 | self.set_password(service, username, "", True) |
56 | 62 | self.keyring = keyring = self.init_keyring() |
57 | 63 | ret_password = keyring.get_password(service, username) |
58 | 64 | self.assertEqual( |
59 | ret_password, "", | |
60 | "Incorrect password for username: '%s' on service: '%s'. '%s' != '%s'" | |
61 | % (service, username, ret_password, "")) | |
62 | ret_password = keyring.get_password('Python', username+'@'+service) | |
65 | ret_password, "", | |
66 | "Incorrect password for username: '%s' on service: '%s'. '%s' != '%s'" | |
67 | % (service, username, ret_password, "")) | |
68 | ret_password = keyring.get_password('Python', username + '@' + service) | |
63 | 69 | self.assertEqual( |
64 | ret_password, None, | |
65 | "Not 'None' password returned for username: '%s' on service: '%s'. '%s' != '%s'. Passwords from old folder should be deleted during migration." | |
66 | % (service, username, ret_password, None)) | |
70 | ret_password, None, | |
71 | "Not 'None' password returned for username: '%s' on service: '%s'. '%s' != '%s'. Passwords from old folder should be deleted during migration." | |
72 | % (service, username, ret_password, None)) | |
67 | 73 | |
68 | 74 | |
69 | 75 | @unittest.skipUnless(kwallet.DBusKeyringKWallet4.viable, |
70 | "KWallet4 unavailable") | |
76 | "KWallet4 unavailable") | |
71 | 77 | class DBusKWallet4TestCase(DBusKWalletTestCase): |
72 | 78 | def init_keyring(self): |
73 | 79 | return kwallet.DBusKeyringKWallet4() |
25 | 25 | # ensure no-ascii chars slip by - watch your editor! |
26 | 26 | assert min(ord(char) for char in UNICODE_CHARS) > 127 |
27 | 27 | |
28 | ||
28 | 29 | def is_ascii_printable(s): |
29 | 30 | return all(32 <= ord(c) < 127 for c in s) |
31 | ||
30 | 32 | |
31 | 33 | class BackendBasicTests(object): |
32 | 34 | """Test for the keyring's basic functions. password_set and password_get |
91 | 93 | def test_delete_one_in_group(self): |
92 | 94 | username1 = random_string(20, self.DIFFICULT_CHARS) |
93 | 95 | username2 = random_string(20, self.DIFFICULT_CHARS) |
94 | password = random_string(20, self.DIFFICULT_CHARS) | |
95 | service = random_string(20, self.DIFFICULT_CHARS) | |
96 | password = random_string(20, self.DIFFICULT_CHARS) | |
97 | service = random_string(20, self.DIFFICULT_CHARS) | |
96 | 98 | self.keyring.set_password(service, username1, password) |
97 | 99 | self.set_password(service, username2, password) |
98 | 100 | self.keyring.delete_password(service, username1) |
109 | 111 | |
110 | 112 | def test_unicode_and_ascii_chars(self): |
111 | 113 | source = (random_string(10, UNICODE_CHARS) + random_string(10) + |
112 | random_string(10, self.DIFFICULT_CHARS)) | |
114 | random_string(10, self.DIFFICULT_CHARS)) | |
113 | 115 | password = random_string(20, source) |
114 | 116 | username = random_string(20, source) |
115 | 117 | service = random_string(20, source) |
3 | 3 | import random |
4 | 4 | import string |
5 | 5 | |
6 | ||
6 | 7 | class ImportKiller(object): |
7 | 8 | "Context manager to make an import of a given name or names fail." |
9 | ||
8 | 10 | def __init__(self, *names): |
9 | 11 | self.names = names |
12 | ||
10 | 13 | def find_module(self, fullname, path=None): |
11 | 14 | if fullname in self.names: |
12 | 15 | return self |
16 | ||
13 | 17 | def load_module(self, fullname): |
14 | 18 | assert fullname in self.names |
15 | 19 | raise ImportError(fullname) |
20 | ||
16 | 21 | def __enter__(self): |
17 | 22 | self.original = {} |
18 | 23 | for name in self.names: |
19 | 24 | self.original[name] = sys.modules.pop(name, None) |
20 | 25 | sys.meta_path.insert(0, self) |
26 | ||
21 | 27 | def __exit__(self, *args): |
22 | 28 | sys.meta_path.remove(self) |
23 | 29 | for key, value in self.original.items(): |
24 | 30 | if value is not None: |
25 | 31 | sys.modules[key] = value |
32 | ||
26 | 33 | |
27 | 34 | @contextlib.contextmanager |
28 | 35 | def NoNoneDictMutator(destination, **changes): |
51 | 58 | """A context manager to temporarily change the os.environ""" |
52 | 59 | return NoNoneDictMutator(os.environ, **changes) |
53 | 60 | |
61 | ||
54 | 62 | ALPHABET = string.ascii_letters + string.digits |
55 | 63 | |
56 | def random_string(k, source = ALPHABET): | |
64 | ||
65 | def random_string(k, source=ALPHABET): | |
57 | 66 | """Generate a random string with length <i>k</i> |
58 | 67 | """ |
59 | 68 | result = '' |
0 | 0 | import functools |
1 | ||
1 | 2 | |
2 | 3 | def once(func): |
3 | 4 | """ |
20 | 21 | return func.always_returns |
21 | 22 | return functools.wraps(func)(wrapper) |
22 | 23 | |
24 | ||
23 | 25 | def suppress_exceptions(callables, exceptions=Exception): |
24 | 26 | """ |
25 | 27 | yield the results of calling each element of callables, suppressing |
14 | 14 | if PY3: |
15 | 15 | def u(s): |
16 | 16 | return s |
17 | ||
17 | 18 | def _unichr(c): |
18 | 19 | return chr(c) |
19 | 20 | else: |
20 | 21 | def u(s): |
21 | 22 | return s.decode('utf-8') |
23 | ||
22 | 24 | def _unichr(c): |
23 | 25 | return unichr(c) |
24 | 26 | |
29 | 31 | |
30 | 32 | ESCAPE_FMT = "_%02X" |
31 | 33 | |
34 | ||
32 | 35 | def _escape_char(c): |
33 | 36 | "Single char escape. Return the char, escaped if not already legal" |
34 | 37 | if isinstance(c, int): |
35 | 38 | c = _unichr(c) |
36 | 39 | return c if c in LEGAL_CHARS else ESCAPE_FMT % ord(c) |
40 | ||
37 | 41 | |
38 | 42 | def escape(value): |
39 | 43 | """ |
42 | 46 | """ |
43 | 47 | return "".join(_escape_char(c) for c in value.encode('utf-8')) |
44 | 48 | |
49 | ||
45 | 50 | def _unescape_code(regex_match): |
46 | 51 | ordinal = int(regex_match.group('code'), 16) |
47 | 52 | if sys.version_info >= (3,): |
48 | 53 | return bytes([ordinal]) |
49 | 54 | return chr(ordinal) |
55 | ||
50 | 56 | |
51 | 57 | def unescape(value): |
52 | 58 | """ |
6 | 6 | def _settings_root_XP(): |
7 | 7 | return os.path.join(os.environ['USERPROFILE'], 'Local Settings') |
8 | 8 | |
9 | ||
9 | 10 | def _settings_root_Vista(): |
10 | 11 | return os.environ.get('LOCALAPPDATA', os.environ.get('ProgramData', '.')) |
12 | ||
11 | 13 | |
12 | 14 | def _data_root_Windows(): |
13 | 15 | release, version, csd, ptype = platform.win32_ver() |
14 | 16 | root = _settings_root_XP() if release == 'XP' else _settings_root_Vista() |
15 | 17 | return os.path.join(root, 'Python Keyring') |
18 | ||
16 | 19 | |
17 | 20 | def _data_root_Linux(): |
18 | 21 | """ |
23 | 26 | root = os.environ.get('XDG_DATA_HOME', None) or fallback |
24 | 27 | return os.path.join(root, 'python_keyring') |
25 | 28 | |
29 | ||
26 | 30 | _config_root_Windows = _data_root_Windows |
31 | ||
27 | 32 | |
28 | 33 | def _check_old_config_root(): |
29 | 34 | """ |
39 | 44 | config_file_old = os.path.join(_data_root_Linux(), 'keyringrc.cfg') |
40 | 45 | if os.path.isfile(config_file_old) and not os.path.isfile(config_file_new): |
41 | 46 | msg = ("Keyring config exists only in the old location " |
42 | "{config_file_old} and should be moved to {config_file_new} " | |
43 | "to work with this version of keyring.") | |
47 | "{config_file_old} and should be moved to {config_file_new} " | |
48 | "to work with this version of keyring.") | |
44 | 49 | raise RuntimeError(msg.format(**locals())) |
50 | ||
45 | 51 | |
46 | 52 | def _config_root_Linux(): |
47 | 53 | """ |
54 | 60 | root = os.environ.get(key, None) or fallback |
55 | 61 | return os.path.join(root, 'python_keyring') |
56 | 62 | |
63 | ||
57 | 64 | # by default, use Unix convention |
58 | 65 | data_root = globals().get('_data_root_' + platform.system(), _data_root_Linux) |
59 | config_root = globals().get('_config_root' + platform.system(), _config_root_Linux) | |
66 | config_root = globals().get( | |
67 | '_config_root' + | |
68 | platform.system(), | |
69 | _config_root_Linux) |
0 | 0 | from collections import Callable |
1 | ||
1 | 2 | |
2 | 3 | class ClassProperty(property): |
3 | 4 | """ |
17 | 18 | >>> YourClass.skillz |
18 | 19 | False |
19 | 20 | """ |
21 | ||
20 | 22 | def __get__(self, cls, owner): |
21 | 23 | return self.fget.__get__(None, owner)() |
22 | 24 | |
23 | 25 | # borrowed from jaraco.util.dictlib |
26 | ||
27 | ||
24 | 28 | class NonDataProperty(object): |
25 | 29 | """Much like the property builtin, but only implements __get__, |
26 | 30 | making it a non-data property, and can be subsequently reset. |
0 | Metadata-Version: 1.1 | |
0 | Metadata-Version: 1.2 | |
1 | 1 | Name: keyring |
2 | Version: 10.4.0 | |
2 | Version: 10.5.0 | |
3 | 3 | Summary: Store and access your passwords safely. |
4 | 4 | Home-page: https://github.com/jaraco/keyring |
5 | 5 | Author: Jason R. Coombs |
6 | 6 | Author-email: jaraco@jaraco.com |
7 | 7 | License: UNKNOWN |
8 | Description-Content-Type: UNKNOWN | |
8 | 9 | Description: .. image:: https://img.shields.io/pypi/v/keyring.svg |
9 | 10 | :target: https://pypi.org/project/keyring |
10 | 11 | |
11 | 12 | .. image:: https://img.shields.io/pypi/pyversions/keyring.svg |
12 | 13 | |
13 | .. image:: https://img.shields.io/pypi/dm/keyring.svg | |
14 | ||
15 | 14 | .. image:: https://img.shields.io/travis/jaraco/keyring/master.svg |
16 | 15 | :target: http://travis-ci.org/jaraco/keyring |
17 | 16 | |
17 | .. image:: https://readthedocs.org/projects/keyring/badge/?version=latest | |
18 | :target: http://keyring.readthedocs.io/en/latest/?badge=latest | |
18 | 19 | |
19 | 20 | ======================================= |
20 | 21 | Installing and Using Python Keyring Lib |
26 | 27 | What is Python keyring lib? |
27 | 28 | --------------------------- |
28 | 29 | |
29 | The Python keyring lib provides a easy way to access the system keyring service | |
30 | The Python keyring lib provides an easy way to access the system keyring service | |
30 | 31 | from python. It can be used in any application that needs safe password storage. |
31 | 32 | |
32 | 33 | The keyring library is licensed under both the `MIT license |
41 | 42 | `secretstorage <https://pypi.python.org/pypi/secretstorage>`_) |
42 | 43 | * `KWallet <https://en.wikipedia.org/wiki/KWallet>`_ |
43 | 44 | (requires `dbus <https://pypi.python.org/pypi/dbus-python>`_) |
44 | * `Windows Credential Vault | |
45 | <http://windows.microsoft.com/en-us/windows7/what-is-credential-manager>`_ | |
45 | * `Windows Credential Locker | |
46 | <https://docs.microsoft.com/en-us/windows/uwp/security/credential-locker>`_ | |
46 | 47 | |
47 | 48 | Other keyring implementations are provided in the `keyrings.alt package`_. |
48 | 49 | |
219 | 220 | # invoke the keyring lib |
220 | 221 | try: |
221 | 222 | keyring.set_password("demo-service", "tarek", "passexample") |
222 | print("password stored sucessfully") | |
223 | print("password stored successfully") | |
223 | 224 | except keyring.errors.PasswordSetError: |
224 | 225 | print("failed to store password") |
225 | 226 | print("password", keyring.get_password("demo-service", "tarek")) |
361 | 362 | Classifier: Programming Language :: Python :: 3.4 |
362 | 363 | Classifier: Programming Language :: Python :: 3.5 |
363 | 364 | Classifier: Programming Language :: Python :: 3.6 |
365 | Requires-Python: >=2.7 |
1 | 1 | release = dists upload |
2 | 2 | dists = clean --all sdist bdist_wheel |
3 | 3 | |
4 | [wheel] | |
4 | [bdist_wheel] | |
5 | 5 | universal = 1 |
6 | 6 | |
7 | 7 | [egg_info] |
10 | 10 | |
11 | 11 | name = 'keyring' |
12 | 12 | description = 'Store and access your passwords safely.' |
13 | nspkg_technique = 'native' | |
14 | """ | |
15 | Does this package use "native" namespace packages or | |
16 | pkg_resources "managed" namespace packages? | |
17 | """ | |
13 | 18 | |
14 | 19 | params = dict( |
15 | 20 | name=name, |
23 | 28 | url="https://github.com/jaraco/" + name, |
24 | 29 | packages=setuptools.find_packages(), |
25 | 30 | include_package_data=True, |
26 | namespace_packages=name.split('.')[:-1], | |
31 | namespace_packages=( | |
32 | name.split('.')[:-1] if nspkg_technique == 'managed' | |
33 | else [] | |
34 | ), | |
35 | python_requires='>=2.7', | |
27 | 36 | install_requires=[ |
28 | 37 | ], |
29 | 38 | extras_require={ |
36 | 45 | 'testing': [ |
37 | 46 | 'pytest>=2.8', |
38 | 47 | 'pytest-sugar', |
48 | 'collective.checkdocs', | |
39 | 49 | ], |
40 | 50 | 'docs': [ |
41 | 51 | 'sphinx', |
67 | 77 | }, |
68 | 78 | ) |
69 | 79 | if __name__ == '__main__': |
70 | setuptools.setup(**params) | |
80 | setuptools.setup(**params) |