def decorated_function(*args, **kwargs): # Create an instance of the RequestValidator class validator = RequestValidator(app.config['TWILIO_AUTH_TOKEN']) # Validate the request using its URL, POST data, # and X-TWILIO-SIGNATURE header request_valid = validator.validate( request.url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '') ) # Some services, like Glitch or ngrok, don't maintain the `https` scheme # when proxying requests to our app. So if the request seemed invalid # on our first try, try again with an https version of the URL if not request_valid: request_valid = validator.validate( request.url.replace('http://', 'https://'), request.form, request.headers.get('X-TWILIO-SIGNATURE', '') ) # Continue processing the request if it's valid (or we're in development # or testing). Otherwise, return a 403 error if it's not if request_valid or app.config['TESTING'] return f(*args, **kwargs) else: return abort(403)
def decorated_function(*args, **kwargs): # Create an instance of the RequestValidator class validator = RequestValidator(tw_auth_token) # validator = RequestValidator(tw_api_secret) # Validate the request using its URL, POST data, # and X_TWILIO_SIGNATURE header logging.info(request.url) if not ('ngrok' in str(request.url)): request_valid = validator.validate( str(request.url).replace('http', 'https'), request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) else: request_valid = validator.validate( # str(request.url), str(request.url).replace('http', 'https'), request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) # Continue processing the request if it's valid, # return a 403 error if it's not if request_valid: return f(*args, **kwargs) else: logging.warning("Signature invalid") logging.info(request.url) logging.info(request.headers) return abort(403)
class ValidationTest(unittest.TestCase): def setUp(self): token = "12345" self.validator = RequestValidator(token) self.uri = "https://mycompany.com/myapp.php?foo=1&bar=2" self.params = { "CallSid": "CA1234567890ABCDE", "Digits": "1234", "From": "+14158675309", "To": "+18005551212", "Caller": "+14158675309", } self.expected = "RSOYDt4T1cUTdK1PDd93/VVr8B8=" self.body = "{\"property\": \"value\", \"boolean\": true}" self.bodyHash = "Ch/3Y02as7ldtcmi3+lBbkFQKyg6gMfPGWMmMvluZiA=" self.encodedBodyHash = self.bodyHash.replace("+", "%2B").replace( "=", "%3D") self.uriWithBody = self.uri + "&bodySHA256=" + self.encodedBodyHash def test_compute_signature_bytecode(self): expected = b(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=False) assert_equal(signature, expected) def test_compute_signature_unicode(self): expected = u(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=True) assert_equal(signature, expected) def test_compute_hash_bytecode(self): expected = b(self.bodyHash) body_hash = self.validator.compute_hash(self.body, utf=False) assert_equal(expected, body_hash) def test_compute_hash_unicode(self): expected = u(self.bodyHash) body_hash = self.validator.compute_hash(self.body, utf=True) assert_equal(expected, body_hash) def test_validation(self): assert_true( self.validator.validate(self.uri, self.params, self.expected)) def test_validation_removes_port_on_https(self): uri = self.uri.replace(".com", ".com:1234") assert_true(self.validator.validate(uri, self.params, self.expected)) def test_validation_of_body_succeeds(self): uri = self.uriWithBody is_valid = self.validator.validate(uri, self.body, "afcFvPLPYT8mg/JyIVkdnqQKa2s=") assert_true(is_valid)
class ValidationTest(unittest.TestCase): def setUp(self): token = "1c892n40nd03kdnc0112slzkl3091j20" self.validator = RequestValidator(token) self.uri = "http://www.postbin.org/1ed898x" self.params = { "AccountSid": "AC9a9f9392lad99kla0sklakjs90j092j3", "ApiVersion": "2010-04-01", "CallSid": "CAd800bb12c0426a7ea4230e492fef2a4f", "CallStatus": "ringing", "Called": "+15306384866", "CalledCity": "OAKLAND", "CalledCountry": "US", "CalledState": "CA", "CalledZip": "94612", "Caller": "+15306666666", "CallerCity": "SOUTH LAKE TAHOE", "CallerCountry": "US", "CallerName": "CA Wireless Call", "CallerState": "CA", "CallerZip": "89449", "Direction": "inbound", "From": "+15306666666", "FromCity": "SOUTH LAKE TAHOE", "FromCountry": "US", "FromState": "CA", "FromZip": "89449", "To": "+15306384866", "ToCity": "OAKLAND", "ToCountry": "US", "ToState": "CA", "ToZip": "94612", } def test_compute_signature_bytecode(self): expected = b("fF+xx6dTinOaCdZ0aIeNkHr/ZAA=") signature = self.validator.compute_signature(self.uri, self.params, utf=False) assert_equal(signature, expected) def test_compute_signature_unicode(self): expected = u("fF+xx6dTinOaCdZ0aIeNkHr/ZAA=") signature = self.validator.compute_signature(self.uri, self.params, utf=True) assert_equal(signature, expected) def test_validation(self): expected = "fF+xx6dTinOaCdZ0aIeNkHr/ZAA=" assert_true(self.validator.validate(self.uri, self.params, expected)) def test_validation_removes_port_on_https(self): self.uri = "https://www.postbin.org:1234/1ed898x" expected = "Y7MeICc5ECftd1G11Fc8qoxAn0A=" assert_true(self.validator.validate(self.uri, self.params, expected))
def decorator(request_or_self, *args, **kwargs): # When using `method_decorator` on class methods, # I haven't been able to get any class views. # i would like more research before just taking the check out. class_based_view = not isinstance(request_or_self, HttpRequest) if not class_based_view: request = request_or_self else: assert len(args) >= 1 request = args[0] # Turn off Twilio authentication when explicitly requested, or # in debug mode. Otherwise things do not work properly. For # more information, see the docs. use_forgery_protection = getattr( settings, 'DJANGO_TWILIO_FORGERY_PROTECTION', not settings.DEBUG, ) if use_forgery_protection: if request.method not in ['GET', 'POST']: return HttpResponseNotAllowed(request.method) # Forgery check try: validator = RequestValidator(TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() if request.method == 'POST': if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() if request.method == 'GET': if not validator.validate(url, request.GET, signature): return HttpResponseForbidden() # Blacklist check, by default is true check_blacklist = getattr( settings, 'DJANGO_TWILIO_BLACKLIST_CHECK', True ) if check_blacklist: blacklisted_resp = get_blacklisted_response(request) if blacklisted_resp: return blacklisted_resp response = f(request_or_self, *args, **kwargs) if isinstance(response, (text_type, bytes)): return HttpResponse(response, content_type='application/xml') elif isinstance(response, Verb): return HttpResponse(str(response), content_type='application/xml') else: return response
class ValidationTest(unittest.TestCase): def setUp(self): token = "12345" self.validator = RequestValidator(token) self.uri = "https://mycompany.com/myapp.php?foo=1&bar=2" self.params = { "CallSid": "CA1234567890ABCDE", "Digits": "1234", "From": "+14158675309", "To": "+18005551212", "Caller": "+14158675309", } self.expected = "RSOYDt4T1cUTdK1PDd93/VVr8B8=" self.body = "{\"property\": \"value\", \"boolean\": true}" self.bodyHash = "Ch/3Y02as7ldtcmi3+lBbkFQKyg6gMfPGWMmMvluZiA=" self.encodedBodyHash = self.bodyHash.replace("+", "%2B").replace("=", "%3D") self.uriWithBody = self.uri + "&bodySHA256=" + self.encodedBodyHash def test_compute_signature_bytecode(self): expected = b(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=False) assert_equal(signature, expected) def test_compute_signature_unicode(self): expected = u(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=True) assert_equal(signature, expected) def test_compute_hash_bytecode(self): expected = b(self.bodyHash) body_hash = self.validator.compute_hash(self.body, utf=False) assert_equal(expected, body_hash) def test_compute_hash_unicode(self): expected = u(self.bodyHash) body_hash = self.validator.compute_hash(self.body, utf=True) assert_equal(expected, body_hash) def test_validation(self): assert_true(self.validator.validate(self.uri, self.params, self.expected)) def test_validation_removes_port_on_https(self): uri = self.uri.replace(".com", ".com:1234") assert_true(self.validator.validate(uri, self.params, self.expected)) def test_validation_of_body_succeeds(self): uri = self.uriWithBody is_valid = self.validator.validate(uri, self.body, "afcFvPLPYT8mg/JyIVkdnqQKa2s=") assert_true(is_valid)
def validate(request, url): request_meta_data = dict() validator = RequestValidator(token) print(url) url = url + "/" + "sms" for key_item in request.form: request_meta_data[key_item] = request.form[key_item] twilio_signature = request.headers.get("X-Twilio-Signature", None) print(twilio_signature) print(request_meta_data) print(validator.validate(url, request_meta_data, twilio_signature)) return (validator.validate(url, request_meta_data, twilio_signature))
class ValidationTest(unittest.TestCase): def setUp(self): token = "12345" self.validator = RequestValidator(token) self.uri = "https://mycompany.com/myapp.php?foo=1&bar=2" self.params = { "CallSid": "CA1234567890ABCDE", "Digits": "1234", "From": "+14158675309", "To": "+18005551212", "Caller": "+14158675309", } self.expected = "RSOYDt4T1cUTdK1PDd93/VVr8B8=" self.body = "{\"property\": \"value\", \"boolean\": true}" self.bodyHash = "0a1ff7634d9ab3b95db5c9a2dfe9416e41502b283a80c7cf19632632f96e6620" self.uriWithBody = self.uri + "&bodySHA256=" + self.bodyHash def test_compute_signature_bytecode(self): expected = b(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=False) assert_equal(signature, expected) def test_compute_signature(self): expected = (self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=True) assert_equal(signature, expected) def test_compute_hash_unicode(self): expected = u(self.bodyHash) body_hash = self.validator.compute_hash(self.body) assert_equal(expected, body_hash) def test_validation(self): assert_true( self.validator.validate(self.uri, self.params, self.expected)) def test_validation_removes_port_on_https(self): uri = self.uri.replace(".com", ".com:1234") assert_true(self.validator.validate(uri, self.params, self.expected)) def test_validation_of_body_succeeds(self): uri = self.uriWithBody is_valid = self.validator.validate(uri, self.body, "a9nBmqA0ju/hNViExpshrM61xv4=") assert_true(is_valid)
class ValidationTest(unittest.TestCase): def setUp(self): token = "12345" self.validator = RequestValidator(token) self.uri = "https://mycompany.com/myapp.php?foo=1&bar=2" self.params = { "CallSid": "CA1234567890ABCDE", "Digits": "1234", "From": "+14158675309", "To": "+18005551212", "Caller": "+14158675309", } self.expected = "RSOYDt4T1cUTdK1PDd93/VVr8B8=" self.body = "{\"property\": \"value\", \"boolean\": true}" self.bodyHash = "0a1ff7634d9ab3b95db5c9a2dfe9416e41502b283a80c7cf19632632f96e6620" self.uriWithBody = self.uri + "&bodySHA256=" + self.bodyHash def test_compute_signature_bytecode(self): expected = b(self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=False) assert_equal(signature, expected) def test_compute_signature(self): expected = (self.expected) signature = self.validator.compute_signature(self.uri, self.params, utf=True) assert_equal(signature, expected) def test_compute_hash_unicode(self): expected = u(self.bodyHash) body_hash = self.validator.compute_hash(self.body) assert_equal(expected, body_hash) def test_validation(self): assert_true(self.validator.validate(self.uri, self.params, self.expected)) def test_validation_removes_port_on_https(self): uri = self.uri.replace(".com", ".com:1234") assert_true(self.validator.validate(uri, self.params, self.expected)) def test_validation_of_body_succeeds(self): uri = self.uriWithBody is_valid = self.validator.validate(uri, self.body, "a9nBmqA0ju/hNViExpshrM61xv4=") assert_true(is_valid)
def answeredby(request): # build validator manually because decorator not working logger.info(request.build_absolute_uri()) twilio_request = decompose(request) validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) # Validate the request using its URL, POST data, # and X-TWILIO-SIGNATURE header request_valid = validator.validate( request.build_absolute_uri(), request.POST, request.META.get('HTTP_X_TWILIO_SIGNATURE', '')) if not request_valid: return HttpResponseForbidden() outbound = Outbound.objects.get(twilio_sid=twilio_request.callsid) response = VoiceResponse() if twilio_request.answeredby in ['human', 'unknown']: response.play(outbound.action.audio_file.url) else: response.hangup() outbound.answered_by = twilio_request.answeredby outbound.save() return HttpResponse(response)
def lambda_handler(event, context): print("received: " + str(event)) # if twilioSignature exists and message from authorized number, create a validator & a dictionary of received data if u'twilioSignature' in event and u'Body' in event and event[ 'From'] == os.environ['MY_NUMBER']: form_parameters = { key: urllib.parse.unquote_plus(value) for key, value in event.items() if key != u'twilioSignature' } validator = RequestValidator(os.environ['AUTH_TOKEN']) # validate api call is from twilio request_valid = validator.validate(os.environ['REQUEST_URL'], form_parameters, event[u'twilioSignature']) # if request valid, authenticate tweepy and send tweet if request_valid: auth = tweepy.OAuthHandler(os.environ['API_KEY'], os.environ['API_SECRET']) auth.set_access_token(os.environ['ACCESS_TOKEN'], os.environ['ACCESS_SECRET']) api = tweepy.API(auth) msg = form_parameters['Body'] api.update_status(msg) return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' \ '<Response><Message>Request Received, OK!</Message></Response>' # if request is not from twilio, give appropriate response else: return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' \ '<Response><Message>Nice Try...</Message></Response>'
def twilio_webhook_handler(event, context): """Receive request from Twilio and passes through to a topic.""" print("Received event: " + str(event)) null_response = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' + \ '<Response></Response>' # Trap no X-Twilio-Signature Header if u'twilioSignature' not in event: return null_response form_parameters = { k: urllib.unquote_plus(v) for k, v in event.items() if k != u'twilioSignature' } validator = RequestValidator(os.environ['AUTH_TOKEN']) request_valid = validator.validate(os.environ['REQUEST_URL'], form_parameters, event[u'twilioSignature']) # Trap invalid requests not from Twilio if not request_valid: return null_response # Trap fields missing if u'Body' not in form_parameters or u'To' not in form_parameters \ or u'From' not in form_parameters: return null_response # Don't let through messages with > 160 characters if len(form_parameters['Body']) > 160: return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' + \ '<Response><Message>Keep it under 160!</Message></Response>' # Now we package up the From, To, and Body field and publish it to the # 'twilio' topic (or whatever you have set). Boto3 lets us easily publish # to any topic in a particular region, but ensure you have correctly set # permissions for the role. 'iot:Publish' needs to be included for these # next lines to work. aws_region = os.environ['AWS_IOT_REGION'] aws_topic = os.environ['AWS_TOPIC'] client = boto3.client('iot-data', region_name=aws_region) client.publish(topic=aws_topic, qos=0, payload=json.dumps({ "To": form_parameters[u'To'], "From": form_parameters[u'From'], "Body": form_parameters[u'Body'], "Type": "Incoming" })) # A blank response informs Twilio not to take any actions. # Since we are reacting asynchronously, if we are to respond # it will come through a different channel. # # Even though we aren't responding to the webhook directly, this will all # happen very quickly. return null_response
def sms_handler(request): """Entry point function for HTTP triggered Google Cloud Functions call. This function is triggered by a Twilio SMS webhook (POST). Args: - request (flask.Request): A Flask request. Returns: - (None) """ firestore = init_firestore() # validate request from Twilio validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"]) request_valid = validator.validate( request.url, request.form, request.headers.get("X-TWILIO-SIGNATURE", "")) if not request_valid: # request is not valid, do nothing print("request is not valid") return params = request.form body = params["Body"].lower().strip() if body == "no": add_unallowed_pair(firestore, params)
def decorator(request, *args, **kwargs): # When using `method_decorator` on class methods, # I haven't been able to get any class views. # i would like more research before just taking the check out. # Forgery check try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() # Blacklist check, by default is true # check_blacklist = getattr( # settings, # 'DJANGO_TWILIO_BLACKLIST_CHECK', # True # ) # if check_blacklist: # blacklisted_resp = get_blacklisted_response(request) # if blacklisted_resp: # return blacklisted_resp response = f(request, *args, **kwargs) return response
class TwilioClient: def __init__(self, account_sid, auth_token): self.client = Client(account_sid, auth_token) self.request_validator = RequestValidator(auth_token) def compute_signature(self, uri, params): """proxy twilio.RequestValidator.compute_signature()""" return self.request_validator.compute_signature(uri, params) def validate_request(self, uri, params, signature): """proxy twilio.RequestValidator.validate()""" return self.request_validator.validate(uri, params, signature) def send_sms(self, to="", from_="", body=""): try: message = self.client.messages.create( to=to, from_=from_, body=body ) except TwilioRestException: # TODO log this original exception for debugging raise TwilioClientException('Failed to send SMS') return message
async def process_sms(request: Request, From: str = Form(...), Body: str = Form(...)): validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"]) form_ = await request.form() if not validator.validate(str(request.url), form_, request.headers.get("X-Twilio-Signature", "")): raise HTTPException(status_code=400, detail="Error in Twilio Signature") response = MessagingResponse() print(Body) vectorized_name = gender_cv.transform([Body]).toarray() prediction = gender_clf.predict(vectorized_name) if prediction[0] == 0: result = 'Female' else: result = 'Male' print(result) response.message(result) return Response(content=str(response), media_type="application/xml")
def fizzbuzzTWIML(): response = VoiceResponse() validator = RequestValidator(TWILIO_AUTH_TOKEN) request_valid = validator.validate( request.url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) if not request_valid: response.say("Not a Twilio account") response.say("Starting now") number = int(request.form.get('Digits', '')) for i in range(1, number + 1): if i % 3 == 0 and i % 5 == 0: response.say("fizzbuzz.") elif i % 3 == 0: response.say("fizz.") elif i % 5 == 0: response.say("buzz.") else: string = str(i) + "." response.say(string) return str(response)
def protect_forged_request(request): if request.method not in ['GET', 'POST']: return HttpResponseNotAllowed(request.method) try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() if request.method == 'POST': if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() if request.method == 'GET': if not validator.validate(url, request.GET, signature): return HttpResponseForbidden()
def validate_twilio_request(): validator = RequestValidator(auth_token) url = request.url[:4] + 's' + request.url[ 4:] # add s because request comes in without it request_valid = validator.validate( url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) if not request_valid: return abort(403)
def validate(request): validator = RequestValidator(os.environ.get('TWILIO_AUTH_TOKEN')) request_valid = validator.validate( URL, request.form, request.headers.get('X-Twilio-Signature', '')) if not request_valid: abort(403)
def decorated_function(*args, **kwargs): validator = RequestValidator(twilio_token) request_valid = validator.validate( request.url, request.form, request.headers.get("X-TWILIO-SIGNATURE", "")) if request_valid: return f(*args, **kwargs) else: return abort(403)
def verify_twilio(request, app): # use twilio's docs on validating a request url = app.config.get('site_url') auth_token = app.config.get('auth_token') params = request.form validator = RequestValidator(auth_token) tw_sig = request.headers.get('X-Twilio-Signature') return (validator.validate(url, params, tw_sig))
def is_valid_twilio_request(request): twilio_request_validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) request_path = request.build_absolute_uri(request.get_full_path()).replace( 'http:', 'https:') # trailing slashes should be removed if request_path[-1] == '/': request_path = request_path[:-1] twilio_signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') return twilio_request_validator.validate(request_path, request.POST, twilio_signature)
def decorated_function(*args, **kwargs): validator = RequestValidator(app.config['TWILIO_AUTH_TOKEN']) request_valid = validator.validate( request.url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) if request_valid: return f(*args, **kwargs) else: return abort(403)
def is_valid_twilio_request(request): twilio_request_validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) request_path = request.build_absolute_uri( request.get_full_path()).replace('http:', 'https:') # trailing slashes should be removed if request_path[-1] == '/': request_path = request_path[:-1] twilio_signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') return twilio_request_validator.validate( request_path, request.POST, twilio_signature)
def authenticatesender(self, url, parameters, signature): if signature and url and parameters: validator = RequestValidator(self.auth_token) if validator.validate(url, parameters, signature): return True return False
def decorated_function(*args, **kwargs): validator = RequestValidator(os.getenv('TWILIO_AUTH_TOKEN')) request_valid = validator.validate( request.url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) if request_valid: return f(*args, **kwargs) else: return f'Sorry! This is not a valid request'
def receive_twilio_sms(): response = MessagingResponse() auth = request.authorization if not auth: current_app.logger.warning("Inbound sms (Twilio) no auth header") abort(401) elif auth.username not in current_app.config[ 'TWILIO_INBOUND_SMS_USERNAMES'] or auth.password not in current_app.config[ 'TWILIO_INBOUND_SMS_PASSWORDS']: current_app.logger.warning( "Inbound sms (Twilio) incorrect username ({}) or password".format( auth.username)) abort(403) # Locally, when using ngrok the URL comes in without HTTPS so force it # otherwise the Twilio signature validator will fail. url = request.url.replace("http://", "https://") post_data = request.form twilio_signature = request.headers.get('X-Twilio-Signature') validator = RequestValidator(os.getenv('TWILIO_AUTH_TOKEN')) if not validator.validate(url, post_data, twilio_signature): current_app.logger.warning( "Inbound sms (Twilio) signature did not match request") abort(400) service = fetch_potential_service(post_data['To'], 'twilio') if not service: # Since this is an issue with our service <-> number mapping, or no # inbound_sms service permission we should still tell Twilio that we # received it successfully. return str(response), 200 statsd_client.incr('inbound.twilio.successful') inbound = create_inbound_sms_object(service, content=post_data["Body"], from_number=post_data['From'], provider_ref=post_data["MessageSid"], provider_name="twilio") tasks.send_inbound_sms_to_service.apply_async( [str(inbound.id), str(service.id)], queue=QueueNames.NOTIFY) current_app.logger.debug( '{} received inbound SMS with reference {} from Twilio'.format( service.id, inbound.provider_reference, )) return str(response), 200
def receive_twilio_sms(): response = MessagingResponse() auth = request.authorization if not auth: current_app.logger.warning("Inbound sms (Twilio) no auth header") abort(401) elif auth.username not in current_app.config['TWILIO_INBOUND_SMS_USERNAMES'] \ or auth.password not in current_app.config['TWILIO_INBOUND_SMS_PASSWORDS']: current_app.logger.warning( "Inbound sms (Twilio) incorrect username ({}) or password".format( auth.username)) abort(403) url = request.url post_data = request.form twilio_signature = request.headers.get('X-Twilio-Signature') validator = RequestValidator(current_app.config['TWILIO_AUTH_TOKEN']) if not validator.validate(url, post_data, twilio_signature): current_app.logger.warning( "Inbound sms (Twilio) signature did not match request") abort(400) try: service = fetch_potential_service(post_data['To'], 'twilio') except NoSuitableServiceForInboundSms: # Since this is an issue with our service <-> number mapping, or no # inbound_sms service permission we should still tell Twilio that we # received it successfully. return str(response), 200 statsd_client.incr('inbound.twilio.successful') inbound = create_inbound_sms_object(service, content=post_data["Body"], notify_number=post_data['To'], from_number=post_data['From'], provider_ref=post_data["MessageSid"], date_received=datetime.utcnow(), provider_name="twilio") send_inbound_sms_to_service.apply_async( [str(inbound.id), str(service.id)], queue=QueueNames.NOTIFY) current_app.logger.debug( '{} received inbound SMS with reference {} from Twilio'.format( service.id, inbound.provider_reference, )) return str(response), 200
def decorated_function(*args, **kwargs): validator = RequestValidator(os.environ.get("TWILIO_AUTH_TOKEN")) request_valid = validator.validate( request.url, request.form, request.headers.get("X-TWILIO-SIGNATURE", "")) if request_valid: return f(*args, **kwargs) else: return abort(403)
def decorator(request_or_self, *args, **kwargs): class_based_view = not isinstance(request_or_self, HttpRequest) if not class_based_view: request = request_or_self else: assert len(args) >= 1 request = args[0] # Turn off Twilio authentication when explicitly requested, or # in debug mode. Otherwise things do not work properly. For # more information, see the docs. use_forgery_protection = getattr( settings, 'DJANGO_TWILIO_FORGERY_PROTECTION', not settings.DEBUG, ) if use_forgery_protection: if request.method not in ['GET', 'POST']: return HttpResponseNotAllowed(request.method) # Forgery check try: twilio_settings = SiteConfiguration.get_twilio_settings() validator = RequestValidator(twilio_settings['auth_token']) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError, ConfigurationError): return HttpResponseForbidden() if request.method == 'POST': if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() if request.method == 'GET': if not validator.validate(url, request.GET, signature): return HttpResponseForbidden() response = f(request_or_self, *args, **kwargs) return response
async def __handle_non_dev_env(self): """ In production or staging, validate that the request comes from Twilio """ validator = RequestValidator(config.TWILIO_AUTH_TOKEN) params = await super().form() x_twilio_signature = super().headers.get("X-Twilio-Signature", "no-header") is_valid = validator.validate(str(super().url), params, x_twilio_signature) if not is_valid: raise HTTPException(status_code=403) return FormData(dict(params.items()))
def verify_request(): if current_app.config['AUTH']: try: twilio_signature = request.headers.get('X-Twilio-Signature', None) twilio_auth_token = os.environ.get('TWILIO_AUTH_TOKEN') validator = RequestValidator(twilio_auth_token) url = iri_to_uri(request.url) content = request.form if not validator.validate(url, content, twilio_signature): abort(401) except Exception as e: logging.exception("Something went wrong") abort(401)
def handler(event, context): """Lambda function handler for Twilio response.""" resp = twiml.Response() print("Event:", event) if u'twilioSignature' in event and u'Body' in event \ and event['Body'].lower() == "secret": form_parameters = { k: urllib.unquote_plus(v) for k, v in event.items() if k != u'twilioSignature' } validator = RequestValidator(os.environ['AUTH_TOKEN']) request_valid = validator.validate( os.environ['REQUEST_URL'], form_parameters, event[u'twilioSignature'] ) # print("Form params:",form_parameters,"validity:",request_valid) # If the request is valid and this is from the master number, # give the secret! if request_valid and u'From' in form_parameters and \ form_parameters[u'From'] == \ os.environ['MASTER_NUMBER'].encode('utf8'): # The message is validated and is from the master number secret_message = "I am putting myself to the fullest possible" \ " use, which is all I think that any conscious" \ " entity can ever hope to do." msg = resp.message(secret_message) # The following lines add media to an MMS reply msg.media('https://upload.wikimedia.org/wikipedia/commons/thumb' '/f/f6/HAL9000.svg/200px-HAL9000.svg.png') return str(resp) else: # Validation failed in some way; don't give up the secret secret_message = "I'm sorry, Dave. I'm afraid I can't do that." resp.message(secret_message) return str(resp) else: resp.message("Hello world! -Lambda") return str(resp)
def decorated_function(request, *args, **kwargs): # Create an instance of the RequestValidator class validator = RequestValidator(os.environ.get('TWILIO_AUTH_TOKEN')) # Validate the request using its URL, POST data, # and X-TWILIO-SIGNATURE header request_valid = validator.validate( request.build_absolute_uri(), request.POST, request.META.get('HTTP_X_TWILIO_SIGNATURE', '')) # Continue processing the request if it's valid (or if DEBUG is True) # and return a 403 error if it's not if request_valid or settings.DEBUG: return f(request, *args, **kwargs) else: return HttpResponseForbidden()
def decorated_function(*args, **kwargs): # Create an instance of the RequestValidator class validator = RequestValidator(os.environ.get('TWILIO_AUTH_TOKEN')) # Validate the request using its URL, POST data, # and X-TWILIO-SIGNATURE header request_valid = validator.validate( request.url, request.form, request.headers.get('X-TWILIO-SIGNATURE', '')) # Continue processing the request if it's valid (or if DEBUG is True) # and return a 403 error if it's not if request_valid or current_app.debug: return f(*args, **kwargs) else: return abort(403)
# Download the twilio-python library from twilio.com/docs/python/install from twilio.request_validator import RequestValidator # Your Auth Token from twilio.com/user/account auth_token = '12345' validator = RequestValidator(auth_token) url = 'https://mycompany.com/myapp.php?foo=1&bar=2' params = { 'CallSid': 'CA1234567890ABCDE', 'Caller': '+14158675309', 'Digits': '1234', 'From': '+14158675309', 'To': '+18005551212' } # The X-Twilio-Signature header attached to the request twilio_signature = 'RSOYDt4T1cUTdK1PDd93/VVr8B8=' print(validator.validate(url, params, twilio_signature))
def post(self, request, *args, **kwargs): from twilio.request_validator import RequestValidator from temba.flows.models import FlowSession signature = request.META.get("HTTP_X_TWILIO_SIGNATURE", "") url = "https://" + request.get_host() + "%s" % request.get_full_path() channel_uuid = kwargs.get("uuid") call_sid = self.get_param("CallSid") direction = self.get_param("Direction") status = self.get_param("CallStatus") to_number = self.get_param("To") to_country = self.get_param("ToCountry") from_number = self.get_param("From") # Twilio sometimes sends un-normalized numbers if to_number and not to_number.startswith("+") and to_country: # pragma: no cover to_number, valid = URN.normalize_number(to_number, to_country) # see if it's a twilio call being initiated if to_number and call_sid and direction == "inbound" and status == "ringing": # find a channel that knows how to answer twilio calls channel = self.get_ringing_channel(uuid=channel_uuid) if not channel: response = VoiceResponse() response.say("Sorry, there is no channel configured to take this call. Goodbye.") response.hangup() return HttpResponse(str(response)) org = channel.org if self.get_channel_type() == "T" and not org.is_connected_to_twilio(): return HttpResponse("No Twilio account is connected", status=400) client = self.get_client(channel=channel) validator = RequestValidator(client.auth[1]) signature = request.META.get("HTTP_X_TWILIO_SIGNATURE", "") url = "https://%s%s" % (request.get_host(), request.get_full_path()) if validator.validate(url, request.POST, signature): from temba.ivr.models import IVRCall # find a contact for the one initiating us urn = URN.from_tel(from_number) contact, urn_obj = Contact.get_or_create(channel.org, urn, channel) flow = Trigger.find_flow_for_inbound_call(contact) if flow: call = IVRCall.create_incoming(channel, contact, urn_obj, channel.created_by, call_sid) session = FlowSession.create(contact, connection=call) call.update_status( request.POST.get("CallStatus", None), request.POST.get("CallDuration", None), "T" ) call.save() FlowRun.create(flow, contact, session=session, connection=call) response = Flow.handle_call(call) return HttpResponse(str(response)) else: # we don't have an inbound trigger to deal with this call. response = channel.generate_ivr_response() # say nothing and hangup, this is a little rude, but if we reject the call, then # they'll get a non-working number error. We send 'busy' when our server is down # so we don't want to use that here either. response.say("") response.hangup() # if they have a missed call trigger, fire that off Trigger.catch_triggers(contact, Trigger.TYPE_MISSED_CALL, channel) # either way, we need to hangup now return HttpResponse(str(response)) # check for call progress events, these include post-call hangup notifications if request.POST.get("CallbackSource", None) == "call-progress-events": if call_sid: from temba.ivr.models import IVRCall call = IVRCall.objects.filter(external_id=call_sid).first() if call: call.update_status( request.POST.get("CallStatus", None), request.POST.get("CallDuration", None), "TW" ) call.save() return HttpResponse("Call status updated") return HttpResponse("No call found") return HttpResponse("Not Handled, unknown action", status=400) # pragma: no cover
def validate(self, request): # pragma: needs cover validator = RequestValidator(self.auth[1]) signature = request.META.get("HTTP_X_TWILIO_SIGNATURE", "") url = "https://%s%s" % (request.get_host(), request.get_full_path()) return validator.validate(url, request.POST, signature)