[Python-modules-commits] [keyrings.alt] 01/04: Import keyrings.alt_2.2.orig.tar.gz
Dmitry Shachnev
mitya57 at moszumanska.debian.org
Mon Mar 27 17:57:01 UTC 2017
This is an automated email from the git hooks/post-receive script.
mitya57 pushed a commit to branch master
in repository keyrings.alt.
commit 1082fb647a48f6780204e14aa51282bd09b5bf72
Author: Dmitry Shachnev <mitya57 at gmail.com>
Date: Mon Mar 27 20:44:02 2017 +0300
Import keyrings.alt_2.2.orig.tar.gz
---
.coveragerc | 29 ++++++
.travis.yml | 5 +-
CHANGES.rst | 20 ++++
PKG-INFO | 18 ++--
README.rst | 13 +--
docs/conf.py | 31 +++++--
docs/index.rst | 5 -
keyrings.alt.egg-info/PKG-INFO | 18 ++--
keyrings.alt.egg-info/SOURCES.txt | 4 +-
keyrings.alt.egg-info/entry_points.txt | 1 -
keyrings.alt.egg-info/requires.txt | 1 +
keyrings/alt/Gnome.py | 5 +-
keyrings/alt/Google.py | 4 +-
keyrings/alt/file.py | 102 ++++++++++++++++-----
keyrings/alt/file_base.py | 90 ++++++++++++++----
keyrings/alt/kwallet.py | 114 -----------------------
keyrings/alt/pyfs.py | 2 +-
setup.cfg | 3 -
setup.py | 13 +--
tests/mocks.py | 6 +-
tests/requirements.txt | 3 +-
tests/test_Google.py | 4 +-
tests/test_file.py | 163 ++++++++++++++++++++++++++++++++-
tests/test_kwallet.py | 81 ----------------
24 files changed, 433 insertions(+), 302 deletions(-)
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..f565452
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,29 @@
+[run]
+branch = True
+
+[report]
+exclude_lines =
+ # Have to re-enable the standard pragma
+ pragma: no cover
+
+ # Don't complain about missing debug-only code:
+ def __repr__
+
+ # Don't complain if tests don't hit defensive assertion code:
+ raise AssertionError
+ raise NotImplementedError
+
+ # Don't complain if non-runnable code isn't run:
+ if 0:
+ if __name__ == .__main__.:
+
+ # don't try to cover abstracts
+ @abc.abstractmethod
+ @abc.abstractproperty
+
+ # don't try to cover special properties
+ @properties.NonDataProperty
+
+show_missing = True
+ignore_errors = True
+
diff --git a/.travis.yml b/.travis.yml
index e2e715f..390133e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ sudo: false
language: python
python:
- 2.7
-- 3.5
+- 3.6
install:
- pip install tox "setuptools>=28.2"
script:
@@ -16,8 +16,9 @@ deploy:
on:
tags: true
all_branches: true
- python: 3.5
+ python: 3.6
user: jaraco
distributions: dists
+ skip_upload_docs: true
password:
secure: iRtbY9yEN8qwJ7wiycL8N5NdZhRDENT5M8Bkpm7YSN5OiM41LRwFYnHDoQhYpz9L/UdfbovgEvv1XsQX/o8XRTn5efmhXRgS/FY3cA7Ry0GG41hmk2fnAgYuivA8EGoPveS9CnbU71ikL0HjRHv93+7Pz1kyMEYXRUpbMZ16K74o1J1MLOoCdQXXlKWfYjqAV/BglWwjIkwXVmNM2JwGV7U2hJ8zjsX1Bn7XqsZdC2KB6jK1frVjEHDfbv3NLQYIzQYqGw8GMWa+9EGVfFzqPnQmUC3E5GA93rC1SceBUb2RDBfCUpyFkyin3lQ05EvyVJoIaZO56gJ9Py1XzzSinSTjylgTxvFWx4uweowv5oM9OWnV+3SsZDw5+55fW5CYiMjdqjLso83gTkc8jbDHeK73Yh0sju2+QnOejnMzKRaBtCBubUkL+TPjEzoeUYSKLgW+iVHIKNKEKNME/WLzNtEhQwEFbLD5 [...]
diff --git a/CHANGES.rst b/CHANGES.rst
index a3bec54..e16fa3e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,23 @@
+2.2
+===
+
+#17: Drop dependency on keyring.py27compat and use six
+instead.
+
+#16: Minor tweaks to file-based backends.
+
+2.1
+===
+
+Add persistent scheme and version tags for file based backends.
+Prepare for associated data handling in file based schemes.
+
+2.0
+===
+
+#12: Drop kwallet support, now superseded by the dual kwallet
+support in keyring.
+
1.3
===
diff --git a/PKG-INFO b/PKG-INFO
index 30df9d9..b5f5da3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: keyrings.alt
-Version: 1.3
+Version: 2.2
Summary: Alternate keyring implementations
Home-page: https://github.com/jaraco/keyrings.alt
Author: Jason R. Coombs
@@ -19,15 +19,12 @@ Description: .. image:: https://img.shields.io/pypi/v/keyrings.alt.svg
Alternate keyring backend implementations for use with the
`keyring package <https://pypi.python.org/pypi/keyring>`_.
- Docs
- ====
+ License
+ =======
- There's `no good mechanism for publishing documentation
- <https://github.com/pypa/python-packaging-user-guide/pull/266>`_
- easily. If there's a documentation link above, it's probably
- stale because PyPI-based documentation is deprecated. This
- project may have documentation published at ReadTheDocs, but
- probably not. Good luck finding it.
+ License is indicated in the project metadata (typically one or more
+ of the Trove classifiers). For more details, see `this explanation
+ <https://github.com/jaraco/skeleton/issues/1>`_.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
@@ -35,3 +32,4 @@ Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
+Requires-Python: >=2.7
diff --git a/README.rst b/README.rst
index 6fb3ff5..6b1a79f 100644
--- a/README.rst
+++ b/README.rst
@@ -11,12 +11,9 @@
Alternate keyring backend implementations for use with the
`keyring package <https://pypi.python.org/pypi/keyring>`_.
-Docs
-====
+License
+=======
-There's `no good mechanism for publishing documentation
-<https://github.com/pypa/python-packaging-user-guide/pull/266>`_
-easily. If there's a documentation link above, it's probably
-stale because PyPI-based documentation is deprecated. This
-project may have documentation published at ReadTheDocs, but
-probably not. Good luck finding it.
+License is indicated in the project metadata (typically one or more
+of the Trove classifiers). For more details, see `this explanation
+<https://github.com/jaraco/skeleton/issues/1>`_.
diff --git a/docs/conf.py b/docs/conf.py
index f69e839..20beec2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,7 +1,13 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-import pkg_resources
+import os
+import sys
+import subprocess
+import datetime
+
+if 'check_output' not in dir(subprocess):
+ import subprocess32 as subprocess
extensions = [
'sphinx.ext.autodoc',
@@ -9,11 +15,19 @@ extensions = [
]
# General information about the project.
-project = 'keyrings.alt'
-copyright = '2016 Jason R. Coombs'
-# The short X.Y version.
-version = pkg_resources.require(project)[0].version
+root = os.path.join(os.path.dirname(__file__), '..')
+setup_script = os.path.join(root, 'setup.py')
+fields = ['--name', '--version', '--url', '--author']
+dist_info_cmd = [sys.executable, setup_script] + fields
+output_bytes = subprocess.check_output(dist_info_cmd, cwd=root)
+project, version, url, author = output_bytes.decode('utf-8').strip().split('\n')
+
+origin_date = datetime.date(2016,1,1)
+today = datetime.date.today()
+
+copyright = '{origin_date.year}-{today.year} {author}'.format(**locals())
+
# The full version, including alpha/beta/rc tags.
release = version
@@ -24,16 +38,21 @@ link_files = {
using=dict(
GH='https://github.com',
project=project,
+ url=url,
),
replace=[
dict(
pattern=r"(Issue )?#(?P<issue>\d+)",
- url='{GH}/jaraco/{project}/issues/{issue}',
+ url='{url}/issues/{issue}',
),
dict(
pattern=r"^(?m)((?P<scm_version>v?\d+(\.\d+){1,2}))\n[-=]+\n",
with_scm="{text}\n{rev[timestamp]:%d %b %Y}\n",
),
+ dict(
+ pattern=r"PEP[- ](?P<pep_number>\d+)",
+ url='https://www.python.org/dev/peps/pep-{pep_number:0>4}/',
+ ),
],
),
}
diff --git a/docs/index.rst b/docs/index.rst
index 4426074..8798b95 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -27,11 +27,6 @@ Welcome to keyrings.alt documentation!
:undoc-members:
:show-inheritance:
-.. automodule:: keyrings.alt.kwallet
- :members:
- :undoc-members:
- :show-inheritance:
-
.. automodule:: keyrings.alt.multi
:members:
:undoc-members:
diff --git a/keyrings.alt.egg-info/PKG-INFO b/keyrings.alt.egg-info/PKG-INFO
index 30df9d9..b5f5da3 100644
--- a/keyrings.alt.egg-info/PKG-INFO
+++ b/keyrings.alt.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: keyrings.alt
-Version: 1.3
+Version: 2.2
Summary: Alternate keyring implementations
Home-page: https://github.com/jaraco/keyrings.alt
Author: Jason R. Coombs
@@ -19,15 +19,12 @@ Description: .. image:: https://img.shields.io/pypi/v/keyrings.alt.svg
Alternate keyring backend implementations for use with the
`keyring package <https://pypi.python.org/pypi/keyring>`_.
- Docs
- ====
+ License
+ =======
- There's `no good mechanism for publishing documentation
- <https://github.com/pypa/python-packaging-user-guide/pull/266>`_
- easily. If there's a documentation link above, it's probably
- stale because PyPI-based documentation is deprecated. This
- project may have documentation published at ReadTheDocs, but
- probably not. Good luck finding it.
+ License is indicated in the project metadata (typically one or more
+ of the Trove classifiers). For more details, see `this explanation
+ <https://github.com/jaraco/skeleton/issues/1>`_.
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
@@ -35,3 +32,4 @@ Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
+Requires-Python: >=2.7
diff --git a/keyrings.alt.egg-info/SOURCES.txt b/keyrings.alt.egg-info/SOURCES.txt
index 2afd3fd..d9eb05f 100644
--- a/keyrings.alt.egg-info/SOURCES.txt
+++ b/keyrings.alt.egg-info/SOURCES.txt
@@ -1,3 +1,4 @@
+.coveragerc
.travis.yml
CHANGES.rst
LICENSE
@@ -17,6 +18,7 @@ keyrings.alt.egg-info/SOURCES.txt
keyrings.alt.egg-info/dependency_links.txt
keyrings.alt.egg-info/entry_points.txt
keyrings.alt.egg-info/namespace_packages.txt
+keyrings.alt.egg-info/requires.txt
keyrings.alt.egg-info/top_level.txt
keyrings/alt/Gnome.py
keyrings/alt/Google.py
@@ -26,7 +28,6 @@ keyrings/alt/_win_crypto.py
keyrings/alt/file.py
keyrings/alt/file_base.py
keyrings/alt/keyczar.py
-keyrings/alt/kwallet.py
keyrings/alt/multi.py
keyrings/alt/pyfs.py
tests/__init__.py
@@ -38,6 +39,5 @@ tests/test_Windows.py
tests/test_crypto.py
tests/test_file.py
tests/test_keyczar.py
-tests/test_kwallet.py
tests/test_multi.py
tests/test_pyfs.py
\ No newline at end of file
diff --git a/keyrings.alt.egg-info/entry_points.txt b/keyrings.alt.egg-info/entry_points.txt
index cdc6313..0adff50 100644
--- a/keyrings.alt.egg-info/entry_points.txt
+++ b/keyrings.alt.egg-info/entry_points.txt
@@ -4,7 +4,6 @@ Google = keyrings.alt.Google
Windows (alt) = keyrings.alt.Windows
file = keyrings.alt.file
keyczar = keyrings.alt.keyczar
-kwallet = keyrings.alt.kwallet
multi = keyrings.alt.multi
pyfs = keyrings.alt.pyfs
diff --git a/keyrings.alt.egg-info/requires.txt b/keyrings.alt.egg-info/requires.txt
new file mode 100644
index 0000000..ffe2fce
--- /dev/null
+++ b/keyrings.alt.egg-info/requires.txt
@@ -0,0 +1 @@
+six
diff --git a/keyrings/alt/Gnome.py b/keyrings/alt/Gnome.py
index 16bca90..c4e02bf 100644
--- a/keyrings/alt/Gnome.py
+++ b/keyrings/alt/Gnome.py
@@ -5,10 +5,11 @@ try:
except (ImportError, ValueError):
pass
+import six
+
from keyring.backend import KeyringBackend
from keyring.errors import PasswordSetError, PasswordDeleteError
from keyring.util import properties
-from keyring.py27compat import unicode_str
class Keyring(KeyringBackend):
@@ -65,7 +66,7 @@ class Keyring(KeyringBackend):
return None
secret = items[0].secret
- return secret if isinstance(secret, unicode_str) else secret.decode('utf-8')
+ return secret if isinstance(secret, six.text_type) else secret.decode('utf-8')
def set_password(self, service, username, password):
"""Set password for the username of the service
diff --git a/keyrings/alt/Google.py b/keyrings/alt/Google.py
index 66affe0..705992e 100644
--- a/keyrings/alt/Google.py
+++ b/keyrings/alt/Google.py
@@ -6,6 +6,9 @@ import copy
import codecs
import base64
import io
+import pickle
+
+from six.moves import input
try:
import gdata.docs.service
@@ -15,7 +18,6 @@ except ImportError:
from . import keyczar
from keyring import errors
from keyring import credentials
-from keyring.py27compat import input, pickle
from keyring.backend import KeyringBackend
from keyring.util import properties
from keyring.errors import ExceptionRaisedContext
diff --git a/keyrings/alt/file.py b/keyrings/alt/file.py
index 89b3142..317c140 100644
--- a/keyrings/alt/file.py
+++ b/keyrings/alt/file.py
@@ -1,34 +1,36 @@
from __future__ import with_statement
import os
-import getpass
-import base64
import sys
import json
+import getpass
-from keyring.py27compat import configparser
+from six.moves import configparser
from keyring.util import properties
from keyring.util.escape import escape as escape_for_ini
-from . import file_base
-
+from keyrings.alt.file_base import (
+ Keyring, decodebytes, encodebytes,
+)
-class PlaintextKeyring(file_base.Keyring):
+class PlaintextKeyring(Keyring):
"""Simple File Keyring with no encryption"""
priority = .5
"Applicable for all platforms, but not recommended"
filename = 'keyring_pass.cfg'
+ scheme = 'no encyption'
+ version = '1.0'
- def encrypt(self, password):
- """Directly return the password itself.
+ def encrypt(self, password, assoc = None):
+ """Directly return the password itself, ignore associated data.
"""
return password
- def decrypt(self, password_encrypted):
- """Directly return encrypted password.
+ def decrypt(self, password_encrypted, assoc = None):
+ """Directly return encrypted password, ignore associated data.
"""
return password_encrypted
@@ -37,7 +39,8 @@ class Encrypted(object):
"""
PyCrypto-backed Encryption support
"""
-
+ scheme = '[PBKDF2] AES256.CFB'
+ version = '1.0'
block_size = 32
def _create_cipher(self, password, salt, IV):
@@ -54,17 +57,17 @@ class Encrypted(object):
password = getpass.getpass(
"Please set a password for your new keyring: ")
confirm = getpass.getpass('Please confirm the password: ')
- if password != confirm:
+ if password != confirm: # pragma: no cover
sys.stderr.write("Error: Your passwords didn't match\n")
continue
- if '' == password.strip():
+ if '' == password.strip(): # pragma: no cover
# forbid the blank password
sys.stderr.write("Error: blank passwords aren't allowed.\n")
continue
return password
-class EncryptedKeyring(Encrypted, file_base.Keyring):
+class EncryptedKeyring(Encrypted, Keyring):
"""PyCrypto File Keyring"""
filename = 'crypted_pass.cfg'
@@ -78,9 +81,9 @@ class EncryptedKeyring(Encrypted, file_base.Keyring):
__import__('Crypto.Cipher.AES')
__import__('Crypto.Protocol.KDF')
__import__('Crypto.Random')
- except ImportError:
+ except ImportError: # pragma: no cover
raise RuntimeError("PyCrypto required")
- if not json:
+ if not json: # pragma: no cover
raise RuntimeError("JSON implementation such as simplejson "
"required.")
return .6
@@ -101,8 +104,15 @@ class EncryptedKeyring(Encrypted, file_base.Keyring):
self.keyring_key = self._get_new_password()
# set a reference password, used to check that the password provided
# matches for subsequent checks.
- self.set_password('keyring-setting', 'password reference',
- 'password reference value')
+ self.set_password('keyring-setting',
+ 'password reference',
+ 'password reference value')
+ self._write_config_value('keyring-setting',
+ 'scheme',
+ self.scheme)
+ self._write_config_value('keyring-setting',
+ 'version',
+ self.version)
def _check_file(self):
"""
@@ -120,6 +130,50 @@ class EncryptedKeyring(Encrypted, file_base.Keyring):
)
except (configparser.NoSectionError, configparser.NoOptionError):
return False
+ try:
+ self._check_scheme(config)
+ except AttributeError:
+ # accept a missing scheme
+ return True
+ return self._check_version(config)
+
+ def _check_scheme(self, config):
+ """
+ check for a valid scheme
+
+ raise ValueError otherwise
+ raise AttributeError if missing
+ """
+ try:
+ scheme = config.get(
+ escape_for_ini('keyring-setting'),
+ escape_for_ini('scheme'),
+ )
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ raise AttributeError("Encryption scheme missing")
+
+ # remove pointless crypto module name
+ if scheme.startswith('PyCrypto '):
+ scheme = scheme[9:]
+
+ if scheme != self.scheme:
+ raise ValueError("Encryption scheme mismatch "
+ "(exp.: %s, found: %s)" % (self.scheme, scheme))
+
+ def _check_version(self, config):
+ """
+ check for a valid version
+ an existing scheme implies an existing version as well
+
+ return True, if version is valid, and False otherwise
+ """
+ try:
+ self.file_version = config.get(
+ escape_for_ini('keyring-setting'),
+ escape_for_ini('version'),
+ )
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ return False
return True
def _unlock(self):
@@ -142,7 +196,8 @@ class EncryptedKeyring(Encrypted, file_base.Keyring):
"""
del self.keyring_key
- def encrypt(self, password):
+ def encrypt(self, password, assoc = None):
+ # encrypt password, ignore associated data
from Crypto.Random import get_random_bytes
salt = get_random_bytes(self.block_size)
from Crypto.Cipher import AES
@@ -154,14 +209,15 @@ class EncryptedKeyring(Encrypted, file_base.Keyring):
salt=salt, IV=IV, password_encrypted=password_encrypted,
)
for key in data:
- data[key] = base64.encodestring(data[key]).decode()
+ # spare a few bytes: throw away newline from base64 encoding
+ data[key] = encodebytes(data[key]).decode()[:-1]
return json.dumps(data).encode()
- def decrypt(self, password_encrypted):
- # unpack the encrypted payload
+ def decrypt(self, password_encrypted, assoc = None):
+ # unpack the encrypted payload, ignore associated data
data = json.loads(password_encrypted.decode())
for key in data:
- data[key] = base64.decodestring(data[key].encode())
+ data[key] = decodebytes(data[key].encode())
cipher = self._create_cipher(self.keyring_key, data['salt'],
data['IV'])
plaintext = cipher.decrypt(data['password_encrypted'])
diff --git a/keyrings/alt/file_base.py b/keyrings/alt/file_base.py
index f0e4cd2..62d42dd 100644
--- a/keyrings/alt/file_base.py
+++ b/keyrings/alt/file_base.py
@@ -1,16 +1,26 @@
from __future__ import with_statement
import os
-import base64
import abc
+import base64
-from keyring.py27compat import configparser
+from six.moves import configparser
from keyring.errors import PasswordDeleteError
from keyring.backend import KeyringBackend
from keyring.util import platform_, properties
from keyring.util.escape import escape as escape_for_ini
+try:
+ encodebytes = base64.encodebytes
+except AttributeError: # pragma: no cover
+ encodebytes = base64.encodestring
+
+try:
+ decodebytes = base64.decodebytes
+except AttributeError: # pragma: no cover
+ decodebytes = base64.decodestring
+
class FileBacked(object):
@abc.abstractproperty
@@ -27,8 +37,30 @@ class FileBacked(object):
"""
return os.path.join(platform_.data_root(), self.filename)
+ @abc.abstractproperty
+ def scheme(self):
+ """
+ The encryption scheme used to store the passwords.
+ """
+ return 'not defined'
+
+ @abc.abstractproperty
+ def version(self):
+ """
+ The encryption version used to store the passwords.
+ """
+ return None
+
+ @properties.NonDataProperty
+ def file_version(self):
+ """
+ The encryption version used in file to store the passwords.
+ """
+ return None
+
def __repr__(self):
- tmpl = "<{self.__class__.__name__} at {self.file_path}>"
+ tmpl = "<{self.__class__.__name__} with {self.scheme} " \
+ "v.{self.version} at {self.file_path}>"
return tmpl.format(**locals())
@@ -43,22 +75,28 @@ class Keyring(FileBacked, KeyringBackend):
"""
@abc.abstractmethod
- def encrypt(self, password):
+ def encrypt(self, password, assoc = None):
"""
- Given a password (byte string), return an encrypted byte string.
+ Given a password (byte string) and assoc (byte string, optional),
+ return an encrypted byte string.
+
+ assoc provides associated data (typically: service and username)
"""
@abc.abstractmethod
- def decrypt(self, password_encrypted):
+ def decrypt(self, password_encrypted, assoc = None):
"""
- Given a password encrypted by a previous call to `encrypt`, return
- the original byte string.
+ Given a password encrypted by a previous call to `encrypt`, and assoc
+ (byte string, optional), return the original byte string.
+
+ assoc provides associated data (typically: service and username)
"""
def get_password(self, service, username):
"""
Read the password from the file.
"""
+ assoc = self._generate_assoc(service, username)
service = escape_for_ini(service)
username = escape_for_ini(username)
@@ -71,9 +109,13 @@ class Keyring(FileBacked, KeyringBackend):
try:
password_base64 = config.get(service, username).encode()
# decode with base64
- password_encrypted = base64.decodestring(password_base64)
- # decrypted the password
- password = self.decrypt(password_encrypted).decode('utf-8')
+ password_encrypted = decodebytes(password_base64)
+ # decrypt the password with associated data
+ try:
+ password = self.decrypt(password_encrypted, assoc).decode('utf-8')
+ except ValueError:
+ # decrypt the password without associated data
+ password = self.decrypt(password_encrypted).decode('utf-8')
except (configparser.NoOptionError, configparser.NoSectionError):
password = None
return password
@@ -81,14 +123,21 @@ class Keyring(FileBacked, KeyringBackend):
def set_password(self, service, username, password):
"""Write the password in the file.
"""
- service = escape_for_ini(service)
- username = escape_for_ini(username)
-
+ assoc = self._generate_assoc(service, username)
# encrypt the password
- password_encrypted = self.encrypt(password.encode('utf-8'))
- # encode with base64
- password_base64 = base64.encodestring(password_encrypted).decode()
+ password_encrypted = self.encrypt(password.encode('utf-8'), assoc)
+ # encode with base64 and add line break to untangle config file
+ password_base64 = '\n' + encodebytes(password_encrypted).decode()
+
+ self._write_config_value(service, username, password_base64)
+
+ def _generate_assoc(self, service, username):
+ """Generate tamper resistant bytestring of associated data
+ """
+ return (escape_for_ini(service) + '\0' +
+ escape_for_ini(username)).encode()
+ def _write_config_value(self, service, key, value):
# ensure the file exists
self._ensure_file_path()
@@ -96,10 +145,13 @@ class Keyring(FileBacked, KeyringBackend):
config = configparser.RawConfigParser()
config.read(self.file_path)
+ service = escape_for_ini(service)
+ key = escape_for_ini(key)
+
# update the keyring with the password
if not config.has_section(service):
config.add_section(service)
- config.set(service, username, password_base64)
+ config.set(service, key, value)
# save the keyring back to the file
with open(self.file_path, 'w') as config_file:
@@ -111,7 +163,7 @@ class Keyring(FileBacked, KeyringBackend):
If it doesn't, create it with "go-rwx" permissions.
"""
storage_root = os.path.dirname(self.file_path)
- if storage_root and not os.path.isdir(storage_root):
+ if storage_root and not os.path.isdir(storage_root): # pragma: no cover
os.makedirs(storage_root)
if not os.path.isfile(self.file_path):
# create the file without group/world permissions
diff --git a/keyrings/alt/kwallet.py b/keyrings/alt/kwallet.py
deleted file mode 100644
index e293236..0000000
--- a/keyrings/alt/kwallet.py
+++ /dev/null
@@ -1,114 +0,0 @@
-from __future__ import absolute_import
-
-import os
-import sys
-
-from keyring.py27compat import unicode_str
-from keyring.backend import KeyringBackend
-from keyring.errors import PasswordDeleteError
-from keyring.errors import PasswordSetError, ExceptionRaisedContext
-from keyring.util import properties
-
-# mixing Qt4 & Qt5 causes errors and may segfault
-if 'PyQt5' not in sys.modules:
- try:
- from PyKDE4.kdeui import KWallet
- from PyQt4 import QtGui
- except ImportError:
- pass
-
-kwallet = None
-
-def open_kwallet(kwallet_module=None, qt_module=None):
-
- # If we specified the kwallet_module and/or qt_module, surely we won't need
- # the cached kwallet object...
- if kwallet_module is None and qt_module is None:
- global kwallet
- if not kwallet is None:
- return kwallet
-
- # Allow for the injection of module-like objects for testing purposes.
- if kwallet_module is None:
- kwallet_module = KWallet.Wallet
- if qt_module is None:
- qt_module = QtGui
-
- # KDE wants us to instantiate an application object.
- app = None
- if qt_module.qApp.instance() == None:
- app = qt_module.QApplication([])
- try:
- window = qt_module.QWidget()
- kwallet = kwallet_module.openWallet(
- kwallet_module.NetworkWallet(),
- window.winId(),
- kwallet_module.Synchronous)
- if kwallet is not None:
- if not kwallet.hasFolder('Python'):
- kwallet.createFolder('Python')
- kwallet.setFolder('Python')
- return kwallet
- finally:
- if app:
- app.exit()
-
-class QtKeyring(KeyringBackend):
- """KDE KWallet"""
-
- @properties.ClassProperty
- @classmethod
- def priority(cls):
- with ExceptionRaisedContext() as exc:
- KWallet.__name__
- if exc:
- raise RuntimeError("KDE libraries not available")
- if "DISPLAY" not in os.environ:
- raise RuntimeError("cannot connect to X server")
- # Infer if KDE environment is active based on environment vars.
- # TODO: Does PyKDE provide a better indicator?
- kde_session_keys = (
- 'KDE_SESSION_ID', # most environments
- 'KDE_FULL_SESSION', # openSUSE
- )
- if not set(os.environ).intersection(kde_session_keys):
- return 0
- return 5
-
- def get_password(self, service, username):
- """Get password of the username for the service
- """
- key = username + '@' + service
- network = KWallet.Wallet.NetworkWallet()
- wallet = open_kwallet()
- if wallet is None:
- # the user pressed "cancel" when prompted to unlock their keyring.
- return None
- if wallet.keyDoesNotExist(network, 'Python', key):
- return None
-
- result = wallet.readPassword(key)[1]
- # The string will be a PyQt4.QtCore.QString, so turn it into a unicode
- # object.
- return unicode_str(result)
-
- def set_password(self, service, username, password):
- """Set password for the username of the service
- """
- wallet = open_kwallet()
- if wallet is None:
- # the user pressed "cancel" when prompted to unlock their keyring.
- raise PasswordSetError("Cancelled by user")
- wallet.writePassword(username+'@'+service, password)
-
- def delete_password(self, service, username):
- """Delete the password for the username of the service.
- """
- key = username + '@' + service
- wallet = open_kwallet()
- if wallet is None:
- # the user pressed "cancel" when prompted to unlock their keyring.
- raise PasswordDeleteError("Cancelled by user")
- if wallet.keyDoesNotExist(wallet.walletName(), 'Python', key):
- raise PasswordDeleteError("Password not found")
- wallet.removeEntry(key)
diff --git a/keyrings/alt/pyfs.py b/keyrings/alt/pyfs.py
index 7896b4b..0165cd5 100644
--- a/keyrings/alt/pyfs.py
+++ b/keyrings/alt/pyfs.py
@@ -2,7 +2,7 @@ import os
import base64
import sys
-from keyring.py27compat import configparser
+from six.moves import configparser
from keyring import errors
from keyring.util.escape import escape as escape_for_ini
diff --git a/setup.cfg b/setup.cfg
index c1794d2..447e8f2 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,9 +5,6 @@ dists = clean --all sdist bdist_wheel
[wheel]
universal = 1
-[upload]
-repository = https://upload.pypi.org/legacy/
-
[egg_info]
tag_build =
tag_date = 0
diff --git a/setup.py b/setup.py
index 90f447a..9e074bd 100644
--- a/setup.py
+++ b/setup.py
@@ -3,20 +3,16 @@
# Project skeleton maintained at https://github.com/jaraco/skeleton
import io
-import sys
import setuptools
with io.open('README.rst', encoding='utf-8') as readme:
long_description = readme.read()
-needs_wheel = {'release', 'bdist_wheel', 'dists'}.intersection(sys.argv)
-wheel = ['wheel'] if needs_wheel else []
-
name = 'keyrings.alt'
description = 'Alternate keyring implementations'
-setup_params = dict(
+params = dict(
name=name,
use_scm_version=True,
author="Jason R. Coombs",
@@ -27,13 +23,15 @@ setup_params = dict(
packages=setuptools.find_packages(exclude=['tests']),
include_package_data=True,
namespace_packages=name.split('.')[:-1],
+ python_requires='>=2.7',
install_requires=[
+ 'six',
],
extras_require={
},
setup_requires=[
'setuptools_scm>=1.15.0',
- ] + wheel,
+ ],
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
@@ -47,7 +45,6 @@ setup_params = dict(
'Gnome = keyrings.alt.Gnome',
'Google = keyrings.alt.Google',
'keyczar = keyrings.alt.keyczar',
- 'kwallet = keyrings.alt.kwallet',
'multi = keyrings.alt.multi',
'pyfs = keyrings.alt.pyfs',
'Windows (alt) = keyrings.alt.Windows',
@@ -55,4 +52,4 @@ setup_params = dict(
},
)
if __name__ == '__main__':
- setuptools.setup(**setup_params)
+ setuptools.setup(**params)
diff --git a/tests/mocks.py b/tests/mocks.py
index 38d95c5..91c1195 100644
--- a/tests/mocks.py
+++ b/tests/mocks.py
@@ -4,8 +4,9 @@ Various mock objects for testing
import base64
import io
+import pickle
-from keyring.py27compat import pickle, unicode_str
+import six
class MockAtom(object):
@@ -113,8 +114,7 @@ class MockDocumentService(MockGDataService):
else:
raise put_err()
# save the data for asserting against
- assert isinstance(data, str) or isinstance(data, unicode_str), \
- 'Should be a string'
+ assert isinstance(data, six.string_types), 'Should be a string'
self._put_data = pickle.loads(base64.urlsafe_b64decode(data))
self._put_count += 1
return MockEntry('', 'mockentry%3A' + '')
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 21a1a09..cc5a1e9 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,6 +1,7 @@
pytest >= 2.8
+subprocess32; python_version=="2.6"
backports.unittest_mock
-keyring[test]
... 309 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/keyrings.alt.git
More information about the Python-modules-commits
mailing list