Show More
@@ -29,12 +29,26 b'' | |||||
29 | # |
|
29 | # | |
30 | # See README.txt for more details. |
|
30 | # See README.txt for more details. | |
31 |
|
31 | |||
32 |
''' |
|
32 | '''securely save HTTP and SMTP passwords to encrypted storage | |
33 | mercurial_keyring is a Mercurial extension used to securely save |
|
33 | ||
34 | HTTP and SMTP authentication passwords in password databases (Gnome |
|
34 | mercurial_keyring securely saves HTTP and SMTP passwords in password | |
35 |
Keyring, KDE KWallet, OSXKeyChain, |
|
35 | databases (Gnome Keyring, KDE KWallet, OSXKeyChain, Win32 crypto | |
36 | command line). This extension uses and wraps services of the keyring |
|
36 | services). | |
37 | library. |
|
37 | ||
|
38 | The process is automatic. Whenever bare Mercurial just prompts for | |||
|
39 | the password, Mercurial with mercurial_keyring enabled checks whether | |||
|
40 | saved password is available first. If so, it is used. If not, you | |||
|
41 | will be prompted for the password, but entered password will be | |||
|
42 | saved for the future use. | |||
|
43 | ||||
|
44 | In case saved password turns out to be invalid (HTTP or SMTP login | |||
|
45 | fails) it is dropped, and you are asked for current password. | |||
|
46 | ||||
|
47 | Actual password storage is implemented by Python keyring library, this | |||
|
48 | extension glues those services to Mercurial. Consult keyring | |||
|
49 | documentation for information how to configure actual password | |||
|
50 | backend (by default keyring guesses, usually correctly, for example | |||
|
51 | you get KDE Wallet under KDE, and Gnome Keyring under Gnome or Unity). | |||
38 | ''' |
|
52 | ''' | |
39 |
|
53 | |||
40 | from mercurial import util, sslutil |
|
54 | from mercurial import util, sslutil | |
@@ -411,27 +425,18 b' class HTTPPasswordHandler(object):' | |||||
411 | local_ui = _ui(ui) |
|
425 | local_ui = _ui(ui) | |
412 | if repo_root: |
|
426 | if repo_root: | |
413 | local_ui.readconfig(os.path.join(repo_root, ".hg", "hgrc")) |
|
427 | local_ui.readconfig(os.path.join(repo_root, ".hg", "hgrc")) | |
414 | try: |
|
428 | ||
415 | local_passwordmgr = passwordmgr(local_ui) |
|
429 | from mercurial.httpconnection import readauthforuri | |
416 | auth_token = local_passwordmgr.readauthtoken(base_url) |
|
430 | if readauthforuri.func_code.co_argcount == 3: | |
417 | except AttributeError: |
|
431 | # Since hg.0593e8f81c71 | |
418 | try: |
|
432 | res = readauthforuri(local_ui, base_url, user) | |
419 | # hg 1.8 |
|
433 | else: | |
420 | import mercurial.url |
|
434 | res = readauthforuri(local_ui, base_url) | |
421 | readauthforuri = mercurial.url.readauthforuri |
|
435 | if res: | |
422 | except (ImportError, AttributeError): |
|
436 | group, auth_token = res | |
423 | # hg 1.9 |
|
437 | else: | |
424 | import mercurial.httpconnection |
|
438 | auth_token = None | |
425 | readauthforuri = mercurial.httpconnection.readauthforuri |
|
439 | ||
426 | if readauthforuri.func_code.co_argcount == 3: |
|
|||
427 | # Since hg.0593e8f81c71 |
|
|||
428 | res = readauthforuri(local_ui, base_url, user) |
|
|||
429 | else: |
|
|||
430 | res = readauthforuri(local_ui, base_url) |
|
|||
431 | if res: |
|
|||
432 | group, auth_token = res |
|
|||
433 | else: |
|
|||
434 | auth_token = None |
|
|||
435 | if auth_token: |
|
440 | if auth_token: | |
436 | username = auth_token.get('username') |
|
441 | username = auth_token.get('username') | |
437 | password = auth_token.get('password') |
|
442 | password = auth_token.get('password') | |
@@ -496,6 +501,8 b' def find_user_password(self, realm, auth' | |||||
496 |
|
501 | |||
497 | @monkeypatch_method(urllib2.AbstractBasicAuthHandler, "http_error_auth_reqed") |
|
502 | @monkeypatch_method(urllib2.AbstractBasicAuthHandler, "http_error_auth_reqed") | |
498 | def basic_http_error_auth_reqed(self, authreq, host, req, headers): |
|
503 | def basic_http_error_auth_reqed(self, authreq, host, req, headers): | |
|
504 | """Preserves current HTTP request so it can be consulted | |||
|
505 | in find_user_password above""" | |||
499 | self.passwd._http_req = req |
|
506 | self.passwd._http_req = req | |
500 | try: |
|
507 | try: | |
501 | return basic_http_error_auth_reqed.orig(self, authreq, host, req, headers) |
|
508 | return basic_http_error_auth_reqed.orig(self, authreq, host, req, headers) | |
@@ -505,6 +512,8 b' def basic_http_error_auth_reqed(self, au' | |||||
505 |
|
512 | |||
506 | @monkeypatch_method(urllib2.AbstractDigestAuthHandler, "http_error_auth_reqed") |
|
513 | @monkeypatch_method(urllib2.AbstractDigestAuthHandler, "http_error_auth_reqed") | |
507 | def digest_http_error_auth_reqed(self, authreq, host, req, headers): |
|
514 | def digest_http_error_auth_reqed(self, authreq, host, req, headers): | |
|
515 | """Preserves current HTTP request so it can be consulted | |||
|
516 | in find_user_password above""" | |||
508 | self.passwd._http_req = req |
|
517 | self.passwd._http_req = req | |
509 | try: |
|
518 | try: | |
510 | return digest_http_error_auth_reqed.orig(self, authreq, host, req, headers) |
|
519 | return digest_http_error_auth_reqed.orig(self, authreq, host, req, headers) | |
@@ -643,3 +652,8 b' def _smtp(ui):' | |||||
643 | return keyring_supported_smtp(ui, username) |
|
652 | return keyring_supported_smtp(ui, username) | |
644 | else: |
|
653 | else: | |
645 | return _smtp.orig(ui) |
|
654 | return _smtp.orig(ui) | |
|
655 | ||||
|
656 | ||||
|
657 | ############################################################ | |||
|
658 | # Custom commands | |||
|
659 | ############################################################ |
General Comments 0
You need to be logged in to leave comments.
Login now