예제 #1
0
    def register(self, manager, stanza):
        # TODO some checking would be nice :)
        fields = stanza.query.x.elements(uri='jabber:x:data', name='field')
        var_phone = None
        var_code = None
        var_pkey = None

        for f in fields:
            if f['var'] == 'phone':
                var_phone = f
            elif f['var'] == 'code':
                var_code = f
            elif f['var'] == 'publickey':
                var_pkey = f

        # validation code request
        if var_phone:

            def _bad_phone():
                e = error.StanzaError('bad-request', 'modify',
                                      'Bad phone number.')
                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                return manager.send(iq, True)

            n = var_phone.value.__str__().encode('utf-8')

            # validate phone number syntax
            if not n or len(n.strip()) == 0:
                log.debug("number empty - %s" % n)
                return _bad_phone()

            phone = phone_num = n.strip()
            # exclude the initial plus to verify the digits
            if (phone[0] == '+'):
                phone_num = phone[1:]

            # not all digits...
            if not phone_num.isdigit():
                log.debug("number is not all-digits - %s" % phone_num)
                return _bad_phone()

            # replace double-zero with plus
            if phone[0:2] == '00':
                phone = '+' + phone[2:]

            # generate userid
            userid = util.sha1(phone)
            d = self.component.validationdb.register(userid)

            def _continue(code, stanza, phone):
                status = self.send_sms(phone, code)

                if status:
                    # send response with sms sender number
                    iq = xmlstream.toResponse(stanza, 'result')
                    query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query'))
                    query.addElement((None, 'instructions'),
                                     content=self.ack_instructions)

                    form = query.addElement(('jabber:x:data', 'x'))
                    form['type'] = 'form'

                    hidden = form.addElement((None, 'field'))
                    hidden['type'] = 'hidden'
                    hidden['var'] = 'FORM_TYPE'
                    hidden.addElement((None, 'value'),
                                      content=xmlstream2.NS_IQ_REGISTER)

                    phone = form.addElement((None, 'field'))
                    phone['type'] = 'text-single'
                    phone['label'] = 'SMS sender'
                    phone['var'] = 'from'
                    phone.addElement((None, 'value'),
                                     content=self.config['from'])

                else:
                    # send error
                    iq = xmlstream.toResponse(stanza, 'error')
                    e = error.StanzaError('not-acceptable', 'modify',
                                          'Unable to send SMS.')
                    iq.addChild(e.getElement())

                return manager.send(iq, True)

            def _error(failure, stanza):
                log.debug("error: %s" % (failure, ))
                if isinstance(failure.value, oursql.IntegrityError):
                    # duplicate key of userid: throttling
                    e = error.StanzaError('service-unavailable', 'wait',
                                          'Too many attempts.')
                else:
                    e = error.StanzaError('service-unavailable', 'cancel',
                                          failure.getErrorMessage())

                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                manager.send(iq, True)

            d.addCallback(_continue, stanza, phone)
            d.addErrback(_error, stanza)

        # code validation + public key
        elif var_code and var_pkey:
            # check validation code from database
            code = var_code.value.__str__().encode('utf-8')
            d = self.component.validationdb.validate(code)

            def _continue(userid):
                pkey = base64.b64decode(
                    var_pkey.value.__str__().encode('utf-8'))
                signed_pkey = manager.link_public_key(pkey, userid)
                if signed_pkey:
                    iq = xmlstream.toResponse(stanza, 'result')
                    query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query'))

                    form = query.addElement(('jabber:x:data', 'x'))
                    form['type'] = 'form'

                    hidden = form.addElement((None, 'field'))
                    hidden['type'] = 'hidden'
                    hidden['var'] = 'FORM_TYPE'
                    hidden.addElement(
                        (None, 'value'),
                        content='http://kontalk.org/protocol/register#code')

                    signed = form.addElement((None, 'field'))
                    signed['type'] = 'text-single'
                    signed['label'] = 'Signed public key'
                    signed['var'] = 'publickey'
                    signed.addElement((None, 'value'),
                                      content=base64.b64encode(signed_pkey))

                    return manager.send(iq, True)

                else:
                    e = error.StanzaError('bad-request', 'modify',
                                          'Invalid public key.')
                    iq = xmlstream.toResponse(stanza, 'error')
                    iq.addChild(e.getElement())
                    manager.send(iq, True)

            def _error(failure):
                log.debug("error: %s" % (failure, ))
                if isinstance(failure.value, RuntimeError):
                    e = error.StanzaError('bad-request', 'modify',
                                          failure.getErrorMessage())
                else:
                    e = error.StanzaError('service-unavailable', 'cancel',
                                          failure.getErrorMessage())
                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                manager.send(iq, True)

            d.addCallback(_continue)
            d.addErrback(_error)

        else:
            e = error.StanzaError(
                'bad-request', 'modify',
                'Please provider phone number and public key or verification code.'
            )
            iq = xmlstream.toResponse(stanza, 'error')
            iq.addChild(e.getElement())
            manager.send(iq, True)
예제 #2
0
 def test_sha1(self):
     text = 'test data'
     data = util.sha1(text)
     self.assertEqual(data, 'f48dd853820860816c75d54d0f584dc863327a7c')
예제 #3
0
 def test_sha1(self):
     text = 'test data'
     data = util.sha1(text)
     self.assertEqual(data, 'f48dd853820860816c75d54d0f584dc863327a7c')
예제 #4
0
    def register(self, manager, stanza):
        # TODO some checking would be nice :)
        fields = stanza.query.x.elements(uri='jabber:x:data', name='field')
        var_phone = None
        var_code = None
        var_pkey = None

        for f in fields:
            if f['var'] == 'phone':
                var_phone = f
            elif f['var'] == 'code':
                var_code = f
            elif f['var'] == 'publickey':
                var_pkey = f

        # validation code request
        if var_phone:
            def _bad_phone():
                e = error.StanzaError('bad-request', 'modify', 'Bad phone number.')
                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                return manager.send(iq, True)

            n = var_phone.value.__str__().encode('utf-8')

            # validate phone number syntax
            if not n or len(n.strip()) == 0:
                log.debug("number empty - %s" % n)
                return _bad_phone()

            phone = phone_num = n.strip()
            # exclude the initial plus to verify the digits
            if (phone[0] == '+'):
                phone_num = phone[1:]

            # not all digits...
            if not phone_num.isdigit():
                log.debug("number is not all-digits - %s" % phone_num)
                return _bad_phone()

            # replace double-zero with plus
            if phone[0:2] == '00':
                phone = '+' + phone[2:]

            # generate userid
            userid = util.sha1(phone)
            d = self.component.validationdb.register(userid)

            def _continue(code, stanza, phone):
                status = self.send_sms(phone, code)

                if status:
                    # send response with sms sender number
                    iq = xmlstream.toResponse(stanza, 'result')
                    query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query'))
                    query.addElement((None, 'instructions'), content=self.ack_instructions)

                    form = query.addElement(('jabber:x:data', 'x'))
                    form['type'] = 'form'

                    hidden = form.addElement((None, 'field'))
                    hidden['type'] = 'hidden'
                    hidden['var'] = 'FORM_TYPE'
                    hidden.addElement((None, 'value'), content=xmlstream2.NS_IQ_REGISTER)

                    phone = form.addElement((None, 'field'))
                    phone['type'] = 'text-single'
                    phone['label'] = 'SMS sender'
                    phone['var'] = 'from'
                    phone.addElement((None, 'value'), content=self.config['from'])

                else:
                    # send error
                    iq = xmlstream.toResponse(stanza, 'error')
                    e = error.StanzaError('not-acceptable', 'modify', 'Unable to send SMS.')
                    iq.addChild(e.getElement())

                return manager.send(iq, True)

            def _error(failure, stanza):
                log.debug("error: %s" % (failure, ))
                if isinstance(failure.value, oursql.IntegrityError):
                    # duplicate key of userid: throttling
                    e = error.StanzaError('service-unavailable', 'wait', 'Too many attempts.')
                else:
                    e = error.StanzaError('service-unavailable', 'cancel', failure.getErrorMessage())

                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                manager.send(iq, True)

            d.addCallback(_continue, stanza, phone)
            d.addErrback(_error, stanza)

        # code validation + public key
        elif var_code and var_pkey:
            # check validation code from database
            code = var_code.value.__str__().encode('utf-8')
            d = self.component.validationdb.validate(code)

            def _continue(userid):
                pkey = base64.b64decode(var_pkey.value.__str__().encode('utf-8'))
                signed_pkey = manager.link_public_key(pkey, userid)
                if signed_pkey:
                    iq = xmlstream.toResponse(stanza, 'result')
                    query = iq.addElement((xmlstream2.NS_IQ_REGISTER, 'query'))

                    form = query.addElement(('jabber:x:data', 'x'))
                    form['type'] = 'form'

                    hidden = form.addElement((None, 'field'))
                    hidden['type'] = 'hidden'
                    hidden['var'] = 'FORM_TYPE'
                    hidden.addElement((None, 'value'), content='http://kontalk.org/protocol/register#code')

                    signed = form.addElement((None, 'field'))
                    signed['type'] = 'text-single'
                    signed['label'] = 'Signed public key'
                    signed['var'] = 'publickey'
                    signed.addElement((None, 'value'), content=base64.b64encode(signed_pkey))

                    return manager.send(iq, True)

                else:
                    e = error.StanzaError('bad-request', 'modify', 'Invalid public key.')
                    iq = xmlstream.toResponse(stanza, 'error')
                    iq.addChild(e.getElement())
                    manager.send(iq, True)

            def _error(failure):
                log.debug("error: %s" % (failure, ))
                if isinstance(failure.value, RuntimeError):
                    e = error.StanzaError('bad-request', 'modify', failure.getErrorMessage())
                else:
                    e = error.StanzaError('service-unavailable', 'cancel', failure.getErrorMessage())
                iq = xmlstream.toResponse(stanza, 'error')
                iq.addChild(e.getElement())
                manager.send(iq, True)

            d.addCallback(_continue)
            d.addErrback(_error)

        else:
            e = error.StanzaError('bad-request', 'modify', 'Please provider phone number and public key or verification code.')
            iq = xmlstream.toResponse(stanza, 'error')
            iq.addChild(e.getElement())
            manager.send(iq, True)