Example #1
0
    def execCommand(self, callable, *args, **keywds):
        try:
            result =  zanshin.util.blockUntil(callable, *args, **keywds)
            return (1, result)

        except Utility.CertificateVerificationError, err:
            assert err.args[1] == 'certificate verify failed'

            # Reason why verification failed is stored in err.args[0], see
            # codes at http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
            try:
                result = (2, None)
                # Send the message to destroy the progress dialog first. This needs
                # to be done in this order on Linux because otherwise killing
                # the progress dialog will also kill the SSL error dialog.
                # Weird, huh? Welcome to the world of wx...
                callMethodInUIThread(self.callback, result)
                if err.args[0] in ssl.unknown_issuer:
                    d = ssl.askTrustServerCertificate(err.host,
                                                      err.untrustedCertificates[0],
                                                      self.reconnect)
                else:
                    d = ssl.askIgnoreSSLError(err.host,
                                              err.untrustedCertificates[0],
                                              err.args[0],
                                              self.reconnect)

                waitForDeferred(d)

                return result
            except Exception, e:
                # There is a bug in the M2Crypto code which needs
                # to be fixed.
                #log.exception('This should not happen')
                return (0, (CANT_CONNECT, _(u"SSL error.")))
Example #2
0
def reset(view):
    """
    Reset master password. Will clear all passwords as well.
    """
    view.refresh()

    try:
        # clear all passwords
        from osaf.framework import password
        for item in password.Password.iterItems(view):
            waitForDeferred(item.clear())

        # Turn off pref
        prefs = schema.ns("osaf.framework.MasterPassword",
                          view).masterPasswordPrefs
        prefs.masterPassword = False

        # set new dummy password
        prefs = schema.ns("osaf.framework.password",
                          view).passwordPrefs
        password = ''.join([string.printable[ord(c) % len(string.printable)] \
                            for c in os.urandom(16)])                  
        waitForDeferred(prefs.dummyPassword.encryptPassword(password, masterPassword=''))
    except:
        try:
            log.exception('Failed to reset master password')
            view.cancel()
        finally:
            raise
    
    view.commit()
    
    # clear the master password itself
    clear()
    def execCommand(self, callable, *args, **keywds):
        try:
            result = zanshin.util.blockUntil(callable, *args, **keywds)
            return (1, result)

        except Utility.CertificateVerificationError, err:
            assert err.args[1] == 'certificate verify failed'

            # Reason why verification failed is stored in err.args[0], see
            # codes at http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
            try:
                result = (2, None)
                # Send the message to destroy the progress dialog first. This needs
                # to be done in this order on Linux because otherwise killing
                # the progress dialog will also kill the SSL error dialog.
                # Weird, huh? Welcome to the world of wx...
                callMethodInUIThread(self.callback, result)
                if err.args[0] in ssl.unknown_issuer:
                    d = ssl.askTrustServerCertificate(
                        err.host, err.untrustedCertificates[0], self.reconnect)
                else:
                    d = ssl.askIgnoreSSLError(err.host,
                                              err.untrustedCertificates[0],
                                              err.args[0], self.reconnect)

                waitForDeferred(d)

                return result
            except Exception, e:
                # There is a bug in the M2Crypto code which needs
                # to be fixed.
                #log.exception('This should not happen')
                return (0, (CANT_CONNECT, _(u"SSL error.")))
Example #4
0
    def clearIncoming(self, IN):
        IN.host = u""
        IN.replyToAddress = None
        IN.username = u""
        waitForDeferred(IN.password.clear())

        self.calc()
Example #5
0
def _change(oldMaster, newMaster, view, prefs):
    # Helper to change or set master password
    from osaf.framework import password
    try:
        again = False
        for item in password.Password.iterItems(view):
            if not waitForDeferred(item.initialized()):
                continue

            try:
                oldPassword = waitForDeferred(item.decryptPassword(masterPassword=oldMaster))
            except password.DecryptionError:
                log.info('Wrong old master password?')
                again = True
                break
            waitForDeferred(item.encryptPassword(oldPassword, masterPassword=newMaster))
        
        if again:
            return False
            
    except:
        view.cancel()
        log.exception('Failed to change master password')
        raise
    
    prefs.masterPassword = True
    view.commit()

    _setTimedPassword(newMaster, prefs.timeout * 60)
    
    return True
Example #6
0
    def clearOutgoing(self, OUT):
        OUT.host = u""
        OUT.fromAddress = None
        OUT.username = u""
        waitForDeferred(OUT.password.clear())
        OUT.useAuth = False

        self.calc()
Example #7
0
 def setPasswd(self, text):
     pw = getattr(self, "password", None)
     if pw is None:
         if text is None:
             return
         pw = Password(itsParent=self)
         self.password = pw
     waitForDeferred(pw.encryptPassword(text))
Example #8
0
 def runTest(self):
     self.setUp()
     try:
         self.RoundTrip()
         self.BackwardsCompatibility()
     finally:
         # otherwise test hangs waiting for Timer thread to finish
         waitForDeferred(MasterPassword.clear())
 def runTest(self):
     self.setUp()
     try:
         self.RoundTrip()
         self.BackwardsCompatibility()
     finally:
         # otherwise test hangs waiting for Timer thread to finish
         waitForDeferred(MasterPassword.clear())
Example #10
0
 def setPasswd(self, text):
     pw = getattr(self, "password", None)
     if pw is None:
         if text is None:
             return
         pw = Password(itsParent=self)
         self.password = pw
     waitForDeferred(pw.encryptPassword(text))
Example #11
0
    def addIncoming(self, IN, emailAddress):
        IN.isActive = True
        IN.host = u"imap.test.com"
        IN.replyToAddress = emailAddress
        IN.username = u"test"
        IN.password = password.Password(itsView=IN.itsView, itsParent=IN)
        waitForDeferred(IN.password.encryptPassword(u'test'))

        self.calc()
Example #12
0
    def addOutgoing(self, OUT, emailAddress):
        OUT.isActive = True
        OUT.host = u"host.test.com"
        OUT.fromAddress = emailAddress
        OUT.username = u"test"
        OUT.password = password.Password(itsView=OUT.itsView, itsParent=OUT)
        waitForDeferred(OUT.password.encryptPassword(u'test'))
        OUT.userAuth = True

        self.calc()
Example #13
0
    def _setCurAccount(self, settings):
        self.smtpAccount.host = self.hostname
        self.smtpAccount.port = settings['port']
        self.smtpAccount.connectionSecurity = settings['connectionSecurity']

        #Reset all username and password info
        self.smtpAccount.useAuth  = False
        self.smtpAccount.username = u""
        if not hasattr(self.smtpAccount, 'password'):
            self.smtpAccount.password = password.Password(itsView=self.smtpAccount.itsView, itsParent=self.smtpAccount)
        waitForDeferred(self.smtpAccount.password.clear())

        self.curAccount = self.smtpAccount
Example #14
0
    def PrepareShares(self):

        servers = [
            ("qacosmo.osafoundation.org", 80, False, "/cosmo", "test", "test1"),
            ("localhost", 8080, False, "/cosmo", "test", "test1"),
            ("hub.chandlerproject.org", 80, False, "/", "username", "password"),
        ]
        server = 1

        view0 = self.views[0]
        coll0 = self.coll
        self.assert_(not pim.has_stamp(coll0, sharing.SharedItem))
        account = cosmo.CosmoAccount(itsView=view0,
            host=servers[server][0],
            port=servers[server][1],
            path=servers[server][3],
            username=servers[server][4],
            password=Password(itsView=view0),
            useSSL=servers[server][2]
        )
        waitForDeferred(account.password.encryptPassword(servers[server][5]))

        conduit = cosmo.CosmoConduit(itsView=view0,
            account=account,
            shareName=coll0.itsUUID.str16(),
            translator=translator.SharingTranslator,
            serializer=eimml.EIMMLSerializer
        )
        self.share0 = sharing.Share("share", itsView=view0,
            contents=coll0, conduit=conduit)


        view1 = self.views[1]
        account = cosmo.CosmoAccount(itsView=view1,
            host=servers[server][0],
            port=servers[server][1],
            path=servers[server][3],
            username=servers[server][4],
            password=Password(itsView=view1),
            useSSL=servers[server][2]
        )
        waitForDeferred(account.password.encryptPassword(servers[server][5]))

        conduit = cosmo.CosmoConduit(itsView=view1,
            account=account,
            shareName=coll0.itsUUID.str16(),
            translator=translator.SharingTranslator,
            serializer=eimml.EIMMLSerializer
        )
        self.share1 = sharing.Share("share", itsView=view1,
            conduit=conduit)
Example #15
0
    def _setCurAccount(self, settings):
        self.smtpAccount.host = self.hostname
        self.smtpAccount.port = settings['port']
        self.smtpAccount.connectionSecurity = settings['connectionSecurity']

        #Reset all username and password info
        self.smtpAccount.useAuth = False
        self.smtpAccount.username = u""
        if not hasattr(self.smtpAccount, 'password'):
            self.smtpAccount.password = password.Password(
                itsView=self.smtpAccount.itsView, itsParent=self.smtpAccount)
        waitForDeferred(self.smtpAccount.password.clear())

        self.curAccount = self.smtpAccount
Example #16
0
    def decryptPassword(self, masterPassword=None, window=None):
        """
        Decrypt password and return it.
        
        @raise NoMasterPassword: NoMasterPassword will be raised if 
                                 masterPassword parameter is None and we have a
                                 non-default master password that has timed out,
                                 and the user cancels the dialog where we ask for
                                 it.

        @raise PasswordTooLong:  Password is too long.

        @return: Return password.
        @rtype:  unicode
        """
        try:
            if not self.ciphertext or not self.iv or not self.salt:
                return u''
        except AttributeError:
            # We can determine the correct master password by iterating over
            # passwords, decrypting them, and getting at least one non-empty
            # password.
            return u''
        
        if len(self.ciphertext) > 1024:
            waitForDeferred(self.clear())
            raise PasswordTooLong(_(u'Password is too long'))
        
        if masterPassword is None:
            masterPassword = waitForDeferred(MasterPassword.get(self.itsView, window))
        
        # the crypto algorithms are unicode unfriendly
        if isinstance(masterPassword, unicode):
            masterPassword = masterPassword.encode('utf8')

        # derive 256 bit key using the pbkdf2 standard
        key = EVP.pbkdf2(masterPassword, self.salt, iter=1000, keylen=32)

        # Derive encryption key and HMAC key from it
        # See Practical Cryptography section 8.4.1.
        hmacKey = sha256(key + 'MAC').digest()
        encKey = sha256(key + 'encrypt').digest()
        del key
        
        # decrypt
        try:
            ret = decrypt(self.ciphertext, encKey, self.iv)
        except EVP.EVPError, e:
            raise DecryptionError(str(e))
Example #17
0
def createHTTPFactory(host, port, username, password, useSSL, repositoryView):

    # See if the user has configured an HTTP proxy
    if repositoryView is not None and not useSSL:
        getProxy = schema.ns("osaf.sharing.accounts", repositoryView).getProxy
        
        proxy = getProxy(repositoryView, 'HTTP')
        if not proxy.appliesTo(host):
            proxy = None
    else:
        proxy = None
        
    if proxy is not None and proxy.active:
        proxyPassword = getattr(proxy, 'password', None)
        factory = ChandlerHTTPProxyClientFactory(
                      host=proxy.host,
                      port=proxy.port,
                      username=proxy.username,
                      password=waitForDeferred(proxyPassword.decryptPassword())
                  )
    else:
        factory = ChandlerHTTPClientFactory()

    factory.protocol = zanshin.webdav.WebDAVProtocol
    factory.startTLS = useSSL
    factory.host = host
    factory.port = port
    factory.username = username
    factory.password = password
    factory.retries = zanshin.webdav.DEFAULT_RETRIES
    factory.repositoryView = repositoryView
    factory.extraHeaders = { 'User-Agent' : Utility.getUserAgent() }
    #factory.extraHeaders = { 'Connection' : "close" }

    return factory
 def getCalendars(self):
     service = getService(self.username,
                          waitForDeferred(self.password.decryptPassword()))
     feed = service.GetCalendarListFeed()
     for entry in feed.entry:
         yield (entry.title.text, entry.GetAlternateLink().href,
                entry.access_level.value, entry.color.value)
Example #19
0
    def _getPublishedShares(self, callback):
        path = self.path.strip("/")
        if path:
            path = "/%s" % path
        path = urllib.quote("%s/mc/user/%s" % (path, self.username))
        handle = WebDAV.ChandlerServerHandle(
            self.host,
            self.port,
            username=self.username,
            password=waitForDeferred(self.password.decryptPassword()),
            useSSL=self.useSSL,
            repositoryView=self.itsView)

        extraHeaders = {}
        body = None
        request = zanshin.http.Request('GET', path, extraHeaders, body)

        try:
            resp = handle.blockUntil(handle.addRequest, request)
        except zanshin.webdav.ConnectionError, err:
            exc = errors.CouldNotConnect(
                _(u"Unable to connect to server: %(error)s") % {'error': err})
            if callback:
                return callMethodInUIThread(callback,
                                            (exc, self.itsUUID, None))
            else:
                raise exc
def createHTTPFactory(host, port, username, password, useSSL, repositoryView):

    # See if the user has configured an HTTP proxy
    if repositoryView is not None and not useSSL:
        getProxy = schema.ns("osaf.sharing.accounts", repositoryView).getProxy

        proxy = getProxy(repositoryView, 'HTTP')
        if not proxy.appliesTo(host):
            proxy = None
    else:
        proxy = None

    if proxy is not None and proxy.active:
        proxyPassword = getattr(proxy, 'password', None)
        factory = ChandlerHTTPProxyClientFactory(
            host=proxy.host,
            port=proxy.port,
            username=proxy.username,
            password=waitForDeferred(proxyPassword.decryptPassword()))
    else:
        factory = ChandlerHTTPClientFactory()

    factory.protocol = zanshin.webdav.WebDAVProtocol
    factory.startTLS = useSSL
    factory.host = host
    factory.port = port
    factory.username = username
    factory.password = password
    factory.retries = zanshin.webdav.DEFAULT_RETRIES
    factory.repositoryView = repositoryView
    factory.extraHeaders = {'User-Agent': Utility.getUserAgent()}
    #factory.extraHeaders = { 'Connection' : "close" }

    return factory
Example #21
0
 def getCalendars(self):
     service = getService(self.username,
         waitForDeferred(self.password.decryptPassword()))
     feed = service.GetCalendarListFeed()
     for entry in feed.entry:
         yield(entry.title.text, entry.GetAlternateLink().href,
             entry.access_level.value, entry.color.value)
Example #22
0
def getExistingResources(account):
    path = account.path.strip("/")
    handle = WebDAV.ChandlerServerHandle(account.host, port=account.port,
         username=account.username,
         password=waitForDeferred(account.password.decryptPassword()),
         useSSL=account.useSSL, repositoryView=account.itsView)

    if len(path) > 0:
        path = "/%s/" % path
    else:
        path = "/"

    existing = []
    parent   = handle.getResource(path)

    skipLen = len(path)

    resources = handle.blockUntil(parent.getAllChildren)

    for resource in resources:
        path = resource.path[skipLen:]
        path = path.strip(u"/")
        if path:
            existing.append(path)

    # @@@ [grant] Localized sort?
    existing.sort( )
    return existing
Example #23
0
    def blockUntil(self, callable, *args, **keywds):
        # Since there can be several errors in a connection, we must keep 
        # trying until we either get a successful connection or the user 
        # decides to cancel/disconnect, or there is an error we don't know 
        # how to deal with.
        while True:
            try:
                return zanshin.util.blockUntil(callable, *args, **keywds)
            except Utility.CertificateVerificationError, err:
                self._reconnect = False

                assert err.args[1] == 'certificate verify failed'
    
                # Reason why verification failed is stored in err.args[0], see
                # codes at http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
    
                retry = lambda: True
    
                if err.args[0] in ssl.unknown_issuer:
                    d = ssl.askTrustServerCertificate(
                        err.host,
                        err.untrustedCertificates[0], 
                        retry)
                else:
                    d = ssl.askIgnoreSSLError(
                        err.host,
                        err.untrustedCertificates[0], 
                        err.args[0], 
                        retry)

                if not waitForDeferred(d):
                    raise ActivityAborted(_(u"Cancelled by user"))
                                            
            except M2Crypto.SSL.Checker.WrongHost, err:
                self._reconnect = False

                retry = lambda: True
        
                d = ssl.askIgnoreSSLError(
                    err.expectedHost,
                    err.pem, 
                    messages.SSL_HOST_MISMATCH % {'actualHost': err.actualHost},
                    retry)

                if not waitForDeferred(d):
                    raise ActivityAborted(_(u"Cancelled by user"))
Example #24
0
def installParcel(parcel, oldVersion = None):
    # Hard code the UUID so that after a new repository is created we can still
    # find the dummy for dump and reload
    dummyPassword = Password.update(parcel,
                                    'dummyPassword',
                                    _uuid = UUID('dd555441-9ddc-416c-b55a-77b073c7bd15'),
                                    )
    
    password = ''.join([string.printable[ord(c) % len(string.printable)] \
                        for c in os.urandom(16)])
    waitForDeferred(dummyPassword.encryptPassword(password, masterPassword=''))
    
    PasswordPrefs.update(parcel, 'passwordPrefs', dummyPassword=dummyPassword)
    
    # This ensures that MasterPassword.installParcel gets called now;
    # not doing this can lead to weird stale parcel items later on.
    schema.ns('osaf.framework.MasterPassword', parcel).masterPasswordPrefs
Example #25
0
 def _getSettings(self, withPassword=True):
     password = None
     if self.account is None:
         if withPassword:
             password = getattr(self, "password", None)
             if password:
                 password = waitForDeferred(password.decryptPassword())
         return (self.host, self.port, self.sharePath.strip("/"),
                 self.username, password, self.useSSL)
     else:
         if withPassword:
             password = getattr(self.account, "password", None)
             if password:
                 password = waitForDeferred(password.decryptPassword())
         return (self.account.host, self.account.port,
                 self.account.path.strip("/"), self.account.username,
                 password, self.account.useSSL)
Example #26
0
    def __populateAccount(self, account):

        #XXX: i18n usernames and passwords can be non-ascii.
        # Need to investigate how best to deal with this as
        # there is no standard. It is server implementation dependent.
        account.username = uw("test")
        account.password = password.Password(itsView=account.itsView,
                                             itsParent=account)
        waitForDeferred(account.password.encryptPassword(uw("test")))
        account.host = uw("test")

        if type(account) == Mail.AccountBase:
            account.port = 1
            account.connectionSecurity = "NONE"

        if type(account) == Mail.SMTPAccount:
            account.fullName = uw("test")
            account.replyToAddress = Mail.EmailAddress(itsView=account.itsView)
            account.replyToAddress.emailAddress = "*****@*****.**"
Example #27
0
    def __populateAccount(self, account):

        #XXX: i18n usernames and passwords can be non-ascii.
        # Need to investigate how best to deal with this as 
        # there is no standard. It is server implementation dependent.
        account.username = uw("test")
        account.password = password.Password(itsView=account.itsView,
                                             itsParent=account)
        waitForDeferred(account.password.encryptPassword(uw("test")))
        account.host = uw("test")

        if type(account) == Mail.AccountBase:
            account.port = 1
            account.connectionSecurity = "NONE"

        if type(account) == Mail.SMTPAccount:
            account.fullName = uw("test")
            account.replyToAddress = Mail.EmailAddress(itsView=account.itsView)
            account.replyToAddress.emailAddress = "*****@*****.**"
Example #28
0
 def _getMorsecodeSettings(self, withPassword=True):
     password = None
     if self.account is None:
         if withPassword:
             password = getattr(self, "password", None)
             if password:
                 password = waitForDeferred(password.decryptPassword())
         return (self.host, self.port, self.morsecodePath.strip("/"),
                 self.username, password, self.useSSL)
     else:
         if withPassword:
             password = getattr(self.account, "password", None)
             if password:
                 password = waitForDeferred(password.decryptPassword())
         path = self.account.path.strip("/") + "/" + self.account.morsecodePath
         return (self.account.host, self.account.port,
                 path.strip("/"),
                 self.account.username,
                 password,
                 self.account.useSSL)
Example #29
0
    def runTest(self):
        self.setUp()
        self.dir = os.path.join(os.getenv("CHANDLERHOME") or ".",
            "parcels", "osaf", "tests")
        self.restoreSettings()

        prefs = schema.ns("osaf.framework.MasterPassword",
                  self.view).masterPasswordPrefs
        saved = os.path.join(self.dir, 'save.ini')
        
        settings.save(self.view, saved)
        
        try:
            self.restoreSettings(filename='save.ini')
            MasterPassword._change('', 'foo', self.view, prefs)
            settings.save(self.view, saved)
            self.restoreSettings(filename='save.ini', masterPassword='******')
        finally:
            os.remove(saved)
            waitForDeferred(MasterPassword.clear())
    def runTest(self):
        self.setUp()
        self.dir = os.path.join(
            os.getenv("CHANDLERHOME") or ".", "parcels", "osaf", "tests")
        self.restoreSettings()

        prefs = schema.ns("osaf.framework.MasterPassword",
                          self.view).masterPasswordPrefs
        saved = os.path.join(self.dir, 'save.ini')

        settings.save(self.view, saved)

        try:
            self.restoreSettings(filename='save.ini')
            MasterPassword._change('', 'foo', self.view, prefs)
            settings.save(self.view, saved)
            self.restoreSettings(filename='save.ini', masterPassword='******')
        finally:
            os.remove(saved)
            waitForDeferred(MasterPassword.clear())
Example #31
0
    def encryptPassword(self, password, masterPassword=None, window=None):
        """
        Encrypt and store password.
        
        @raise NoMasterPassword: NoMasterPassword will be raised if 
                                 masterPassword parameter is None and we have a
                                 non-default master password that has timed out,
                                 and the user cancels the dialog where we ask for
                                 it.

        @raise PasswordTooLong:  Password is too long.

        @param password: The password to store
        @type param:     str or unicode
        """
        if masterPassword is None:
            masterPassword = waitForDeferred(MasterPassword.get(self.itsView, window))
            
        # the crypto algorithms are unicode unfriendly
        if isinstance(password, unicode):
            password = password.encode('utf8')
        if isinstance(masterPassword, unicode):
            masterPassword = masterPassword.encode('utf8')
        
        # get 256 bit random encryption salt
        self.salt = os.urandom(32)
        # derive 256 bit encryption key using the pbkdf2 standard
        key = EVP.pbkdf2(masterPassword, self.salt, iter=1000, keylen=32)
        
        # Derive encryption key and HMAC key from it
        # See Practical Cryptography section 8.4.1.
        hmacKey = sha256(key + 'MAC').digest()
        encKey = sha256(key + 'encrypt').digest()
        del key

        # get 256 bit random iv
        self.iv = os.urandom(32)

        # Add HMAC to password so that we can check during decrypt if we got
        # the right password back. We are doing sign-then-encrypt, which let's
        # us encrypt empty passwords (otherwise we'd need to pad with some
        # string to encrypt). Practical Cryptography by Schneier & Ferguson
        # also recommends doing it in this order in section 8.2.
        mac = hmac.new(hmacKey,
                       password + self.iv + self.salt,
                       sha256).hexdigest()
        del hmacKey

        # encrypt using AES (Rijndael)
        try:
            self.ciphertext = encrypt(password + mac, encKey, self.iv)
        except EVP.EVPError, e:
            raise EncryptionError(str(e))
    def blockUntil(self, callable, *args, **keywds):
        # Since there can be several errors in a connection, we must keep
        # trying until we either get a successful connection or the user
        # decides to cancel/disconnect, or there is an error we don't know
        # how to deal with.
        while True:
            try:
                return zanshin.util.blockUntil(callable, *args, **keywds)
            except Utility.CertificateVerificationError, err:
                self._reconnect = False

                assert err.args[1] == 'certificate verify failed'

                # Reason why verification failed is stored in err.args[0], see
                # codes at http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS

                retry = lambda: True

                if err.args[0] in ssl.unknown_issuer:
                    d = ssl.askTrustServerCertificate(
                        err.host, err.untrustedCertificates[0], retry)
                else:
                    d = ssl.askIgnoreSSLError(err.host,
                                              err.untrustedCertificates[0],
                                              err.args[0], retry)

                if not waitForDeferred(d):
                    raise ActivityAborted(_(u"Cancelled by user"))

            except M2Crypto.SSL.Checker.WrongHost, err:
                self._reconnect = False

                retry = lambda: True

                d = ssl.askIgnoreSSLError(
                    err.expectedHost, err.pem, messages.SSL_HOST_MISMATCH %
                    {'actualHost': err.actualHost}, retry)

                if not waitForDeferred(d):
                    raise ActivityAborted(_(u"Cancelled by user"))
Example #33
0
    def _setCurAccount(self, settings):
        if settings['type'] == "IMAP":
            self.imapAccount.host = self.hostname
            self.imapAccount.port = settings['port']
            self.imapAccount.connectionSecurity = settings['connectionSecurity']
            self.curAccount = self.imapAccount

        elif settings['type'] == "POP":
            self.popAccount.host = self.hostname
            self.popAccount.port = settings['port']
            self.popAccount.connectionSecurity = settings['connectionSecurity']
            self.curAccount = self.popAccount

        else:
            #XXX this should never be reached
            raise Exception()

        # reset all username and password info
        self.curAccount.username = u""
        if not hasattr(self.curAccount, 'password'):
            self.curAccount.password = password.Password(itsView=self.curAccount.itsView, itsParent=self.curAccount)
        waitForDeferred(self.curAccount.password.clear())
Example #34
0
    def sync(self, modeOverride=None, activity=None, forceUpdate=None,
            debug=False):

        if self.account:
            username = self.account.username
            password = waitForDeferred(self.account.password.decryptPassword())
        else:
            username = self.username
            password = self.password

        self.gService = getService(username, password)

        return super(GDataConduit, self).sync(modeOverride=modeOverride,
            activity=activity, forceUpdate=forceUpdate, debug=debug)
Example #35
0
    def _setCurAccount(self, settings):
        if settings['type'] == "IMAP":
            self.imapAccount.host = self.hostname
            self.imapAccount.port = settings['port']
            self.imapAccount.connectionSecurity = settings[
                'connectionSecurity']
            self.curAccount = self.imapAccount

        elif settings['type'] == "POP":
            self.popAccount.host = self.hostname
            self.popAccount.port = settings['port']
            self.popAccount.connectionSecurity = settings['connectionSecurity']
            self.curAccount = self.popAccount

        else:
            #XXX this should never be reached
            raise Exception()

        # reset all username and password info
        self.curAccount.username = u""
        if not hasattr(self.curAccount, 'password'):
            self.curAccount.password = password.Password(
                itsView=self.curAccount.itsView, itsParent=self.curAccount)
        waitForDeferred(self.curAccount.password.clear())
    def sync(self,
             modeOverride=None,
             activity=None,
             forceUpdate=None,
             debug=False):

        if self.account:
            username = self.account.username
            password = waitForDeferred(self.account.password.decryptPassword())
        else:
            username = self.username
            password = self.password

        self.gService = getService(username, password)

        return super(GDataConduit, self).sync(modeOverride=modeOverride,
                                              activity=activity,
                                              forceUpdate=forceUpdate,
                                              debug=debug)
Example #37
0
def beforeBackup(view, parent=None):
    """
    Call before doing any kind of backup or export of data that includes
    account passwords. Will prompt the user to set their master password
    if appropriate.
    
    Must be called from the UI thread.
    """
    prefs = schema.ns("osaf.framework.MasterPassword",
                      view).masterPasswordPrefs
    if not prefs.masterPassword:
        # Check if we have any passwords we'd want to protect
        from osaf.framework import password
        count = 0
        for item in password.Password.iterItems(view):
            if not waitForDeferred(item.initialized()):
                continue
            
            if waitForDeferred(item.decryptPassword()):
                count += 1
        if count == 1: # We will always have at least one, the dummy password
            return
        if parent is None:
            parent = wx.GetApp().mainFrame

        # Check if the user has set a persistent preference on what to do
        protect = getattr(prefs, 'protect', None)
        if protect is not None:
            if protect:
                waitForDeferred(change(view, parent))
            return
        
        dlg = Util.checkboxUserDialog(parent,
                                     _(u'Protect Passwords'),
                                     _(u'Anyone who gains access to your data can view your account passwords. Do you want to protect your account passwords by encrypting them with a master password?'),
                                     value = _(u'&Never ask again'))
        try:
            val = dlg.ShowModal()
            neverAskAgain = dlg.GetValue()
            
            if val == wx.ID_YES:
                waitForDeferred(change(view, parent))
                if neverAskAgain:
                    prefs.protect = True
            else:
                if neverAskAgain:
                    prefs.protect = False
        finally:
            dlg.Destroy()
Example #38
0
    def _getPublishedShares(self, callback):
        path = self.path.strip("/")
        if path:
            path = "/%s" % path
        path = urllib.quote("%s/mc/user/%s" % (path, self.username))
        handle = WebDAV.ChandlerServerHandle(self.host, self.port,
            username=self.username,
            password=waitForDeferred(self.password.decryptPassword()),
            useSSL=self.useSSL, repositoryView=self.itsView)

        extraHeaders = {}
        body = None
        request = zanshin.http.Request('GET', path, extraHeaders, body)

        try:
            resp = handle.blockUntil(handle.addRequest, request)
        except zanshin.webdav.ConnectionError, err:
            exc = errors.CouldNotConnect(_(u"Unable to connect to server: %(error)s") % {'error': err})
            if callback:
                return callMethodInUIThread(callback, (exc, self.itsUUID, None))
            else:
                raise exc
Example #39
0
def restorePassword(account, section, sectionName=u"password"):
    if not hasattr(account, 'password'):
        account.password = password.Password(itsView=account.itsView,
                                             itsParent=account)
    
    try:
        iv, salt, ciphertext = section[sectionName].split('|')
    except ValueError:
        # Backwards compatibility
        waitForDeferred(account.password.encryptPassword(section[sectionName]))
    else:
        if iv and salt and ciphertext:
            try:
                account.password.iv = unhexlify(iv)
                account.password.salt = unhexlify(salt)
                account.password.ciphertext = unhexlify(ciphertext)
            except TypeError:
                # Backwards compatibility, somebody had a long password!
                waitForDeferred(account.password.encryptPassword(section[sectionName]))
        else:
            # Backwards compatibility
            waitForDeferred(account.password.encryptPassword(section[sectionName]))
    def restoreSettings(self, filename='settings.ini', masterPassword=''):

        rv = self.view

        # If we don't load osaf.app now, before restoring settings, it will
        # get loaded afterwards, which messes up the notion of "current"
        # accounts
        schema.ns("osaf.app", rv).me

        # restore settings
        settings.restore(rv,
                         os.path.join(self.dir, filename),
                         testmode=True,
                         newMaster=masterPassword)

        # verify accounts

        act = rv.findUUID(UUID("1bfc2a92-53eb-11db-9367-d2f16e571a02"))
        self.assert_(act)
        self.assert_(isinstance(act, sharing.CosmoAccount))
        self.assertEquals(act.displayName, "Test Sharing Service")
        self.assertEquals(act.port, 443)
        self.assertEquals(act.useSSL, True)
        self.assertEquals(act.host, "cosmo-demo.osafoundation.org")
        self.assertEquals(act.username, "sharing")
        self.assertEquals(
            waitForDeferred(
                act.password.decryptPassword(masterPassword=masterPassword)),
            "sharing_password")
        self.assertRaises(
            password.DecryptionError, waitForDeferred,
            act.password.decryptPassword(masterPassword=masterPassword + 'A'))

        act = rv.findUUID(UUID("1bfc2a92-53eb-11db-9367-d2f16e571a03"))
        self.assert_(act)
        self.assertEquals(act.displayName, "Another Sharing Service")
        self.assertEquals(act.port, 8080)
        self.assertEquals(act.useSSL, False)

        act = rv.findUUID(UUID("1bfd96f2-53eb-11db-9367-d2f16e571a02"))
        self.assert_(act)
        self.assert_(isinstance(act, pim.mail.SMTPAccount))
        self.assertEquals(act.displayName, "Test Outgoing SMTP mail")
        self.assertEquals(act.host, "smtp.example.com")
        self.assertEquals(act.useAuth, True)
        self.assertEquals(act.username, "smtp")
        self.assertEquals(
            waitForDeferred(
                act.password.decryptPassword(masterPassword=masterPassword)),
            "smtp_password")
        self.assertEquals(act.port, 465)
        self.assertEquals(act.connectionSecurity, "SSL")

        act = rv.findUUID(UUID("1bffa488-53eb-11db-9367-d2f16e571a02"))
        self.assert_(act)
        self.assert_(isinstance(act, pim.mail.IMAPAccount))
        self.assertEquals(act.host, "imap.example.com")
        self.assertEquals(act.username, "imap")
        self.assertEquals(
            waitForDeferred(
                act.password.decryptPassword(masterPassword=masterPassword)),
            "imap_password")
        self.assertEquals(act.port, 993)
        self.assertEquals(act.connectionSecurity, "SSL")

        # Get the current Mail account which should be
        # the pop.example.com account
        act = schema.ns("osaf.pim", rv).currentIncomingAccount.item
        self.assert_(act)
        self.assert_(isinstance(act, pim.mail.POPAccount))
        self.assertEquals(act.host, "pop.example.com")
        self.assertEquals(act.username, "pop")
        self.assertEquals(
            waitForDeferred(
                act.password.decryptPassword(masterPassword=masterPassword)),
            "pop_password")
        self.assertEquals(act.port, 995)
        self.assertEquals(act.connectionSecurity, "SSL")

        # verify shares

        mine = schema.ns("osaf.pim", rv).mine

        foundA = False
        foundB = False
        for col in pim.ContentCollection.iterItems(rv):
            name = getattr(col, "displayName", "")
            if name == "pub_mine":
                foundA = True
                self.assert_(col in mine.sources)

            elif name == "sub_notmine":
                foundB = True
                self.assert_(col not in mine.sources)

        self.assert_(foundA and foundB)

        # verify timezone
        self.assert_(schema.ns("osaf.pim", rv).TimezonePrefs.showUI)

        # verify visible hours
        calPrefs = schema.ns("osaf.framework.blocks.calendar",
                             rv).calendarPrefs
        self.assertEquals(calPrefs.visibleHours, 24)
        self.assertEquals(calPrefs.hourHeightMode, "visibleHours")
                #log.exception('This should not happen')
                return (0, (CANT_CONNECT, _(u"SSL error.")))

        except M2Crypto.SSL.Checker.WrongHost, err:
            result = (2, None)
            # Send the message to destroy the progress dialog first. This needs
            # to be done in this order on Linux because otherwise killing
            # the progress dialog will also kill the SSL error dialog.
            # Weird, huh? Welcome to the world of wx...
            callMethodInUIThread(self.callback, result)
            d = ssl.askIgnoreSSLError(err.expectedHost,
                                      err.pem,
                                      messages.SSL_HOST_MISMATCH % \
                                        {'actualHost': err.actualHost},
                                      self.reconnect)
            waitForDeferred(d)

            return result

        except M2Crypto.BIO.BIOError, err:
            return (0, (CANT_CONNECT, str(err)))

        except zanshin.webdav.ConnectionError, err:
            return (0, (CANT_CONNECT, err.message))

        except zanshin.webdav.WebDAVError, err:
            return (0, (NO_ACCESS, err.status))

        except error.SSLError, err:
            return (0, (CANT_CONNECT, err))  # Unhandled SSL error
Example #42
0
def reload(rv, filename, serializer=PickleSerializer, activity=None,
    testmode=False):
    """ Loads EIM records from a file and applies them """

    translator = getTranslator()

    if not testmode:
        oldMaster = waitForDeferred(MasterPassword.get(rv))
    else:
        oldMaster = ''
        newMaster = 'secret'

    if activity is not None:
        activity.update(totalWork=None, msg=_(u"Counting records..."))
        input = open(filename, "rb")
        load = serializer.loader(input)
        i = 0
        while True:
            record = load()
            if not record:
                break
            i += 1
        input.close()
        activity.update(totalWork=i)


    trans = translator(rv)
    trans.startImport()

    input = open(filename, "rb")
    try:
        load = serializer.loader(input)
        i = 0
        while True:
            record = load()
            if not record:
                break
            trans.importRecord(record)
            i += 1
            if activity is not None:
                activity.update(msg=_(u"Imported %(total)d records") % {'total':i}, work=1)
            if i % 1000 == 0: # Commit every 1,000 records
                if activity is not None:
                    activity.update(msg=_(u"Saving..."))
                rv.commit()

        logger.info("Imported %d records", i)

        del load
    finally:
        input.close()

    trans.finishImport()

    if activity is not None:
        activity.update(msg=_(u"Saving..."))
    rv.commit()


    # Passwords that existed before reload are encrypted with oldMaster, and
    # passwords that we reloaded are encrypted with newMaster, so now we need
    # to go through all passwords and re-encrypt all the old ones with
    # newMaster.
    
    # First, let's get the newMaster
    waitForDeferred(MasterPassword.clear())
    if not testmode:
        prefs = schema.ns("osaf.framework.MasterPassword",
                          rv).masterPasswordPrefs
        if prefs.masterPassword:
            wx.MessageBox (_(u"Please enter the master password you used to protect this file to reload account passwords."),
                           _(u'Protect Passwords'),
                           parent=wx.GetApp().mainFrame)
        
        dummy = schema.ns("osaf.framework.password",
                          rv).passwordPrefs.dummyPassword

        while True:
            try:
                newMaster = waitForDeferred(MasterPassword.get(rv, testPassword=dummy))
                break
            except password.NoMasterPassword:
                if wx.MessageBox(_(u'If you do not remember your master password, all account passwords will be deleted. Delete account passwords?'),
                                 _(u'Reset Master Password'),
                                 style = wx.YES_NO,
                                 parent=wx.GetApp().mainFrame) == wx.YES:
                    MasterPassword.reset(rv)
                    return
    
    # Then re-encrypt
    for item in password.Password.iterItems(rv):
        if not waitForDeferred(item.initialized()):
            # Don't need to re-encrypt uninitialized passwords
            continue
        
        try:
            pw = waitForDeferred(item.decryptPassword(masterPassword=oldMaster))
        except password.DecryptionError:
            # Maybe this was one of the new passwords loaded from
            # dump, so let's try the new master password
            try:
                waitForDeferred(item.decryptPassword(masterPassword=newMaster))
            except password.DecryptionError:
                # Oops, we are in trouble, can't really do much but
                # reset() to avoid further problems.
                logger.exception('found passwords that could not be decrypted; clearing passwords')
                MasterPassword.reset(rv)
                break
            # Since this is already encrypted with the new
            # master password we don't need to re-encrypt
            continue

        waitForDeferred(item.encryptPassword(pw, masterPassword=newMaster))
Example #43
0
def reload(rv, filename, serializer=PickleSerializer, activity=None, testmode=False):
    """ Loads EIM records from a file and applies them """

    translator = getTranslator()

    if not testmode:
        oldMaster = waitForDeferred(MasterPassword.get(rv))
    else:
        oldMaster = ""
        newMaster = "secret"

    if activity is not None:
        activity.update(totalWork=None, msg=_(u"Counting records..."))
        input = open(filename, "rb")
        load = serializer.loader(input)
        i = 0
        while True:
            record = load()
            if not record:
                break
            i += 1
        input.close()
        activity.update(totalWork=i)

    trans = translator(rv)
    trans.startImport()

    input = open(filename, "rb")
    try:
        load = serializer.loader(input)
        i = 0
        while True:
            record = load()
            if not record:
                break
            trans.importRecord(record)
            i += 1
            if activity is not None:
                activity.update(msg=_(u"Imported %(total)d records") % {"total": i}, work=1)
            if i % 1000 == 0:  # Commit every 1,000 records
                if activity is not None:
                    activity.update(msg=_(u"Saving..."))
                rv.commit()

        logger.info("Imported %d records", i)

        del load
    finally:
        input.close()

    trans.finishImport()

    if activity is not None:
        activity.update(msg=_(u"Saving..."))
    rv.commit()

    # Passwords that existed before reload are encrypted with oldMaster, and
    # passwords that we reloaded are encrypted with newMaster, so now we need
    # to go through all passwords and re-encrypt all the old ones with
    # newMaster.

    # First, let's get the newMaster
    waitForDeferred(MasterPassword.clear())
    if not testmode:
        prefs = schema.ns("osaf.framework.MasterPassword", rv).masterPasswordPrefs
        if prefs.masterPassword:
            wx.MessageBox(
                _(u"Please enter the master password you used to protect this file to reload account passwords."),
                _(u"Protect Passwords"),
                parent=wx.GetApp().mainFrame,
            )

        dummy = schema.ns("osaf.framework.password", rv).passwordPrefs.dummyPassword

        while True:
            try:
                newMaster = waitForDeferred(MasterPassword.get(rv, testPassword=dummy))
                break
            except password.NoMasterPassword:
                if (
                    wx.MessageBox(
                        _(
                            u"If you do not remember your master password, all account passwords will be deleted. Delete account passwords?"
                        ),
                        _(u"Reset Master Password"),
                        style=wx.YES_NO,
                        parent=wx.GetApp().mainFrame,
                    )
                    == wx.YES
                ):
                    MasterPassword.reset(rv)
                    return

    # Then re-encrypt
    for item in password.Password.iterItems(rv):
        if not waitForDeferred(item.initialized()):
            # Don't need to re-encrypt uninitialized passwords
            continue

        try:
            pw = waitForDeferred(item.decryptPassword(masterPassword=oldMaster))
        except password.DecryptionError:
            # Maybe this was one of the new passwords loaded from
            # dump, so let's try the new master password
            try:
                waitForDeferred(item.decryptPassword(masterPassword=newMaster))
            except password.DecryptionError:
                # Oops, we are in trouble, can't really do much but
                # reset() to avoid further problems.
                logger.exception("found passwords that could not be decrypted; clearing passwords")
                MasterPassword.reset(rv)
                break
            # Since this is already encrypted with the new
            # master password we don't need to re-encrypt
            continue

        waitForDeferred(item.encryptPassword(pw, masterPassword=newMaster))
    def testPassword(self):
        self.loadParcel("osaf.framework.MasterPassword")
        self.loadParcel("osaf.framework.password")

        pword = uw('my secr3t p4ssw0rd')
        masterPassword = uw('M0r3 s3cr3t')
        
        self.assertEqual(masterPassword, unicode(masterPassword.encode('utf8'), 'utf8'))
        
        # create
        pw = password.Password(itsView=self.view)

        # check that we can't get password yet
        self.assertFalse(waitForDeferred(pw.initialized()))
        
        # Check that empty values lead to uninitialized as well
        pw.ciphertext = ''
        pw.iv   = ''
        pw.salt = ''
        self.assertFalse(waitForDeferred(pw.initialized()))
        # And that bad values leads to DecryptionError
        pw.ciphertext = \
                  unhexlify('0001efa4bd154ee415b9413a421cedf04359fff945a30e7c115465b1c780a85b65c0e45c')
        pw.iv   = unhexlify('5cd148eeaf680d4ff933aed83009cad4110162f53ef89fd44fad09611b0524d4')
        pw.salt = unhexlify('a48e09ba0530422c7e96fe62643e149efce2a17e026ba98da8ee51a895ead25b')
        self.assertRaises(password.DecryptionError, waitForDeferred, pw.decryptPassword(masterPassword))
                
        # What happens if we supply wrong master password?
        pw.ciphertext = unhexlify('908ed5801146c55f7305dd8a07fa468f68fd0e3e7e075c6e42a9f922f8f5b461a2d32cc2eda4130085fa27c2a124d89f6e1c004245f3a1f9f101cb9bb30b6bcfe8685d01bffa2e659f567c9d1c44d564e87b469884de3dd070e9611be4666391')
        pw.iv = unhexlify('2a4c722617afd356bc0dc9c2cb26aa0013fbaf81928769485ed7c01d333f2952')
        pw.salt = unhexlify('0ee664ffa11c6856d5c6dc553413b6a3ee7d43b3b2c4252c1b8a4ca308387b9c')
        self.assertEqual(waitForDeferred(pw.decryptPassword(masterPassword=masterPassword)), pword)
        self.assertRaises(password.DecryptionError, waitForDeferred, pw.decryptPassword(masterPassword=uw('M0r3 wrongt')))
        self.assertRaises(password.DecryptionError, waitForDeferred, pw.decryptPassword(masterPassword=''))

        # check that we can use even empty master password
        waitForDeferred(pw.encryptPassword(pword, masterPassword=''))
        # make sure we didn't do anything stupid
        self._dontBeStupid(pw, pword, masterPassword='')
        # confirm we can get the password out
        self.assertEqual(waitForDeferred(pw.decryptPassword(masterPassword='')), pword)

        # check normal
        waitForDeferred(pw.encryptPassword(pword, masterPassword=masterPassword))        
        # make sure we didn't do anything stupid
        self._dontBeStupid(pw, pword, masterPassword)
        # confirm we can get the password out
        self.assertEqual(waitForDeferred(pw.decryptPassword(masterPassword=masterPassword)), pword)
        # and double check...
        self._dontBeStupid(pw, pword, masterPassword)

        # check long password
        waitForDeferred(pw.encryptPassword('12345678901234567890123456789012345678901234567890123456789012345678901234567890', masterPassword=masterPassword))
        # make sure we didn't do anything stupid
        self._dontBeStupid(pw, '12345678901234567890123456789012345678901234567890123456789012345678901234567890', masterPassword, 320)
        # confirm we can get the password out
        self.assertEqual(waitForDeferred(pw.decryptPassword(masterPassword=masterPassword)), '12345678901234567890123456789012345678901234567890123456789012345678901234567890')
        waitForDeferred(pw.encryptPassword('A'*959, masterPassword=masterPassword))
        self.assertRaises(password.PasswordTooLong, waitForDeferred, pw.encryptPassword('A'*960, masterPassword=masterPassword))

        # check empty passwords
        waitForDeferred(pw.encryptPassword('', masterPassword=''))
        # make sure we didn't do anything stupid
        self._dontBeStupid(pw, '', '', 160)
        # confirm we can get the password out
        self.assertEqual(waitForDeferred(pw.decryptPassword(masterPassword='')), '')
        
        # test async deferred (in our case more like sync...)
        d = pw.decryptPassword(masterPassword='')
        self.called = False
        def callback(passwordString):
            self.assertEqual(passwordString, '')
            self.called = True
        d.addCallback(callback)
        self.assertTrue(self.called)
        
        # clear
        waitForDeferred(pw.clear())
        self.assertFalse(waitForDeferred(pw.initialized()))

        d = pw.clear()
        self.called = False
        def nonecallback(a):
            self.assertTrue(a is None)
            self.called = True
        d.addCallback(nonecallback)
        self.assertTrue(self.called)
Example #45
0
def subscribe(view, url, activity=None, username=None, password=None, filters=None):

    if not isOnline(view):
        raise OfflineError(_(u"Could not perform request. Sharing is offline."))

    if not url:
        raise URLParseError(_(u"No URL provided."))

    logger.info("Subscribing to URL: %s", url)

    inspection = inspect(view, url, username=username, password=password)

    logger.info("Inspection results for %s: %s", url, inspection)

    info = getAccountInfo(view, url, username, password)
    account = info["account"]
    username = info["username"]
    password = info["password"]
    shareName = info["shareName"]
    scheme = info["scheme"]
    useSSL = info["useSSL"]
    host = info["host"]
    port = info["port"]
    path = info["path"]
    ticket = info["ticket"]
    parentPath = info["parentPath"]

    for share in Share.iterItems(view):
        if url == share.getLocation("subscribed"):
            raise AlreadySubscribed(_(u"You are already subscribed to this collection."))

    # TODO: upgrade to read-write if provided new ticket

    # Override, because we can't trust .mac to return 'text/calendar'
    parsedUrl = urlparse.urlsplit(url)
    if parsedUrl.scheme.startswith("webcal"):
        inspection["contentType"] = "text/calendar"

    contentType = inspection.get("contentType", None)

    if contentType:
        contentType = contentType.split(";")[0]

    if inspection["calendar"]:  # CalDAV collection

        if not ticket and account is None:
            # Create a new account
            account = WebDAVAccount(itsView=view)
            account.displayName = url
            account.host = host
            account.path = parentPath
            account.useSSL = useSSL
            account.port = port
            if username is not None:
                account.username = username
            if password is not None:
                account.password = Password(itsParent=account)
                waitForDeferred(account.password.encryptPassword(password))

        collection = subscribeCalDAV(
            view,
            url,
            inspection,
            activity=activity,
            account=account,
            parentPath=parentPath,
            shareName=shareName,
            ticket=ticket,
            username=username,
            password=password,
            filters=filters,
        )
        return collection

    elif inspection["collection"]:  # WebDAV collection

        if not ticket and account is None:
            # Create a new account
            account = WebDAVAccount(itsView=view)
            account.displayName = url
            account.host = host
            account.path = parentPath
            account.useSSL = useSSL
            account.port = port
            if username is not None:
                account.username = username
            if password is not None:
                account.password = Password(itsParent=account)
                waitForDeferred(account.password.encryptPassword(password))

        collection = subscribeWebDAV(
            view,
            url,
            inspection,
            activity=activity,
            account=account,
            parentPath=parentPath,
            shareName=shareName,
            ticket=ticket,
            username=username,
            password=password,
            filters=filters,
        )
        return collection

    elif contentType == "text/html":
        # parse the webpage for embedded link to real url
        text = blockingGetPage(view, url, username=username, password=password)

        # blockingGetPage needs to raise Forbidden exception, right?

        if text:
            links = extractLinks(text)

            selfUrl = links["self"]
            if selfUrl is not None:
                if selfUrl.endswith("forbidden"):
                    raise NotAllowed(_(u"You don't have permission to access this collection."))

                davUrl = links["alternate"].get("text/html", None)
                if davUrl:
                    davUrl = urlparse.urlunparse((parsedUrl.scheme, parsedUrl.netloc, davUrl, "", "", ""))

                morsecodeUrl = links["alternate"].get("text/xml", None)
                if morsecodeUrl:
                    morsecodeUrl = urlparse.urlunparse((parsedUrl.scheme, parsedUrl.netloc, morsecodeUrl, "", "", ""))

                if davUrl and morsecodeUrl:

                    collection = subscribeMorsecode(
                        view,
                        url,
                        morsecodeUrl,
                        inspection,
                        activity=activity,
                        account=account,
                        username=username,
                        password=password,
                        filters=filters,
                    )
                    return collection

            # See if this was a "pim/collection" URL, and try the "mc" version
            try:
                index = url.index("pim/collection")
                url = url.replace("pim/collection", "mc/collection", 1)

                collection = subscribeMorsecode(
                    view,
                    url,
                    url,
                    inspection,
                    activity=activity,
                    account=account,
                    username=username,
                    password=password,
                    filters=filters,
                )
                return collection

            except ValueError:
                # oh well, I can't find subscription information
                pass

        raise errors.WebPageParseError("Can't parse web page")

    elif contentType == "text/calendar":

        # monolithic .ics file
        collection = subscribeICS(
            view,
            url,
            inspection,
            activity=activity,
            account=account,
            parentPath=parentPath,
            shareName=shareName,
            ticket=ticket,
            username=username,
            password=password,
            filters=filters,
        )
        return collection

    elif contentType == "application/eim+xml":

        # Note: For now we won't allow a subscription to a morsecode url
        # with no ticket and no pre-existing CosmoAccount set up,
        # since creation of a CosmoAccount item requires handshaking
        # with the server; we can add this later if needed

        # morsecode + eimml recordsets
        collection = subscribeMorsecode(
            view,
            url,
            url,
            inspection,
            activity=activity,
            account=account,
            username=username,
            password=password,
            filters=filters,
        )
        return collection

    else:
        # unknown
        raise errors.SharingError("Unknown content type")
Example #46
0
def subscribeICS(
    view,
    url,
    inspection,
    activity=None,
    account=None,
    parentPath=None,
    shareName=None,
    ticket=None,
    username=None,
    password=None,
    filters=None,
):

    share = Share(itsView=view)

    (scheme, useSSL, host, port, ignore, query, ignore, ignore, ignore, ignore) = splitUrl(url)

    if not account and not ticket and username:
        # Create a new account
        account = WebDAVAccount(itsView=view)
        account.displayName = url
        account.host = host
        account.path = parentPath
        account.useSSL = useSSL
        account.port = port
        account.username = username
        if password:
            account.password = Password(itsParent=account)
            waitForDeferred(account.password.encryptPassword(password))

    if account:
        share.conduit = WebDAVMonolithicRecordSetConduit(
            itsParent=share,
            shareName=shareName,
            account=account,
            translator=SharingTranslator,
            serializer=ICSSerializer,
        )

    else:
        share.conduit = WebDAVMonolithicRecordSetConduit(
            itsParent=share,
            host=host,
            port=port,
            sharePath=parentPath,
            shareName=shareName,
            useSSL=useSSL,
            translator=SharingTranslator,
            serializer=ICSSerializer,
        )
        if query:
            share.conduit.shareName += "?%s" % query
        # Not setting share.conduit.ticket here because we'll just include it
        # in the URL during get/put

    share.mode = "both" if inspection["priv:write"] else "get"
    if filters:
        share.conduit.filters = filters

    if activity:
        activity.update(msg=_(u"Subscribing to calendar..."))

    share.get(activity=activity)

    try:
        SharedItem(share.contents).shares.append(share, "main")
    except ValueError:
        # There is already a 'main' share for this collection
        SharedItem(share.contents).shares.append(share)

    return share.contents
    def RoundTrip(self):

        filename = "tmp_dump_file"

        view0 = self.views[0]
        view1 = self.views[1]

        # uuids to dump; add your items to this:
        uuids = set()

        # Prepare test data

        coll0 = pim.SmartCollection("testCollection",
                                    itsView=view0,
                                    displayName="Test Collection")
        uuids.add(coll0.itsUUID)

        titles = [
            u"dunder",
            u"mifflin",
        ]

        tzinfo = view0.tzinfo.floating
        createdOn = datetime.datetime(2007, 3, 1, 10, 0, 0, 0, tzinfo)
        lastModified = datetime.datetime(2007, 3, 1, 12, 0, 0, 0, tzinfo)
        email = "*****@*****.**"
        emailAddress = pim.EmailAddress.getEmailAddress(view0, email)

        count = len(titles)
        for i in xrange(count):
            n = pim.Note(itsView=view0)
            n.createdOn = createdOn
            n.displayName = titles[i % count]
            n.body = u"Here is the body"
            n.lastModifiedBy = emailAddress
            n.lastModified = lastModified
            coll0.add(n)
            uuids.add(n.itsUUID)

        # Read/unread items
        readNote = pim.Note(itsView=view0, read=True)
        unreadNote = pim.Note(itsView=view0, read=False)

        # "Private" items
        publicNote = pim.Note(itsView=view0, private=False)
        privateNote = pim.Note(itsView=view0, private=True)

        # Mine/Not-Mine/Dashboard

        directlyInDashboard = pim.Note(itsView=view0)
        dashboard = schema.ns("osaf.pim", view0).allCollection
        dashboard.add(directlyInDashboard)

        aMineCollection = pim.SmartCollection(itsView=view0)
        schema.ns('osaf.pim', view0).mine.addSource(aMineCollection)
        inMine = pim.Note(itsView=view0)
        aMineCollection.add(inMine)

        aNotMineCollection = pim.SmartCollection(itsView=view0)
        inNotMine = pim.Note(itsView=view0)
        aNotMineCollection.add(inNotMine)

        trash = schema.ns("osaf.pim", view0).trashCollection
        trashTestCollection = pim.SmartCollection(itsView=view0)
        trashedItem = pim.Note(itsView=view0)
        trashTestCollection.add(trashedItem)
        trash.add(trashedItem)
        self.assert_(trashedItem in trashTestCollection.inclusions)
        self.assert_(trashedItem not in trashTestCollection)
        self.assert_(trashedItem in trash)

        # Sharing related items
        account0 = sharing.CosmoAccount(itsView=view0,
                                        host="chandler.o11n.org",
                                        port=8080,
                                        path="/cosmo",
                                        username="******",
                                        password=Password(itsView=view0),
                                        useSSL=True)
        waitForDeferred(account0.password.encryptPassword('4cc0unt0'))
        uuids.add(account0.itsUUID)
        cosmo_conduit0 = sharing.CosmoConduit(
            itsView=view0,
            account=account0,
            shareName=coll0.itsUUID.str16(),
            translator=sharing.SharingTranslator,
            serializer=sharing.EIMMLSerializer)
        uuids.add(cosmo_conduit0.itsUUID)
        cosmo_share0 = sharing.Share(itsView=view0,
                                     contents=coll0,
                                     conduit=cosmo_conduit0)
        uuids.add(cosmo_share0.itsUUID)

        hub_account0 = sharing.HubAccount(
            itsView=view0,
            username="******",
            password=Password(itsView=view0),
        )
        waitForDeferred(hub_account0.password.encryptPassword('4cc0unt0'))
        uuids.add(hub_account0.itsUUID)

        inmemory_conduit0 = sharing.InMemoryDiffRecordSetConduit(
            itsView=view0,
            shareName="in_memory",
            translator=sharing.SharingTranslator,
            serializer=sharing.EIMMLSerializer)
        uuids.add(inmemory_conduit0.itsUUID)

        inmemory_share0 = sharing.Share(itsView=view0,
                                        conduit=inmemory_conduit0,
                                        contents=coll0)
        uuids.add(inmemory_share0.itsUUID)

        # Create some State objects
        inmemory_share0.create()
        view0.commit()
        inmemory_share0.sync()
        for state in inmemory_share0.states:
            uuids.add(state.itsUUID)
        # Set one of the states to be a pendingRemoval
        pendingRemoval = state.itsUUID
        state.pendingRemoval = True

        # Peer states
        peerNote = pim.Note(itsView=view0)
        peerAddress = pim.EmailAddress(
            itsView=view0,
            fullName="Michael Scott",
            emailAddress="*****@*****.**")
        peerState = sharing.State(
            itsView=view0,
            conflictFor=peerNote,
            peer=peerAddress,
        )
        sharing.SharedItem(peerNote).add()
        sharedPeerNote = sharing.SharedItem(peerNote)
        sharedPeerNote.peerStates = []
        sharedPeerNote.peerStates.append(peerState,
                                         peerAddress.itsUUID.str16())
        uuids.add(peerNote.itsUUID)
        uuids.add(peerAddress.itsUUID)
        uuids.add(peerState.itsUUID)

        # Sharing proxy
        proxy = sharing.getProxy(view0)
        proxy.host = "host"
        proxy.port = 123
        proxy.username = "******"
        proxy.passwd = "password"
        proxy.active = True
        proxy.useAuth = True
        proxy.bypass = "******"
        uuids.add(proxy.itsUUID)

        # Online state
        schema.ns('osaf.app', view0).prefs.isOnline = False
        schema.ns('osaf.sharing', view0).prefs.isOnline = False

        #Mail Accounts

        imapAddress = mail.EmailAddress.getEmailAddress(
            view0, "*****@*****.**", "test")

        popAddress = mail.EmailAddress.getEmailAddress(view0, "*****@*****.**",
                                                       "test1")

        smtpOldAddress = mail.EmailAddress.getEmailAddress(
            view0, "*****@*****.**", "test2")

        smtpNewAddress = mail.EmailAddress.getEmailAddress(
            view0, "*****@*****.**", "test3")

        testFolder = mail.IMAPFolder(itsView=view0,
                                     displayName="TestFolder",
                                     folderName="INBOX.TestFolder",
                                     folderType="MAIL")

        queuedMessage0 = pim.MailStamp(pim.Note(itsView=view0))
        queuedMessage0.add()

        queuedMessage0.subject = "Test for SMTP Queue"

        uuids.add(queuedMessage0.itsItem.itsUUID)

        imapaccount0 = mail.IMAPAccount(
            itsView=view0,
            displayName="IMAP Test",
            host="localhost",
            port=143,
            username="******",
            password=Password(itsView=view0),
            connectionSecurity="TLS",
            numRetries=2,
            pollingFrequency=300,
            isActive=False,
            replyToAddress=imapAddress,
            folders=[testFolder],
        )
        waitForDeferred(imapaccount0.password.encryptPassword('imap4acc0unt0'))

        uuids.add(imapaccount0.itsUUID)

        popaccount0 = mail.POPAccount(
            itsView=view0,
            displayName="POP Test",
            host="localhost",
            port=110,
            username="******",
            password=Password(itsView=view0),
            connectionSecurity="NONE",
            numRetries=3,
            pollingFrequency=200,
            isActive=True,
            replyToAddress=popAddress,
        )
        waitForDeferred(popaccount0.password.encryptPassword('pop4acc0unt0'))

        uuids.add(popaccount0.itsUUID)

        smtpaccount0 = mail.SMTPAccount(
            itsView=view0,
            displayName="SMTP Test",
            host="localhost",
            port=587,
            username="******",
            password=Password(itsView=view0),
            connectionSecurity="SSL",
            numRetries=5,
            pollingFrequency=500,
            isActive=True,
            fromAddress=smtpOldAddress,
            useAuth=True,
            messageQueue=[queuedMessage0.itsItem],
        )
        waitForDeferred(smtpaccount0.password.encryptPassword('smtp4acc0unt0'))

        # This orphans smtpOldAddress leaving it as
        # an old me address which is stored in the
        # meEmailAddressCollection.
        # The purpose of this is to test dump and reload
        # of the meEmailAddressCollection.
        smtpaccount0.fromAddress = smtpNewAddress

        uuids.add(smtpaccount0.itsUUID)

        #Take the mail service offline
        schema.ns("osaf.pim", view0).MailPrefs.isOnline = False

        # Calendar prefs
        pref = schema.ns('osaf.pim', view0).TimezonePrefs
        pref.showUI = True  # change from default
        pref.showPrompt = False  # change from default

        pref = schema.ns('osaf.framework.blocks.calendar', view0).calendarPrefs
        pref.hourHeightMode = "auto"
        pref.visibleHours = 20

        # TODO: TimeZoneInfo

        # passwords
        pw = Password(itsView=view0)
        waitForDeferred(pw.encryptPassword('foobar'))
        uuids.add(pw.itsUUID)
        # password prefs
        mpwPrefs = schema.ns("osaf.framework.MasterPassword",
                             view0).masterPasswordPrefs
        MasterPassword._change('', 'secret', view0, mpwPrefs)
        mpwPrefs.timeout = 10

        # backup on quit preference
        backupPrefs = schema.ns("osaf.app", view0).prefs
        self.assertFalse(hasattr(backupPrefs, 'backupOnQuit'))
        backupPrefs.backupOnQuit = True

        # tip of the day prefs
        self.assertFalse(backupPrefs.showTip)
        self.assertEqual(backupPrefs.tipIndex, 0)
        backupPrefs.tipIndex = 1

        # Ensure sidebar is loaded in view1
        sidebar1 = schema.ns("osaf.app", view1).sidebarCollection

        try:

            dumpreload.dump(view0, filename)
            dumpreload.reload(view1, filename, testmode=True)

            # Ensure the items are now in view1
            for uuid in uuids:
                item0 = view0.findUUID(uuid)
                item1 = view1.findUUID(uuid)

                self.assert_(item1 is not None)
                if hasattr(item0, 'displayName'):
                    self.assertEqual(item0.displayName, item1.displayName)
                if hasattr(item0, 'body'):
                    self.assertEqual(item0.body, item1.body)

            # Verify ContentItem.read
            self.assert_(view1.findUUID(readNote.itsUUID).read is True)
            self.assert_(view1.findUUID(unreadNote.itsUUID).read is False)

            # Verify ContentItem.private
            self.assert_(view1.findUUID(publicNote.itsUUID).private is False)
            self.assert_(view1.findUUID(privateNote.itsUUID).private is True)

            # Verify Mine/Not-Mine/Dashboard
            dashboard = schema.ns("osaf.pim", view1).allCollection
            self.assert_(
                view1.findUUID(directlyInDashboard.itsUUID) in
                dashboard.inclusions)

            self.assert_(view1.findUUID(inMine.itsUUID) in dashboard)
            self.assert_(view1.findUUID(inNotMine.itsUUID) not in dashboard)

            # Verify collection membership:
            coll1 = view1.findUUID(coll0.itsUUID)
            for item0 in coll0:
                item1 = view1.findUUID(item0.itsUUID)
                self.assert_(item1 in coll1)

            # Verify trash membership
            trash = schema.ns("osaf.pim", view1).trashCollection
            trashedItem = view1.findUUID(trashedItem.itsUUID)
            self.assert_(trashedItem in trash)
            trashTestCollection = view1.findUUID(trashTestCollection.itsUUID)
            self.assert_(trashedItem not in trashTestCollection)
            self.assert_(trashedItem in trashTestCollection.inclusions)

            # Verify passwords
            pw1 = view1.findUUID(pw.itsUUID)
            self.assertEqual(waitForDeferred(pw1.decryptPassword('secret')),
                             'foobar')

            mpwPrefs1 = schema.ns("osaf.framework.MasterPassword",
                                  view1).masterPasswordPrefs
            self.assertEqual(mpwPrefs1.masterPassword, True)
            self.assertEqual(mpwPrefs1.timeout, 10)

            pwPrefs1 = schema.ns("osaf.framework.password",
                                 view1).passwordPrefs
            self.assertEqual(
                len(
                    waitForDeferred(
                        pwPrefs1.dummyPassword.decryptPassword('secret'))), 16)
            self.assertEqual(str(pwPrefs1.dummyPassword.itsUUID),
                             'dd555441-9ddc-416c-b55a-77b073c7bd15')
            dummyByUUID = view1.findUUID(
                'dd555441-9ddc-416c-b55a-77b073c7bd15')
            self.assertEqual(dummyByUUID, pwPrefs1.dummyPassword)

            count = 0
            for item in Password.iterItems(view0):
                waitForDeferred(item.decryptPassword('secret'))
                count += 1

            count1 = 0
            for item in Password.iterItems(view1):
                waitForDeferred(item.decryptPassword('secret'))
                count1 += 1

            self.assertEqual(count + 2, count1)  # XXX Shouldn't count==count1?

            # Verify sharing
            account1 = view1.findUUID(account0.itsUUID)
            self.assertEquals(account1.host, "chandler.o11n.org")
            self.assertEquals(account1.port, 8080)
            self.assertEquals(account1.path, "/cosmo")
            self.assertEquals(account1.username, "test")
            self.assertEquals(account1.useSSL, True)
            self.assertEquals(
                waitForDeferred(account1.password.decryptPassword('secret')),
                '4cc0unt0')

            hub_account1 = view1.findUUID(hub_account0.itsUUID)
            self.assert_(isinstance(hub_account0, sharing.HubAccount))

            inmemory_share1 = view1.findUUID(inmemory_share0.itsUUID)
            self.assert_(inmemory_share1 is not None)
            self.assertEqual(inmemory_share0.contents.itsUUID,
                             inmemory_share1.contents.itsUUID)
            self.assertEqual(inmemory_share0.conduit.syncToken,
                             inmemory_share1.conduit.syncToken)
            for state0 in inmemory_share0.states:
                state1 = view1.findUUID(state0.itsUUID)
                self.assert_(state1 in inmemory_share1.states)
                self.assertEqual(state0.agreed, state1.agreed)
                self.assertEqual(state0.pending, state1.pending)
                self.assertEqual(state1.pendingRemoval,
                                 state1.itsUUID == pendingRemoval)
            for item0 in coll0:
                item1 = view1.findUUID(item0.itsUUID)
                sharedItem1 = sharing.SharedItem(item1)
                self.assert_(inmemory_share1 in sharedItem1.sharedIn)

            # Peer states
            peerNote1 = view1.findUUID(peerNote.itsUUID)
            sharedPeerNote1 = sharing.SharedItem(peerNote1)
            peerAddress1 = view1.findUUID(peerAddress.itsUUID)
            peerState1 = view1.findUUID(peerState.itsUUID)
            self.assert_(peerState1 in sharedPeerNote1.peerStates)
            self.assertEquals(sharedPeerNote1.peerStates.getAlias(peerState1),
                              peerAddress1.itsUUID.str16())
            self.assert_(peerState1 in sharedPeerNote1.conflictingStates)
            self.assert_(isinstance(peerAddress1, pim.EmailAddress))

            proxy1 = view1.findUUID(proxy.itsUUID)
            self.assertEquals(proxy1.host, "host")
            self.assertEquals(proxy1.port, 123)
            self.assertEquals(proxy1.username, "username")
            self.assertEquals(proxy1.bypass, "192.168.1, localhost")

            pw = waitForDeferred(proxy1.password.decryptPassword('secret'))
            self.assertEquals(pw, "password")
            self.assertEquals(proxy1.active, True)
            self.assertEquals(proxy1.useAuth, True)

            self.assertEquals(
                schema.ns('osaf.app', view1).prefs.isOnline, False)
            self.assertEquals(
                schema.ns('osaf.sharing', view1).prefs.isOnline, False)

            # Verify Calendar prefs
            pref = schema.ns('osaf.pim', view1).TimezonePrefs
            self.assertEqual(pref.showUI, True)
            self.assertEqual(pref.showPrompt, False)

            pref = schema.ns('osaf.framework.blocks.calendar',
                             view1).calendarPrefs
            self.assertEqual(pref.hourHeightMode, "auto")
            self.assertEqual(pref.visibleHours, 20)

            #Verify Mail Accounts

            imapaccount1 = view1.findUUID(imapaccount0.itsUUID)
            self.assertEquals(imapaccount1.host, "localhost")
            self.assertEquals(imapaccount1.port, 143)
            self.assertEquals(imapaccount1.username, "test")
            self.assertEquals(imapaccount1.connectionSecurity, "TLS")
            self.assertEquals(imapaccount1.numRetries, 2)
            self.assertEquals(imapaccount1.pollingFrequency, 300)
            self.assertEquals(imapaccount1.isActive, False)
            self.assertEquals(imapaccount1.replyToAddress.format(),
                              imapAddress.format())
            self.assertEquals(
                waitForDeferred(
                    imapaccount1.password.decryptPassword('secret')),
                'imap4acc0unt0')

            folder = imapaccount1.folders.first()
            self.assertEquals(folder.displayName, "TestFolder")
            self.assertEquals(folder.folderName, "INBOX.TestFolder")
            self.assertEquals(folder.folderType, "MAIL")

            popaccount1 = view1.findUUID(popaccount0.itsUUID)

            self.assertEquals(popaccount1.host, "localhost")
            self.assertEquals(popaccount1.port, 110)
            self.assertEquals(popaccount1.username, "test1")
            self.assertEquals(popaccount1.connectionSecurity, "NONE")
            self.assertEquals(popaccount1.numRetries, 3)
            self.assertEquals(popaccount1.pollingFrequency, 200)
            self.assertEquals(popaccount1.isActive, True)
            self.assertEquals(popaccount1.replyToAddress.format(),
                              popAddress.format())
            self.assertEquals(
                waitForDeferred(
                    popaccount1.password.decryptPassword('secret')),
                'pop4acc0unt0')

            smtpaccount1 = view1.findUUID(smtpaccount0.itsUUID)

            self.assertEquals(smtpaccount1.host, "localhost")
            self.assertEquals(smtpaccount1.port, 587)
            self.assertEquals(smtpaccount1.username, "test2")
            self.assertEquals(smtpaccount1.connectionSecurity, "SSL")
            self.assertEquals(smtpaccount1.numRetries, 5)
            self.assertEquals(smtpaccount1.pollingFrequency, 500)
            self.assertEquals(smtpaccount1.isActive, True)
            self.assertEquals(smtpaccount1.useAuth, True)
            self.assertEquals(smtpaccount1.fromAddress.format(),
                              smtpNewAddress.format())
            self.assertEquals(
                waitForDeferred(
                    smtpaccount1.password.decryptPassword('secret')),
                'smtp4acc0unt0')

            queuedMessage1 = smtpaccount1.messageQueue[0]

            self.assertEquals(queuedMessage1.itsUUID,
                              queuedMessage0.itsItem.itsUUID)
            self.assertEquals(
                schema.ns("osaf.pim", view1).MailPrefs.isOnline, False)

            col = schema.ns("osaf.pim", view1).meEmailAddressCollection

            found = False
            oldAddr = smtpOldAddress.format()

            # Confirm that the old email address smtpOldAddress
            # is in the meEmailAddressCollection for calculating
            # the MailStamp.fromMe and MailStamp.toMe attributes
            for ea in col:
                if ea.format() == oldAddr:
                    found = True
                    break

            self.assertTrue(found)

            # backup on quit preference
            backupPrefs1 = schema.ns("osaf.app", view1).prefs
            self.assertTrue(backupPrefs1.backupOnQuit)

            # tip of the day prefs
            self.assertFalse(backupPrefs1.showTip)
            self.assertEqual(backupPrefs1.tipIndex, 1)

        finally:
            try:
                os.remove(filename)
            except:
                pass
Example #48
0
                #log.exception('This should not happen')
                return (0, (CANT_CONNECT, _(u"SSL error.")))

        except M2Crypto.SSL.Checker.WrongHost, err:
            result = (2, None)
            # Send the message to destroy the progress dialog first. This needs
            # to be done in this order on Linux because otherwise killing
            # the progress dialog will also kill the SSL error dialog.
            # Weird, huh? Welcome to the world of wx...
            callMethodInUIThread(self.callback, result)
            d = ssl.askIgnoreSSLError(err.expectedHost,
                                      err.pem,
                                      messages.SSL_HOST_MISMATCH % \
                                        {'actualHost': err.actualHost},
                                      self.reconnect)
            waitForDeferred(d)

            return result

        except M2Crypto.BIO.BIOError, err:
            return (0, (CANT_CONNECT, str(err)))

        except zanshin.webdav.ConnectionError, err:
            return (0, (CANT_CONNECT, err.message))

        except zanshin.webdav.WebDAVError, err:
            return (0, (NO_ACCESS, err.status))

        except error.SSLError, err:
            return (0, (CANT_CONNECT, err)) # Unhandled SSL error