[Python-modules-commits] [keyrings.alt] 01/04: Import keyrings.alt_1.1.orig.tar.gz
Dmitry Shachnev
mitya57 at moszumanska.debian.org
Sat Feb 6 09:32:15 UTC 2016
This is an automated email from the git hooks/post-receive script.
mitya57 pushed a commit to branch master
in repository keyrings.alt.
commit afa347e693b1ad6b9467d7437eacc2ab62d53b43
Author: Dmitry Shachnev <mitya57 at gmail.com>
Date: Sat Feb 6 12:05:53 2016 +0300
Import keyrings.alt_1.1.orig.tar.gz
---
.gitignore | 0
.hgtags | 3 +
.travis.yml | 8 +
CHANGES.rst | 10 +
PKG-INFO | 20 ++
README.rst | 5 +
conftest.py | 6 +
docs/conf.py | 19 ++
docs/history.rst | 8 +
docs/index.rst | 56 +++++
keyrings.alt.egg-info/PKG-INFO | 20 ++
keyrings.alt.egg-info/SOURCES.txt | 39 ++++
keyrings.alt.egg-info/dependency_links.txt | 1 +
keyrings.alt.egg-info/entry_points.txt | 10 +
keyrings.alt.egg-info/namespace_packages.txt | 1 +
keyrings.alt.egg-info/top_level.txt | 2 +
keyrings/__init__.py | 1 +
keyrings/alt/Gnome.py | 108 +++++++++
keyrings/alt/Google.py | 321 ++++++++++++++++++++++++++
keyrings/alt/Windows.py | 193 ++++++++++++++++
keyrings/alt/__init__.py | 0
keyrings/alt/_win_crypto.py | 101 ++++++++
keyrings/alt/file.py | 299 ++++++++++++++++++++++++
keyrings/alt/keyczar.py | 99 ++++++++
keyrings/alt/kwallet.py | 114 +++++++++
keyrings/alt/multi.py | 63 +++++
keyrings/alt/pyfs.py | 272 ++++++++++++++++++++++
pytest.ini | 4 +
setup.cfg | 12 +
setup.py | 79 +++++++
tests/__init__.py | 0
tests/test_Gnome.py | 35 +++
tests/test_Google.py | 331 +++++++++++++++++++++++++++
tests/test_Windows.py | 49 ++++
tests/test_crypto.py | 32 +++
tests/test_file.py | 52 +++++
tests/test_keyczar.py | 76 ++++++
tests/test_kwallet.py | 81 +++++++
tests/test_multi.py | 58 +++++
tests/test_pyfs.py | 136 +++++++++++
40 files changed, 2724 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000..fb6f4b7
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1,3 @@
+b3173ad03e2b87d50ab31eecc5e6e57e9963785d 1.0
+f9defd8cbdfabaeb1739fd02929f272ba7e4be73 1.0.1
+acdefb2c6c473bf6460004dbbe1f62280fcdeac8 1.1
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6e5e969
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+sudo: false
+language: python
+python:
+ - 2.7
+ - 3.5
+script:
+ - pip install -U pytest
+ - python setup.py test
diff --git a/CHANGES.rst b/CHANGES.rst
new file mode 100644
index 0000000..b8a1c5a
--- /dev/null
+++ b/CHANGES.rst
@@ -0,0 +1,10 @@
+1.1
+===
+
+FileBacked backends now have a ``repr`` that includes the file path.
+
+
+1.0
+===
+
+Initial release based on Keyring 7.3.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..5ba33cf
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,20 @@
+Metadata-Version: 1.1
+Name: keyrings.alt
+Version: 1.1
+Summary: Alternate keyring implementations
+Home-page: https://github.com/jaraco/keyrings.alt
+Author: Jason R. Coombs
+Author-email: jaraco at jaraco.com
+License: UNKNOWN
+Description: keyrings.alt
+ ============
+
+ Alternate keyring backend implementations for use with the
+ `keyring package <https://pypi.python.org/pypi/keyring>`_.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..83a0c9f
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,5 @@
+keyrings.alt
+============
+
+Alternate keyring backend implementations for use with the
+`keyring package <https://pypi.python.org/pypi/keyring>`_.
diff --git a/conftest.py b/conftest.py
new file mode 100644
index 0000000..4af6077
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,6 @@
+import platform
+
+collect_ignore = []
+
+if platform.system() != 'Windows':
+ collect_ignore.append('keyrings/alt/_win_crypto.py')
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..7a15d08
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import setuptools_scm
+
+extensions = [
+ 'sphinx.ext.autodoc',
+]
+
+# General information about the project.
+project = 'keyrings.alt'
+copyright = '2016 Jason R. Coombs'
+
+# The short X.Y version.
+version = setuptools_scm.get_version(root='..', relative_to=__file__)
+# The full version, including alpha/beta/rc tags.
+release = version
+
+master_doc = 'index'
diff --git a/docs/history.rst b/docs/history.rst
new file mode 100644
index 0000000..907000b
--- /dev/null
+++ b/docs/history.rst
@@ -0,0 +1,8 @@
+:tocdepth: 2
+
+.. _changes:
+
+History
+*******
+
+.. include:: ../CHANGES.rst
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..4426074
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,56 @@
+Welcome to keyrings.alt documentation!
+======================================
+
+.. toctree::
+ :maxdepth: 1
+
+ history
+
+
+.. automodule:: keyrings.alt.file
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.Gnome
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.Google
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.keyczar
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.kwallet
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.multi
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.pyfs
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: keyrings.alt.Windows
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/keyrings.alt.egg-info/PKG-INFO b/keyrings.alt.egg-info/PKG-INFO
new file mode 100644
index 0000000..5ba33cf
--- /dev/null
+++ b/keyrings.alt.egg-info/PKG-INFO
@@ -0,0 +1,20 @@
+Metadata-Version: 1.1
+Name: keyrings.alt
+Version: 1.1
+Summary: Alternate keyring implementations
+Home-page: https://github.com/jaraco/keyrings.alt
+Author: Jason R. Coombs
+Author-email: jaraco at jaraco.com
+License: UNKNOWN
+Description: keyrings.alt
+ ============
+
+ Alternate keyring backend implementations for use with the
+ `keyring package <https://pypi.python.org/pypi/keyring>`_.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
diff --git a/keyrings.alt.egg-info/SOURCES.txt b/keyrings.alt.egg-info/SOURCES.txt
new file mode 100644
index 0000000..bf82f11
--- /dev/null
+++ b/keyrings.alt.egg-info/SOURCES.txt
@@ -0,0 +1,39 @@
+.gitignore
+.hgtags
+.travis.yml
+CHANGES.rst
+README.rst
+conftest.py
+pytest.ini
+setup.cfg
+setup.py
+docs/conf.py
+docs/history.rst
+docs/index.rst
+keyrings/__init__.py
+keyrings.alt.egg-info/PKG-INFO
+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/top_level.txt
+keyrings/alt/Gnome.py
+keyrings/alt/Google.py
+keyrings/alt/Windows.py
+keyrings/alt/__init__.py
+keyrings/alt/_win_crypto.py
+keyrings/alt/file.py
+keyrings/alt/keyczar.py
+keyrings/alt/kwallet.py
+keyrings/alt/multi.py
+keyrings/alt/pyfs.py
+tests/__init__.py
+tests/test_Gnome.py
+tests/test_Google.py
+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/dependency_links.txt b/keyrings.alt.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/keyrings.alt.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/keyrings.alt.egg-info/entry_points.txt b/keyrings.alt.egg-info/entry_points.txt
new file mode 100644
index 0000000..cdc6313
--- /dev/null
+++ b/keyrings.alt.egg-info/entry_points.txt
@@ -0,0 +1,10 @@
+[keyring.backends]
+Gnome = keyrings.alt.Gnome
+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/namespace_packages.txt b/keyrings.alt.egg-info/namespace_packages.txt
new file mode 100644
index 0000000..3814a76
--- /dev/null
+++ b/keyrings.alt.egg-info/namespace_packages.txt
@@ -0,0 +1 @@
+keyrings
diff --git a/keyrings.alt.egg-info/top_level.txt b/keyrings.alt.egg-info/top_level.txt
new file mode 100644
index 0000000..a664fbf
--- /dev/null
+++ b/keyrings.alt.egg-info/top_level.txt
@@ -0,0 +1,2 @@
+keyrings
+tests
diff --git a/keyrings/__init__.py b/keyrings/__init__.py
new file mode 100644
index 0000000..5284146
--- /dev/null
+++ b/keyrings/__init__.py
@@ -0,0 +1 @@
+__import__("pkg_resources").declare_namespace(__name__)
diff --git a/keyrings/alt/Gnome.py b/keyrings/alt/Gnome.py
new file mode 100644
index 0000000..16bca90
--- /dev/null
+++ b/keyrings/alt/Gnome.py
@@ -0,0 +1,108 @@
+try:
+ import gi
+ gi.require_version('GnomeKeyring', '1.0')
+ from gi.repository import GnomeKeyring
+except (ImportError, ValueError):
+ pass
+
+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):
+ """Gnome Keyring"""
+
+ KEYRING_NAME = None
+ """
+ Name of the keyring in which to store the passwords.
+ Use None for the default keyring.
+ """
+
+ @properties.ClassProperty
+ @classmethod
+ def priority(cls):
+ if 'GnomeKeyring' not in globals():
+ raise RuntimeError("GnomeKeyring module required")
+ result = GnomeKeyring.get_default_keyring_sync()[0]
+ if result != GnomeKeyring.Result.OK:
+ raise RuntimeError(result.value_name)
+ return 1
+
+ @property
+ def keyring_name(self):
+ system_default = GnomeKeyring.get_default_keyring_sync()[1]
+ return self.KEYRING_NAME or system_default
+
+ def _find_passwords(self, service, username, deleting=False):
+ """Get password of the username for the service
+ """
+ passwords = []
+
+ service = self._safe_string(service)
+ username = self._safe_string(username)
+ for attrs_tuple in (('username', 'service'), ('user', 'domain')):
+ attrs = GnomeKeyring.Attribute.list_new()
+ GnomeKeyring.Attribute.list_append_string(attrs, attrs_tuple[0], username)
+ GnomeKeyring.Attribute.list_append_string(attrs, attrs_tuple[1], service)
+ result, items = GnomeKeyring.find_items_sync(
+ GnomeKeyring.ItemType.NETWORK_PASSWORD, attrs)
+ if result == GnomeKeyring.Result.OK:
+ passwords += items
+ elif deleting:
+ if result == GnomeKeyring.Result.CANCELLED:
+ raise PasswordDeleteError("Cancelled by user")
+ elif result != GnomeKeyring.Result.NO_MATCH:
+ raise PasswordDeleteError(result.value_name)
+ return passwords
+
+ def get_password(self, service, username):
+ """Get password of the username for the service
+ """
+ items = self._find_passwords(service, username)
+ if not items:
+ return None
+
+ secret = items[0].secret
+ return secret if isinstance(secret, unicode_str) else secret.decode('utf-8')
+
+ def set_password(self, service, username, password):
+ """Set password for the username of the service
+ """
+ service = self._safe_string(service)
+ username = self._safe_string(username)
+ password = self._safe_string(password)
+ attrs = GnomeKeyring.Attribute.list_new()
+ GnomeKeyring.Attribute.list_append_string(attrs, 'username', username)
+ GnomeKeyring.Attribute.list_append_string(attrs, 'service', service)
+ GnomeKeyring.Attribute.list_append_string(attrs, 'application', 'python-keyring')
+ result = GnomeKeyring.item_create_sync(
+ self.keyring_name, GnomeKeyring.ItemType.NETWORK_PASSWORD,
+ "Password for '%s' on '%s'" % (username, service),
+ attrs, password, True)[0]
+ if result == GnomeKeyring.Result.CANCELLED:
+ # The user pressed "Cancel" when prompted to unlock their keyring.
+ raise PasswordSetError("Cancelled by user")
+ elif result != GnomeKeyring.Result.OK:
+ raise PasswordSetError(result.value_name)
+
+ def delete_password(self, service, username):
+ """Delete the password for the username of the service.
+ """
+ items = self._find_passwords(service, username, deleting=True)
+ if not items:
+ raise PasswordDeleteError("Password not found")
+ for current in items:
+ result = GnomeKeyring.item_delete_sync(current.keyring,
+ current.item_id)
+ if result == GnomeKeyring.Result.CANCELLED:
+ raise PasswordDeleteError("Cancelled by user")
+ elif result != GnomeKeyring.Result.OK:
+ raise PasswordDeleteError(result.value_name)
+
+ def _safe_string(self, source, encoding='utf-8'):
+ """Convert unicode to string as gnomekeyring barfs on unicode"""
+ if not isinstance(source, str):
+ return source.encode(encoding)
+ return str(source)
diff --git a/keyrings/alt/Google.py b/keyrings/alt/Google.py
new file mode 100644
index 0000000..66affe0
--- /dev/null
+++ b/keyrings/alt/Google.py
@@ -0,0 +1,321 @@
+from __future__ import absolute_import
+
+import os
+import sys
+import copy
+import codecs
+import base64
+import io
+
+try:
+ import gdata.docs.service
+except ImportError:
+ pass
+
+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
+
+class EnvironCredential(credentials.EnvironCredential):
+ """Retrieve credentials from specifically named environment variables
+ """
+
+ def __init__(self):
+ super(EnvironCredential, self).__init__('GOOGLE_KEYRING_USER',
+ 'GOOGLE_KEYRING_PASSWORD')
+
+class DocsKeyring(KeyringBackend):
+ """Backend that stores keyring on Google Docs.
+ Note that login and any other initialisation is deferred until it is
+ actually required to allow this keyring class to be added to the
+ global _all_keyring list.
+ """
+
+ keyring_title = 'GoogleKeyring'
+ # status enums
+ OK = 1
+ FAIL = 0
+ CONFLICT = -1
+
+ def __init__(self, credential, source, crypter,
+ collection=None, client=None,
+ can_create=True, input_getter=input
+ ):
+ self.credential = credential
+ self.crypter = crypter
+ self.source = source
+ self._collection = collection
+ self.can_create = can_create
+ self.input_getter = input_getter
+ self._keyring_dict = None
+
+ if not client:
+ self._client = gdata.docs.service.DocsService()
+ else:
+ self._client = client
+
+ self._client.source = source
+ self._client.ssl = True
+ self._login_reqd = True
+
+ @properties.ClassProperty
+ @classmethod
+ def priority(cls):
+ if not cls._has_gdata():
+ raise RuntimeError("Requires gdata")
+ if not keyczar.has_keyczar():
+ raise RuntimeError("Requires keyczar")
+ return 3
+
+ @classmethod
+ def _has_gdata(cls):
+ with ExceptionRaisedContext() as exc:
+ gdata.__name__
+ return not bool(exc)
+
+ def get_password(self, service, username):
+ """Get password of the username for the service
+ """
+ result = self._get_entry(self._keyring, service, username)
+ if result:
+ result = self._decrypt(result)
+ return result
+
+ def set_password(self, service, username, password):
+ """Set password for the username of the service
+ """
+ password = self._encrypt(password or '')
+ keyring_working_copy = copy.deepcopy(self._keyring)
+ service_entries = keyring_working_copy.get(service)
+ if not service_entries:
+ service_entries = {}
+ keyring_working_copy[service] = service_entries
+ service_entries[username] = password
+ save_result = self._save_keyring(keyring_working_copy)
+ if save_result == self.OK:
+ self._keyring_dict = keyring_working_copy
+ return
+ elif save_result == self.CONFLICT:
+ # check if we can avoid updating
+ self.docs_entry, keyring_dict = self._read()
+ existing_pwd = self._get_entry(self._keyring, service, username)
+ conflicting_pwd = self._get_entry(keyring_dict, service, username)
+ if conflicting_pwd == password:
+ # if someone else updated it to the same value then we are done
+ self._keyring_dict = keyring_working_copy
+ return
+ elif conflicting_pwd is None or conflicting_pwd == existing_pwd:
+ # if doesn't already exist or is unchanged then update it
+ new_service_entries = keyring_dict.get(service, {})
+ new_service_entries[username] = password
+ keyring_dict[service] = new_service_entries
+ save_result = self._save_keyring(keyring_dict)
+ if save_result == self.OK:
+ self._keyring_dict = keyring_dict
+ return
+ else:
+ raise errors.PasswordSetError(
+ 'Failed write after conflict detected')
+ else:
+ raise errors.PasswordSetError(
+ 'Conflict detected, service:%s and username:%s was '\
+ 'set to a different value by someone else' %(service,
+ username))
+
+ raise errors.PasswordSetError('Could not save keyring')
+
+ def delete_password(self, service, username):
+ return self._del_entry(self._keyring, service, username)
+
+ @property
+ def client(self):
+ if not self._client.GetClientLoginToken():
+ try:
+ self._client.ClientLogin(self.credential.username,
+ self.credential.password,
+ self._client.source)
+ except gdata.service.CaptchaRequired:
+ sys.stdout.write('Please visit ' + self._client.captcha_url)
+ answer = self.input_getter('Answer to the challenge? ')
+ self._client.email = self.credential.username
+ self._client.password = self.credential.password
+ self._client.ClientLogin(
+ self.credential.username,
+ self.credential.password,
+ self._client.source,
+ captcha_token=self._client.captcha_token,
+ captcha_response=answer)
+ except gdata.service.BadAuthentication:
+ raise errors.InitError('Users credential were unrecognized')
+ except gdata.service.Error:
+ raise errors.InitError('Login Error')
+
+ return self._client
+
+ @property
+ def collection(self):
+ return self._collection or self.credential.username.split('@')[0]
+
+ @property
+ def _keyring(self):
+ if self._keyring_dict is None:
+ self.docs_entry, self._keyring_dict = self._read()
+ return self._keyring_dict
+
+ def _get_entry(self, keyring_dict, service, username):
+ result = None
+ service_entries = keyring_dict.get(service)
+ if service_entries:
+ result = service_entries.get(username)
+ return result
+
+ def _del_entry(self, keyring_dict, service, username):
+ service_entries = keyring_dict.get(service)
+ if not service_entries:
+ raise errors.PasswordDeleteError("No matching service")
+ try:
+ del service_entries[username]
+ except KeyError:
+ raise errors.PasswordDeleteError("Not found")
+ if not service_entries:
+ del keyring_dict[service]
+
+ def _decrypt(self, value):
+ if not value:
+ return ''
+ return self.crypter.decrypt(value)
+
+ def _encrypt(self, value):
+ if not value:
+ return ''
+ return self.crypter.encrypt(value)
+
+ def _get_doc_title(self):
+ return '%s' %self.keyring_title
+
+ def _read(self):
+ from gdata.docs.service import DocumentQuery
+ title_query = DocumentQuery(categories=[self.collection])
+ title_query['title'] = self._get_doc_title()
+ title_query['title-exact'] = 'true'
+ docs = self.client.QueryDocumentListFeed(title_query.ToUri())
+
+ if not docs.entry:
+ if self.can_create:
+ docs_entry = None
+ keyring_dict = {}
+ else:
+ raise errors.InitError(
+ '%s not found in %s and create not permitted'
+ %(self._get_doc_title(), self.collection))
+ else:
+ docs_entry = docs.entry[0]
+ file_contents = ''
+ try:
+ url = docs_entry.content.src
+ url += '&exportFormat=txt'
+ server_response = self.client.request('GET', url)
+ if server_response.status != 200:
+ raise errors.InitError(
+ 'Could not read existing Google Docs keyring')
+ file_contents = server_response.read()
+ if file_contents.startswith(codecs.BOM_UTF8):
+ file_contents = file_contents[len(codecs.BOM_UTF8):]
+ keyring_dict = pickle.loads(base64.urlsafe_b64decode(
+ file_contents.decode('string-escape')))
+ except pickle.UnpicklingError as ex:
+ raise errors.InitError(
+ 'Could not unpickle existing Google Docs keyring', ex)
+ except TypeError as ex:
+ raise errors.InitError(
+ 'Could not decode existing Google Docs keyring', ex)
+
+ return docs_entry, keyring_dict
+
+ def _save_keyring(self, keyring_dict):
+ """Helper to actually write the keyring to Google"""
+ import gdata
+ result = self.OK
+ file_contents = base64.urlsafe_b64encode(pickle.dumps(keyring_dict))
+ try:
+ if self.docs_entry:
+ extra_headers = {'Content-Type': 'text/plain',
+ 'Content-Length': len(file_contents)}
+ self.docs_entry = self.client.Put(
+ file_contents,
+ self.docs_entry.GetEditMediaLink().href,
+ extra_headers=extra_headers
+ )
+ else:
+ from gdata.docs.service import DocumentQuery
+ # check for existence of folder, create if required
+ folder_query = DocumentQuery(categories=['folder'])
+ folder_query['title'] = self.collection
+ folder_query['title-exact'] = 'true'
+ docs = self.client.QueryDocumentListFeed(folder_query.ToUri())
+ if docs.entry:
+ folder_entry = docs.entry[0]
+ else:
+ folder_entry = self.client.CreateFolder(self.collection)
+ file_handle = io.BytesIO(file_contents)
+ media_source = gdata.MediaSource(
+ file_handle=file_handle,
+ content_type='text/plain',
+ content_length=len(file_contents),
+ file_name='temp')
+ self.docs_entry = self.client.Upload(
+ media_source,
+ self._get_doc_title(),
+ folder_or_uri=folder_entry
+ )
+ except gdata.service.RequestError as ex:
+ try:
+ if ex.message['reason'].lower().find('conflict') != -1:
+ result = self.CONFLICT
+ else:
+ # Google docs has a bug when updating a shared document
+ # using PUT from any account other that the owner.
+ # It returns an error 400 "Sorry, there was an error saving the file. Please try again"
+ # *despite* actually updating the document!
+ # Workaround by re-reading to see if it actually updated
+ if ex.message['body'].find(
+ 'Sorry, there was an error saving the file') != -1:
+ new_docs_entry, new_keyring_dict = self._read()
+ if new_keyring_dict == keyring_dict:
+ result = self.OK
+ else:
+ result = self.FAIL
+ else:
+ result = self.FAIL
+ except:
+ result = self.FAIL
+
+ return result
+
+class KeyczarDocsKeyring(DocsKeyring):
+ """Google Docs keyring using keyczar initialized from environment
+ variables
+ """
+
+ def __init__(self):
+ crypter = keyczar.EnvironCrypter()
+ credential = EnvironCredential()
+ source = os.environ.get('GOOGLE_KEYRING_SOURCE')
+ super(KeyczarDocsKeyring, self).__init__(
+ credential, source, crypter)
+
+ def supported(self):
+ """Return if this keyring supports current environment:
+ -1: not applicable
+ 0: suitable
+ 1: recommended
+ """
+ try:
+ from keyczar import keyczar
+ return super(KeyczarDocsKeyring, self).supported()
+ except ImportError:
+ return -1
diff --git a/keyrings/alt/Windows.py b/keyrings/alt/Windows.py
new file mode 100644
index 0000000..1b591c0
--- /dev/null
+++ b/keyrings/alt/Windows.py
@@ -0,0 +1,193 @@
+import sys
+import base64
+import platform
+import functools
+
+from keyring.util import properties
+from keyring.backend import KeyringBackend
+from keyring.errors import PasswordDeleteError, ExceptionRaisedContext
+from . import file
+
+try:
+ # prefer pywin32-ctypes
+ from win32ctypes import pywintypes
+ from win32ctypes import win32cred
+ # force demand import to raise ImportError
+ win32cred.__name__
+except ImportError:
+ # fallback to pywin32
+ try:
+ import pywintypes
+ import win32cred
+ except ImportError:
+ pass
+
+try:
+ import winreg
+except ImportError:
+ try:
+ # Python 2 compatibility
+ import _winreg as winreg
+ except ImportError:
+ pass
+
+try:
+ from . import _win_crypto
+except ImportError:
+ pass
+
+def has_pywin32():
+ """
+ Does this environment have pywin32?
+ Should return False even when Mercurial's Demand Import allowed import of
+ win32cred.
+ """
+ with ExceptionRaisedContext() as exc:
+ win32cred.__name__
+ return not bool(exc)
+
+def has_wincrypto():
+ """
+ Does this environment have wincrypto?
+ Should return False even when Mercurial's Demand Import allowed import of
+ _win_crypto, so accesses an attribute of the module.
+ """
+ with ExceptionRaisedContext() as exc:
+ _win_crypto.__name__
+ return not bool(exc)
+
+class EncryptedKeyring(file.BaseKeyring):
+ """
+ A File-based keyring secured by Windows Crypto API.
+ """
+
+ @properties.ClassProperty
+ @classmethod
+ def priority(self):
+ """
+ Preferred over file.EncryptedKeyring but not other, more sophisticated
+ Windows backends.
+ """
+ if not platform.system() == 'Windows':
+ raise RuntimeError("Requires Windows")
+ return .8
+
+ filename = 'wincrypto_pass.cfg'
+
+ def encrypt(self, password):
+ """Encrypt the password using the CryptAPI.
+ """
+ return _win_crypto.encrypt(password)
+
+ def decrypt(self, password_encrypted):
+ """Decrypt the password using the CryptAPI.
+ """
+ return _win_crypto.decrypt(password_encrypted)
+
+
+class RegistryKeyring(KeyringBackend):
+ """
+ RegistryKeyring is a keyring which use Windows CryptAPI to encrypt
+ the user's passwords and store them under registry keys
+ """
+
+ @properties.ClassProperty
+ @classmethod
+ def priority(self):
+ """
+ Preferred on Windows when pywin32 isn't installed
+ """
+ if platform.system() != 'Windows':
+ raise RuntimeError("Requires Windows")
+ if not has_wincrypto():
+ raise RuntimeError("Requires ctypes")
+ return 2
+
+ def get_password(self, service, username):
+ """Get password of the username for the service
+ """
+ try:
+ # fetch the password
+ key = r'Software\%s\Keyring' % service
+ hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key)
+ password_saved = winreg.QueryValueEx(hkey, username)[0]
+ password_base64 = password_saved.encode('ascii')
+ # decode with base64
+ password_encrypted = base64.decodestring(password_base64)
+ # decrypted the password
+ password = _win_crypto.decrypt(password_encrypted).decode('utf-8')
+ except EnvironmentError:
+ password = None
+ return password
+
+ def set_password(self, service, username, password):
+ """Write the password to the registry
+ """
+ # encrypt the password
+ password_encrypted = _win_crypto.encrypt(password.encode('utf-8'))
+ # encode with base64
+ password_base64 = base64.encodestring(password_encrypted)
+ # encode again to unicode
+ password_saved = password_base64.decode('ascii')
+
+ # store the password
+ key_name = r'Software\%s\Keyring' % service
+ hkey = winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_name)
+ winreg.SetValueEx(hkey, username, 0, winreg.REG_SZ, password_saved)
+
+ def delete_password(self, service, username):
+ """Delete the password for the username of the service.
+ """
+ try:
+ key_name = r'Software\%s\Keyring' % service
+ hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_name, 0,
+ winreg.KEY_ALL_ACCESS)
+ winreg.DeleteValue(hkey, username)
+ winreg.CloseKey(hkey)
+ except WindowsError:
+ e = sys.exc_info()[1]
+ raise PasswordDeleteError(e)
+ self._delete_key_if_empty(service)
+
+ def _delete_key_if_empty(self, service):
+ key_name = r'Software\%s\Keyring' % service
+ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_name, 0,
+ winreg.KEY_ALL_ACCESS)
+ try:
+ winreg.EnumValue(key, 0)
+ return
+ except WindowsError:
+ pass
+ winreg.CloseKey(key)
+
+ # it's empty; delete everything
+ while key_name != 'Software':
+ parent, sep, base = key_name.rpartition('\\')
+ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, parent, 0,
+ winreg.KEY_ALL_ACCESS)
+ winreg.DeleteKey(key, base)
+ winreg.CloseKey(key)
+ key_name = parent
+
+
+class OldPywinError(object):
+ """
+ A compatibility wrapper for old PyWin32 errors, such as reported in
+ https://bitbucket.org/kang/python-keyring-lib/issue/140/
+ """
+ def __init__(self, orig):
+ self.orig = orig
+
+ @property
+ def funcname(self):
+ return self.orig[1]
+
+ @property
+ def winerror(self):
+ return self.orig[0]
+
+ @classmethod
+ def wrap(cls, orig_err):
+ attr_check = functools.partial(hasattr, orig_err)
+ is_old = not all(map(attr_check, ['funcname', 'winerror']))
+ return cls(orig_err) if is_old else orig_err
diff --git a/keyrings/alt/__init__.py b/keyrings/alt/__init__.py
new file mode 100644
index 0000000..e69de29
... 2004 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