##// END OF EJS Templates
Working in-process cache
Marcin Kasperski -
r2:f4014c71 default
parent child Browse files
Show More
@@ -1,74 +1,105 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 """
3 """
4 Storing HTTP authentication passwords in keyring database.
4 Storing HTTP authentication passwords in keyring database.
5
5
6 Installation method(s):
6 Installation method(s):
7
7
8 1) in ~/.hgrc (or /etc/hgext/...)
8 1) in ~/.hgrc (or /etc/hgext/...)
9
9
10 [extensions]
10 [extensions]
11 ...
11 ...
12 hgext.mercurial_keyring = /path/to/mercurial_keyring.py
12 hgext.mercurial_keyring = /path/to/mercurial_keyring.py
13
13
14
14
15 2) Drop this file to hgext directory and in ~/.hgrc
15 2) Drop this file to hgext directory and in ~/.hgrc
16
16
17 [extensions]
17 [extensions]
18 hgext.mercurial_keyring =
18 hgext.mercurial_keyring =
19
19
20 """
20 """
21
21
22 from mercurial import hg, repo, util
22 from mercurial import hg, repo, util
23 from mercurial.i18n import _
23 from mercurial.i18n import _
24 try:
24 try:
25 from mercurial.url import passwordmgr
25 from mercurial.url import passwordmgr
26 except:
26 except:
27 from mercurial.httprepo import passwordmgr
27 from mercurial.httprepo import passwordmgr
28
28
29 import keyring
29 import keyring
30 import getpass
30 import getpass
31 from urlparse import urlparse
31 from urlparse import urlparse
32
32
33 KEYRING_SERVICE = "Mercurial"
33 KEYRING_SERVICE = "Mercurial"
34
34
35 ############################################################
36
37 def monkeypatch_class(name, bases, namespace):
38 """http://mail.python.org/pipermail/python-dev/2008-January/076194.html"""
39 assert len(bases) == 1, "Exactly one base class required"
40 base = bases[0]
41 for name, value in namespace.iteritems():
42 if name != "__metaclass__":
43 setattr(base, name, value)
44 return base
45
35 def monkeypatch_method(cls):
46 def monkeypatch_method(cls):
36 def decorator(func):
47 def decorator(func):
37 setattr(cls, func.__name__, func)
48 setattr(cls, func.__name__, func)
38 return func
49 return func
39 return decorator
50 return decorator
40
51
52 ############################################################
53
54 class PasswordStore(object):
55 """
56 Helper object handling password save&restore. Passwords
57 are saved both in local memory cache, and keyring, and are
58 restored from those.
59 """
60 def __init__(self):
61 self.cache = dict()
62 def save_password(self, url, username, password):
63 self.cache[url] = (username, password)
64 # TODO: keyring save
65 def get_password(self, url):
66 r = self.cache.get(url)
67 if r:
68 return r
69 # TODO: keyring restore
70 return None, None
71
72 password_store = PasswordStore()
73
74 ############################################################
75
41 @monkeypatch_method(passwordmgr)
76 @monkeypatch_method(passwordmgr)
42 def find_user_password(self, realm, authuri):
77 def find_user_password(self, realm, authuri):
43 """
78 """
44 keyring-based implementation of username/password query
79 keyring-based implementation of username/password query
45
80
46 Passwords are saved in gnome keyring, OSX/Chain or other platform
81 Passwords are saved in gnome keyring, OSX/Chain or other platform
47 specific storage and keyed by the repository url
82 specific storage and keyed by the repository url
48 """
83 """
49 # Calculate the true url. authuri happens to contain things like
84 # Calculate the true url. authuri happens to contain things like
50 # https://repo.machine.com/repos/apps/module?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between
85 # https://repo.machine.com/repos/apps/module?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between
51 parsed_url = urlparse(authuri)
86 parsed_url = urlparse(authuri)
52 base_url = "%s://%s%s" % (parsed_url.scheme, parsed_url.netloc, parsed_url.path)
87 base_url = "%s://%s%s" % (parsed_url.scheme, parsed_url.netloc, parsed_url.path)
53 print "find_user_password", realm, base_url
88 print "find_user_password", realm, base_url
54
89
55
90 user, pwd = password_store.get_password(base_url)
56 # TODO: odczyt danych z cache w procesie
91 if user and pwd:
57
92 return user, pwd
58 # TODO: odczyt danych już obecnych w keyring-u
59
93
60 if not self.ui.interactive():
94 if not self.ui.interactive():
61 raise util.Abort(_('mercurial_keyring: http authorization required'))
95 raise util.Abort(_('mercurial_keyring: http authorization required'))
62 self.ui.write(_("http authorization required\n"))
96 self.ui.write(_("http authorization required\n"))
63 self.ui.status(_("realm: %s, url: %s\n" % (realm, base_url)))
97 self.ui.status(_("realm: %s, url: %s\n" % (realm, base_url)))
64 username = self.ui.prompt(_("user:"), default = None)
98 user = self.ui.prompt(_("user:"), default = user)
65 password = self.ui.getpass(_("password for user %s:" % username))
99 pwd = self.ui.getpass(_("password: "))
66
67 # TODO: zapis w keyringu
68
100
69 # TODO: zapis w cache w procesie
101 password_store.save_password(base_url, user, pwd)
70
71
102
72 return username, password
103 return user, pwd
73 #return None, None
104 #return None, None
74
105
General Comments 0
You need to be logged in to leave comments. Login now