def generate_phone_verification_code(phone):
        phone = normalize_number(phone)

        db_code = VC.query \
            .filter(VC.phone == phone) \
            .first()
        if db_code is None:
            db_code = db_models.VerificationCode()
            db.session.add(db_code)
        elif (time_.utcnow() - db_code.updated_at).total_seconds() < 10:
            # If the client has requested a verification code already within
            # the last 10 seconds,
            # throw a rate limit error, so they can't just keep creating codes
            # and guessing them
            # rapidly.
            raise PhoneVerificationError(
                'Please wait briefly before requesting'
                ' a new verification code.')
        db_code.phone = phone
        db_code.code = random_numeric_token()
        db_code.expires_at = time_.utcnow() + datetime.timedelta(
            minutes=CODE_EXPIRATION_TIME_MINUTES)
        db.session.commit()
        try:
            send_code_via_sms(phone, db_code.code)
        except TwilioRestException as e:
            db.session.rollback()
            raise PhoneVerificationError('Could not send'
                                         ' verification code.')
        return VerificationServiceResponse()
Esempio n. 2
0
 def verify_phone(self, req):
     addr = numeric_eth(req.eth_address)
     db_code = VC.query \
         .filter(VC.eth_address == addr) \
         .filter(VC.phone == req.phone) \
         .first()
     if db_code is None:
         raise service_utils.req_error(
             code='NOT_FOUND',
             path='phone',
             message='The given phone number was not found.')
     if req.code != db_code.code:
         raise service_utils.req_error(
             code='INVALID',
             path='code',
             message='The code you provided is invalid.')
     if time_.utcnow() > db_code.expires_at:
         raise service_utils.req_error(
             code='EXPIRED',
             path='code',
             message='The code you provided has expired.')
     db_identity = db_models.Identity(eth_address=addr,
                                      phone=req.phone,
                                      verified=True)
     db.session.add(db_identity)
     db.session.commit()
     return verification.VerifyPhoneResponse(
         attestation=generate_signed_attestation(addr))
    def verify_phone(phone, code, eth_address):
        phone = normalize_number(phone)

        db_code = VC.query \
            .filter(VC.phone == phone) \
            .first()
        if db_code is None:
            raise PhoneVerificationError(
                'The given phone number was not found.')
        if code != db_code.code:
            raise PhoneVerificationError('The code you provided'
                                         ' is invalid.')
        if time_.utcnow() > db_code.expires_at:
            raise PhoneVerificationError('The code you provided'
                                         ' has expired.')
        # TODO: determine what the text should be
        data = 'phone verified'
        # TODO: determine claim type integer code for phone verification
        signature = attestations.generate_signature(signing_key, eth_address,
                                                    CLAIM_TYPES['phone'], data)
        return VerificationServiceResponse({
            'signature': signature,
            'claim_type': CLAIM_TYPES['phone'],
            'data': data
        })
 def generate_email_verification_code(email):
     db_code = VC.query \
         .filter(func.lower(VC.email) == func.lower(email)) \
         .first()
     if db_code is None:
         db_code = db_models.VerificationCode()
         db.session.add(db_code)
     elif (time_.utcnow() - db_code.updated_at).total_seconds() < 10:
         # If the client has requested a verification code already within
         # the last 10 seconds, throw a rate limit error, so they can't just
         # keep creating codes and guessing them rapidly.
         raise EmailVerificationError(
             'Please wait briefly before requesting'
             ' a new verification code.')
     db_code.email = email
     db_code.code = random_numeric_token()
     db_code.expires_at = time_.utcnow() + datetime.timedelta(
         minutes=CODE_EXPIRATION_TIME_MINUTES)
     db.session.commit()
     send_code_via_email(email, db_code.code)
     return VerificationServiceResponse()
Esempio n. 5
0
def test_generate_phone_verification_rate_limit_exceeded(
        session, mock_normalize_number):
    vc_obj = VerificationCodeFactory.build()
    vc_obj.updated_at = utcnow() + datetime.timedelta(seconds=9)
    session.add(vc_obj)
    session.commit()

    phone = vc_obj.phone
    with pytest.raises(PhoneVerificationError) as service_err:
        VerificationService.generate_phone_verification_code(phone)
    assert str(service_err.value) == ('Please wait briefly before requesting a'
                                      ' new verification code.')
Esempio n. 6
0
def test_generate_email_verification_code_email_already_in_db(
        MockHttpClient, session):
    vc_obj = VerificationCodeFactory.build()
    expires_at = vc_obj.expires_at
    vc_obj.created_at = utcnow() - datetime.timedelta(seconds=10)
    vc_obj.updated_at = utcnow() - datetime.timedelta(seconds=10)
    session.add(vc_obj)
    session.commit()

    email = vc_obj.email
    resp = VerificationService.generate_email_verification_code(email)
    assert isinstance(resp, VerificationServiceResponse)

    assert VC.query.filter(VC.email == email).count() == 1
    db_code = VC.query.filter(VC.email == email).first()
    assert db_code is not None
    assert db_code.code is not None
    assert len(db_code.code) == 6
    assert db_code.expires_at is not None
    assert db_code.created_at is not None
    assert db_code.updated_at is not None
    assert db_code.updated_at >= db_code.created_at
    assert db_code.expires_at > expires_at
Esempio n. 7
0
 def generate_phone_verification_code(self, req):
     addr = numeric_eth(req.eth_address)
     db_code = VC.query \
         .filter(VC.eth_address == addr) \
         .first()
     if db_code is None:
         db_code = db_models.VerificationCode(eth_address=addr)
         db.session.add(db_code)
     elif (time_.utcnow() - db_code.updated_at).total_seconds() < 10:
         # If the client has requested a verification code already within the last 10 seconds,
         # throw a rate limit error, so they can't just keep creating codes and guessing them
         # rapidly.
         raise service_utils.req_error(
             code='RATE_LIMIT_EXCEEDED',
             message=
             'Please wait briefly before requesting a new verification code.'
         )
     db_code.phone = req.phone
     db_code.code = random_numeric_token()
     db_code.expires_at = time_.utcnow() + datetime.timedelta(
         minutes=CODE_EXPIRATION_TIME_MINUTES)
     db.session.commit()
     send_code_via_sms(req.phone, db_code.code)
     return verification.GeneratePhoneVerificationCodeResponse()
Esempio n. 8
0
def test_verify_phone_expired_code(session, mock_normalize_number):
    vc_obj = VerificationCodeFactory.build()
    vc_obj.expires_at = utcnow() - datetime.timedelta(days=1)
    session.add(vc_obj)
    session.commit()

    args = {
        'eth_address': str_eth(sample_eth_address),
        'phone': vc_obj.phone,
        'code': vc_obj.code
    }
    with pytest.raises(PhoneVerificationError) as service_err:
        VerificationService.verify_phone(**args)

    assert str(service_err.value) == 'The code you provided has expired.'
Esempio n. 9
0
def test_generate_phone_verification_code_phone_already_in_db(
        mock_send_sms, session, mock_normalize_number):
    vc_obj = VerificationCodeFactory.build()
    expires_at = vc_obj.expires_at
    vc_obj.created_at = utcnow() - datetime.timedelta(seconds=10)
    vc_obj.updated_at = utcnow() - datetime.timedelta(seconds=10)
    session.add(vc_obj)
    session.commit()

    phone = vc_obj.phone
    resp = VerificationService.generate_phone_verification_code(phone)
    assert isinstance(resp, VerificationServiceResponse)

    assert VC.query.filter(VC.phone == phone).count() == 1

    db_code = VC.query.filter(VC.phone == phone).first()
    assert db_code is not None
    assert db_code.code is not None
    assert len(db_code.code) == 6
    assert db_code.expires_at is not None
    assert db_code.created_at is not None
    assert db_code.updated_at is not None
    assert db_code.updated_at >= db_code.created_at
    assert db_code.expires_at > expires_at
Esempio n. 10
0
    def verify_email(email, code, eth_address):
        db_code = VC.query \
            .filter(func.lower(VC.email) == func.lower(email)) \
            .first()
        if db_code is None:
            raise EmailVerificationError('The given email was' ' not found.')
        if code != db_code.code:
            raise EmailVerificationError('The code you provided'
                                         ' is invalid.')
        if time_.utcnow() > db_code.expires_at:
            raise EmailVerificationError('The code you provided'
                                         ' has expired.')

        # TODO: determine what the text should be
        data = 'email verified'
        # TODO: determine claim type integer code for email verification
        signature = attestations.generate_signature(signing_key, eth_address,
                                                    CLAIM_TYPES['email'], data)
        return VerificationServiceResponse({
            'signature': signature,
            'claim_type': CLAIM_TYPES['email'],
            'data': data
        })
Esempio n. 11
0
def get_future_expiry():
    return utcnow() + datetime.timedelta(seconds=20)