def verify_twitter(oauth_verifier, eth_address): # Verify authenticity of user if 'request_token' not in session: raise TwitterVerificationError('Session not found.') oauth = OAuth1( settings.TWITTER_CONSUMER_KEY, settings.TWITTER_CONSUMER_SECRET, session['request_token']['oauth_token'], session['request_token']['oauth_token_secret'], verifier=oauth_verifier) r = requests.post(url=twitter_access_token_url, auth=oauth) if r.status_code != 200: raise TwitterVerificationError( 'The verifier you provided is invalid.') # TODO: determine what the text should be data = 'twitter verified' # TODO: determine claim type integer code for phone verification signature = attestations.generate_signature( signing_key, eth_address, CLAIM_TYPES['twitter'], data) attestation = Attestation( method=AttestationTypes.TWITTER, eth_address=eth_address, signature=signature ) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['twitter'], 'data': data })
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 verify_facebook(code, eth_address): base_url = 'graph.facebook.com' client_id = settings.FACEBOOK_CLIENT_ID client_secret = settings.FACEBOOK_CLIENT_SECRET redirect_uri = urls.absurl("/redirects/facebook/") code = code path = ('/v2.12/oauth/access_token?client_id={}' '&client_secret={}&redirect_uri={}&code={}').format( client_id, client_secret, redirect_uri, code) conn = http.client.HTTPSConnection(base_url) conn.request('GET', path) response = json.loads(conn.getresponse().read()) has_access_token = ('access_token' in response) if not has_access_token or 'error' in response: raise FacebookVerificationError( 'The code you provided is invalid.') # TODO: determine what the text should be data = 'facebook verified' # TODO: determine claim type integer code for phone verification signature = attestations.generate_signature(signing_key, eth_address, CLAIM_TYPES['facebook'], data) return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['facebook'], 'data': data })
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_airbnb(eth_address, airbnbUserId): validate_airbnb_user_id(airbnbUserId) code = get_airbnb_verification_code(eth_address, airbnbUserId) # TODO: determine if this user agent is acceptable. # We need to set an user agent otherwise Airbnb returns 403 request = Request( url='https://www.airbnb.com/users/show/' + airbnbUserId, headers={'User-Agent': 'Origin Protocol client-0.1.0'} ) try: response = urlopen(request) except HTTPError as e: if e.code == 404: raise AirbnbVerificationError( 'Airbnb user id: ' + airbnbUserId + ' not found.') else: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") except URLError as e: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") if code not in response.read().decode('utf-8'): raise AirbnbVerificationError( "Origin verification code: " + code + " has not been found in user's Airbnb profile." ) # TODO: determine the schema for claim data data = 'airbnbUserId:' + airbnbUserId signature = attestations.generate_signature( signing_key, eth_address, CLAIM_TYPES['airbnb'], data ) attestation = Attestation( method=AttestationTypes.AIRBNB, eth_address=eth_address, value=airbnbUserId, signature=signature ) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['airbnb'], 'data': data })
def verify_facebook(code, eth_address): base_url = "https://graph.facebook.com" response = requests.get("{}/v2.12/oauth/access_token".format(base_url), params={ "client_id": settings.FACEBOOK_CLIENT_ID, "client_secret": settings.FACEBOOK_CLIENT_SECRET, "redirect_uri": urls.absurl("/redirects/facebook/"), "code": code }) if "access_token" not in response.json() or "error" in response.json(): if "error" in response.json(): logger.error(response.json()["error"]) raise FacebookVerificationError( "The code you provided is invalid.") access_token = response.json()["access_token"] response = requests.get("{}/me".format(base_url), params={"access_token": access_token}) # TODO: determine what the text should be data = 'facebook verified' # TODO: determine claim type integer code for phone verification signature = attestations.generate_signature(signing_key, eth_address, CLAIM_TYPES['facebook'], data) attestation = Attestation(method=AttestationTypes.FACEBOOK, eth_address=eth_address, value=response.json()['name'], signature=signature, remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['facebook'], 'data': data })
def verify_twitter(oauth_verifier, eth_address): ipfs_helper = IPFSHelper() # Verify authenticity of user if 'request_token' not in session: raise TwitterVerificationError('Session not found.') oauth = OAuth1(settings.TWITTER_CONSUMER_KEY, settings.TWITTER_CONSUMER_SECRET, session['request_token']['oauth_token'], session['request_token']['oauth_token_secret'], verifier=oauth_verifier) response = requests.post(url=twitter_access_token_url, auth=oauth) try: response.raise_for_status() except requests.exceptions.HTTPError as exc: logger.exception(exc) raise TwitterVerificationError( 'The verifier you provided is invalid.') query_string = urllib.parse.parse_qs(response.content) screen_name = query_string[b'screen_name'][0].decode('utf-8') ipfs_hash = ipfs_helper.add_json({ 'schemaId': 'https://schema.originprotocol.com/twitter-attestation_1.0.0.json', 'screen_name': screen_name }) signature = attestations.generate_signature(signing_key, eth_address, TOPICS['twitter'], base58_to_hex(ipfs_hash)) attestation = Attestation(method=AttestationTypes.TWITTER, eth_address=eth_address, value=screen_name, signature=signature, remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': TOPICS['twitter'], 'data': ipfs_hash })
def verify_twitter(oauth_verifier, eth_address): # Verify authenticity of user if 'request_token' not in session: raise TwitterVerificationError('Session not found.') oauth = OAuth1(settings.TWITTER_CONSUMER_KEY, settings.TWITTER_CONSUMER_SECRET, session['request_token']['oauth_token'], session['request_token']['oauth_token_secret'], verifier=oauth_verifier) response = requests.post(url=twitter_access_token_url, auth=oauth) try: response.raise_for_status() except requests.exceptions.HTTPError as exc: logger.exception(exc) raise TwitterVerificationError( 'The verifier you provided is invalid.') # TODO: determine what the text should be data = 'twitter verified' # TODO: determine claim type integer code for phone verification signature = attestations.generate_signature(signing_key, eth_address, CLAIM_TYPES['twitter'], data) query_string = urllib.parse.parse_qs(response.content) screen_name = query_string[b'screen_name'][0].decode('utf-8') attestation = Attestation(method=AttestationTypes.TWITTER, eth_address=eth_address, value=screen_name, signature=signature, remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['twitter'], '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 verify_airbnb(eth_address, airbnbUserId): validate_airbnb_user_id(airbnbUserId) code = get_airbnb_verification_code(eth_address, airbnbUserId) try: # TODO: determine if this user agent is acceptable. # We need to set an user agent otherwise Airbnb returns 403 response = urlopen( Request( url='https://www.airbnb.com/users/show/' + airbnbUserId, headers={'User-Agent': 'Origin Protocol client-0.1.0'})) except HTTPError as e: if e.code == 404: raise AirbnbVerificationError('Airbnb user id: ' + airbnbUserId + ' not found.') else: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") except URLError as e: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") if code not in response.read().decode('utf-8'): raise AirbnbVerificationError( "Origin verification code: " + code + " has not been found in user's Airbnb profile.") data = { 'issuer': ISSUER, 'issueDate': current_time(), 'attestation': { 'verificationMethod': { 'pubAuditableUrl': {} }, 'site': { 'siteName': 'airbnb.com', 'userId': { 'raw': airbnbUserId } } } } # 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.AIRBNB, eth_address=eth_address, value=airbnbUserId, 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 })
def verify_twitter(oauth_verifier, eth_address): # Verify authenticity of user if 'request_token' not in session: raise TwitterVerificationError('Session not found.') oauth = OAuth1(settings.TWITTER_CONSUMER_KEY, settings.TWITTER_CONSUMER_SECRET, session['request_token']['oauth_token'], session['request_token']['oauth_token_secret'], verifier=oauth_verifier) response = requests.post(url=twitter_access_token_url, auth=oauth) try: response.raise_for_status() except requests.exceptions.HTTPError as exc: logger.exception(exc) raise TwitterVerificationError( 'The verifier you provided is invalid.') query_string = urllib.parse.parse_qs(response.content) screen_name = query_string[b'screen_name'][0].decode('utf-8') data = { 'issuer': ISSUER, 'issueDate': current_time(), 'attestation': { 'verificationMethod': { 'oAuth': True }, 'site': { 'siteName': 'twitter.com', 'userId': { 'raw': screen_name } } } } # 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.TWITTER, eth_address=eth_address, value=screen_name, 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, })
def verify_facebook(code, eth_address): base_url = "https://graph.facebook.com" response = requests.get("{}/v2.12/oauth/access_token".format(base_url), params={ "client_id": settings.FACEBOOK_CLIENT_ID, "client_secret": settings.FACEBOOK_CLIENT_SECRET, "redirect_uri": urls.absurl("/redirects/facebook/"), "code": code }) if "access_token" not in response.json() or "error" in response.json(): if "error" in response.json(): logger.error(response.json()["error"]) raise FacebookVerificationError( "The code you provided is invalid.") access_token = response.json()["access_token"] response = requests.get("{}/me".format(base_url), params={"access_token": access_token}) data = { 'issuer': ISSUER, 'issueDate': current_time(), 'attestation': { 'verificationMethod': { 'oAuth': True }, 'site': { 'siteName': 'facebook.com', 'userId': { '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.FACEBOOK, eth_address=eth_address, value=response.json()['name'], 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 })
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 })
def verify_phone(country_calling_code, phone, code, eth_address): """Check a phone verification code against the Twilio Verify API for a phone number. Args: country_calling_code (str): Dialling prefix for the country. phone (str): Phone number in national format. code (int): Verification code for the country_calling_code and phone combination eth_address (str): ETH address of the user Returns: VerificationServiceResponse Raises: ValidationError: Verification request failed due to invalid arguments PhoneVerificationError: Verification request failed for a reason not related to the arguments """ method = session.get('phone_verification_method', None) if method not in ['sms', 'call']: raise ValidationError('Invalid phone verification method ', method) params = { 'country_code': country_calling_code, 'phone_number': phone, 'verification_code': code } headers = {'X-Authy-API-Key': settings.TWILIO_VERIFY_API_KEY} url = 'https://api.authy.com/protected/json/phones/verification/check' response = requests.get(url, params=params, headers=headers) try: response.raise_for_status() except requests.exceptions.HTTPError as exc: logger.exception(exc) if response.json()['error_code'] == '60023': # This error code could also mean that no phone verification was ever # created for that country calling code and phone number raise ValidationError('Verification code has expired.', field_names=['code']) elif response.json()['error_code'] == '60022': raise ValidationError('Verification code is incorrect.', field_names=['code']) else: raise PhoneVerificationError( 'Could not verify code. Please try again shortly.') # This may be unnecessary because the response has a 200 status code # but it a good precaution to handle any inconsistency between the # success field and the status code if response.json()['success'] is True: data = { 'issuer': ISSUER, 'issueDate': current_time(), 'attestation': { 'verificationMethod': { method: True }, 'phone': { '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.PHONE, eth_address=eth_address, value="{} {}".format( country_calling_code, phone), signature=signature['bytes'], remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() session.pop('phone_verification_method') return VerificationServiceResponse({ 'schemaId': 'https://schema.originprotocol.com/attestation_1.0.0.json', 'data': data, 'signature': signature }) raise PhoneVerificationError( 'Could not verify code. Please try again shortly.')
def verify_phone(country_calling_code, phone, code, eth_address): """Check a phone verification code against the Twilio Verify API for a phone number. Args: country_calling_code (str): Dialling prefix for the country. phone (str): Phone number in national format. code (int): Verification code for the country_calling_code and phone combination eth_address (str): Address of ERC725 identity token for claim Returns: VerificationServiceResponse Raises: ValidationError: Verification request failed due to invalid arguments PhoneVerificationError: Verification request failed for a reason not related to the arguments """ params = { 'country_code': country_calling_code, 'phone_number': phone, 'verification_code': code } headers = { 'X-Authy-API-Key': settings.TWILIO_VERIFY_API_KEY } url = 'https://api.authy.com/protected/json/phones/verification/check' response = requests.get(url, params=params, headers=headers) try: response.raise_for_status() except requests.exceptions.HTTPError as exc: if response.json()['error_code'] == '60023': # This error code could also mean that no phone verification was ever # created for that country calling code and phone number raise ValidationError('Verification code has expired.', field_names=['code']) elif response.json()['error_code'] == '60022': raise ValidationError('Verification code is incorrect.', field_names=['code']) else: raise PhoneVerificationError( 'Could not verify code. Please try again shortly.' ) # This may be unnecessary because the response has a 200 status code # but it a good precaution to handle any inconsistency between the # success field and the status code if response.json()['success'] is True: # 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 ) attestation = Attestation( method=AttestationTypes.PHONE, eth_address=eth_address, value="{} {}".format(country_calling_code, phone), signature=signature ) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': CLAIM_TYPES['phone'], 'data': data }) raise PhoneVerificationError( 'Could not verify code. Please try again shortly.' )
def verify_airbnb(eth_address, airbnbUserId): ipfs_helper = IPFSHelper() validate_airbnb_user_id(airbnbUserId) code = get_airbnb_verification_code(eth_address, airbnbUserId) try: # TODO: determine if this user agent is acceptable. # We need to set an user agent otherwise Airbnb returns 403 response = urlopen( Request( url='https://www.airbnb.com/users/show/' + airbnbUserId, headers={'User-Agent': 'Origin Protocol client-0.1.0'})) except HTTPError as e: if e.code == 404: raise AirbnbVerificationError('Airbnb user id: ' + airbnbUserId + ' not found.') else: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") except URLError as e: raise AirbnbVerificationError( "Can not fetch user's Airbnb profile.") if code not in response.read().decode('utf-8'): raise AirbnbVerificationError( "Origin verification code: " + code + " has not been found in user's Airbnb profile.") ipfs_hash = ipfs_helper.add_json({ 'schemaId': 'https://schema.originprotocol.com/airbnb-attestation_1.0.0.json', 'airbnb_user_id': airbnbUserId }) """ - IPFS hash is a base58 encoded string - We store IPFS hashes in solidity claims in bytes32 binary format to minimise gas cost. - bytes32 is not string serialisable so it can not be transmitted in that form from bridge to the DApp - bridge needs to transform ipfs hash to bytes32 format (that is how it is going to be stored in the contract) before signing the claim, and then send IPFS hash to the DApp in base58 string encoding. - this way claim has a correct signature if IPFS hash has bytes32 hex encoding - the DApp takes signature and other claim info and transforms the base58 encoded IPFS hash to base32 hex before submitting the claim to web3. """ signature = attestations.generate_signature(signing_key, eth_address, TOPICS['airbnb'], base58_to_hex(ipfs_hash)) attestation = Attestation(method=AttestationTypes.AIRBNB, eth_address=eth_address, value=airbnbUserId, signature=signature, remote_ip_address=request.remote_addr) db.session.add(attestation) db.session.commit() return VerificationServiceResponse({ 'signature': signature, 'claim_type': TOPICS['airbnb'], 'data': ipfs_hash })