Merge lp:~barry/ubuntu/natty/python-keyring/bug-686257 into lp:ubuntu/natty/python-keyring
- Natty (11.04)
- bug-686257
- Merge into natty
Status: | Merged |
---|---|
Merged at revision: | 6 |
Proposed branch: | lp:~barry/ubuntu/natty/python-keyring/bug-686257 |
Merge into: | lp:ubuntu/natty/python-keyring |
Diff against target: |
1991 lines (+762/-609) 27 files modified
CHANGES.txt (+46/-0) CONTRIBUTORS.txt (+11/-0) PKG-INFO (+167/-118) README.txt (+12/-9) debian/changelog (+21/-0) debian/control (+9/-33) debian/copyright (+4/-2) debian/python-keyring-gnome.install (+0/-1) debian/python-keyring-kwallet.install (+0/-1) debian/python-keyring.install (+0/-2) debian/rules (+4/-10) demo/keyring_demo.py (+17/-11) extensions.py (+0/-83) keyring/__init__.py (+1/-0) keyring/backend.py (+258/-53) keyring/backends/__init__.py (+1/-0) keyring/backends/gnome_keyring.c (+0/-111) keyring/backends/kde_kwallet.cpp (+0/-121) keyring/backends/osx_keychain.c (+2/-2) keyring/core.py (+20/-11) keyring/getpassbackend.py (+13/-0) keyring/tests/__init__.py (+1/-0) keyring/tests/test_backend.py (+65/-25) keyring/tests/test_core.py (+44/-13) keyring/tests/test_util.py (+37/-0) keyring/util/escape.py (+25/-0) setup.py (+4/-3) |
To merge this branch: | bzr merge lp:~barry/ubuntu/natty/python-keyring/bug-686257 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+48967@code.launchpad.net |
Commit message
Description of the change
Update to latest upstream version.
Barry Warsaw (barry) wrote : | # |
Sorry, I don't quite understand the comment. Do you mean that the tests aren't being installed or shouldn't be installed? Because I think they are installed, and I kind of think they should be. :)
There was a debate recently on one of the Python mailing lists about this (I forget which one, but probably either distutils or the testing sig) and there were definitely opinions on both sides. I'm personally of the opinion that tests should be installed, for various reasons:
* They can serve as documentation to users
* They can be run by end users to verify a package works properly
* They rarely take up much additional space
* It's usually easier to include the tests than not when they are shipped upstream as a subpackage
Others disagree and it can be decided on a case-by-case basis, but in this case, I see no harm and some potential good, so I would continue to include the tests.
Preview Diff
1 | === added file 'CHANGES.txt' |
2 | --- CHANGES.txt 1970-01-01 00:00:00 +0000 |
3 | +++ CHANGES.txt 2011-02-08 19:21:29 +0000 |
4 | @@ -0,0 +1,46 @@ |
5 | +------- |
6 | +CHANGES |
7 | +------- |
8 | + |
9 | +----- |
10 | +0.5.1 |
11 | +----- |
12 | + |
13 | +* Remove a spurious KDE debug message when using KWallet |
14 | + |
15 | +* Fix a bug that caused an exception if the user canceled the KWallet dialog |
16 | + (https://bitbucket.org/kang/python-keyring-lib/issue/37/user-canceling-of-kde-wallet-dialogs). |
17 | + |
18 | +--- |
19 | +0.5 |
20 | +--- |
21 | + |
22 | +* Now using the existing Gnome and KDE python libs instead of custom C++ |
23 | + code. |
24 | + |
25 | +* Using the getpass module instead of custom code |
26 | + |
27 | +--- |
28 | +0.4 |
29 | +--- |
30 | + |
31 | +* Fixed the setup script (some subdirs were not included in the release.) |
32 | + |
33 | +--- |
34 | +0.3 |
35 | +--- |
36 | + |
37 | +* Fixed keyring.core when the user doesn't have a cfg, or is not |
38 | + properly configured. |
39 | + |
40 | +* Fixed escaping issues for usernames with non-ascii characters |
41 | + |
42 | +--- |
43 | +0.2 |
44 | +--- |
45 | + |
46 | +* Add support for Python 2.4+ |
47 | + http://bitbucket.org/kang/python-keyring-lib/issue/2 |
48 | + |
49 | +* Fix the bug in KDE Kwallet extension compiling |
50 | + http://bitbucket.org/kang/python-keyring-lib/issue/3 |
51 | |
52 | === added file 'CONTRIBUTORS.txt' |
53 | --- CONTRIBUTORS.txt 1970-01-01 00:00:00 +0000 |
54 | +++ CONTRIBUTORS.txt 2011-02-08 19:21:29 +0000 |
55 | @@ -0,0 +1,11 @@ |
56 | +------------ |
57 | +Contributors |
58 | +------------ |
59 | + |
60 | +* Kang Zhang |
61 | +* Tarek Ziade |
62 | +* Marcin Kasperski |
63 | +* Steve Borho |
64 | +* Michael Gruenewald |
65 | +* Jason R. Coombs |
66 | +* Benji York |
67 | |
68 | === modified file 'PKG-INFO' |
69 | --- PKG-INFO 2009-09-24 23:24:02 +0000 |
70 | +++ PKG-INFO 2011-02-08 19:21:29 +0000 |
71 | @@ -1,6 +1,6 @@ |
72 | Metadata-Version: 1.0 |
73 | Name: keyring |
74 | -Version: 0.2 |
75 | +Version: 0.5.1 |
76 | Summary: Store and access your passwords safely. |
77 | Home-page: http://home.python-keyring.org/ |
78 | Author: Kang Zhang |
79 | @@ -41,18 +41,18 @@ |
80 | |
81 | Run easy_install or pip:: |
82 | |
83 | - $ easy_install keyring |
84 | - $ pip install keyring |
85 | + $ easy_install keyring |
86 | + $ pip install keyring |
87 | |
88 | Source installation |
89 | =================== |
90 | |
91 | Download the source tarball, and uncompress it, then run the install command:: |
92 | |
93 | - $ wget http://pypi.python.org/packages/source/k/keyring/keyring-0.2.tar.gz |
94 | - $ tar -xzvf keyring-0.2.tar.gz |
95 | - $ cd keyring-0.2 |
96 | - $ python setup.py install |
97 | + $ wget http://pypi.python.org/packages/source/k/keyring/keyring-0.3.tar.gz |
98 | + $ tar -xzvf keyring-0.3.tar.gz |
99 | + $ cd keyring-0.3 |
100 | + $ python setup.py install |
101 | |
102 | |
103 | -------------------------- |
104 | @@ -96,9 +96,9 @@ |
105 | Here's a sample config file(The full demo can be accessed in the ``demo/keyring.py``): |
106 | :: |
107 | |
108 | - [backend] |
109 | - default-keyring=simplekeyring.SimpleKeyring |
110 | - keyring-path=/home/kang/pyworkspace/python-keyring-lib/demo/ |
111 | + [backend] |
112 | + default-keyring=simplekeyring.SimpleKeyring |
113 | + keyring-path=/home/kang/pyworkspace/python-keyring-lib/demo/ |
114 | |
115 | |
116 | Write your own keyring backend |
117 | @@ -112,44 +112,44 @@ |
118 | The usage of the three functions: |
119 | |
120 | * ``supported(self)`` : Return if this backend is supported in current |
121 | - environment. The returned value can be **0**, **1** , or **-1**. **0** means |
122 | - suitable; **1** means recommended and **-1** means this backend is not |
123 | - available for current environment. |
124 | + environment. The returned value can be **0**, **1** , or **-1**. **0** means |
125 | + suitable; **1** means recommended and **-1** means this backend is not |
126 | + available for current environment. |
127 | * ``get_password(self, service, username)`` : Return the stored password for the |
128 | - ``username`` of the ``service``. |
129 | + ``username`` of the ``service``. |
130 | * ``set_password(self, service, username, password)`` : Store the ``password`` |
131 | - for ``username`` of the ``service`` in the backend. |
132 | + for ``username`` of the ``service`` in the backend. |
133 | |
134 | For an instance, there's the source code of the demo mentioned above. It's a |
135 | simple keyring which stores the password directly in memory. |
136 | |
137 | :: |
138 | |
139 | - """ |
140 | - simplekeyring.py |
141 | - |
142 | - A simple keyring class for the keyring_demo.py |
143 | - |
144 | - Created by Kang Zhang on 2009-07-12 |
145 | - """ |
146 | - from keyring.backend import KeyringBackend |
147 | - |
148 | - class SimpleKeyring(KeyringBackend): |
149 | - """Simple Keyring is a keyring which can store only one |
150 | - password in memory. |
151 | - """ |
152 | - def __init__(self): |
153 | - self.password = '' |
154 | - |
155 | - def supported(self): |
156 | - return 0 |
157 | - |
158 | - def get_password(self, service, username): |
159 | - return self.password |
160 | - |
161 | - def set_password(self, service, username, password): |
162 | - self.password = password |
163 | - return 0 |
164 | + """ |
165 | + simplekeyring.py |
166 | + |
167 | + A simple keyring class for the keyring_demo.py |
168 | + |
169 | + Created by Kang Zhang on 2009-07-12 |
170 | + """ |
171 | + from keyring.backend import KeyringBackend |
172 | + |
173 | + class SimpleKeyring(KeyringBackend): |
174 | + """Simple Keyring is a keyring which can store only one |
175 | + password in memory. |
176 | + """ |
177 | + def __init__(self): |
178 | + self.password = '' |
179 | + |
180 | + def supported(self): |
181 | + return 0 |
182 | + |
183 | + def get_password(self, service, username): |
184 | + return self.password |
185 | + |
186 | + def set_password(self, service, username, password): |
187 | + self.password = password |
188 | + return 0 |
189 | |
190 | |
191 | Set the keyring in runtime |
192 | @@ -163,24 +163,27 @@ |
193 | ``set_keyring()`` |
194 | :: |
195 | |
196 | - # define a new keyring class which extends the KeyringBackend |
197 | - import keyring.backend |
198 | - class TestKeyring(keyring.backend.KeyringBackend): |
199 | - """A test keyring which always outputs same password |
200 | - """ |
201 | - def supported(self): return 0 |
202 | - def set_password(self, servicename, username, password): return 0 |
203 | - def get_password(self, servicename, username): |
204 | - return "password from TestKeyring" |
205 | - |
206 | - # set the keyring for keyring lib |
207 | - import keyring |
208 | - keyring.set_keyring(TestKeyring()) |
209 | - |
210 | - # invoke the keyring lib |
211 | - if keyring.set_password("demo-service", "tarek", "passexample") == 0: |
212 | - print "password stored successful" |
213 | - print "password", keyring.get_password("demo-service", "tarek") |
214 | + # define a new keyring class which extends the KeyringBackend |
215 | + import keyring.backend |
216 | + class TestKeyring(keyring.backend.KeyringBackend): |
217 | + """A test keyring which always outputs same password |
218 | + """ |
219 | + def supported(self): return 0 |
220 | + def set_password(self, servicename, username, password): return 0 |
221 | + def get_password(self, servicename, username): |
222 | + return "password from TestKeyring" |
223 | + |
224 | + # set the keyring for keyring lib |
225 | + import keyring |
226 | + keyring.set_keyring(TestKeyring()) |
227 | + |
228 | + # invoke the keyring lib |
229 | + try: |
230 | + keyring.set_password("demo-service", "tarek", "passexample") |
231 | + print "password stored sucessfully" |
232 | + except keyring.backend.PasswordError: |
233 | + print "failed to store password" |
234 | + print "password", keyring.get_password("demo-service", "tarek") |
235 | |
236 | |
237 | ----------------------------------------------- |
238 | @@ -193,9 +196,9 @@ |
239 | The keyring lib has two functions: |
240 | |
241 | * ``get_password(service, username)`` : Returns the password stored in keyring. |
242 | - If the password does not exist, it will return None. |
243 | + If the password does not exist, it will return None. |
244 | * ``set_password(service, username, password)`` : Store the password in the |
245 | - keyring. |
246 | + keyring. |
247 | |
248 | Example |
249 | ======= |
250 | @@ -205,62 +208,62 @@ |
251 | only returns true when the password equals to the username. |
252 | :: |
253 | |
254 | - """ |
255 | - auth_demo.py |
256 | - |
257 | - Created by Kang Zhang 2009-08-14 |
258 | - """ |
259 | - |
260 | - import keyring |
261 | - import getpass |
262 | - import ConfigParser |
263 | - |
264 | - def auth(username, password): |
265 | - """A faked authorization function. |
266 | - """ |
267 | - return username == password |
268 | - |
269 | - def main(): |
270 | - """This scrip demos how to use keyring facilite the authorization. The |
271 | - username is stored in a config named 'auth_demo.cfg' |
272 | - """ |
273 | - # config file init |
274 | - config_file = 'auth_demo.cfg' |
275 | - config = ConfigParser.SafeConfigParser({ |
276 | - 'username':'', |
277 | - }) |
278 | - config.read(config_file) |
279 | - if not config.has_section('auth_demo_login'): |
280 | - config.add_section('auth_demo_login') |
281 | - |
282 | - username = config.get('auth_demo_login','username') |
283 | - password = None |
284 | - if username != '': |
285 | - password = keyring.get_password('auth_demo_login', username) |
286 | - |
287 | - if password == None or not auth(username, password): |
288 | - |
289 | - while 1: |
290 | - username = raw_input("Username:\n") |
291 | - password = getpass.getpass("Password:\n") |
292 | - |
293 | - if auth(username, password): |
294 | - break |
295 | - else: |
296 | - print "Authorization failed." |
297 | - |
298 | - # store the username |
299 | - config.set('auth_demo_login', 'username', username) |
300 | - config.write(open(config_file, 'w')) |
301 | - |
302 | - # store the password |
303 | - keyring.set_password('auth_demo_login', username, password) |
304 | - |
305 | - # the stuff that needs authorization here |
306 | - print "Authorization successful." |
307 | - |
308 | - if __name__ == "__main__": |
309 | - main() |
310 | + """ |
311 | + auth_demo.py |
312 | + |
313 | + Created by Kang Zhang 2009-08-14 |
314 | + """ |
315 | + |
316 | + import keyring |
317 | + import getpass |
318 | + import ConfigParser |
319 | + |
320 | + def auth(username, password): |
321 | + """A faked authorization function. |
322 | + """ |
323 | + return username == password |
324 | + |
325 | + def main(): |
326 | + """This scrip demos how to use keyring facilite the authorization. The |
327 | + username is stored in a config named 'auth_demo.cfg' |
328 | + """ |
329 | + # config file init |
330 | + config_file = 'auth_demo.cfg' |
331 | + config = ConfigParser.SafeConfigParser({ |
332 | + 'username':'', |
333 | + }) |
334 | + config.read(config_file) |
335 | + if not config.has_section('auth_demo_login'): |
336 | + config.add_section('auth_demo_login') |
337 | + |
338 | + username = config.get('auth_demo_login','username') |
339 | + password = None |
340 | + if username != '': |
341 | + password = keyring.get_password('auth_demo_login', username) |
342 | + |
343 | + if password == None or not auth(username, password): |
344 | + |
345 | + while 1: |
346 | + username = raw_input("Username:\n") |
347 | + password = getpass.getpass("Password:\n") |
348 | + |
349 | + if auth(username, password): |
350 | + break |
351 | + else: |
352 | + print "Authorization failed." |
353 | + |
354 | + # store the username |
355 | + config.set('auth_demo_login', 'username', username) |
356 | + config.write(open(config_file, 'w')) |
357 | + |
358 | + # store the password |
359 | + keyring.set_password('auth_demo_login', username, password) |
360 | + |
361 | + # the stuff that needs authorization here |
362 | + print "Authorization successful." |
363 | + |
364 | + if __name__ == "__main__": |
365 | + main() |
366 | |
367 | ------------ |
368 | Get involved |
369 | @@ -284,8 +287,54 @@ |
370 | .. _this post: http://tarekziade.wordpress.com/2009/03/27/pycon-hallway-session-1-a-keyring-library-for-python/ |
371 | .. _Google Summer of Code: http://socghop.appspot.com/ |
372 | |
373 | - * Kang Zhang |
374 | - * Tarek Ziade |
375 | + See CONTRIBUTORS.txt for a complete list of contributors. |
376 | + |
377 | + ------- |
378 | + CHANGES |
379 | + ------- |
380 | + |
381 | + ----- |
382 | + 0.5.1 |
383 | + ----- |
384 | + |
385 | + * Remove a spurious KDE debug message when using KWallet |
386 | + |
387 | + * Fix a bug that caused an exception if the user canceled the KWallet dialog |
388 | + (https://bitbucket.org/kang/python-keyring-lib/issue/37/user-canceling-of-kde-wallet-dialogs). |
389 | + |
390 | + --- |
391 | + 0.5 |
392 | + --- |
393 | + |
394 | + * Now using the existing Gnome and KDE python libs instead of custom C++ |
395 | + code. |
396 | + |
397 | + * Using the getpass module instead of custom code |
398 | + |
399 | + --- |
400 | + 0.4 |
401 | + --- |
402 | + |
403 | + * Fixed the setup script (some subdirs were not included in the release.) |
404 | + |
405 | + --- |
406 | + 0.3 |
407 | + --- |
408 | + |
409 | + * Fixed keyring.core when the user doesn't have a cfg, or is not |
410 | + properly configured. |
411 | + |
412 | + * Fixed escaping issues for usernames with non-ascii characters |
413 | + |
414 | + --- |
415 | + 0.2 |
416 | + --- |
417 | + |
418 | + * Add support for Python 2.4+ |
419 | + http://bitbucket.org/kang/python-keyring-lib/issue/2 |
420 | + |
421 | + * Fix the bug in KDE Kwallet extension compiling |
422 | + http://bitbucket.org/kang/python-keyring-lib/issue/3 |
423 | |
424 | Keywords: keyring Keychain GnomeKeyring Kwallet password storage |
425 | Platform: Many |
426 | |
427 | === modified file 'README.txt' |
428 | --- README.txt 2009-09-24 23:24:02 +0000 |
429 | +++ README.txt 2011-02-08 19:21:29 +0000 |
430 | @@ -41,9 +41,9 @@ |
431 | |
432 | Download the source tarball, and uncompress it, then run the install command:: |
433 | |
434 | - $ wget http://pypi.python.org/packages/source/k/keyring/keyring-0.2.tar.gz |
435 | - $ tar -xzvf keyring-0.2.tar.gz |
436 | - $ cd keyring-0.2 |
437 | + $ wget http://pypi.python.org/packages/source/k/keyring/keyring-0.3.tar.gz |
438 | + $ tar -xzvf keyring-0.3.tar.gz |
439 | + $ cd keyring-0.3 |
440 | $ python setup.py install |
441 | |
442 | |
443 | @@ -170,8 +170,11 @@ |
444 | keyring.set_keyring(TestKeyring()) |
445 | |
446 | # invoke the keyring lib |
447 | - if keyring.set_password("demo-service", "tarek", "passexample") == 0: |
448 | - print "password stored successful" |
449 | + try: |
450 | + keyring.set_password("demo-service", "tarek", "passexample") |
451 | + print "password stored sucessfully" |
452 | + except keyring.backend.PasswordError: |
453 | + print "failed to store password" |
454 | print "password", keyring.get_password("demo-service", "tarek") |
455 | |
456 | |
457 | @@ -269,12 +272,12 @@ |
458 | Credits |
459 | ------- |
460 | |
461 | -The project was based on Tarek Ziade's idea in `this post`_. Kang Zhang |
462 | -initially carried it out as a `Google Summer of Code`_ project, and Tarek |
463 | +The project was based on Tarek Ziade's idea in `this post`_. Kang Zhang |
464 | +initially carried it out as a `Google Summer of Code`_ project, and Tarek |
465 | mentored Kang on this project. |
466 | |
467 | .. _this post: http://tarekziade.wordpress.com/2009/03/27/pycon-hallway-session-1-a-keyring-library-for-python/ |
468 | .. _Google Summer of Code: http://socghop.appspot.com/ |
469 | |
470 | -* Kang Zhang |
471 | -* Tarek Ziade |
472 | +See CONTRIBUTORS.txt for a complete list of contributors. |
473 | + |
474 | |
475 | === modified file 'debian/changelog' |
476 | --- debian/changelog 2010-12-03 00:11:03 +0000 |
477 | +++ debian/changelog 2011-02-08 19:21:29 +0000 |
478 | @@ -1,3 +1,24 @@ |
479 | +python-keyring (0.5.1-0ubuntu1~ppa0) natty; urgency=low |
480 | + |
481 | + * New upstream release. (LP: #686257) |
482 | + * debian/control |
483 | + - The upstream package no longer builds extension modules for |
484 | + keyring-gnome or keyring-kwallet, so those binary packages are deleted. |
485 | + - Specify Python 2.6 as the minimum requirement and use |
486 | + X-Python-Version instead of XS-Python-Version (dh_python2). |
487 | + - Update Vcs-* headers to match what is given on the Cheeseshop page. |
488 | + - Update Standards-Version and Depends. |
489 | + - Suggests is no longer relevant, so it's removed. |
490 | + - Trim Build-Depends to only what's needed now. |
491 | + * debian/rules |
492 | + - Update to dh_python2 build system and simplify. |
493 | + * debian/python-keyring{,-gnome,-kwallet}.install |
494 | + - Removed as there is now only one binary package. |
495 | + * debian/copyright |
496 | + - Include my name since the packaging has changed quite a bit. |
497 | + |
498 | + -- Barry Warsaw <barry@ubuntu.com> Wed, 02 Feb 2011 15:17:50 -0500 |
499 | + |
500 | python-keyring (0.2-3build1) natty; urgency=low |
501 | |
502 | * Rebuild to add support for python 2.7. |
503 | |
504 | === modified file 'debian/control' |
505 | --- debian/control 2009-10-13 22:59:53 +0000 |
506 | +++ debian/control 2011-02-08 19:21:29 +0000 |
507 | @@ -1,45 +1,21 @@ |
508 | Source: python-keyring |
509 | Priority: optional |
510 | Section: python |
511 | -XS-Python-Version: >= 2.5 |
512 | -Maintainer: Carl Chenet <chaica@ohmytux.com> |
513 | +X-Python-Version: >= 2.6 |
514 | +Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
515 | +XSBC-Original-Maintainer: Carl Chenet <chaica@ohmytux.com> |
516 | Uploaders: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org> |
517 | -Build-Depends: debhelper (>= 7.0.50~), python(>= 2.5), python-support, python-all-dev, pkg-config, libdbus-1-dev, libglib2.0-dev, libgnome-keyring-dev, kdelibs5-dev, kdelibs-bin, libqt4-dev |
518 | -Standards-Version: 3.8.3 |
519 | -Homepage: http://pypi.python.org/pypi/keyring |
520 | -Vcs-Svn: svn://svn.debian.org/svn/python-modules/packages/python-keyring/trunk/ |
521 | -Vcs-Browser: http://svn.debian.org/wsvn/python-modules/packages/python-keyring/trunk/ |
522 | +Build-Depends: debhelper (>= 7.0.50~), python-setuptools, python-all |
523 | +Standards-Version: 3.9.1 |
524 | +Homepage: http://home.python-keyring.org/ |
525 | +Vcs-Hg: http://bitbucket.org/kang/python-keyring-lib/ |
526 | +Vcs-Browser: http://bitbucket.org/kang/python-keyring-lib/ |
527 | |
528 | Package: python-keyring |
529 | Architecture: all |
530 | -Depends: ${python:Depends}, ${misc:Depends}, ${shlibs:Depends} |
531 | +Depends: ${python:Depends}, ${misc:Depends} |
532 | Recommends: python-crypto |
533 | -Suggests: python-keyring-gnome (>= ${source:Version}), python-keyring-kwallet (>= ${source:Version}) |
534 | Description: store and access your passwords safely |
535 | The Python keyring library provides an easy way to access the system |
536 | keyring service (e.g Gnome-Keyring, KWallet) from Python. |
537 | it can be used in any application that needs safe password storage. |
538 | - . |
539 | - This package does not provides the Gnome-Keyring or KWallet backends. |
540 | - |
541 | -Package: python-keyring-gnome |
542 | -Architecture: any |
543 | -Depends: ${python:Depends}, ${misc:Depends}, ${shlibs:Depends}, python-keyring (= ${source:Version}) |
544 | -Provides: ${python:Provides} |
545 | -Description: store and access your passwords safely - Gnome-Keyring backend |
546 | - The Python keyring library provides an easy way to access the system |
547 | - keyring service (e.g Gnome-Keyring, KWallet) from Python. |
548 | - It can be used in any application that needs safe password storage. |
549 | - . |
550 | - This package only provides the Gnome-Keyring backend. |
551 | - |
552 | -Package: python-keyring-kwallet |
553 | -Architecture: any |
554 | -Depends: ${python:Depends}, ${misc:Depends}, ${shlibs:Depends}, python-keyring (= ${source:Version}) |
555 | -Provides: ${python:Provides} |
556 | -Description: store and access your passwords safely - KWallet backend |
557 | - The Python keyring library provides an easy way to access the system |
558 | - keyring service (e.g Gnome-Keyring, KWallet) from Python. |
559 | - it can be used in any application that needs safe password storage. |
560 | - . |
561 | - This package only provides the KWallet backend. |
562 | |
563 | === modified file 'debian/copyright' |
564 | --- debian/copyright 2009-09-24 23:24:02 +0000 |
565 | +++ debian/copyright 2011-02-08 19:21:29 +0000 |
566 | @@ -1,5 +1,6 @@ |
567 | -This package was debianized by Carl Chenet <chaica@ohmytux.com> on |
568 | -Tue, 01 Sep 2009 00:22:25 +0200. |
569 | +This package was originally debianized by Carl Chenet <chaica@ohmytux.com> on |
570 | +Tue, 01 Sep 2009 00:22:25 +0200. The packaging was updated by Barry Warsaw |
571 | +<barry@python.org> on 2011-02-02. |
572 | |
573 | It was downloaded from http://pypi.python.org/pypi/keyring |
574 | |
575 | @@ -278,6 +279,7 @@ |
576 | The Debian packaging is: |
577 | |
578 | Copyright © 2009 Carl Chenet <chaica@ohmytux.com> |
579 | + Copyright © 2011 Barry Warsaw <barry@python.org> |
580 | |
581 | and is licensed under the GPL version 3, |
582 | see `/usr/share/common-licenses/GPL-3'. |
583 | |
584 | === removed file 'debian/python-keyring-gnome.install' |
585 | --- debian/python-keyring-gnome.install 2009-09-24 23:24:02 +0000 |
586 | +++ debian/python-keyring-gnome.install 1970-01-01 00:00:00 +0000 |
587 | @@ -1,1 +0,0 @@ |
588 | -usr/lib/python*/*-packages/gnome_keyring.so |
589 | |
590 | === removed file 'debian/python-keyring-kwallet.install' |
591 | --- debian/python-keyring-kwallet.install 2009-09-24 23:24:02 +0000 |
592 | +++ debian/python-keyring-kwallet.install 1970-01-01 00:00:00 +0000 |
593 | @@ -1,1 +0,0 @@ |
594 | -usr/lib/python*/*-packages/kde_kwallet.so |
595 | |
596 | === removed file 'debian/python-keyring.install' |
597 | --- debian/python-keyring.install 2009-09-24 23:24:02 +0000 |
598 | +++ debian/python-keyring.install 1970-01-01 00:00:00 +0000 |
599 | @@ -1,2 +0,0 @@ |
600 | -usr/lib/python*/*-packages/keyring/*.py |
601 | -usr/lib/python*/*-packages/keyring-*.egg-info |
602 | |
603 | === modified file 'debian/rules' |
604 | --- debian/rules 2009-10-13 22:59:53 +0000 |
605 | +++ debian/rules 2011-02-08 19:21:29 +0000 |
606 | @@ -1,13 +1,7 @@ |
607 | #!/usr/bin/make -f |
608 | -HOME=$(CURDIR)/debian/tmphome |
609 | |
610 | %: |
611 | - dh $@ |
612 | - |
613 | -override_dh_auto_clean: |
614 | - rm -rf $(HOME) |
615 | - dh_auto_clean |
616 | - |
617 | -override_dh_auto_build: |
618 | - mkdir -p $(HOME) |
619 | - dh_auto_build |
620 | + dh $@ --with python2 |
621 | + |
622 | +override_dh_installchangelogs: |
623 | + dh_installchangelogs -k CHANGES.txt |
624 | |
625 | === modified file 'demo/keyring_demo.py' |
626 | --- demo/keyring_demo.py 2009-09-24 23:24:02 +0000 |
627 | +++ demo/keyring_demo.py 2011-02-08 19:21:29 +0000 |
628 | @@ -19,7 +19,7 @@ |
629 | config_file.writelines(["[backend]\n", |
630 | # the path for the user created keyring |
631 | "keyring-path= %s\n" % str(os.path.abspath(__file__))[:-16], |
632 | - # the name of the keyring class |
633 | + # the name of the keyring class |
634 | "default-keyring=simplekeyring.SimpleKeyring\n" ]) |
635 | config_file.close() |
636 | |
637 | @@ -28,14 +28,17 @@ |
638 | import keyring |
639 | |
640 | # invoke the keyring to store and fetch the password |
641 | - if keyring.set_password("demo-service", "tarek", "passexample") == 0: |
642 | - print "password stored sucessful" |
643 | + try: |
644 | + keyring.set_password("demo-service", "tarek", "passexample") |
645 | + print "password stored sucessfully" |
646 | + except keyring.backend.PasswordSetError: |
647 | + print "failed to store password" |
648 | print "password", keyring.get_password("demo-service", "tarek") |
649 | |
650 | os.remove(KEYRINGRC) |
651 | |
652 | def set_keyring_in_runtime(): |
653 | - """This function shows how to create a keyring manully and use it |
654 | + """This function shows how to create a keyring manully and use it |
655 | in runtime |
656 | """ |
657 | |
658 | @@ -45,22 +48,25 @@ |
659 | """A test keyring which always outputs same password |
660 | """ |
661 | def supported(self): return 0 |
662 | - def set_password(self, servicename, username, password): return 0 |
663 | - def get_password(self, servicename, username): |
664 | + def set_password(self, servicename, username, password): return 0 |
665 | + def get_password(self, servicename, username): |
666 | return "password from TestKeyring" |
667 | - |
668 | + |
669 | # set the keyring for keyring lib |
670 | import keyring |
671 | keyring.set_keyring(TestKeyring()) |
672 | |
673 | # invoke the keyring lib |
674 | - if keyring.set_password("demo-service", "tarek", "passexample") == 0: |
675 | - print "password stored successful" |
676 | + try: |
677 | + keyring.set_password("demo-service", "tarek", "passexample") |
678 | + print "password stored sucessfully" |
679 | + except keyring.backend.PasswordSetError: |
680 | + print "failed to store password" |
681 | print "password", keyring.get_password("demo-service", "tarek") |
682 | |
683 | def main(): |
684 | - """This script shows how to enable the keyring using the config |
685 | - file and in runtime. |
686 | + """This script shows how to enable the keyring using the config |
687 | + file and in runtime. |
688 | """ |
689 | |
690 | load_keyring_by_config() |
691 | |
692 | === modified file 'extensions.py' |
693 | --- extensions.py 2009-09-24 23:24:02 +0000 |
694 | +++ extensions.py 2011-02-08 19:21:29 +0000 |
695 | @@ -4,67 +4,10 @@ |
696 | Created by Kang Zhang on 2009-08-07 |
697 | """ |
698 | |
699 | -import os |
700 | import sys |
701 | -import commands |
702 | |
703 | from distutils.core import Extension |
704 | |
705 | -def pkg_check(packages): |
706 | - """Return false if not all packages has been installed properly. |
707 | - """ |
708 | - status, output = commands.getstatusoutput("pkg-config --exists %s" % |
709 | - ' '.join(packages)) |
710 | - return len(output) == 0 and status == 0 |
711 | - |
712 | -def pkg_config(packages): |
713 | - """Return the config parameters for all packages |
714 | - """ |
715 | - keywords = {} |
716 | - flag_map = {'-I':'include_dirs', '-L':'library_dirs', '-l':'libraries'} |
717 | - |
718 | - for token in commands.getoutput("pkg-config --libs --cflags %s" % |
719 | - ' '.join(packages)).split(): |
720 | - try: |
721 | - key = flag_map[token[:2]] |
722 | - keywords.setdefault(key, []).append(token[2:]) |
723 | - except KeyError: |
724 | - keywords.setdefault('extra_link_args', []).append(token) |
725 | - |
726 | - return keywords |
727 | - |
728 | -def kde_exec(cmd, option): |
729 | - """Execute the kde-config command and get the output dirs |
730 | - """ |
731 | - return commands.getoutput("%s %s --expandvars" % (cmd, option)).split(':') |
732 | - |
733 | -def kde_check(cmd, headfiles): |
734 | - includes = kde_exec(cmd, '--install include') |
735 | - for filename in headfiles: |
736 | - # generate all possible paths for the headfile |
737 | - paths = [os.path.join(dir, filename) for dir in includes] |
738 | - # check if file exists on any path |
739 | - exists = any([ os.path.exists(path) for path in paths]) |
740 | - if not exists: |
741 | - return False |
742 | - return True |
743 | - |
744 | -def kde_config(cmd, keywords): |
745 | - """Add the compile parameters for kdelibs |
746 | - """ |
747 | - |
748 | - # KDE guys hate pkg-config, so we need due with it seperately. :-( |
749 | - # See following link for more details |
750 | - # http://lists.kde.org/?t=109647896600005&r=1&w=2 |
751 | - |
752 | - keywords.setdefault('libraries', []).append('kdeui') |
753 | - |
754 | - libs = kde_exec(cmd, '--path lib') |
755 | - includes = kde_exec(cmd, '--install include') |
756 | - |
757 | - keywords.setdefault('library_dirs', []).extend(libs) |
758 | - keywords.setdefault('include_dirs', []).extend(includes) |
759 | - return keywords |
760 | |
761 | def get_extensions(): |
762 | """Collect the extensions that can be installed. |
763 | @@ -82,32 +25,6 @@ |
764 | 'CoreServices']) |
765 | exts.append(osx_keychain_module) |
766 | |
767 | - gnome_keyring_libs = ['dbus-1', 'glib-2.0', 'gnome-keyring-1'] |
768 | - if pkg_check(gnome_keyring_libs): |
769 | - # gnome-keyring installed |
770 | - gnome_keychain_module = Extension('gnome_keyring', |
771 | - sources = ['keyring/backends/gnome_keyring.c'], |
772 | - **pkg_config(gnome_keyring_libs) |
773 | - ) |
774 | - exts.append(gnome_keychain_module) |
775 | - |
776 | - # check for KWallet heardfiles |
777 | - kde_kwallet_headfiles = ['kwallet.h'] |
778 | - kde_cmd = None |
779 | - for cmd in ('kde-config','kde4-config'): |
780 | - if kde_check(cmd, kde_kwallet_headfiles): |
781 | - kde_cmd = cmd |
782 | - |
783 | - # check for Kwallet related libs |
784 | - kde_kwallet_libs = ['dbus-1', 'glib-2.0', 'QtGui'] |
785 | - if pkg_check(kde_kwallet_libs) and kde_cmd is not None: |
786 | - # KDE Kwallet is installed. |
787 | - kde_kwallet_module = Extension('kde_kwallet', |
788 | - sources = ['keyring/backends/kde_kwallet.cpp'], |
789 | - **kde_config(kde_cmd, pkg_config(kde_kwallet_libs)) |
790 | - ) |
791 | - exts.append(kde_kwallet_module) |
792 | - |
793 | if platform in ['win32'] and sys.getwindowsversion()[-2] == 2: |
794 | # windows 2k+ |
795 | win32_crypto_module = Extension('win32_crypto', |
796 | |
797 | === modified file 'keyring/__init__.py' |
798 | --- keyring/__init__.py 2009-09-24 23:24:02 +0000 |
799 | +++ keyring/__init__.py 2011-02-08 19:21:29 +0000 |
800 | @@ -7,3 +7,4 @@ |
801 | logger = logging.getLogger('keyring') |
802 | |
803 | from core import set_keyring, get_keyring, set_password, get_password |
804 | +from keyring.getpassbackend import get_password as get_pass_get_password |
805 | |
806 | === modified file 'keyring/backend.py' |
807 | --- keyring/backend.py 2009-09-24 23:24:02 +0000 |
808 | +++ keyring/backend.py 2011-02-08 19:21:29 +0000 |
809 | @@ -6,9 +6,10 @@ |
810 | |
811 | import os |
812 | import sys |
813 | -import getpass |
814 | import ConfigParser |
815 | |
816 | +from keyring.util.escape import escape as escape_for_ini |
817 | + |
818 | try: |
819 | from abc import ABCMeta, abstractmethod |
820 | except ImportError: |
821 | @@ -19,12 +20,20 @@ |
822 | def abstractmethod(funcobj): |
823 | return funcobj |
824 | |
825 | +try: |
826 | + import gnomekeyring |
827 | +except ImportError: |
828 | + pass |
829 | |
830 | _KEYRING_SETTING = 'keyring-setting' |
831 | _CRYPTED_PASSWORD = 'crypted-password' |
832 | _BLOCK_SIZE = 32 |
833 | _PADDING = '0' |
834 | |
835 | +class PasswordSetError(Exception): |
836 | + """Raised when the password can't be set. |
837 | + """ |
838 | + |
839 | class KeyringBackend(object): |
840 | """The abstract base class of the keyring, every backend must implement |
841 | this interface. |
842 | @@ -44,13 +53,13 @@ |
843 | def get_password(self, service, username): |
844 | """Get password of the username for the service |
845 | """ |
846 | - pass |
847 | + return None |
848 | |
849 | @abstractmethod |
850 | def set_password(self, service, username, password): |
851 | """Set password for the username of the service |
852 | """ |
853 | - return -1 |
854 | + raise PasswordSetError() |
855 | |
856 | class _ExtensionKeyring(KeyringBackend): |
857 | """_ExtensionKeyring is a adaptor class for the platform related keyring |
858 | @@ -94,11 +103,13 @@ |
859 | def set_password(self, service, username, password): |
860 | """Overide the set_password() in KeyringBackend. |
861 | """ |
862 | - return self.keyring_impl.password_set(service, username, password) |
863 | + try: |
864 | + self.keyring_impl.password_set(service, username, password) |
865 | + except OSError: |
866 | + raise PasswordSetError() |
867 | |
868 | class OSXKeychain(_ExtensionKeyring): |
869 | - """The keyring backend based on Keychain Service of the Mac OSX |
870 | - """ |
871 | + """Mac OSX Keychain""" |
872 | def _init_backend(self): |
873 | """Return the handler: osx_keychain |
874 | """ |
875 | @@ -110,36 +121,100 @@ |
876 | """ |
877 | return sys.platform == 'darwin' |
878 | |
879 | -class GnomeKeyring(_ExtensionKeyring): |
880 | - """The keyring backend using Gnome Keyring. |
881 | - """ |
882 | - def _init_backend(self): |
883 | - """Return the gnome_keyring handler. |
884 | - """ |
885 | - import gnome_keyring |
886 | - return gnome_keyring |
887 | - |
888 | - def _recommend(self): |
889 | - """Recommend this keyring when Gnome is running. |
890 | - """ |
891 | - # Gnome is running |
892 | - return os.getenv("GNOME_DESKTOP_SESSION_ID") is not None |
893 | - |
894 | - |
895 | -class KDEKWallet(_ExtensionKeyring): |
896 | - """The keyring backend based on KDE KWallet |
897 | - """ |
898 | - def _init_backend(self): |
899 | - """Return the kde_kwallet handler. |
900 | - """ |
901 | - import kde_kwallet |
902 | - return kde_kwallet |
903 | - |
904 | - def _recommend(self): |
905 | - """Recommend this keyring backend when KDE is running. |
906 | - """ |
907 | - # KDE is running |
908 | - return os.getenv("KDE_FULL_SESSION") == "true" |
909 | +class GnomeKeyring(KeyringBackend): |
910 | + """Gnome Keyring""" |
911 | + |
912 | + def supported(self): |
913 | + try: |
914 | + import gnomekeyring |
915 | + except ImportError: |
916 | + return -1 |
917 | + else: |
918 | + return 1 |
919 | + |
920 | + def get_password(self, service, username): |
921 | + """Get password of the username for the service |
922 | + """ |
923 | + try: |
924 | + items = gnomekeyring.find_network_password_sync(username, service) |
925 | + except gnomekeyring.NoMatchError: |
926 | + return None |
927 | + except gnomekeyring.CancelledError: |
928 | + # The user pressed "Cancel" when prompted to unlock their keyring. |
929 | + return None |
930 | + |
931 | + assert len(items) == 1, 'no more than one entry should ever match' |
932 | + return items[0]['password'] |
933 | + |
934 | + def set_password(self, service, username, password): |
935 | + """Set password for the username of the service |
936 | + """ |
937 | + try: |
938 | + gnomekeyring.set_network_password_sync(None, username, service, |
939 | + None, None, None, None, 0, password) |
940 | + except gnomekeyring.CancelledError: |
941 | + # The user pressed "Cancel" when prompted to unlock their keyring. |
942 | + raise PasswordSetError() |
943 | + |
944 | +def open_kwallet(kwallet_module=None, qt_module=None): |
945 | + # Allow for the injection of module-like objects for testing purposes. |
946 | + if kwallet_module is None: |
947 | + kwallet_module = KWallet.Wallet |
948 | + if qt_module is None: |
949 | + qt_module = QtGui |
950 | + |
951 | + # KDE wants us to instantiate an application object. |
952 | + app = qt_module.QApplication([]) |
953 | + try: |
954 | + window = QtGui.QWidget() |
955 | + kwallet = kwallet_module.openWallet( |
956 | + kwallet_module.NetworkWallet(), |
957 | + window.winId(), |
958 | + kwallet_module.Synchronous) |
959 | + if kwallet is not None: |
960 | + if not kwallet.hasFolder('Python'): |
961 | + kwallet.createFolder('Python') |
962 | + kwallet.setFolder('Python') |
963 | + finally: |
964 | + app.exit() |
965 | + |
966 | + |
967 | +kwallet = None |
968 | +try: |
969 | + from PyKDE4.kdeui import KWallet |
970 | + from PyQt4 import QtCore, QtGui |
971 | +except ImportError: |
972 | + kwallet = None |
973 | +else: |
974 | + kwallet = open_kwallet() |
975 | + |
976 | + |
977 | +class KDEKWallet(KeyringBackend): |
978 | + """KDE KWallet""" |
979 | + |
980 | + def supported(self): |
981 | + if kwallet is None: |
982 | + return -1 |
983 | + else: |
984 | + return 1 |
985 | + |
986 | + def get_password(self, service, username): |
987 | + """Get password of the username for the service |
988 | + """ |
989 | + key = username + '@' + service |
990 | + network = KWallet.Wallet.NetworkWallet() |
991 | + if kwallet.keyDoesNotExist(network, 'Python', key): |
992 | + return None |
993 | + |
994 | + result = kwallet.readPassword(key)[1] |
995 | + # The string will be a PyQt4.QtCore.QString, so turn it into a unicode |
996 | + # object. |
997 | + return unicode(result) |
998 | + |
999 | + def set_password(self, service, username, password): |
1000 | + """Set password for the username of the service |
1001 | + """ |
1002 | + kwallet.writePassword(username+'@'+service, password) |
1003 | |
1004 | class BasicFileKeyring(KeyringBackend): |
1005 | """BasicFileKeyring is a filebased implementation of keyring. |
1006 | @@ -173,6 +248,9 @@ |
1007 | def get_password(self, service, username): |
1008 | """Read the password from the file. |
1009 | """ |
1010 | + service = escape_for_ini(service) |
1011 | + username = escape_for_ini(username) |
1012 | + |
1013 | # load the passwords from the file |
1014 | config = ConfigParser.RawConfigParser() |
1015 | if os.path.exists(self.file_path): |
1016 | @@ -192,6 +270,9 @@ |
1017 | def set_password(self, service, username, password): |
1018 | """Write the password in the file. |
1019 | """ |
1020 | + service = escape_for_ini(service) |
1021 | + username = escape_for_ini(username) |
1022 | + |
1023 | # encrypt the password |
1024 | password_encrypted = self.encrypt(password) |
1025 | # load the password from the disk |
1026 | @@ -208,11 +289,8 @@ |
1027 | config_file = open(self.file_path,'w') |
1028 | config.write(config_file) |
1029 | |
1030 | - return 0 |
1031 | - |
1032 | class UncryptedFileKeyring(BasicFileKeyring): |
1033 | - """A simple filekeyring which dose not encrypt the password. |
1034 | - """ |
1035 | + """Uncrypted File Keyring""" |
1036 | def filename(self): |
1037 | """Return the filename of the password file. It should be |
1038 | "keyring_pass.cfg" . |
1039 | @@ -235,8 +313,7 @@ |
1040 | return 0 |
1041 | |
1042 | class CryptedFileKeyring(BasicFileKeyring): |
1043 | - """CryptedFileKeyring is a keyring using lib pycryto to encrypt the password |
1044 | - """ |
1045 | + """PyCrypto File Keyring""" |
1046 | def __init__(self): |
1047 | super(CryptedFileKeyring, self).__init__() |
1048 | self.crypted_password = None |
1049 | @@ -264,6 +341,7 @@ |
1050 | password = None |
1051 | while 1: |
1052 | if not password: |
1053 | + import getpass |
1054 | password = getpass.getpass() |
1055 | password2 = getpass.getpass('Password (again): ') |
1056 | if password != password2: |
1057 | @@ -325,6 +403,7 @@ |
1058 | self._init_file() |
1059 | |
1060 | print "Please input your password for the keyring" |
1061 | + import getpass |
1062 | password = getpass.getpass() |
1063 | |
1064 | if not self._auth(password): |
1065 | @@ -352,9 +431,7 @@ |
1066 | |
1067 | |
1068 | class Win32CryptoKeyring(BasicFileKeyring): |
1069 | - """Win32CryptoKeyring is a keyring which use Windows CryptAPI to encrypt |
1070 | - the user's passwords and store them in a file. |
1071 | - """ |
1072 | + """Win32 Cryptography Keyring""" |
1073 | def __init__(self): |
1074 | super(Win32CryptoKeyring, self).__init__() |
1075 | |
1076 | @@ -370,14 +447,15 @@ |
1077 | return "wincrypto_pass.cfg" |
1078 | |
1079 | def supported(self): |
1080 | - """Recommend for all Windows is higher than Windows 2000. |
1081 | + """Recommend when other Windows backends are unavailable |
1082 | """ |
1083 | - if self.crypt_handler is not None and sys.platform == 'win32': |
1084 | - major, minor, build, platform, text = sys.getwindowsversion() |
1085 | - if platform == 2: |
1086 | - # recommend for windows 2k+ |
1087 | - return 1 |
1088 | - return -1 |
1089 | + recommended = select_windows_backend() |
1090 | + if recommended == None: |
1091 | + return -1 |
1092 | + elif recommended == 'file': |
1093 | + return 1 |
1094 | + else: |
1095 | + return 0 |
1096 | |
1097 | def encrypt(self, password): |
1098 | """Encrypt the password using the CryptAPI. |
1099 | @@ -390,6 +468,132 @@ |
1100 | return self.crypt_handler.decrypt(password_encrypted) |
1101 | |
1102 | |
1103 | +class WinVaultKeyring(KeyringBackend): |
1104 | + def __init__(self): |
1105 | + super(WinVaultKeyring, self).__init__() |
1106 | + try: |
1107 | + import pywintypes, win32cred |
1108 | + self.win32cred = win32cred |
1109 | + self.pywintypes = pywintypes |
1110 | + except ImportError: |
1111 | + self.win32cred = None |
1112 | + |
1113 | + def supported(self): |
1114 | + '''Default Windows backend, when it is available |
1115 | + ''' |
1116 | + recommended = select_windows_backend() |
1117 | + if recommended == None: |
1118 | + return -1 |
1119 | + elif recommended == 'cred': |
1120 | + return 1 |
1121 | + else: |
1122 | + return 0 |
1123 | + |
1124 | + def get_password(self, service, username): |
1125 | + try: |
1126 | + blob = self.win32cred.CredRead(Type=self.win32cred.CRED_TYPE_GENERIC, |
1127 | + TargetName=service)['CredentialBlob'] |
1128 | + except self.pywintypes.error, e: |
1129 | + if e[:2] == (1168, 'CredRead'): |
1130 | + return None |
1131 | + raise |
1132 | + return blob.decode("utf16") |
1133 | + |
1134 | + def set_password(self, service, username, password): |
1135 | + credential = dict(Type=self.win32cred.CRED_TYPE_GENERIC, |
1136 | + TargetName=service, |
1137 | + UserName=username, |
1138 | + CredentialBlob=unicode(password), |
1139 | + Comment="Stored using python-keyring", |
1140 | + Persist=self.win32cred.CRED_PERSIST_ENTERPRISE) |
1141 | + self.win32cred.CredWrite(credential, 0) |
1142 | + |
1143 | + |
1144 | +class Win32CryptoRegistry(KeyringBackend): |
1145 | + """Win32CryptoRegistry is a keyring which use Windows CryptAPI to encrypt |
1146 | + the user's passwords and store them under registry keys |
1147 | + """ |
1148 | + def __init__(self): |
1149 | + super(Win32CryptoRegistry, self).__init__() |
1150 | + |
1151 | + try: |
1152 | + import win32_crypto |
1153 | + import _winreg |
1154 | + self.crypt_handler = win32_crypto |
1155 | + except ImportError: |
1156 | + self.crypt_handler = None |
1157 | + |
1158 | + def supported(self): |
1159 | + """Return if this keyring supports current enviroment. |
1160 | + -1: not applicable |
1161 | + 0: suitable |
1162 | + 1: recommended |
1163 | + """ |
1164 | + recommended = select_windows_backend() |
1165 | + if recommended == None: |
1166 | + return -1 |
1167 | + elif recommended == 'reg': |
1168 | + return 1 |
1169 | + else: |
1170 | + return 0 |
1171 | + |
1172 | + def get_password(self, service, username): |
1173 | + """Get password of the username for the service |
1174 | + """ |
1175 | + from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx |
1176 | + try: |
1177 | + # fetch the password |
1178 | + key = r'Software\%s\Keyring' % service |
1179 | + hkey = OpenKey(HKEY_CURRENT_USER, key) |
1180 | + password_base64 = QueryValueEx(hkey, username)[0] |
1181 | + # decode with base64 |
1182 | + password_encrypted = password_base64.decode("base64") |
1183 | + # decrypted the password |
1184 | + password = self.crypt_handler.decrypt(password_encrypted) |
1185 | + except EnvironmentError: |
1186 | + password = None |
1187 | + return password |
1188 | + |
1189 | + |
1190 | + def set_password(self, service, username, password): |
1191 | + """Write the password to the registry |
1192 | + """ |
1193 | + # encrypt the password |
1194 | + password_encrypted = self.crypt_handler.encrypt(password) |
1195 | + # encode with base64 |
1196 | + password_base64 = password_encrypted.encode("base64") |
1197 | + |
1198 | + # store the password |
1199 | + from _winreg import HKEY_CURRENT_USER, CreateKey, SetValueEx, REG_SZ |
1200 | + hkey = CreateKey(HKEY_CURRENT_USER, r'Software\%s\Keyring' % service) |
1201 | + SetValueEx(hkey, username, 0, REG_SZ, password_base64) |
1202 | + |
1203 | +def select_windows_backend(): |
1204 | + if os.name != 'nt': |
1205 | + return None |
1206 | + major, minor, build, platform, text = sys.getwindowsversion() |
1207 | + try: |
1208 | + import pywintypes, win32cred |
1209 | + if (major, minor) >= (5, 1): |
1210 | + # recommend for windows xp+ |
1211 | + return 'cred' |
1212 | + except ImportError: |
1213 | + pass |
1214 | + try: |
1215 | + import win32_crypto, _winreg |
1216 | + if (major, minor) >= (5, 0): |
1217 | + # recommend for windows 2k+ |
1218 | + return 'reg' |
1219 | + except ImportError: |
1220 | + pass |
1221 | + try: |
1222 | + import win32_crypto |
1223 | + return 'file' |
1224 | + except ImportError: |
1225 | + pass |
1226 | + return None |
1227 | + |
1228 | + |
1229 | _all_keyring = None |
1230 | |
1231 | def get_all_keyring(): |
1232 | @@ -399,6 +603,7 @@ |
1233 | if _all_keyring is None: |
1234 | _all_keyring = [ OSXKeychain(), GnomeKeyring(), KDEKWallet(), |
1235 | CryptedFileKeyring(), UncryptedFileKeyring(), |
1236 | - Win32CryptoKeyring()] |
1237 | + Win32CryptoKeyring(), Win32CryptoRegistry(), |
1238 | + WinVaultKeyring()] |
1239 | return _all_keyring |
1240 | |
1241 | |
1242 | === added file 'keyring/backends/__init__.py' |
1243 | --- keyring/backends/__init__.py 1970-01-01 00:00:00 +0000 |
1244 | +++ keyring/backends/__init__.py 2011-02-08 19:21:29 +0000 |
1245 | @@ -0,0 +1,1 @@ |
1246 | +# |
1247 | |
1248 | === removed file 'keyring/backends/gnome_keyring.c' |
1249 | --- keyring/backends/gnome_keyring.c 2009-09-24 23:24:02 +0000 |
1250 | +++ keyring/backends/gnome_keyring.c 1970-01-01 00:00:00 +0000 |
1251 | @@ -1,111 +0,0 @@ |
1252 | -/* |
1253 | - * Comment by Kang. This lib dose not support non_interactive mode |
1254 | - */ |
1255 | -#include <glib.h> |
1256 | -#include <dbus/dbus.h> |
1257 | -#include <gnome-keyring.h> |
1258 | - |
1259 | -#include "Python.h" |
1260 | -#include "keyring_util.h" |
1261 | - |
1262 | -static PyObject* |
1263 | -gnome_keyring_password_get(PyObject *self, PyObject *args) |
1264 | -{ |
1265 | - const char *realmstring; |
1266 | - const char *username; |
1267 | - const char *password; |
1268 | - |
1269 | - if (!PyArg_ParseTuple(args, "ss", &realmstring, &username)){ |
1270 | - PyErr_Clear(); |
1271 | - PyErr_SetString(PyExc_TypeError, |
1272 | - "password_get() must be called as (servicename,username)"); |
1273 | - return NULL; |
1274 | - } |
1275 | - if ((! dbus_bus_get(DBUS_BUS_SESSION,NULL)) || |
1276 | - (!gnome_keyring_is_available())){ |
1277 | - PyErr_Clear(); |
1278 | - PyErr_SetString(PyExc_OSError, "Can's access the keyring now"); |
1279 | - return NULL; |
1280 | - } |
1281 | - |
1282 | - GnomeKeyringResult result; |
1283 | - GList *items; |
1284 | - |
1285 | - result = gnome_keyring_find_network_password_sync(username, realmstring, |
1286 | - NULL, NULL, NULL, NULL, 0, &items); |
1287 | - |
1288 | - int status = 0; |
1289 | - if (result == GNOME_KEYRING_RESULT_OK){ |
1290 | - if (items && items->data){ |
1291 | - GnomeKeyringNetworkPasswordData *item; |
1292 | - item = (GnomeKeyringNetworkPasswordData *)items->data; |
1293 | - if (item->password){ |
1294 | - size_t len = strlen(item->password); |
1295 | - password = string_dump(item->password, len); |
1296 | - status = 1; |
1297 | - } |
1298 | - gnome_keyring_network_password_list_free(items); |
1299 | - } |
1300 | - } |
1301 | - |
1302 | - if (!status){ |
1303 | - PyErr_Clear(); |
1304 | - PyErr_SetString(PyExc_OSError, "Can't fech password from system"); |
1305 | - return NULL; |
1306 | - } |
1307 | - |
1308 | - return Py_BuildValue("s",password); |
1309 | -} |
1310 | -static PyObject* |
1311 | -gnome_keyring_password_set(PyObject *self, PyObject *args) |
1312 | -{ |
1313 | - const char *realmstring; |
1314 | - const char *username; |
1315 | - const char *password; |
1316 | - |
1317 | - if (!PyArg_ParseTuple(args, "sss", &realmstring, &username, &password)){ |
1318 | - PyErr_Clear(); |
1319 | - PyErr_SetString(PyExc_TypeError, |
1320 | - "password_set() must be called as (servicename,username,password)"); |
1321 | - return NULL; |
1322 | - } |
1323 | - if ((! dbus_bus_get(DBUS_BUS_SESSION,NULL)) || |
1324 | - (!gnome_keyring_is_available())){ |
1325 | - PyErr_Clear(); |
1326 | - PyErr_SetString(PyExc_OSError, |
1327 | - "Can's access the keyring now"); |
1328 | - return NULL; |
1329 | - } |
1330 | - |
1331 | - |
1332 | - GnomeKeyringResult result; |
1333 | - guint32 item_id; |
1334 | - |
1335 | - result = gnome_keyring_set_network_password_sync(NULL, username, realmstring, |
1336 | - NULL, NULL, NULL, NULL, 0, password, &item_id); |
1337 | - |
1338 | - return Py_BuildValue("i", (result!=GNOME_KEYRING_RESULT_OK)); |
1339 | -} |
1340 | - |
1341 | - |
1342 | -static struct PyMethodDef gnome_keyring_methods[] = { |
1343 | - {"password_set", gnome_keyring_password_set, METH_VARARGS}, |
1344 | - {"password_get", gnome_keyring_password_get, METH_VARARGS}, |
1345 | - {} /* Sentinel */ |
1346 | -}; |
1347 | - |
1348 | -static void |
1349 | -init_application_name(void) |
1350 | -{ |
1351 | - const char *application_name = NULL; |
1352 | - application_name = g_get_application_name(); |
1353 | - if (!application_name) |
1354 | - g_set_application_name("Python"); |
1355 | -} |
1356 | - |
1357 | -PyMODINIT_FUNC |
1358 | -initgnome_keyring(void) |
1359 | -{ |
1360 | - init_application_name(); |
1361 | - Py_InitModule("gnome_keyring", gnome_keyring_methods); |
1362 | -} |
1363 | |
1364 | === removed file 'keyring/backends/kde_kwallet.cpp' |
1365 | --- keyring/backends/kde_kwallet.cpp 2009-09-24 23:24:02 +0000 |
1366 | +++ keyring/backends/kde_kwallet.cpp 1970-01-01 00:00:00 +0000 |
1367 | @@ -1,121 +0,0 @@ |
1368 | -#include <dbus/dbus.h> |
1369 | -#include <QtCore/QCoreApplication> |
1370 | -#include <QtCore/QString> |
1371 | - |
1372 | -#include <kwallet.h> |
1373 | - |
1374 | -#include "Python.h" |
1375 | -#include "keyring_util.h" |
1376 | - |
1377 | -static PyObject * |
1378 | -kde_kwallet_password_get(PyObject *self, PyObject *args) |
1379 | -{ |
1380 | - const char *realmstring; |
1381 | - const char *username; |
1382 | - const char *password; |
1383 | - |
1384 | - if (!PyArg_ParseTuple(args, "ss", &realmstring, &username)){ |
1385 | - PyErr_Clear(); |
1386 | - PyErr_SetString(PyExc_TypeError, |
1387 | - "password_get() must be called as (service,username)"); |
1388 | - return NULL; |
1389 | - } |
1390 | - |
1391 | - if (!dbus_bus_get(DBUS_BUS_SESSION,NULL)){ |
1392 | - PyErr_Clear(); |
1393 | - PyErr_SetString(PyExc_OSError,"can't get access to dbus"); |
1394 | - return NULL; |
1395 | - } |
1396 | - |
1397 | - QCoreApplication *app; |
1398 | - if (!qApp) { |
1399 | - int argc = 1; |
1400 | - app = new QCoreApplication(argc, (char *[1]){ (char*) "python"}); |
1401 | - } |
1402 | - QString folder = QString::fromUtf8("Python"); |
1403 | - QString key = QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring); |
1404 | - QString wallet_name = KWallet::Wallet::NetworkWallet(); |
1405 | - bool fetch_success = false; |
1406 | - if (!KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key)){ |
1407 | - KWallet::Wallet *wallet = KWallet::Wallet::openWallet(wallet_name, -1, |
1408 | - KWallet::Wallet::Synchronous); |
1409 | - if (wallet){ |
1410 | - if (wallet->setFolder(folder)){ |
1411 | - QString q_password; |
1412 | - if (wallet->readPassword(key, q_password) == 0){ |
1413 | - password = string_dump(q_password.toUtf8().data(), q_password.size()); |
1414 | - fetch_success = true; |
1415 | - } |
1416 | - } |
1417 | - } |
1418 | - } |
1419 | - if (!fetch_success){ |
1420 | - PyErr_Clear(); |
1421 | - PyErr_SetString(PyExc_OSError, "Can't access the password from the system"); |
1422 | - return NULL; |
1423 | - } |
1424 | - return Py_BuildValue("s",password); |
1425 | -} |
1426 | - |
1427 | -static PyObject * |
1428 | -kde_kwallet_password_set(PyObject *self, PyObject *args) |
1429 | -{ |
1430 | - const char *realmstring; |
1431 | - const char *username; |
1432 | - const char *password; |
1433 | - |
1434 | - if (!PyArg_ParseTuple(args,"sss", &realmstring, &username, &password)){ |
1435 | - PyErr_Clear(); |
1436 | - PyErr_SetString(PyExc_TypeError, |
1437 | - "password_set() must be called as (service,username,password)"); |
1438 | - return NULL; |
1439 | - } |
1440 | - if (!dbus_bus_get(DBUS_BUS_SESSION,NULL)){ |
1441 | - PyErr_Clear(); |
1442 | - PyErr_SetString(PyExc_OSError, "can't get access to dbus"); |
1443 | - return NULL; |
1444 | - } |
1445 | - QCoreApplication *app; |
1446 | - if (! qApp){ |
1447 | - int argc = 1; |
1448 | - app = new QCoreApplication(argc,(char *[1]) {(char*) "Python"}); |
1449 | - } |
1450 | - |
1451 | - bool write_success = false; |
1452 | - QString q_password = QString::fromUtf8(password); |
1453 | - QString wallet_name = KWallet::Wallet::NetworkWallet(); |
1454 | - QString folder = QString::fromUtf8("Python"); |
1455 | - KWallet::Wallet *wallet = KWallet::Wallet::openWallet(wallet_name, -1, |
1456 | - KWallet::Wallet::Synchronous); |
1457 | - if (wallet){ |
1458 | - if (!wallet->hasFolder(folder)){ |
1459 | - wallet->createFolder(folder); |
1460 | - } |
1461 | - if (wallet->setFolder(folder)){ |
1462 | - QString key = QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring); |
1463 | - if (wallet->writePassword(key, q_password) == 0){ |
1464 | - write_success = true; |
1465 | - } |
1466 | - } |
1467 | - } |
1468 | - |
1469 | - if (!write_success){ |
1470 | - PyErr_Clear(); |
1471 | - PyErr_SetString(PyExc_OSError, "Can't write the password in the system"); |
1472 | - return NULL; |
1473 | - } |
1474 | - return Py_BuildValue("i", write_success != true); |
1475 | -} |
1476 | - |
1477 | - |
1478 | -static struct PyMethodDef kde_kwallet_methods[] = { |
1479 | - {"password_set", kde_kwallet_password_set, METH_VARARGS}, |
1480 | - {"password_get", kde_kwallet_password_get, METH_VARARGS}, |
1481 | - {NULL,NULL}/* Sentinel */ |
1482 | -}; |
1483 | - |
1484 | -PyMODINIT_FUNC |
1485 | -initkde_kwallet(void) |
1486 | -{ |
1487 | - Py_InitModule("kde_kwallet", kde_kwallet_methods); |
1488 | -} |
1489 | |
1490 | === modified file 'keyring/backends/osx_keychain.c' |
1491 | --- keyring/backends/osx_keychain.c 2009-09-24 23:24:02 +0000 |
1492 | +++ keyring/backends/osx_keychain.c 2011-02-08 19:21:29 +0000 |
1493 | @@ -53,8 +53,8 @@ |
1494 | PyErr_SetString(PyExc_OSError, "Can't store password in Keychain"); |
1495 | return NULL; |
1496 | } |
1497 | - |
1498 | - return Py_BuildValue("i",(status != 0)); |
1499 | + |
1500 | + Py_RETURN_NONE; |
1501 | } |
1502 | |
1503 | |
1504 | |
1505 | === modified file 'keyring/core.py' |
1506 | --- keyring/core.py 2009-09-24 23:24:02 +0000 |
1507 | +++ keyring/core.py 2011-02-08 19:21:29 +0000 |
1508 | @@ -7,7 +7,9 @@ |
1509 | import ConfigParser |
1510 | import imp |
1511 | import sys |
1512 | -import backend |
1513 | + |
1514 | +from keyring import logger |
1515 | +from keyring import backend |
1516 | |
1517 | def set_keyring(keyring): |
1518 | """Set current keyring backend. |
1519 | @@ -30,31 +32,31 @@ |
1520 | def set_password(service_name, username, password): |
1521 | """Set password for the user in the spcified service |
1522 | """ |
1523 | - return _keyring_backend.set_password(service_name, username, password) |
1524 | + _keyring_backend.set_password(service_name, username, password) |
1525 | |
1526 | def init_backend(): |
1527 | """first try to load the keyring in the config file, if it has not |
1528 | been decleared, assign a defult keyring according to the platform. |
1529 | """ |
1530 | #select a backend according to the config file |
1531 | - keyring_impl = load_config() |
1532 | + keyring = load_config() |
1533 | |
1534 | # if the user dose not specify a keyring, we apply a default one |
1535 | - if keyring_impl is None: |
1536 | + if keyring is None: |
1537 | |
1538 | keyrings = backend.get_all_keyring() |
1539 | # rank according the supported |
1540 | keyrings.sort(lambda x, y: y.supported() - x.supported()) |
1541 | # get the most recommend one |
1542 | - keyring_impl = keyrings[0] |
1543 | + keyring = keyrings[0] |
1544 | |
1545 | - set_keyring(keyring_impl) |
1546 | + set_keyring(keyring) |
1547 | |
1548 | def load_config(): |
1549 | """load a keyring using the config file, the config file can be |
1550 | in the current working directory, or in the user's home directory. |
1551 | """ |
1552 | - keyring_impl = None |
1553 | + keyring = None |
1554 | |
1555 | # search from current working directory and the home folder |
1556 | keyring_cfg_list = [os.path.join(os.getcwd(), "keyringrc.cfg"), |
1557 | @@ -71,12 +73,19 @@ |
1558 | config.read(keyring_cfg) |
1559 | # load the keyring-path option |
1560 | try: |
1561 | - keyring_path = config.get("backend", "keyring-path").strip() |
1562 | + if config.has_section("backend"): |
1563 | + keyring_path = config.get("backend", "keyring-path").strip() |
1564 | + else: |
1565 | + keyring_path = None |
1566 | except ConfigParser.NoOptionError: |
1567 | keyring_path = None |
1568 | + |
1569 | # load the keyring class name, and load it |
1570 | try: |
1571 | - keyring_name = config.get("backend", "default-keyring").strip() |
1572 | + if config.has_section("backend"): |
1573 | + keyring_name = config.get("backend", "default-keyring").strip() |
1574 | + else: |
1575 | + raise ConfigParser.NoOptionError('backend', 'default-keyring') |
1576 | |
1577 | def load_module(name, path): |
1578 | """Load the specified module from the disk. |
1579 | @@ -111,12 +120,12 @@ |
1580 | keyring_class = keyring_name.split('.')[-1].strip() |
1581 | exec "keyring_temp = module." + keyring_class + "() " in locals() |
1582 | |
1583 | - keyring_impl = keyring_temp |
1584 | + keyring = keyring_temp |
1585 | except (ConfigParser.NoOptionError, ImportError): |
1586 | logger.warning("Keyring Config file does not write correctly.\n" + \ |
1587 | "Config file: %s" % keyring_cfg) |
1588 | |
1589 | - return keyring_impl |
1590 | + return keyring |
1591 | |
1592 | # init the _keyring_backend |
1593 | init_backend() |
1594 | |
1595 | === added file 'keyring/getpassbackend.py' |
1596 | --- keyring/getpassbackend.py 1970-01-01 00:00:00 +0000 |
1597 | +++ keyring/getpassbackend.py 2011-02-08 19:21:29 +0000 |
1598 | @@ -0,0 +1,13 @@ |
1599 | +"""Specific support for getpass.""" |
1600 | +import os |
1601 | +import getpass |
1602 | + |
1603 | +from keyring.core import get_password as original_get_password |
1604 | + |
1605 | +get_default_user = getpass.getuser |
1606 | + |
1607 | +def get_password(prompt='Password: ', stream=None, |
1608 | + service_name='Python', |
1609 | + username=get_default_user()): |
1610 | + return original_get_password(service_name, username) |
1611 | + |
1612 | |
1613 | === added file 'keyring/tests/__init__.py' |
1614 | --- keyring/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1615 | +++ keyring/tests/__init__.py 2011-02-08 19:21:29 +0000 |
1616 | @@ -0,0 +1,1 @@ |
1617 | +# |
1618 | |
1619 | === modified file 'keyring/tests/test_backend.py' |
1620 | --- keyring/tests/test_backend.py 2009-09-24 23:24:02 +0000 |
1621 | +++ keyring/tests/test_backend.py 2011-02-08 19:21:29 +0000 |
1622 | @@ -15,14 +15,17 @@ |
1623 | import commands |
1624 | import keyring.backend |
1625 | |
1626 | +from keyring.backend import PasswordSetError |
1627 | + |
1628 | ALPHABET = string.ascii_letters + string.digits |
1629 | +DIFFICULT_CHARS = string.whitespace + string.punctuation |
1630 | |
1631 | -def random_string(k): |
1632 | +def random_string(k, source = ALPHABET): |
1633 | """Generate a random string with length <i>k</i> |
1634 | """ |
1635 | result = '' |
1636 | for i in range(0, k): |
1637 | - result += random.choice(ALPHABET) |
1638 | + result += random.choice(source) |
1639 | return result |
1640 | |
1641 | def backup(file): |
1642 | @@ -41,16 +44,10 @@ |
1643 | |
1644 | __test__ = False |
1645 | |
1646 | - def init_keyring(self): |
1647 | - return None |
1648 | - |
1649 | def setUp(self): |
1650 | self.keyring = self.init_keyring() |
1651 | |
1652 | - def test_password_set_get(self): |
1653 | - password = random_string(20) |
1654 | - username = random_string(20) |
1655 | - service = random_string(20) |
1656 | + def check_set_get(self, service, username, password): |
1657 | keyring = self.keyring |
1658 | |
1659 | if self.supported() == -1: # skip the unsupported keyring |
1660 | @@ -60,13 +57,25 @@ |
1661 | self.assertEqual(keyring.get_password(service, username), None) |
1662 | |
1663 | # common usage |
1664 | - self.assertEqual(keyring.set_password(service, username, password), 0) |
1665 | + keyring.set_password(service, username, password) |
1666 | self.assertEqual(keyring.get_password(service, username), password) |
1667 | |
1668 | # for the empty password |
1669 | - self.assertEqual(keyring.set_password(service, username, ""), 0) |
1670 | + keyring.set_password(service, username, "") |
1671 | self.assertEqual(keyring.get_password(service, username), "") |
1672 | |
1673 | + def test_password_set_get(self): |
1674 | + password = random_string(20) |
1675 | + username = random_string(20) |
1676 | + service = random_string(20) |
1677 | + self.check_set_get(service, username, password) |
1678 | + |
1679 | + def test_difficult_chars(self): |
1680 | + password = random_string(20, DIFFICULT_CHARS) |
1681 | + username = random_string(20, DIFFICULT_CHARS) |
1682 | + service = random_string(20, DIFFICULT_CHARS) |
1683 | + self.check_set_get(service, username, password) |
1684 | + |
1685 | def supported(self): |
1686 | """Return the correct value for supported. |
1687 | """ |
1688 | @@ -81,6 +90,7 @@ |
1689 | __test__ = True |
1690 | |
1691 | def init_keyring(self): |
1692 | + print >> sys.stderr, "Testing OSXKeychain, following password prompts are for this keyring" |
1693 | return keyring.backend.OSXKeychain() |
1694 | |
1695 | def supported(self): |
1696 | @@ -92,31 +102,58 @@ |
1697 | __test__ = True |
1698 | |
1699 | def init_keyring(self): |
1700 | + print >> sys.stderr, "Testing GnomeKeyring, following password prompts are for this keyring" |
1701 | return keyring.backend.GnomeKeyring() |
1702 | |
1703 | def supported(self): |
1704 | - try: |
1705 | - import gnome_keyring |
1706 | - except ImportError: |
1707 | - return -1 |
1708 | - if os.getenv("GNOME_DESKTOP_SESSION_ID") is not None: |
1709 | - return 1 |
1710 | - return 0 |
1711 | + return self.keyring.supported() |
1712 | |
1713 | class KDEKWalletTestCase(BackendBasicTestCase): |
1714 | __test__ = True |
1715 | |
1716 | def init_keyring(self): |
1717 | + print >> sys.stderr, "Testing KDEKWallet, following password prompts are for this keyring" |
1718 | return keyring.backend.KDEKWallet() |
1719 | |
1720 | def supported(self): |
1721 | - try: |
1722 | - import kde_kwallet |
1723 | - except ImportError: |
1724 | - return -1 |
1725 | - if os.getenv("KDE_FULL_SESSION") == "true": |
1726 | - return 1 |
1727 | - return 0 |
1728 | + return self.keyring.supported() |
1729 | + |
1730 | + |
1731 | +class UnOpenableKWallet(object): |
1732 | + """A module-like object used to test KDE wallet fall-back.""" |
1733 | + |
1734 | + Synchronous = None |
1735 | + |
1736 | + def openWallet(self, *args): |
1737 | + return None |
1738 | + |
1739 | + def NetworkWallet(self): |
1740 | + return None |
1741 | + |
1742 | + |
1743 | +class FauxQtGui(object): |
1744 | + """A fake module-like object used in testing the open_kwallet function.""" |
1745 | + |
1746 | + class QApplication(object): |
1747 | + def __init__(self, *args): |
1748 | + pass |
1749 | + |
1750 | + def exit(self): |
1751 | + pass |
1752 | + |
1753 | + |
1754 | +class KDEWalletCanceledTestCase(unittest.TestCase): |
1755 | + |
1756 | + def test_user_canceled(self): |
1757 | + # If the user cancels either the "enter your password to unlock the |
1758 | + # keyring" dialog or clicks "deny" on the "can this application access |
1759 | + # the wallet" dialog then openWallet() will return None. The |
1760 | + # open_wallet() function should handle that eventuality by returning |
1761 | + # None to signify that the KWallet backend is not available. |
1762 | + self.assertEqual( |
1763 | + keyring.backend.open_kwallet(UnOpenableKWallet(), FauxQtGui()), |
1764 | + None) |
1765 | + |
1766 | |
1767 | class FileKeyringTestCase(BackendBasicTestCase): |
1768 | __test__ = False |
1769 | @@ -148,6 +185,7 @@ |
1770 | __test__ = True |
1771 | |
1772 | def init_keyring(self): |
1773 | + print >> sys.stderr, "Testing UnecryptedFile, following password prompts are for this keyring" |
1774 | return keyring.backend.UncryptedFileKeyring() |
1775 | |
1776 | def supported(self): |
1777 | @@ -157,6 +195,7 @@ |
1778 | __test__ = True |
1779 | |
1780 | def init_keyring(self): |
1781 | + print >> sys.stderr, "Testing CryptedFile, following password prompts are for this keyring" |
1782 | return keyring.backend.CryptedFileKeyring() |
1783 | |
1784 | def supported(self): |
1785 | @@ -171,6 +210,7 @@ |
1786 | __test__ = True |
1787 | |
1788 | def init_keyring(self): |
1789 | + print >> sys.stderr, "Testing Win32, following password prompts are for this keyring" |
1790 | return keyring.backend.Win32CryptoKeyring() |
1791 | |
1792 | def supported(self): |
1793 | |
1794 | === modified file 'keyring/tests/test_core.py' |
1795 | --- keyring/tests/test_core.py 2009-09-24 23:24:02 +0000 |
1796 | +++ keyring/tests/test_core.py 2011-02-08 19:21:29 +0000 |
1797 | @@ -3,10 +3,12 @@ |
1798 | |
1799 | Created by Kang Zhang on 2009-08-09 |
1800 | """ |
1801 | - |
1802 | import unittest |
1803 | import os |
1804 | import sys |
1805 | +import tempfile |
1806 | +import shutil |
1807 | + |
1808 | import keyring.backend |
1809 | import keyring.core |
1810 | |
1811 | @@ -36,17 +38,15 @@ |
1812 | def test_set_get_password(self): |
1813 | """Test the basic function of the keyring. |
1814 | """ |
1815 | - self.assertEqual(keyring.core.set_password("test", "user", "passtest"), |
1816 | - 0) |
1817 | + keyring.core.set_password("test", "user", "passtest") |
1818 | self.assertEqual(keyring.core.get_password("test", "user"), "passtest") |
1819 | - |
1820 | + |
1821 | def test_set_keyring_in_runtime(self): |
1822 | """Test the function of set keyring in runtime. |
1823 | """ |
1824 | keyring.core.set_keyring(TestKeyring()) |
1825 | |
1826 | - self.assertEqual(keyring.core.set_password("test", "user", "password"), |
1827 | - 0) |
1828 | + keyring.core.set_password("test", "user", "password") |
1829 | self.assertEqual(keyring.core.get_password("test", "user"), |
1830 | PASSWORD_TEXT) |
1831 | |
1832 | @@ -56,23 +56,54 @@ |
1833 | # create the config file |
1834 | config_file = open(KEYRINGRC,'w') |
1835 | config_file.writelines(["[backend]\n", |
1836 | - # the path for the user created keyring |
1837 | - "keyring-path= %s\n" % str(os.path.abspath(__file__))[:-16], |
1838 | - # the name of the keyring class |
1839 | - "default-keyring=test_core.TestKeyring2\n" ]) |
1840 | + # the path for the user created keyring |
1841 | + "keyring-path= %s\n" % os.path.dirname(os.path.abspath(__file__)), |
1842 | + # the name of the keyring class |
1843 | + "default-keyring=test_core.TestKeyring2\n" ]) |
1844 | config_file.close() |
1845 | |
1846 | # init the keyring lib, the lib will automaticlly load the |
1847 | # config file and load the user defined module |
1848 | keyring.core.init_backend() |
1849 | |
1850 | - self.assertEqual(keyring.core.set_password("test", "user", "password"), |
1851 | - 0) |
1852 | + keyring.core.set_password("test", "user", "password") |
1853 | self.assertEqual(keyring.core.get_password("test", "user"), |
1854 | - PASSWORD_TEXT_2) |
1855 | + PASSWORD_TEXT_2) |
1856 | |
1857 | os.remove(KEYRINGRC) |
1858 | |
1859 | + def test_load_config(self): |
1860 | + tempdir = tempfile.mkdtemp() |
1861 | + old_location = os.getcwd() |
1862 | + os.chdir(tempdir) |
1863 | + personal_cfg = os.path.join(os.path.expanduser("~"), "keyringrc.cfg") |
1864 | + if os.path.exists(personal_cfg): |
1865 | + os.rename(personal_cfg, personal_cfg+'.old') |
1866 | + personal_renamed = True |
1867 | + else: |
1868 | + personal_renamed = False |
1869 | + |
1870 | + # loading with an empty environment |
1871 | + keyring.core.load_config() |
1872 | + |
1873 | + # loading with a file that doesn't have a backend section |
1874 | + cfg = os.path.join(tempdir, "keyringrc.cfg") |
1875 | + f = open(cfg, 'w') |
1876 | + f.write('[keyring]') |
1877 | + f.close() |
1878 | + keyring.core.load_config() |
1879 | + |
1880 | + # loading with a file that doesn't have a default-keyring value |
1881 | + cfg = os.path.join(tempdir, "keyringrc.cfg") |
1882 | + f = open(cfg, 'w') |
1883 | + f.write('[backend]') |
1884 | + f.close() |
1885 | + keyring.core.load_config() |
1886 | + |
1887 | + os.chdir(old_location) |
1888 | + shutil.rmtree(tempdir) |
1889 | + if personal_renamed: |
1890 | + os.rename(personal_cfg+'.old', personal_cfg) |
1891 | |
1892 | def test_suite(): |
1893 | suite = unittest.TestSuite() |
1894 | |
1895 | === added file 'keyring/tests/test_util.py' |
1896 | --- keyring/tests/test_util.py 1970-01-01 00:00:00 +0000 |
1897 | +++ keyring/tests/test_util.py 2011-02-08 19:21:29 +0000 |
1898 | @@ -0,0 +1,37 @@ |
1899 | +# -*- coding: utf-8 -*- |
1900 | + |
1901 | +""" |
1902 | +Test for simple escape/unescape routine |
1903 | +""" |
1904 | + |
1905 | + |
1906 | +import unittest |
1907 | +import os |
1908 | +import sys |
1909 | +import tempfile |
1910 | +import shutil |
1911 | + |
1912 | +from keyring.util import escape |
1913 | + |
1914 | +class EscapeTestCase(unittest.TestCase): |
1915 | + |
1916 | + def check_escape_unescape(self, initial): |
1917 | + escaped = escape.escape(initial) |
1918 | + self.assertTrue(all( c in (escape.LEGAL_CHARS + escape.ESCAPE_CHAR) |
1919 | + for c in escaped)) |
1920 | + unescaped = escape.unescape(escaped) |
1921 | + self.assertEqual(initial, unescaped) |
1922 | + |
1923 | + def test_escape_unescape(self): |
1924 | + self.check_escape_unescape("aaaa") |
1925 | + self.check_escape_unescape("aaaa bbbb cccc") |
1926 | + self.check_escape_unescape(u"Zażółć gęślą jaźń".encode("utf-8")) |
1927 | + self.check_escape_unescape("(((P{{{{'''---; ;; '\"|%^") |
1928 | + |
1929 | +def test_suite(): |
1930 | + suite = unittest.TestSuite() |
1931 | + suite.addTest(unittest.makeSuite(EscapeTestCase)) |
1932 | + return suite |
1933 | + |
1934 | +if __name__ == "__main__": |
1935 | + unittest.main(defaultTest="test_suite") |
1936 | |
1937 | === added directory 'keyring/util' |
1938 | === added file 'keyring/util/__init__.py' |
1939 | === added file 'keyring/util/escape.py' |
1940 | --- keyring/util/escape.py 1970-01-01 00:00:00 +0000 |
1941 | +++ keyring/util/escape.py 2011-02-08 19:21:29 +0000 |
1942 | @@ -0,0 +1,25 @@ |
1943 | +""" |
1944 | +escape/unescape routines available for backends which need |
1945 | +alphanumeric usernames, services, or other values |
1946 | +""" |
1947 | + |
1948 | +import string, re |
1949 | + |
1950 | +LEGAL_CHARS = string.letters + string.digits |
1951 | +ESCAPE_CHAR = "_" |
1952 | + |
1953 | +def escape(value): |
1954 | + """Escapes given value so the result consists of alphanumeric chars and underscore |
1955 | + only, and alphanumeric chars are preserved""" |
1956 | + def escape_char(c, legal = LEGAL_CHARS): |
1957 | + # Single char escape. Either normal char, or _<hexcode> |
1958 | + if c in legal: |
1959 | + return c |
1960 | + else: |
1961 | + return "%s%X" % (ESCAPE_CHAR, ord(c)) |
1962 | + return "".join( escape_char(c) for c in value ) |
1963 | + |
1964 | +def unescape(value): |
1965 | + """Reverts escape""" |
1966 | + re_esc = re.compile("_([0-9A-F]{2})") |
1967 | + return re_esc.sub(lambda i: chr(int(i.group(1),16)), value) |
1968 | |
1969 | === modified file 'setup.py' |
1970 | --- setup.py 2009-09-24 23:24:02 +0000 |
1971 | +++ setup.py 2011-02-08 19:21:29 +0000 |
1972 | @@ -12,16 +12,17 @@ |
1973 | from extensions import get_extensions |
1974 | |
1975 | setup(name = 'keyring', |
1976 | - version = "0.2", |
1977 | + version = "0.5.1", |
1978 | description = "Store and access your passwords safely.", |
1979 | url = "http://home.python-keyring.org/", |
1980 | keywords = "keyring Keychain GnomeKeyring Kwallet password storage", |
1981 | maintainer = "Kang Zhang", |
1982 | maintainer_email = "jobo.zh@gmail.com", |
1983 | license="PSF", |
1984 | - long_description = open('README.txt').read(), |
1985 | + long_description = open('README.txt').read() + open('CHANGES.txt').read(), |
1986 | platforms = ["Many"], |
1987 | - packages = ['keyring'], |
1988 | + packages = ['keyring', 'keyring.tests', 'keyring.util', |
1989 | + 'keyring.backends'], |
1990 | ext_modules = get_extensions() |
1991 | ) |
1992 |
I guess the tests don't need to be installed.