summaryrefslogtreecommitdiff
path: root/src/leap/gui/firstrun/providerselect.py
diff options
context:
space:
mode:
authorkali <kali@leap.se>2012-11-28 01:11:05 +0900
committerkali <kali@leap.se>2012-11-28 01:11:05 +0900
commit16f19a225a922dd77f3f6c75c94194ebd229fc67 (patch)
treed77ba10cdad970b5025e75daa2b3be24e35ce0c7 /src/leap/gui/firstrun/providerselect.py
parent862014f68fce37318f77309a8f8f9782dabc60d2 (diff)
parent3ea766452e3c4708c724509d03001c0a0314fcf6 (diff)
Merge branch 'feature/wizard-usability' into develop
Diffstat (limited to 'src/leap/gui/firstrun/providerselect.py')
-rw-r--r--src/leap/gui/firstrun/providerselect.py334
1 files changed, 304 insertions, 30 deletions
diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py
index 8d1aa869..3ffc6ff6 100644
--- a/src/leap/gui/firstrun/providerselect.py
+++ b/src/leap/gui/firstrun/providerselect.py
@@ -3,35 +3,69 @@ Select Provider Page, used in First Run Wizard
"""
import logging
+import requests
+
from PyQt4 import QtCore
from PyQt4 import QtGui
-#from leap.base import exceptions as baseexceptions
+from leap.base import exceptions as baseexceptions
#from leap.crypto import certs
-#from leap.eip import exceptions as eipexceptions
+from leap.eip import exceptions as eipexceptions
+from leap.gui.progress import InlineValidationPage
+from leap.gui import styles
+from leap.util.web import get_https_domain_and_port
from leap.gui.constants import APP_LOGO
-from leap.gui.styles import ErrorLabelStyleSheet
logger = logging.getLogger(__name__)
-class SelectProviderPage(QtGui.QWizardPage):
+def delay(obj, method_str):
+ # XXX check newer version in progress.py...
+ """
+ this is a hack to get responsiveness in the ui
+ """
+ QtCore.QTimer().singleShot(
+ 10,
+ lambda: QtCore.QMetaObject.invokeMethod(
+ obj, method_str))
+
+
+class SelectProviderPage(InlineValidationPage):
+
+ #disableCheckButton = QtCore.pyqtSignal()
+ launchChecks = QtCore.pyqtSignal()
+
def __init__(self, parent=None, providers=None):
super(SelectProviderPage, self).__init__(parent)
+ self.current_page = 'providerselection'
- self.setTitle("Enter Provider")
- self.setSubTitle(
+ self.setTitle(self.tr("Enter Provider"))
+ self.setSubTitle(self.tr(
"Please enter the domain of the provider you want "
- "to use for your connection."
+ "to use for your connection.")
)
self.setPixmap(
QtGui.QWizard.LogoPixmap,
QtGui.QPixmap(APP_LOGO))
self.did_cert_check = False
- self.current_page = 'providerselection'
+ self.is_done = False
+
+ self.setupSteps()
+ self.setupUI()
+
+ self.launchChecks.connect(
+ self.launch_checks)
+
+ self.providerNameEdit.editingFinished.connect(
+ lambda: self.providerCheckButton.setFocus(True))
+
+ def setupUI(self):
+ """
+ initializes the UI
+ """
providerNameLabel = QtGui.QLabel("h&ttps://")
# note that we expect the bare domain name
# we will add the scheme later
@@ -59,8 +93,10 @@ class SelectProviderPage(QtGui.QWizardPage):
#self.registerField('provider_name_index', providerNameSelect)
validationMsg = QtGui.QLabel("")
- validationMsg.setStyleSheet(ErrorLabelStyleSheet)
+ validationMsg.setStyleSheet(styles.ErrorLabelStyleSheet)
self.validationMsg = validationMsg
+ providerCheckButton = QtGui.QPushButton(self.tr("chec&k!"))
+ self.providerCheckButton = providerCheckButton
# cert info
@@ -69,7 +105,8 @@ class SelectProviderPage(QtGui.QWizardPage):
# tricky, since the first time came
# from the exception message.
# should get string from exception too!
- self.bad_cert_status = "Server certificate could not be verified."
+ self.bad_cert_status = self.tr(
+ "Server certificate could not be verified.")
self.certInfo = QtGui.QLabel("")
self.certInfo.setWordWrap(True)
@@ -81,25 +118,226 @@ class SelectProviderPage(QtGui.QWizardPage):
self.onTrustCheckChanged)
self.providerNameEdit.textChanged.connect(
self.onProviderChanged)
+ self.providerCheckButton.clicked.connect(
+ self.onCheckButtonClicked)
layout = QtGui.QGridLayout()
layout.addWidget(validationMsg, 0, 2)
layout.addWidget(providerNameLabel, 1, 1)
layout.addWidget(providerNameEdit, 1, 2)
+ layout.addWidget(providerCheckButton, 1, 3)
+
+ # add certinfo group
+ # XXX not shown now. should move to validation box.
+ #layout.addWidget(certinfoGroup, 4, 1, 4, 2)
+ #self.certinfoGroup = certinfoGroup
+ #self.certinfoGroup.hide()
+
+ # add validation frame
+ self.setupValidationFrame()
+ layout.addWidget(self.valFrame, 4, 2, 4, 2)
+ self.valFrame.hide()
- # XXX get a groupbox or something....
- certinfoGroup = QtGui.QGroupBox("Certificate validation")
+ self.setLayout(layout)
+
+ # certinfo
+
+ def setupCertInfoGroup(self):
+ # XXX not used now.
+ certinfoGroup = QtGui.QGroupBox(
+ self.tr("Certificate validation"))
certinfoLayout = QtGui.QVBoxLayout()
certinfoLayout.addWidget(self.certInfo)
certinfoLayout.addWidget(self.certWarning)
certinfoLayout.addWidget(self.trustProviderCertCheckBox)
certinfoGroup.setLayout(certinfoLayout)
+ self.certinfoGroup = self.certinfoGroup
- layout.addWidget(certinfoGroup, 4, 1, 4, 2)
- self.certinfoGroup = certinfoGroup
- self.certinfoGroup.hide()
+ # progress frame
- self.setLayout(layout)
+ def setupValidationFrame(self):
+ qframe = QtGui.QFrame
+ valFrame = qframe()
+ valFrame.setFrameStyle(qframe.NoFrame)
+ valframeLayout = QtGui.QVBoxLayout()
+ zeros = (0, 0, 0, 0)
+ valframeLayout.setContentsMargins(*zeros)
+
+ valframeLayout.addWidget(self.stepsTableWidget)
+ valFrame.setLayout(valframeLayout)
+ self.valFrame = valFrame
+
+ @QtCore.pyqtSlot()
+ def onDisableCheckButton(self):
+ #print 'CHECK BUTTON DISABLED!!!'
+ self.providerCheckButton.setDisabled(True)
+
+ @QtCore.pyqtSlot()
+ def launch_checks(self):
+ self.do_checks()
+
+ def onCheckButtonClicked(self):
+ QtCore.QMetaObject.invokeMethod(
+ self, "onDisableCheckButton")
+
+ QtCore.QMetaObject.invokeMethod(
+ self, "showStepsFrame")
+
+ # is this still needed?
+ # XXX can I doo delay(self, "do_checks") ?
+ delay(self, "launch_checks")
+
+ def _do_checks(self):
+ """
+ generator that yields actual checks
+ that are executed in a separate thread
+ """
+
+ wizard = self.wizard()
+ full_domain = self.providerNameEdit.text()
+
+ # we check if we have a port in the domain string.
+ domain, port = get_https_domain_and_port(full_domain)
+ _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain)
+
+ netchecker = wizard.netchecker()
+
+ providercertchecker = wizard.providercertchecker()
+ eipconfigchecker = wizard.eipconfigchecker(domain=_domain)
+
+ yield(("head_sentinel", 0), lambda: None)
+
+ ########################
+ # 1) try name resolution
+ ########################
+
+ def namecheck():
+ """
+ in which we check if
+ we are able to name resolve
+ this domain
+ """
+ try:
+ netchecker.check_name_resolution(
+ domain)
+
+ except baseexceptions.LeapException as exc:
+ logger.error(exc.message)
+ return self.fail(exc.usermessage)
+
+ except Exception as exc:
+ return self.fail(exc.message)
+
+ else:
+ return True
+
+ logger.debug('checking name resolution')
+ yield((self.tr("checking domain name"), 20), namecheck)
+
+ #########################
+ # 2) try https connection
+ #########################
+
+ def httpscheck():
+ """
+ in which we check
+ if the provider
+ is offering service over
+ https
+ """
+ try:
+ providercertchecker.is_https_working(
+ "https://%s" % _domain,
+ verify=True)
+
+ except eipexceptions.HttpsBadCertError as exc:
+ logger.debug('exception')
+ return self.fail(exc.usermessage)
+ # XXX skipping for now...
+ ##############################################
+ # We had this validation logic
+ # in the provider selection page before
+ ##############################################
+ #if self.trustProviderCertCheckBox.isChecked():
+ #pass
+ #else:
+ #fingerprint = certs.get_cert_fingerprint(
+ #domain=domain, sep=" ")
+
+ # it's ok if we've trusted this fgprt before
+ #trustedcrts = wizard.trusted_certs
+ #if trustedcrts and \
+ # fingerprint.replace(' ', '') in trustedcrts:
+ #pass
+ #else:
+ # let your user face panick :P
+ #self.add_cert_info(fingerprint)
+ #self.did_cert_check = True
+ #self.completeChanged.emit()
+ #return False
+
+ except baseexceptions.LeapException as exc:
+ return self.fail(exc.usermessage)
+
+ except Exception as exc:
+ return self.fail(exc.message)
+
+ else:
+ return True
+
+ logger.debug('checking https connection')
+ yield((self.tr("checking https connection"), 40), httpscheck)
+
+ ##################################
+ # 3) try download provider info...
+ ##################################
+
+ def fetchinfo():
+ try:
+ # XXX we already set _domain in the initialization
+ # so it should not be needed here.
+ eipconfigchecker.fetch_definition(domain=_domain)
+ wizard.set_providerconfig(
+ eipconfigchecker.defaultprovider.config)
+ except requests.exceptions.SSLError:
+ # XXX we should have catched this before.
+ # but cert checking is broken.
+ return self.fail(self.tr(
+ "Could not get info from provider."))
+ except requests.exceptions.ConnectionError:
+ return self.fail(self.tr(
+ "Could not download provider info "
+ "(refused conn.)."))
+
+ except Exception as exc:
+ return self.fail(
+ self.tr(exc.message))
+ else:
+ return True
+
+ yield((self.tr("fetching provider info"), 80), fetchinfo)
+
+ # done!
+
+ self.is_done = True
+ yield(("end_sentinel", 100), lambda: None)
+
+ def on_checks_validation_ready(self):
+ """
+ called after _do_checks has finished.
+ """
+ self.domain_checked = True
+ self.completeChanged.emit()
+ # let's set focus...
+ if self.is_done:
+ self.wizard().clean_validation_error(self.current_page)
+ nextbutton = self.wizard().button(QtGui.QWizard.NextButton)
+ nextbutton.setFocus()
+ else:
+ self.providerNameEdit.setFocus()
+
+ # cert trust verification
+ # (disabled for now)
def is_insecure_cert_trusted(self):
return self.trustProviderCertCheckBox.isChecked()
@@ -117,38 +355,50 @@ class SelectProviderPage(QtGui.QWizardPage):
# trigger signal to redraw next button
self.completeChanged.emit()
+ def add_cert_info(self, certinfo):
+ self.certWarning.setText(
+ "Do you want to <b>trust this provider certificate?</b>")
+ self.certInfo.setText(
+ 'SHA-256 fingerprint: <i>%s</i><br>' % certinfo)
+ self.certInfo.setWordWrap(True)
+ self.certinfoGroup.show()
+
def onProviderChanged(self, text):
+ self.is_done = False
+ provider = self.providerNameEdit.text()
+ if provider:
+ self.providerCheckButton.setDisabled(False)
+ else:
+ self.providerCheckButton.setDisabled(True)
self.completeChanged.emit()
def reset_validation_status(self):
"""
empty the validation msg
+ and clean the inline validation widget.
"""
self.validationMsg.setText('')
-
- #def set_validation_status(selF, STATUS):
- #self.validationMsg.setText(status)
-
- def add_cert_info(self, certinfo):
- self.certWarning.setText(
- "Do you want to <b>trust this provider certificate?</b>")
- self.certInfo.setText(
- 'SHA-256 fingerprint: <i>%s</i><br>' % certinfo)
- self.certInfo.setWordWrap(True)
- self.certinfoGroup.show()
+ self.steps.removeAllSteps()
+ self.clearTable()
+ self.domain_checked = False
# pagewizard methods
def isComplete(self):
provider = self.providerNameEdit.text()
+ if not self.is_done:
+ return False
+
if not provider:
return False
else:
if self.is_insecure_cert_trusted():
return True
if not self.did_cert_check:
- return True
+ if self.is_done:
+ # XXX sure?
+ return True
return False
def populateErrors(self):
@@ -163,17 +413,33 @@ class SelectProviderPage(QtGui.QWizardPage):
bad_str = getattr(self, 'bad_string', None)
cur_str = self.providerNameEdit.text()
showerr = self.validationMsg.setText
+ markred = lambda: self.providerNameEdit.setStyleSheet(
+ styles.ErrorLineEdit)
+ umarkrd = lambda: self.providerNameEdit.setStyleSheet(
+ styles.RegularLineEdit)
if bad_str is None:
# first time we fall here.
# save the current bad_string value
self.bad_string = cur_str
showerr(errors)
+ markred()
else:
# not the first time
+ # XXX hey, this is getting convoluted.
+ # roll out this.
+ # but be careful about all the possibilities
+ # with going back and forth once you
+ # enter a domain.
if cur_str == bad_str:
showerr(errors)
+ markred()
else:
- showerr('')
+ if not getattr(self, 'domain_checked', None):
+ showerr('')
+ umarkrd()
+ else:
+ self.bad_string = cur_str
+ showerr(errors)
def cleanup_errormsg(self):
"""
@@ -181,6 +447,7 @@ class SelectProviderPage(QtGui.QWizardPage):
should be called before leaving the page
"""
self.bad_string = None
+ self.domain_checked = False
def paintEvent(self, event):
"""
@@ -195,7 +462,14 @@ class SelectProviderPage(QtGui.QWizardPage):
def initializePage(self):
self.validationMsg.setText('')
- self.certinfoGroup.hide()
+ if hasattr(self, 'certinfoGroup'):
+ # XXX remove ?
+ self.certinfoGroup.hide()
+ self.is_done = False
+ self.providerCheckButton.setDisabled(True)
+ self.valFrame.hide()
+ self.steps.removeAllSteps()
+ self.clearTable()
def validatePage(self):
# some cleanup before we leave the page