comparison easyhg.py @ 673:e4d18e8ef430

Update for newer APIs
author Chris Cannam
date Wed, 05 Dec 2018 13:20:51 +0000
parents e34de484415c
children c59c17665162
comparison
equal deleted inserted replaced
672:88fa1544b407 673:e4d18e8ef430
33 # the Python version suffixed 33 # the Python version suffixed
34 version_suffix = 'Py%d.%d' % (sys.version_info[0], sys.version_info[1]) 34 version_suffix = 'Py%d.%d' % (sys.version_info[0], sys.version_info[1])
35 sys.path.append(easyhg_import_path + "/" + version_suffix) 35 sys.path.append(easyhg_import_path + "/" + version_suffix)
36 sys.path.append(easyhg_import_path) 36 sys.path.append(easyhg_import_path)
37 37
38 # Try to load the PyQt4 module that we need. If this fails, we should 38 # Try to load the PyQt5 module that we need. If this fails, we should
39 # bail out later (in uisetup), because if we bail out now, Mercurial 39 # bail out later (in uisetup), because if we bail out now, Mercurial
40 # will just continue without us and report success. The invoking 40 # will just continue without us and report success. The invoking
41 # application needs to be able to discover whether the module load 41 # application needs to be able to discover whether the module load
42 # succeeded or not, so we need to ensure that Mercurial itself returns 42 # succeeded or not, so we need to ensure that Mercurial itself returns
43 # failure if it didn't. 43 # failure if it didn't.
44 # 44 #
45 easyhg_pyqt_ok = True 45 easyhg_pyqt_ok = True
46 try: 46 try:
47 from PyQt4 import QtCore, QtGui 47 from PyQt5 import QtCore, QtGui, QtWidgets
48 except ImportError: 48 except ImportError:
49 easyhg_pyqt_ok = False 49 easyhg_pyqt_ok = False
50 easyhg_qtapp = None 50 easyhg_qtapp = None
51 51
52 # These imports are optional, we just can't use the authfile (i.e. 52 # These imports are optional, we just can't use the authfile (i.e.
80 80
81 self.auth_key = self.ui.config('easyhg', 'authkey') 81 self.auth_key = self.ui.config('easyhg', 'authkey')
82 self.auth_file = self.ui.config('easyhg', 'authfile') 82 self.auth_file = self.ui.config('easyhg', 'authfile')
83 83
84 self.use_auth_file = (easyhg_authfile_imports_ok and 84 self.use_auth_file = (easyhg_authfile_imports_ok and
85 self.auth_key and self.auth_file) 85 self.auth_key and self.auth_file)
86 86
87 self.auth_config = None 87 self.auth_config = None
88 self.auth_cipher = None 88 self.auth_cipher = None
89 self.remember = False 89 self.remember = False
90 90
91 if self.use_auth_file: 91 if self.use_auth_file:
92 self.auth_cipher = AES.new(self.auth_key, AES.MODE_CBC,
93 os.urandom(16))
94 self.auth_file = os.path.expanduser(self.auth_file) 92 self.auth_file = os.path.expanduser(self.auth_file)
95 self.load_auth_data() 93 self.load_auth_data()
96 94
97 def save(self): 95 def save(self):
98 if self.use_auth_file: 96 if self.use_auth_file:
99 self.save_auth_data() 97 self.save_auth_data()
100 98
101 def encrypt(self, text): 99 def encrypt(self, utext):
102 iv = os.urandom(12) 100 iv = os.urandom(12)
101 text = utext.encode('utf-8')
103 text = '%s.%d.%s.easyhg' % (base64.b64encode(iv), len(text), text) 102 text = '%s.%d.%s.easyhg' % (base64.b64encode(iv), len(text), text)
104 text += (16 - (len(text) % 16)) * ' ' 103 text += (16 - (len(text) % 16)) * ' '
105 ctext = base64.b64encode(self.auth_cipher.encrypt(text)) 104 cipher = AES.new(self.auth_key, AES.MODE_CBC, os.urandom(16))
105 ctext = base64.b64encode(cipher.encrypt(text))
106 return ctext 106 return ctext
107 107
108 def decrypt(self, ctext): 108 def decrypt(self, ctext):
109 try: 109 try:
110 text = self.auth_cipher.decrypt(base64.b64decode(ctext)) 110 cipher = AES.new(self.auth_key, AES.MODE_CBC, os.urandom(16))
111 text = cipher.decrypt(base64.b64decode(ctext))
111 (iv, d, text) = text.partition('.') 112 (iv, d, text) = text.partition('.')
112 (tlen, d, text) = text.partition('.') 113 (tlen, d, text) = text.partition('.')
113 return text[0:int(tlen)] 114 return text[0:int(tlen)].decode('utf-8')
114 except: 115 except:
115 self.ui.write("failed to decrypt/convert cached data!") 116 self.ui.write("failed to decrypt/convert cached data!")
116 return '' 117 return ''
117 118
118 def argless_url(self): 119 def argless_url(self):
241 242
242 if self.auth_store.user and self.auth_store.passwd and self.auth_store.remember: 243 if self.auth_store.user and self.auth_store.passwd and self.auth_store.remember:
243 if not repeat: 244 if not repeat:
244 return (self.auth_store.user, self.auth_store.passwd) 245 return (self.auth_store.user, self.auth_store.passwd)
245 246
246 dialog = QtGui.QDialog() 247 dialog = QtWidgets.QDialog()
247 layout = QtGui.QGridLayout() 248 layout = QtWidgets.QGridLayout()
248 dialog.setLayout(layout) 249 dialog.setLayout(layout)
249 250
250 heading = _('Login required') 251 heading = _('Login required')
251 if repeat: 252 if repeat:
252 heading = _('Login failed: please try again') 253 heading = _('Login failed: please try again')
253 label_text = _(('<h3>%s</h3><p>Please provide your login details for the repository at<br><code>%s</code>:') % (heading, self.auth_store.argless_url())) 254 label_text = _(('<h3>%s</h3><p>Please provide your login details for the repository at<br><code>%s</code>:') % (heading, self.auth_store.argless_url()))
254 layout.addWidget(QtGui.QLabel(label_text), 0, 0, 1, 2) 255 layout.addWidget(QtWidgets.QLabel(label_text), 0, 0, 1, 2)
255 256
256 user_field = QtGui.QLineEdit() 257 user_field = QtWidgets.QLineEdit()
257 if self.auth_store.user: user_field.setText(self.auth_store.user) 258 if self.auth_store.user: user_field.setText(self.auth_store.user)
258 layout.addWidget(QtGui.QLabel(_('User:')), 1, 0) 259 layout.addWidget(QtWidgets.QLabel(_('User:')), 1, 0)
259 layout.addWidget(user_field, 1, 1) 260 layout.addWidget(user_field, 1, 1)
260 261
261 passwd_field = QtGui.QLineEdit() 262 passwd_field = QtWidgets.QLineEdit()
262 passwd_field.setEchoMode(QtGui.QLineEdit.Password) 263 passwd_field.setEchoMode(QtWidgets.QLineEdit.Password)
263 if self.auth_store.passwd: passwd_field.setText(self.auth_store.passwd) 264 if self.auth_store.passwd: passwd_field.setText(self.auth_store.passwd)
264 layout.addWidget(QtGui.QLabel(_('Password:')), 2, 0) 265 layout.addWidget(QtWidgets.QLabel(_('Password:')), 2, 0)
265 layout.addWidget(passwd_field, 2, 1) 266 layout.addWidget(passwd_field, 2, 1)
266 user_field.textChanged.connect(passwd_field.clear) 267 user_field.textChanged.connect(passwd_field.clear)
267 268
268 remember_field = None 269 remember_field = None
269 if self.auth_store.use_auth_file: 270 if self.auth_store.use_auth_file:
270 remember_field = QtGui.QCheckBox() 271 remember_field = QtWidgets.QCheckBox()
271 remember_field.setChecked(self.auth_store.remember) 272 remember_field.setChecked(self.auth_store.remember)
272 remember_field.setText(_('Remember these details while EasyMercurial is running')) 273 remember_field.setText(_('Remember these details while EasyMercurial is running'))
273 layout.addWidget(remember_field, 3, 1) 274 layout.addWidget(remember_field, 3, 1)
274 warning_field = QtGui.QLabel() 275 warning_field = QtWidgets.QLabel()
275 warning_field.setText(_('<qt><i><small>Do not use this option if anyone else has access to your computer!</small></i><br></qt>')) 276 warning_field.setText(_('<qt><i><small>Do not use this option if anyone else has access to your computer!</small></i><br></qt>'))
276 warning_field.hide() 277 warning_field.hide()
277 remember_field.clicked.connect(warning_field.show) 278 remember_field.clicked.connect(warning_field.show)
278 layout.addWidget(warning_field, 4, 1, QtCore.Qt.AlignRight) 279 layout.addWidget(warning_field, 4, 1, QtCore.Qt.AlignRight)
279 280
280 bb = QtGui.QDialogButtonBox() 281 bb = QtWidgets.QDialogButtonBox()
281 ok = bb.addButton(bb.Ok) 282 ok = bb.addButton(bb.Ok)
282 cancel = bb.addButton(bb.Cancel) 283 cancel = bb.addButton(bb.Cancel)
283 cancel.setDefault(False) 284 cancel.setDefault(False)
284 cancel.setAutoDefault(False) 285 cancel.setAutoDefault(False)
285 ok.setDefault(True) 286 ok.setDefault(True)
298 ok.setFocus(True) 299 ok.setFocus(True)
299 300
300 dialog.raise_() 301 dialog.raise_()
301 ok = dialog.exec_() 302 ok = dialog.exec_()
302 if not ok: 303 if not ok:
303 raise util.Abort(_('password entry cancelled')) 304 raise error.Abort(_('password entry cancelled'))
304 305
305 self.auth_store.user = user_field.text() 306 self.auth_store.user = user_field.text()
306 self.auth_store.passwd = passwd_field.text() 307 self.auth_store.passwd = passwd_field.text()
307 308
308 if remember_field: 309 if remember_field:
313 return (self.auth_store.user, self.auth_store.passwd) 314 return (self.auth_store.user, self.auth_store.passwd)
314 315
315 316
316 def uisetup(ui): 317 def uisetup(ui):
317 if not easyhg_pyqt_ok: 318 if not easyhg_pyqt_ok:
318 raise util.Abort(_('Failed to load PyQt4 module required by easyhg.py')) 319 raise error.Abort(_('Failed to load PyQt5 module required by easyhg.py'))
319 global easyhg_qtapp 320 global easyhg_qtapp
320 easyhg_qtapp = QtGui.QApplication([]) 321 easyhg_qtapp = QtWidgets.QApplication([])
321 322
322 def monkeypatch_method(cls): 323 def monkeypatch_method(cls):
323 def decorator(func): 324 def decorator(func):
324 setattr(cls, func.__name__, func) 325 setattr(cls, func.__name__, func)
325 return func 326 return func
336 if not self.ui.interactive(): 337 if not self.ui.interactive():
337 return orig_find(self, realm, authuri) 338 return orig_find(self, realm, authuri)
338 if not easyhg_pyqt_ok: 339 if not easyhg_pyqt_ok:
339 return orig_find(self, realm, authuri) 340 return orig_find(self, realm, authuri)
340 341
341 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password( 342 mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
342 self, realm, authuri) 343 authinfo = mgr.find_user_password(realm, authuri)
343 user, passwd = authinfo 344 user, passwd = authinfo
344 345
345 repeat = False 346 repeat = False
346 347
347 if (realm, authuri) == self.__easyhg_last: 348 if (realm, authuri) == self.__easyhg_last: