Can you filter out personal details from Python Twilio logger? - twilio

By default the Twilio Python client seems to log out personal information (emails and numbers). I know you can access the logger like this twilio_logger = logging.getLogger('twilio.http_client')
Is there a simple setting change we can make to filter out this personal information, either directly through the library or by changing the logger?
NOTE: I have attempted to do this by creating a custom formatter:
class SensitiveDataFormatter(logging.Formatter):
"""Formatter that removes sensitive information in urls."""
#staticmethod
def _filter(s):
print('filter')
return re.sub(r'([A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,})', r'[email_redacted]', s)
def format(self, record):
original = logging.Formatter.format(self, record)
return self._filter(original)
LOGGING = {
'version': 1,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'sensitive'
},
},
'root': {
'handlers': ['console'],
'level': 'INFO'
},
'formatters': {
'sensitive': {
'()': 'my_project.settings.logging.sensitive_data_formatter.SensitiveDataFormatter'
}
}
}
This works in the general case, however I'm struggling to apply it to Twilio

It seems that you can apply filters to Python loggers using logger config and a custom class that inherits from logging.Filter.
I'm not a Python developer, so pointing you to this blog post is the best way I can answer this question. I will note that the post appears to be from 2014, so may need updates for Python 3, but the Python logging documentation is also pretty extensive, so should help you out here.

Here is how you can configure the Twilio logger in the Python library to use a custom formatter. To test this I took your formatter and modified it to redact Twilio accounts, messaging services and phone numbers.
client = Client(account_sid, auth_token)
class SensitiveDataFormatter(logging.Formatter):
#staticmethod
def _filter(s):
filters = [
[r'(AC[a-f0-9]+)', '[account_redacted]'],
[r'(MG[a-f0-9]+)', '[messaging_service_redacted]'],
[r'(\+[0-9]+)', '[phone_redacted]'],
]
for f in filters:
s = re.sub(f[0], f[1], s)
return s
def format(self, record):
original = logging.Formatter.format(self, record)
return self._filter(original)
# create a logging handler with the custom formatter attached
handler = logging.StreamHandler()
handler.setFormatter(SensitiveDataFormatter())
# add the stream handler to the Twilio logger
client.http_client.logger.addHandler(handler)
client.http_client.logger.setLevel(logging.INFO)
Example log after sending an SMS:
POST Request: https://api.twilio.com/2010-04-01/Accounts/[account_redacted]/Messages.json
PAYLOAD: {'To': '[phone_redacted]', 'From': '[messaging_service_redacted]', 'Body': 'Friendly reminder that you have an appointment with us next week.'}
POST Response: 201 {"sid": "SM4428eb430949461d9bd58d44da1dd999", "date_created": "Thu, 19 May 2022 08:57:49 [phone_redacted]", "date_updated": "Thu, 19 May 2022 08:57:49 [phone_redacted]", "date_sent": null, "account_sid": "[account_redacted]", "to": "[phone_redacted]", "from": null, "messaging_service_sid": "[messaging_service_redacted]", "body": "Friendly reminder that you have an appointment with us next week.", "status": "accepted", "num_segments": "0", "num_media": "0", "direction": "outbound-api", "api_version": "2010-04-01", "price": null, "price_unit": null, "error_code": null, "error_message": null, "uri": "/2010-04-01/Accounts/[account_redacted]/Messages/SM4428eb430949461d9bd58d44da1dd999.json", "subresource_uris": {"media": "/2010-04-01/Accounts/[account_redacted]/Messages/SM4428eb430949461d9bd58d44da1dd999/Media.json"}}

Related

Implementing Call Transfer via button click

I'm looking to implement a call system that supports call transfer on our 'softphone' built using the Voice SDk, and frankly, I'm overwhelmed by the numerous articles on this but most are outdated (early 2015) or not just working for some reason.
My code involves initiating calls as a conference so warm transfer can be utilized. Hence, I'll demonstrate one side of the call (incoming) for this example.
Lead calls one of the sales person on our app, say SalesPerson A, SpA for short.
SpA would like, probably even before picking the call, transfer it to SpB on the same app.
I'm using each sales person fullname as Identity with every token (return jsonify(identity=fetch_user_fullname(), token=token.to_jwt().decode()), and call transfer is only applicable to all online sales persons.
#app.route('/call', methods=['POST'])
def inbound():
call_sid = flask.request.values.get('CallSid')
response = VoiceResponse()
response.dial().conference(call_sid)
call = client.calls.create(to='client:salespersonA',
from_='twilio_number_called_by_lead',
url = BASE_URL + '/conf/' + call_sid)
return Response(str(response), mimetype='application/xml')
#app.route('/conf/<conference_name>', methods=['GET', 'POST'])
def conference_line(conference_name):
response = VoiceResponse()
response.dial(hangupOnStar=True).conference(conference_name)
response.gather(action=BASE_URL + '/add-agent/' + conference_name,
numDigits=1)
return Response(str(response), 200, mimetype="application/xml")
#app.route('/add-agent/<conference_name>', methods=['POST'])
def add_second_agent(conference_name):
client.calls.create(to='client:salespersonB', from_='twilio_number_called_by_lead',
url=BASE_URL + '/conference/' + conference_name)
response = VoiceResponse()
response.dial(hangupOnStar=True).conference(conference_name)
return Response(str(response), 200, mimetype="application/xml")
My problem with this is since a conference call is initiated when a salesperson answers the line, that associated twilio account is billed (I would have like that caller gets billed only) - due to my twilio number initiating conference call to salespersonA
Also, my issue is most of these holders have a null value and that when lead calls and the conference is initiated, the caller ID to our salespersonA is the twilio number lead dialed, I would have expected the caller ID to be the lead's contact.
Response: 201 {"date_updated": null, "price_unit": "USD", "parent_call_sid": null, "caller_name": null, "duration": null, "from": "twilio_number_called_by_lead", "to": "client:salespersonA", "annotation": null, "answered_by": null, "sid": "CA04...", "queue_time": "0", "price": null, "api_version": "2010-04-01", "status": "queued", "direction": "outbound-api", "start_time": null, "date_created": null, "from_formatted": "twilio_number_called_by_lead_formatted", "group_sid": null, "trunk_sid": null, "forwarded_from": null, "uri": "/2010-04-01/Accounts/AC6../Calls/CA04....json", "account_sid": "AC6", "end_time": null, "to_formatted": "LABEL-9EQk7FJ", "phone_number_sid": null, "subresource_uris": {"feedback": "/2010-04-01/Accounts/AC6/Calls/CA04.../Feedback.json", "notifications": "/2010-04-01/Accounts/AC6/Calls/CA04.../Notifications.json", "recordings": "/2010-04-01/Accounts/AC6.../Calls/CA04.../Recordings.json", "streams": "/2010-04-01/Accounts/AC6.../Calls/CA04.../Streams.json", "payments": "/2010-04-01/Accounts/AC6.../Calls/CA04.../Payments.json", "siprec": "/2010-04-01/Accounts/AC6.../Calls/CA04.../Siprec.json", "events": "/2010-04-01/Accounts/AC6.../Calls/CA04.../Events.json", "feedback_summaries": "/2010-04-01/Accounts/AC6.../Calls/FeedbackSummary.json"}}
This implementation uses keypad to transfer the call, I'm looking to use a button. And Gather does not listen to buttons so I'm lost.
call_sid: CA044876bcd8b74071f9bf9daec3bbae01

AWS Lex Python Codehook references

I am still pretty new to Python (and coding) but I am trying to build my own Lex bot with a Lambda function. I have been following the tutorials and I can understand how it all works. Problem is when I am trying to write my own Lambda functions for Lex, I cannot find any references to help me write my code for example looking at the code below.
def get_slots(intent_request):
return intent_request['currentIntent']['slots']
What is "(intent_request)" and where would I find reference to this? Same for "['currentIntent'], how can I find out what it is and why it is there??
Sorry if this seems stupid to most people on here but I can't start writing code and continue to learn if I can't find any documentation to suggest what these are and why they are needed in order to write code for my own Lex bots.
Thanks in advance!!!
The intent_request is the incoming "request" or "event" from Lex to your Lambda Function. It holds all the necessary information about the user's input and your Lex bot's processing of that input (trigger certain intent, fill certain slots, confirmations, etc.)
This should be the documentation you are looking for.
Lambda Function Input Event and Response Format:
This section describes the structure of the event data that Amazon Lex provides to a Lambda function. Use this information to parse the input in your Lambda code. It also explains the format of the response that Amazon Lex expects your Lambda function to return.
And here is the Event/Request format:
{
"currentIntent": {
"name": "intent-name",
"slots": {
"slot name": "value",
"slot name": "value"
},
"slotDetails": {
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
},
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
}
},
"confirmationStatus": "None, Confirmed, or Denied (intent confirmation, if configured)"
},
"bot": {
"name": "bot name",
"alias": "bot alias",
"version": "bot version"
},
"userId": "User ID specified in the POST request to Amazon Lex.",
"inputTranscript": "Text used to process the request",
"invocationSource": "FulfillmentCodeHook or DialogCodeHook",
"outputDialogMode": "Text or Voice, based on ContentType request header in runtime API request",
"messageVersion": "1.0",
"sessionAttributes": {
"key": "value",
"key": "value"
},
"requestAttributes": {
"key": "value",
"key": "value"
}
}
The slots data is found inside currentIntent and that is inside of this whole intent_request object. That is why you are seeing the code: intent_request['currentIntent']['slots']
So to get session attributes you can find them here: intent_request['sessionAttributes']
Also extremely useful is the exact user input text:
intent_request['inputTranscript']

How to create user with ROLE_API_ACCESS in Sylius?

I followed the official rest-api documentation of sylius but couldn't create the user with field user[authorizationRoles]. Since role_user is default role, i provided arrays of roles as mentioned in docs like this
POST http://localhost:8000/api/customers/
firstName = Ram
lastName = Thakuri
email = ram#yahoo.com
gender = m
user[plainPassword] = ******
user[authorizationRoles] = [ROLE_API_ACCESS]
I even searched in similar posts but couldn't found right answer, don't know where i am wrong but got validation failed message and errors as below (i am using POSTMAN).
{
"code": 400,
"message": "Validation Failed",
"errors": {
"errors": [
"This form should not contain extra fields."
],
"children": {
"firstName": {},
"lastName": {},
"email": {},
"birthday": {},
"gender": {},
"phoneNumber": {},
"subscribedToNewsletter": {},
"group": {},
"user": {
"children": {
"plainPassword": {},
"enabled": {}
}
}
}
}
}
I want to receive an access token using an OAUTH for every registered user to have an api access.
I am newbie to sylius so please help me out on this.
Thanks in advance
You are not able to do it out-of-the-box. The endpoint you are trying to use is related to customers, therefore setting authorization roles has been removed. This part of the documentation is outdated. You can open a PR with the fix, if you want :)
Anyway, it will be possible to do it with the PR #7711 which will allow managing SyliusUsers but through /users/ endpoint which will not create a customer.
The best solution for you would be to customise Sylius\Bundle\CoreBundle\Form\Type\User\ShopUserType and add that field to FormType. Just take a look at the PR I have mentioned before.
Just as a warning, I want to stress, that ShopApi is an experimental concept for Sylius, so you can meet a lot more complex problems if you want to use it this way. It is doable, but not trivial.

SendGrid spec differences between versions of Event Notification Webhook

I have an existing rails3 application with SendGrid Service integration based on SMTP relay, and subscribed to Event Notification Webhooks.
I've got reminder email from Service, informing about impending change to SendGrid's service, and I need make some changes to match new version of Event Notification Webhooks v3.
Email I got contains instructions about How To Upgrade:
Review the documentation to understand how to consume this new version's events.
Implement changes on your side to handle the new in-formatting of event data.
Make changes on SendGrid's configuration page
I wounder, what changes now need I implement on my site? I read manual for v3, but there no information about specifications differences between old and new versions.
Previously, the SendGrid event webhook sent improper batched JSON, with documents seperated by line breaks:
{ "email": "john.doe#sendgrid.com", "timestamp": 1337197600, "smtp-id": "<4FB4041F.6080505#sendgrid.com>", "event": "processed" }
{ "email": "john.doe#sendgrid.com", "timestamp": 1337966815, "category": "newuser", "event": "click", "url": "http://sendgrid.com" }
{ "email": "john.doe#sendgrid.com", "timestamp": 1337969592, "smtp-id": "<20120525181309.C1A9B40405B3#Example-Mac.local>", "event": "processed" }
Today, with v3 it sends proper JSON as such:
[
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337197600,
"smtp-id": "<4FB4041F.6080505#sendgrid.com>",
"event": "processed"
},
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337966815,
"category": "newuser",
"event": "click",
"url": "http://sendgrid.com"
},
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337969592,
"smtp-id": "<20120525181309.C1A9B40405B3#Example-Mac.local>",
"event": "processed"
}
]
If you'd previously been dealing with non-batched events you'll need to adjust your code so that it interprets an array, rather than just a single document, and then loops through said array. Put into code:
# This
consume_data(params)
# Becomes this
params.each { |doc|
consume_data(doc)
}

Limiting Twitter API results to tweets sent to all users (no #replies)?

I'm trying to find a way to just get tweets to all users. The JSON code indicates these as "to_user" null. For example the tweet below edent tweets to everyone, thus the to_user=null.
I tried a few alternatives without success:
http://search.twitter.com/search.json?q=to:null%20from:edent&result_type=mixed
http://search.twitter.com/search.json?q=to:0%20from:edent&result_type=mixed
http://search.twitter.com/search.json?q=to:%20from:edent&result_type=mixed
{
"created_at": "Thu, 28 Jun 2012 06:55:58 +0000",
"from_user": "edent",
"from_user_id": 14054507,
"from_user_id_str": "14054507",
"from_user_name": "Terence Eden",
"geo": null,
"id": 218236278402068480,
"id_str": "218236278402068480",
"iso_language_code": "en",
"metadata": {
"result_type": "recent"
},
"profile_image_url": "http://a0.twimg.com/profile_images/2318692719/7182974111_ec8e1fb46f_s_normal.jpg",
"profile_image_url_https": "https://si0.twimg.com/profile_images/2318692719/7182974111_ec8e1fb46f_s_normal.jpg",
"source": "<a href="http://twitter.com/">web</a>",
"text": "RT #straczynski: #edent Clearly the man was ahead of his time.",
"to_user": null,
"to_user_id": 0,
"to_user_id_str": "0",
"to_user_name": null,
"in_reply_to_status_id": 218075066452287500,
"in_reply_to_status_id_str": "218075066452287488"
},
If you're just looking to get tweets from a particular user that aren't to anyone, use the /get/statuses/user_timeline REST API endpoint instead of the Search API. /get/statuses/user_timeline has an exclude_replies parameter that should do what you're looking for.
The Search API doesn't have any way to exclude replies. Your only option is to get tweets matching whatever other parameters you pass, and process them on your end to remove any whose text starts with "#".

Resources