def verify_email(email, code, eth_address): """Check a email verification code against the verification code stored in the session for that email. Args: email (str): Email address being verified code (int): Verification code for the email address eth_address (str): Address of ERC725 identity token for claim Returns: VerificationServiceResponse Raises: ValidationError: Verification request failed due to invalid arguments """ verification_obj = session.get('email_attestation', None) if not verification_obj: raise EmailVerificationError('No verification code was found.') if not check_password_hash(verification_obj['email'], email): raise EmailVerificationError( 'No verification code was found for that email.' ) if verification_obj['expiry'] < datetime.datetime.utcnow(): raise ValidationError('Verification code has expired.', 'code') if verification_obj['code'] != code: raise ValidationError('Verification code is incorrect.', 'code') session.pop('email_attestation') # 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 ) attestation = Attestation( method=AttestationTypes.EMAIL, eth_address=eth_address, value=email, signature=signature ) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['email'], 'data': data })
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 })
def send_email_verification(email): """Send a verification code to an email address using the SendGrid API. The verification code and the expiry are stored in a server side session to compare against user input. Args: email (str): Email address to send the verification to Raises: ValidationError: Verification request failed due to invalid arguments EmailVerificationError: Verification request failed for a reason not related to the arguments """ verification_code = str(randint(100000, 999999)) # Save the verification code and expiry in a server side session session['email_attestation'] = { 'email': generate_password_hash(email), 'code': verification_code, 'expiry': datetime.datetime.utcnow() + datetime.timedelta(minutes=30) } # Build the email containing the verification code from_email = Email(settings.SENDGRID_FROM_EMAIL) to_email = Email(email) subject = 'Your Origin Verification Code' message = 'Your Origin verification code is {}.'.format( verification_code) message += ' It will expire in 30 minutes.' content = Content('text/plain', message) mail = Mail(from_email, subject, to_email, content) try: _send_email_using_sendgrid(mail) except Exception as exc: logger.exception(exc) # SendGrid does not have its own error types but might in the future # See https://github.com/sendgrid/sendgrid-python/issues/315 raise EmailVerificationError( 'Could not send verification code. Please try again shortly.') return VerificationServiceResponse()
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()
def verify_email(email, code, eth_address): """Check a email verification code against the verification code stored in the session for that email. Args: email (str): Email address being verified code (int): Verification code for the email address eth_address (str): ETH address of the user Returns: VerificationServiceResponse Raises: ValidationError: Verification request failed due to invalid arguments """ verification_obj = session.get('email_attestation', None) if not verification_obj: raise EmailVerificationError('No verification code was found.') if not check_password_hash(verification_obj['email'], email): raise EmailVerificationError( 'No verification code was found for that email.') if verification_obj['expiry'] < datetime.datetime.utcnow(): raise ValidationError('Verification code has expired.', 'code') if verification_obj['code'] != code: raise ValidationError('Verification code is incorrect.', 'code') session.pop('email_attestation') data = { 'issuer': ISSUER, 'issueDate': current_time(), 'attestation': { 'verificationMethod': { 'email': True }, 'email': { 'verified': True } } } # Note: use sort_keys option to make the output deterministic for hashing purposes. json_data = json.dumps(data, separators=(',', ':'), sort_keys=True) signature = { 'bytes': attestations.generate_signature(signing_key, eth_address, json_data), 'version': '1.0.0' } attestation = Attestation(method=AttestationTypes.EMAIL, eth_address=eth_address, value=email, signature=signature['bytes'], remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'schemaId': 'https://schema.originprotocol.com/attestation_1.0.0.json', 'data': data, 'signature': signature })