def test_international_sms(self): token = os.environ["TWILIO_AUTH_TOKEN"] validator = RequestValidator(token) uri = "http://www.postbin.org/1c2pdoc" params = { "AccountSid": "AC4bf2dafb92341f7caf8650403e422d23", "ApiVersion": "2010-04-01", "Body": "Chloéñ", "From": "+15305451766", "FromCity": "SOUTH LAKE TAHOE", "FromCountry": "US", "FromState": "CA", "FromZip": "89449", "SmsMessageSid": "SM51d6d055f53f1072543872c601aae89b", "SmsStatus": "SM51d6d055f53f1072543872c601aae89b", "SmsStatus": "received", "To": "+15304194304", "ToCity": "WOODLAND", "ToCountry": "US", "ToState": "CA", "ToZip": "95695", } expected = "UHkWu+6WLOzPunzb8PuCGPeW1Uw=" self.assertEquals(validator.compute_signature(uri, params), expected) self.assertTrue(validator.validate(uri, params, expected))
def authenticate(): """Verify that request came from Twilio""" if current_app.config.get("DEBUG"): return # Don't auth in dev # Auth that it came from twilio validator = RequestValidator(current_app.config.get("TWILIO_AUTH_TOKEN")) valid = validator.validate(request.url, request.form, request.headers.get('X-Twilio-Signature', '')) if not valid: # If the request was spoofed, then send '403 Forbidden'. current_app.logger.info("IVR detected spoofed incoming call") abort(403) # Final thing - check that the number is registered to the application. # HYPOTHETICALLY - somebody could buy a number through their own # twilio account and point it at our app, and be able to cause # issues. to = request.values.get("To") if not to: current_app.logger.info("IVR missing To parameter") abort(403) p = phonenumbers.parse(to) if not current_app.config["TWILIO_NUMBER"].get(str(p.country_code)) == str( p.national_number): current_app.logger.info("IVR call to unregistered number - %s" % to) abort(403) return
def validate(self, request): validator = RequestValidator(self.auth[1]) signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') base_url = settings.TEMBA_HOST url = "https://%s%s" % (base_url, request.get_full_path()) return validator.validate(url, request.POST, signature)
def incoming_sms(): form = request.form validator = RequestValidator(os.getenv("TWILIO_AUTH_TOKEN")) url = request.url.replace("http:", "https:") sig = request.headers['X-Twilio-Signature'] if not validator.validate(url, form, sig): return "oops, invalid signature, no spoofs accepted" if not form['To'] == os.getenv('RRN_PHONE_NUMBER'): return "ignoring you, wrong To: phone number" if not form['AccountSid'] == os.getenv('TWILIO_ACCOUNT_SID'): return "ignoring you, wrong Twilio SID" text = "<!channel> Message from: {}: {}".format(form['From'], form['Body']) media_keys = [x for x in form.keys() if x.startswith("MediaUrl")] media_urls = [form[x] for x in sorted(media_keys)] if len(media_urls): text = "{} \nAttachments: \n{}".format(text, "\n".join(media_urls)) payload = dict(channel=os.getenv('SLACK_CHANNEL'), username=os.getenv('SLACK_USERNAME'), icon_emoji=os.getenv('SLACK_ICON_EMOJI'), text=text) response = requests.post(os.getenv('SLACK_POST_URL'), json.dumps(payload)) # FIXME check response return code # FIXME deal with MMS attachments # import IPython;IPython.embed() return Response( '<?xml version="1.0" encoding="UTF-8" ?><Response></Response>', mimetype='text/xml')
def decorator(request, *args, **kwargs): # Here we'll use the twilio library's request validation code to ensure # that the current request actually came from twilio, and isn't a # forgery. If it is a forgery, then we'll return a HTTP 403 error # (forbidden). try: url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() # Run the wrapped view, and capture the data returned. response = f(request, *args, **kwargs) # If the view returns a string, we'll assume it is XML TwilML data and # pass it back with the appropriate mimetype. We won't check the XML # data because that would be too time consuming for every request. # Instead, we'll let the errors pass through to be dealt with by the # developer. if isinstance(response, Verb): return HttpResponse(response, mimetype='text/xml') else: return response
def decorator(request, *args, **kwargs): # Here we'll use the twilio library's request validation code to ensure # that the current request actually came from twilio, and isn't a # forgery if settings.DEBUG is True. If it is a forgery, then we'll #return a HTTP 403 error (forbidden). if not settings.DEBUG: try: url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() # Run the wrapped view, and capture the data returned. response = require_POST(f(request, *args, **kwargs)) else: response = f(request, *args, **kwargs) # If the view returns a string, we'll assume it is XML TwilML data and # pass it back with the appropriate mimetype. We won't check the XML # data because that would be too time consuming for every request. # Instead, we'll let the errors pass through to be dealt with by the # developer. if isinstance(response, Verb): return HttpResponse(response, mimetype='text/xml') else: return response
def get(self): client = TwilioRestClient(account_sid, auth_token) validator = RequestValidator(auth_token) url = self.request.url params = {} try: twilio_signature = self.request.headers["X-Twilio-Signature"] logging.debug(twilio_signature) except: twilio_signature = "" if validator.validate(url, params, twilio_signature): logging.debug("Validated") call_id = self.request.get('to_call') print call_id infos = Call.query(Call.key==ndb.Key(Call, int(call_id))).fetch() print infos for info in infos: print info for i in json.loads(info.calls): print i call_out = client.calls.create(to=i, from_="2065576875", url="https://teen-link.appspot.com/make-calls?RecordingUrl=" + self.request.get("RecordingUrl"), method="GET", if_machine="Continue") print call_out else: self.response.headers['Content-Type'] = 'text/html' self.response.write("Please don't try to hack me.")
def hello(): """Respond to incoming requests.""" resp = twiml.Response() first_request = True twilio_account_sid = os.environ.get("TWILIO_ACCOUNT_SID") twilio_auth_token = os.environ.get("TWILIO_AUTH_TOKEN") twilio_number = os.environ.get("TWILIO_NUMBER") validator = RequestValidator(twilio_auth_token) if 'X-Twilio-Signature' not in request.headers: if first_request: first_request = False else: abort(401) else: my_url = request.url if my_url.startswith('http://'): my_url = my_url.replace("http", "https") params = request.form twilio_signature = request.headers['X-Twilio-Signature'] if validator.validate(my_url, params, twilio_signature): resp.say("Hello! Welcome to the telephone fizz buzz game!") with resp.gather(timeout=10, finishOnKey="*", action="/handle-key", method="POST") as g: g.say("Please enter your number and then press star.") else: abort(401) return str(resp)
def sms(self, body, path="/sms/", to="+15558675309", from_="+15556667777", extra_params=None): params = { "MessageSid": "CAtesting", "AccountSid": "ACxxxxx", "To": to, "From": from_, "Body": body, "Direction": "inbound", "FromCity": "BROOKLYN", "FromState": "NY", "FromCountry": "US", "FromZip": "55555" } if extra_params: for k, v in extra_params.items(): params[k] = v HTTP_HOST = "example.com" validator = RequestValidator("yyyyyyyy") absolute_url = "http://{0}{1}".format(HTTP_HOST, path) signature = validator.compute_signature(absolute_url, params) return self.post(path, params, HTTP_X_TWILIO_SIGNATURE=signature, HTTP_HOST=HTTP_HOST)
def decorated(*args, **kwargs): print request.values if 'CallSid' not in request.values: return abort(401, 'Request must be a signed Twilio request.') if validate and False: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) sig_header = request.headers.get('X-Twilio-Signature', '') if request.method == 'POST': vparams = request.form vurl = request.url else: vparams = {} vurl = request.url # validator params are called URL, POST vars, and signature if not validator.validate(vurl, vparams, sig_header): return abort(401, 'Request signature could not be validated') # load the call from Mongo or create if one does not exist g.call = load_call(request.values['CallSid'], request.values) g.zipcode = read_context('zipcode', None) g.legislator = read_context('legislator', None) twilio_response = func(*args, **kwargs) return Response(str(twilio_response), mimetype='application/xml')
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 decorator(request, *args, **kwargs): # Only handle Twilio forgery protection stuff if we're running in # production. This way, developers can test their Twilio view code # without getting errors. if not settings.DEBUG: # Attempt to gather all required information to allow us to check the # incoming HTTP request for forgery. If any of this information is not # available, then we'll throw a HTTP 403 error (forbidden). # # The required fields to check for forged requests are: # # 1. ``TWILIO_ACCOUNT_SID`` (set in the site's settings module). # 2. ``TWILIO_AUTH_TOKEN`` (set in the site's settings module). # 3. The full URI of the request, eg: 'http://mysite.com/test/view/'. # This may not necessarily be available if this view is being # called via a unit testing library, or in certain localized # environments. # 4. A special HTTP header, ``HTTP_X_TWILIO_SIGNATURE`` which # contains a hash that we'll use to check for forged requests. # Ensure the request method is POST response = require_POST(f)(request, *args, **kwargs) if isinstance(response, HttpResponse): return response # Validate the request try: validator = RequestValidator(django_twilio_settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() # Now that we have all the required information to perform forgery # checks, we'll actually do the forgery check. if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() # If the user requesting service is blacklisted, reject their # request. blacklisted_resp = get_blacklisted_response(request) if blacklisted_resp: return blacklisted_resp # Run the wrapped view, and capture the data returned. response = f(request, *args, **kwargs) # If the view returns a string (or a ``twilio.Verb`` object), we'll # assume it is XML TwilML data and pass it back with the appropriate # mimetype. We won't check the XML data because that would be too time # consuming for every request. Instead, we'll let the errors pass # through to be dealt with by the developer. if isinstance(response, str): return HttpResponse(response, mimetype='application/xml') elif isinstance(response, Verb): return HttpResponse(str(response), mimetype='application/xml') else: return response
def _wrapped_view (request, *args, **kwargs): validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = settings.TWILIO_CALLBACK_URL post = request.POST signature = request.META.get("HTTP_X_TWILIO_SIGNATURE") if not validator.validate(url, post, signature): return HttpResponse("Invalid call. Are you twilio?") return view_func(request, *args, **kwargs)
def wrapped(*args, **kwargs): # https://www.twilio.com/docs/api/security validator = RequestValidator(auth_token) signature = request.headers.get('X-Twilio-Signature', '') url = get_original_request_url(request) if not validator.validate(url, request.form, signature): app.logger.error('Invalid signature.') return None return f(*args, **kwargs)
class TwiMLTest(unittest.TestCase): def setUp(self): self.app = app.test_client() self.validator = RequestValidator(app.config['TWILIO_AUTH_TOKEN']) def assertTwiML(self, response): self.assertTrue("<Response>" in response.data, "Did not find " \ "<Response>: %s" % response.data) self.assertTrue("</Response>" in response.data, "Did not find " \ "</Response>: %s" % response.data) self.assertEqual("200 OK", response.status) def sms(self, body, url='/sms', to=app.config['TWILIO_CALLER_ID'], from_='+15558675309', extra_params=None, signed=True): params = { 'SmsSid': 'SMtesting', 'AccountSid': app.config['TWILIO_ACCOUNT_SID'], 'To': to, 'From': from_, 'Body': body, 'FromCity': 'BROOKLYN', 'FromState': 'NY', 'FromCountry': 'US', 'FromZip': '55555'} if extra_params: params = dict(params.items() + extra_params.items()) if signed: abs_url = 'http://{0}{1}'.format(app.config['SERVER_NAME'], url) signature = self.validator.compute_signature(abs_url, params) return self.app.post(url, data=params, headers={'X-Twilio-Signature': signature}) return self.app.post(url, data=params) def call(self, url='/voice', to=app.config['TWILIO_CALLER_ID'], from_='+15558675309', digits=None, extra_params=None, signed=True): params = { 'CallSid': 'CAtesting', 'AccountSid': app.config['TWILIO_ACCOUNT_SID'], 'To': to, 'From': from_, 'CallStatus': 'ringing', 'Direction': 'inbound', 'FromCity': 'BROOKLYN', 'FromState': 'NY', 'FromCountry': 'US', 'FromZip': '55555'} if digits: params['Digits'] = digits if extra_params: params = dict(params.items() + extra_params.items()) if signed: abs_url = 'http://{0}{1}'.format(app.config['SERVER_NAME'], url) signature = self.validator.compute_signature(abs_url, params) return self.app.post(url, data=params, headers={'X-Twilio-Signature': signature}) return self.app.post(url, data=params)
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: 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
def dec(request, *args, **kwargs): signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') data = dict() for k, v in request.REQUEST.items(): data[k] = v validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) if validator.validate(settings.TWILIO_URL, data, signature): return func(request, *args, **kwargs) else: return HttpResponse(status=401)
def decorator(request_or_self, methods=['POST'], blacklist=True, *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 methods: return HttpResponseNotAllowed(request.method) # Forgery check try: validator = RequestValidator( django_twilio_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() # Blacklist check checkBlackList = (getattr(settings, 'DJANGO_TWILIO_BLACKLIST_CHECK', blacklist)) if checkBlackList: blacklisted_resp = get_blacklisted_response(request) if blacklisted_resp: return blacklisted_resp response = f(request_or_self, *args, **kwargs) if isinstance(response, str): return HttpResponse(response, content_type='application/xml') elif isinstance(response, Verb): return HttpResponse(str(response), content_type='application/xml') else: return response
def decorator(request, *args, **kwargs): # Attempt to gather all required information to allow us to check the # incoming HTTP request for forgery. If any of this information is not # available, then we'll throw a HTTP 403 error (forbidden). # Ensure the request method is POST if request.method != "POST": logger.error( "Twilio: Expected POST request", extra={"request": request}) return HttpResponseNotAllowed(request.method) if not getattr(settings, "TWILIO_SKIP_SIGNATURE_VALIDATION"): # Validate the request try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() # Ensure the original requested url is tested for validation # Prevents breakage when processed behind a proxy server if "HTTP_X_FORWARDED_SERVER" in request.META: protocol = "https" if request.META[ "HTTP_X_TWILIO_SSL"] == "Enabled" else "http" url = "{0}://{1}{2}".format( protocol, request.META[ "HTTP_X_FORWARDED_SERVER"], request.META["REQUEST_URI"] ) signature = request.META["HTTP_X_TWILIO_SIGNATURE"] except (AttributeError, KeyError) as e: logger.exception( "Twilio: Missing META param", extra={"request": request}) return HttpResponseForbidden("Missing META param: %s" % e) # Now that we have all the required information to perform forgery # checks, we'll actually do the forgery check. if not validator.validate(url, request.POST, signature): logger.error( "Twilio: Invalid url signature %s - %s - %s", url, request.POST, signature, extra={"request": request} ) return HttpResponseForbidden("Invalid signature") # Run the wrapped view, and capture the data returned. response = f(request, *args, **kwargs) # If the view returns a string (or a ``twilio.Verb`` object), we'll # assume it is XML TwilML data and pass it back with the appropriate # mimetype. We won't check the XML data because that would be too time # consuming for every request. Instead, we'll let the errors pass # through to be dealt with by the developer. if isinstance(response, six.text_type): return HttpResponse(response, mimetype="application/xml") elif isinstance(response, Verb): return HttpResponse(force_text(response), mimetype="application/xml") else: return response
def twilio_validator_function(request): """returns true for authentic Twilio request, false for unauthenticated request""" validator = RequestValidator(app.config['TWILIO_AUTH_TOKEN']) URL = request.url params = {} if request.method == 'POST': params = request.values else: params = request.args twilio_signature = request.headers.get('X-Twilio-Signature') return validator.validate(URL, params, twilio_signature)
def decorator(*args, **kwargs): if not current_app.config['DEBUG']: validator = RequestValidator(current_app.config['TWILIO_AUTH_TOKEN']) if not validator.validate(request.url, request.form, request.headers['HTTP_X_TWILIO_SIGNATURE']): abort(401) response = f(*args, **kwargs) if isinstance(response, Verb): response = str(response) response = make_response(response) response.mimetype = 'application/xml' return response
def _validate(self, request): full_path = self._site + request.path validator = RequestValidator(self._auth_token) signature = request.getHeader('X-Twilio-Signature') signature = signature if signature else '' post_vars = {k: v[0] for k, v in request.args.iteritems()} if validator.validate(full_path, post_vars, signature): return post_vars else: raise CallException(400, 'Twilio validation failed')
def post(self): text = self.get_argument("Body") sender = self.get_argument("From").lstrip("+") number = self.get_argument("To").lstrip("+") signature = self.request.headers.get('X-Twilio-Signature') proto = self.request.headers.get('X-Forwarded-Proto', self.request.protocol ) url = proto + "://"+ self.request.host + self.request.path var = self.request.arguments for x in var: var[x] = ''.join(var[x]) creds = get_creds(number) validator = RequestValidator(creds[1]) if validator.validate(url, var, signature): r = twiml.Response() if isadmin(sender, number): client = TwilioRestClient(creds[0], creds[1]) gc = gspread.authorize(credentials) worksheet = gc.open(number).worksheet("members") members = worksheet.col_values(1) members = filter(None, members) for member in members: client.messages.create(body=text, to_=member, from_=number) r.message("Mesaage sent to %s recipients" % len(members)) else: if re.match("^start*", text.lower()): gc = gspread.authorize(credentials) membersheet = gc.open(number).worksheet("members") name = text.lower().lstrip("start").lstrip().capitalize() membersheet.append_row([sender, name]) r.message("Thankyou, you have been added to the list") elif re.match("^stop*", text.lower()): gc = gspread.authorize(credentials) membersheet = gc.open(number).worksheet("members") try: cell = membersheet.find(sender) membersheet.update_cell(cell.row, cell.col, '') r.message("You have been removed") except: r.message("Sorry you are not subscribed on this number") else: if ismember(sender, number): gc = gspread.authorize(credentials) membersheet = gc.open(number).worksheet("replies") membersheet.append_row([timestamp('%Y-%m-%d %H:%M:%S'), sender, text]) else: r.message("Sorry you are not subscribed to this list") self.content_type = 'text/xml' self.write(str(r)) self.finish() else: self.clear() self.set_status(403) self.finish("INVALID SOURCE")
def validate_twiml(): twilio_signature = request.get_header('X-Twilio-Signature') params = request.forms url = application.config.Twiml.callback_base_url + request.fullpath auth_token = application.config.Twilio.auth_token validator = RequestValidator(auth_token) validation = validator.validate(url, params, twilio_signature) log.debug("Validator: {}".format(validation)) log.debug("Twilio-signature: {}\r".format(twilio_signature) + \ "Params: {}\r".format(params) + \ "Url: {}".format(url)) return validation
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 call(): ''' Handles incoming calls ''' validator = RequestValidator(TWILIO_AUTH_TOKEN) signature = request.headers.get('X-Twilio-Signature', '') if not validator.validate(request.url, request.form, signature): return abort(403) resp = twiml.Response() with resp.gather(timeout=5, action="/handle-input", finishOnKey="#", method="POST") as g: g.say("Hi, please enter your FizzBuzz number and then press pound") return str(resp)
def verify_request(self): 'verify request comes from Twilio' # this bit taken from Randal Degges' django-twilio library, which as of # 1c020e2a7c6f4845e7309d7277380c8b76d38ba4 has been released into the # public domain try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = self.request.build_absolute_uri() signature = self.request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): raise PermissionDenied() if not validator.validate(url, self.request.POST, signature): raise PermissionDenied()
def _wrapped_view(request, *args, **kwargs): backend = kwargs.get('backend_name', backend_name) config = settings.INSTALLED_BACKENDS[backend]['config'] validator = RequestValidator(config['auth_token']) signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') url = request.build_absolute_uri() body = {} if request.method == 'POST': body = request.POST require_validation = config.get('validate', True) if validator.validate(url, body, signature) or not require_validation: return view_func(request, *args, **kwargs) else: return HttpResponseBadRequest()
def decorator(request, *args, **kwargs): # Attempt to gather all required information to allow us to check the # incoming HTTP request for forgery. If any of this information is not # available, then we'll throw a HTTP 403 error (forbidden). # Ensure the request method is POST if request.method != "POST": logger.error("Twilio: Expected POST request", extra={"request": request}) return HttpResponseNotAllowed(request.method) if not getattr(settings, "TWILIO_SKIP_SIGNATURE_VALIDATION"): # Validate the request try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() # Ensure the original requested url is tested for validation # Prevents breakage when processed behind a proxy server if "HTTP_X_FORWARDED_SERVER" in request.META: protocol = "https" if request.META["HTTP_X_TWILIO_SSL"] == "Enabled" else "http" url = "{0}://{1}{2}".format( protocol, request.META["HTTP_X_FORWARDED_SERVER"], request.META["REQUEST_URI"] ) signature = request.META["HTTP_X_TWILIO_SIGNATURE"] except (AttributeError, KeyError) as e: logger.exception("Twilio: Missing META param", extra={"request": request}) return HttpResponseForbidden("Missing META param: %s" % e) # Now that we have all the required information to perform forgery # checks, we'll actually do the forgery check. if not validator.validate(url, request.POST, signature): logger.error( "Twilio: Invalid url signature %s - %s - %s", url, request.POST, signature, extra={"request": request} ) return HttpResponseForbidden("Invalid signature") # Run the wrapped view, and capture the data returned. response = f(request, *args, **kwargs) # If the view returns a string (or a ``twilio.Verb`` object), we'll # assume it is XML TwilML data and pass it back with the appropriate # mimetype. We won't check the XML data because that would be too time # consuming for every request. Instead, we'll let the errors pass # through to be dealt with by the developer. if isinstance(response, six.text_type): return HttpResponse(response, mimetype="application/xml") elif isinstance(response, Verb): return HttpResponse(force_text(response), mimetype="application/xml") else: return response
def get(self): validator = RequestValidator(auth_token) url = self.request.url params = {} try: twilio_signature = self.request.headers["X-Twilio-Signature"] except: twilio_signature = "" r = twiml.Response() if validator.validate(url, params, twilio_signature): logging.debug(self.request.get('to_call')) r.record(action="/handle-recording?to_call=%s" % (self.request.get('to_call')), method="GET") self.response.headers['Content-Type'] = 'text/xml' self.response.write(str(r))
def send(self, method, url, authtoken): validator = RequestValidator(authtoken) params = urllib.urlencode(self.url_params) if method == "GET": url = "{0}?{1}".format(url, params) sig = validator.compute_signature(url, {}) req = urllib2.Request(url) elif method == "POST": sig = validator.compute_signature(url, self.url_params) req = urllib2.Request(url, params) else: raise CwurlioUserException("Invalid method: %s" % method) req.add_header("X-Twilio-Signature", sig) return urllib2.urlopen(req).read()
def valid(self): url = self.request.url logging.info("Validating url:" + url) validator = RequestValidator(secrets.AUTH_TOKEN) params = {} logging.info("Validating parameters: ") for name in self.request.arguments(): params[name] = self.request.get(name); logging.info(name + ': ' + params[name]) try: signature = self.request.headers["X-Twilio-Signature"] logging.info('Validating signature: %s' % signature) except KeyError: logging.info('Could not find X-Twilio-Signature, validation will fail.') return validator.validate(url, params, signature)
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, return a 403 error if # it's not if request_valid: return f(request, *args, **kwargs) else: return HttpResponseForbidden()
def decorator(request, *args, **kw): try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META['HTTP_X_TWILIO_SIGNATURE'] except (AttributeError, KeyError): return HttpResponseForbidden() # Now that we have all the required information to perform forgery # checks, we'll actually do the forgery check. if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() twiml = viewfunc(request, *args, **kw) return HttpResponse(str(twiml), content_type='application/xml')
def get(self): validator = RequestValidator(auth_token) url = self.request.url params = {} try: twilio_signature = self.request.headers["X-Twilio-Signature"] except: twilio_signature = "" if validator.validate(url, params, twilio_signature): r = twiml.Response() r.play(self.request.get("RecordingUrl")) self.response.headers['Content-Type'] = 'text/xml' self.response.write(str(r)) else: self.response.headers['Content-Type'] = 'text/html' self.response.write("Please don't try to hack me.")
def decorator(request, *args, **kw): try: validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) url = request.build_absolute_uri() signature = request.META["HTTP_X_TWILIO_SIGNATURE"] except (AttributeError, KeyError): return HttpResponseForbidden() # Now that we have all the required information to perform forgery # checks, we'll actually do the forgery check. if not validator.validate(url, request.POST, signature): return HttpResponseForbidden() twiml = viewfunc(request, *args, **kw) return HttpResponse(str(twiml), content_type="application/xml")
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)
def test_good_signature_GET(self): 'good signature is allowed on GET' with self.settings(TWILIO_AUTH_TOKEN='fred'): req = self.factory.get('/', data={'a': 'b'}) validator = RequestValidator(settings.TWILIO_AUTH_TOKEN) req.META['HTTP_X_TWILIO_SIGNATURE'] = validator.compute_signature( req.build_absolute_uri(), req.POST ) self.view.request = req try: self.view.verify_request() except PermissionDenied: self.fail('Raised PermissionDenied when not expecting it')
class SMSReceiver(ApplicationSession): webapp = Klein() logger = Logger() def __init__(self, config): ApplicationSession.__init__(self) self.t_token = config.extra["twilio-token"] self.t_receiver = config.extra["twilio-receiver"] self.t_validator = RequestValidator(self.t_token) self.logger.info("receiving SMS at %s" % '/'+ SMS_EVENT.replace('.','/')) def onConnect(self): self.join("realm1") reactor.listenTCP(9090, Site(self.webapp.resource())) def validSignature(self, request): signature = request.getHeader("X-Twilio-Signature") if not signature: return False return self.t_validator.validate(self.t_receiver, request.args, signature) @webapp.route('/'+ SMS_EVENT.replace('.','/'), methods=['POST']) @inlineCallbacks def receive(self, request): "publish incoming new SMS as (sender, recipient, message)" if self.validSignature(request): form = request.args msg = (form["sender"], form["recipient"], form["message"]) yield self.session.publish(SMS_EVENT, msg) returnValue(succeed(None)) else: request.setResponseCode(401) signature = request.getHeader("X-Twilio-Signature") or "(no signature)" returnValue("Missing or invalid signature: %s" % signature)
def decorator(request_or_self, methods=['POST'], blacklist=True, *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 in debug mode otherwise # things do not work properly. For more information see the docs if not settings.DEBUG: if request.method not in methods: return HttpResponseNotAllowed(request.method) # Forgery check try: validator = RequestValidator( django_twilio_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() # Blacklist check if blacklist: blacklisted_resp = get_blacklisted_response(request) if blacklisted_resp: return blacklisted_resp response = f(request_or_self, *args, **kwargs) if isinstance(response, str): return HttpResponse(response, content_type='application/xml') elif isinstance(response, Verb): return HttpResponse(str(response), content_type='application/xml') else: return response
def get(self): # Validate that request came from Twilio service. validator = RequestValidator(strings.AUTH_TOKEN) url = self.request.url url = url.replace("http", "https") signature = self.request.headers.get("X-Twilio-Signature", "") if not validator.validate(url, {}, signature): logging.warn("Request did not come from Twilio.") self.response.status = 403 return phone = self.request.get("From", None) account = Account.query().filter(Account.phone == phone).get() # Sending messages separately, send empty TwiML for now. twiml = twilio.twiml.Response() response = get_response(response_strings.CALL_HELLO, response_strings.VAR_NAME) if account and account.first: response = response.replace(response_strings.VAR_NAME, account.first) else: response = response.replace(response_strings.VAR_NAME, "") twiml.addSay(response) tracks = [ "better_things", "dare", "enchanted", "makes_me_wonder", "the_reeling", "viva_la_vida" ] track_num = random.randint(0, len(tracks) - 1) twiml.addPlay(self.request.application_url + "/static/mp3/" + tracks[track_num] + ".mp3") response = get_response(response_strings.CALL_GOODBYE) twiml.addSay(response) twiml.addHangup() self.response.write(twiml)
def call(): # Credentials twilio_account_sid = os.environ.get("TWILIO_ACCOUNT_SID") twilio_auth_token = os.environ.get("TWILIO_AUTH_TOKEN") twilio_number = os.environ.get("TWILIO_NUMBER") print twilio_account_sid, twilio_auth_token, twilio_number validator = RequestValidator(twilio_auth_token) first_request = True # Get phone number we need to call phone_number = request.form.get('phoneNumber', None) if 'X-Twilio-Signature' not in request.headers: if first_request: first_request = False else: abort(401) else: my_url = request.url if my_url.startswith('http://'): my_url = my_url.replace("http", "https") params = request.form twilio_signature = request.headers['X-Twilio-Signature'] if not validator.validate(my_url, params, twilio_signature): abort(401) try: twilio_client = TwilioRestClient(twilio_account_sid, twilio_auth_token) except Exception as e: msg = 'Missing configuration variable: {0}'.format(e) return jsonify({'error': msg}) try: twilio_client.calls.create(from_=twilio_number, to=phone_number, url=url_for('.outbound', _external=True)) except Exception as e: app.logger.error(e) return jsonify({'error': str(e)}) return jsonify({'message': 'Call incoming!'})
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(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(*args, **kwargs): validator = RequestValidator(TWILIO_SECRET) url = list(urlparse(request.url)) url[1] = url[1].encode("idna").decode("utf-8") url = urlunparse(url) signature = request.headers.get("X-TWILIO-SIGNATURE", "") request_valid = validator.validate(url, request.form, signature) if request_valid or current_app.debug: resp = Response() f(resp, *args, **kwargs) return str(resp) else: return abort(403)
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 prepare(self): #Security validator = RequestValidator(TWILIO_AUTH_TOKEN) # the POST variables attached to the request (eg "From", "To") post_vars = dict([(k, v[0]) for k,v in parse_qs_bytes(self.request.body, True).items()]) signature = self.request.headers.get('X-Twilio-Signature', '') # X-Twilio-Signature header value if not validator.validate(self.request.full_url(), post_vars, signature): logger.critical('BAD SIGNATURE') response = twiml.Response() response.say('Sorry') response.hangup() self.finish(str(response)) return #Session: Each call is somewhat like a session. self.session = None
def validate(self, attrs): AUTH_TOKEN = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' validator = RequestValidator(AUTH_TOKEN) # the callback URL you provided to Twilio url = "http://www.example.com/my/callback/url.xml" # the POST variables attached to the request (eg "From", "To") post_vars = {} # X-Twilio-Signature header value signature = "HpS7PBa1Agvt4OtO+wZp75IuQa0=" # will look something like that if validator.validate(url, post_vars, signature): print "Confirmed to have come from Twilio." else: print "NOT VALID. It might have been spoofed!"
def get(self): # Validate that request came from Twilio service. validator = RequestValidator(strings.AUTH_TOKEN) url = self.request.url url = url.replace("http", "https") signature = self.request.headers.get("X-Twilio-Signature", "") if not validator.validate(url, {}, signature): logging.warn("Request did not come from Twilio.") self.response.status = 403 return # Sending messages separately, send empty TwiML for now. twiml = twilio.twiml.Response() self.response.write(twiml) twilio_client = TwilioRestClient(strings.ACCOUNT_SID, strings.AUTH_TOKEN) phone = self.request.get("From", None) account = Account.query().filter(Account.phone == phone).get() if account is None: account = create.controller(self.request) was_command = False if not account.state_locked: was_command = command.controller(self.request, account) if not was_command: if account.state == account_model.STATE_ONBOARD: onboard.controller(self.request, account) elif account.state == account_model.STATE_DELETE: delete.controller(self.request, account) else: response = get_response(response_strings.NO_MATCH, response_strings.VAR_NAME) response = response.replace(response_strings.VAR_NAME, account.first) twilio_client.messages.create(to=account.phone, from_=strings.SERVICE_NUMBER, body=response)
def receiver(request): resp = twilio.twiml.Response() validator = RequestValidator(live_credentials) if validator.validate(request.build_absolute_uri(), request.POST, request.META.get('HTTP_X_TWILIO_SIGNATURE', "fail")): print 'Yay for twilio' else: print 'Not twilio resopnse!' return HttpResponseForbidden() resp.say( "Welcome to Kevin's PhoneBuzz! To play, please enter a number on the keypad and then press pound." ) with resp.gather(finishOnKey='#', action='player', method='POST', timeout=10) as g: resp.redirect('') resp.redirect('player') return HttpResponse(str(resp))
def post(self, request, *args, **kwargs): from twilio.util import RequestValidator call = IVRCall.objects.filter(pk=kwargs['pk']).first() if not call: return HttpResponse("Not found", status=404) client = call.channel.get_ivr_client() if request.REQUEST.get('hangup', 0): if not request.user.is_anonymous(): user_org = request.user.get_org() if user_org and user_org.pk == call.org.pk: client.calls.hangup(call.external_id) return HttpResponse(json.dumps(dict(status='Canceled')), content_type="application/json") else: return HttpResponse("Not found", status=404) validator = RequestValidator(client.auth[1]) signature = request.META.get('HTTP_X_TWILIO_SIGNATURE', '') base_url = settings.TEMBA_HOST url = "https://%s%s" % (base_url, request.get_full_path()) # make sure this is coming from twilio if validator.validate(url, request.POST, signature): call.update_status(request.POST.get('CallStatus', None), request.POST.get('CallDuration', None)) call.save() if call.status == IN_PROGRESS: if call.is_flow(): response = Flow.handle_call(call, request.POST) return HttpResponse(unicode(response)) else: return build_json_response(dict(message="Updated call status")) else: # pragma: no cover # raise an exception that things weren't properly signed raise ValidationError("Invalid request signature") return build_json_response(dict(message="Unhandled"))
def validator(self): """ An application-specific instance of :py:class:`twilio.util.RequestValidator`. Primarily for internal use. """ ctx = stack.top if ctx is not None: if not hasattr(ctx, 'twilio_validator'): ctx.twilio_validator = RequestValidator( current_app.config['TWILIO_AUTH_TOKEN']) return ctx.twilio_validator