2021-03-10 13:55:06 +00:00
|
|
|
import json
|
2018-07-17 15:27:43 +01:00
|
|
|
import random
|
2018-07-12 16:53:10 +01:00
|
|
|
from datetime import datetime, timedelta
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
from flask import current_app
|
2018-01-26 13:52:13 +00:00
|
|
|
from notifications_utils.s3 import s3upload
|
2021-03-10 13:55:06 +00:00
|
|
|
from requests import HTTPError, request
|
2018-01-26 13:52:13 +00:00
|
|
|
|
|
|
|
|
from app import notify_celery
|
2018-07-12 16:53:10 +01:00
|
|
|
from app.aws.s3 import file_exists
|
2017-12-01 16:15:21 +00:00
|
|
|
from app.celery.process_ses_receipts_tasks import process_ses_results
|
2021-03-10 13:55:06 +00:00
|
|
|
from app.config import QueueNames
|
|
|
|
|
from app.models import SMS_TYPE
|
2016-06-29 11:50:54 +01:00
|
|
|
|
2022-12-21 15:10:44 -05:00
|
|
|
temp_fail = "5558675303"
|
|
|
|
|
perm_fail = "5558675302"
|
|
|
|
|
delivered = "5558675309"
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
delivered_email = "delivered@simulator.notify"
|
|
|
|
|
perm_fail_email = "perm-fail@simulator.notify"
|
|
|
|
|
temp_fail_email = "temp-fail@simulator.notify"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def send_sms_response(provider, reference, to):
|
2022-12-21 15:10:44 -05:00
|
|
|
body = sns_callback(reference, to)
|
|
|
|
|
headers = {"Content-type": "application/json"}
|
2017-01-20 13:17:53 +00:00
|
|
|
|
2016-06-29 11:50:54 +01:00
|
|
|
make_request(SMS_TYPE, provider, body, headers)
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
|
2017-11-17 13:41:45 +00:00
|
|
|
def send_email_response(reference, to):
|
2016-05-31 16:55:26 +01:00
|
|
|
if to == perm_fail_email:
|
|
|
|
|
body = ses_hard_bounce_callback(reference)
|
|
|
|
|
elif to == temp_fail_email:
|
|
|
|
|
body = ses_soft_bounce_callback(reference)
|
|
|
|
|
else:
|
|
|
|
|
body = ses_notification_callback(reference)
|
|
|
|
|
|
2017-11-17 13:41:45 +00:00
|
|
|
process_ses_results.apply_async([body], queue=QueueNames.RESEARCH_MODE)
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_request(notification_type, provider, data, headers):
|
|
|
|
|
api_call = "{}/notifications/{}/{}".format(current_app.config["API_HOST_NAME"], notification_type, provider)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
response = request(
|
|
|
|
|
"POST",
|
|
|
|
|
api_call,
|
|
|
|
|
headers=headers,
|
2017-04-04 16:05:25 +01:00
|
|
|
data=data,
|
2017-04-05 16:39:46 +01:00
|
|
|
timeout=60
|
2016-05-31 16:55:26 +01:00
|
|
|
)
|
|
|
|
|
response.raise_for_status()
|
2020-12-21 14:30:39 +00:00
|
|
|
except HTTPError as e:
|
2016-05-31 16:55:26 +01:00
|
|
|
current_app.logger.error(
|
2020-12-21 14:30:39 +00:00
|
|
|
"API POST request on {} failed with status {}".format(
|
2016-05-31 16:55:26 +01:00
|
|
|
api_call,
|
2020-12-21 14:30:39 +00:00
|
|
|
e.response.status_code
|
2016-05-31 16:55:26 +01:00
|
|
|
)
|
|
|
|
|
)
|
2020-12-21 14:30:39 +00:00
|
|
|
raise e
|
2016-05-31 16:55:26 +01:00
|
|
|
finally:
|
|
|
|
|
current_app.logger.info("Mocked provider callback request finished")
|
|
|
|
|
return response.json()
|
|
|
|
|
|
|
|
|
|
|
2022-12-21 15:10:44 -05:00
|
|
|
def sns_callback(notification_id, to):
|
|
|
|
|
raise Exception("Need to update for SNS callback format along with test_send_to_providers")
|
|
|
|
|
|
|
|
|
|
# example from mmg_callback
|
|
|
|
|
# if to.strip().endswith(temp_fail):
|
|
|
|
|
# # status: 4 - expired (temp failure)
|
|
|
|
|
# status = "4"
|
|
|
|
|
# elif to.strip().endswith(perm_fail):
|
|
|
|
|
# # status: 5 - rejected (perm failure)
|
|
|
|
|
# status = "5"
|
|
|
|
|
# else:
|
|
|
|
|
# # status: 3 - delivered
|
|
|
|
|
# status = "3"
|
|
|
|
|
|
|
|
|
|
# return json.dumps({"reference": "mmg_reference",
|
|
|
|
|
# "CID": str(notification_id),
|
|
|
|
|
# "MSISDN": to,
|
|
|
|
|
# "status": status,
|
|
|
|
|
# "deliverytime": "2016-04-05 16:01:07"})
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
|
2018-01-26 13:52:13 +00:00
|
|
|
@notify_celery.task(bind=True, name="create-fake-letter-response-file", max_retries=5, default_retry_delay=300)
|
|
|
|
|
def create_fake_letter_response_file(self, reference):
|
|
|
|
|
now = datetime.utcnow()
|
2018-01-29 16:39:53 +00:00
|
|
|
dvla_response_data = '{}|Sent|0|Sorted'.format(reference)
|
2018-07-12 16:53:10 +01:00
|
|
|
|
2018-07-17 15:27:43 +01:00
|
|
|
# try and find a filename that hasn't been taken yet - from a random time within the last 30 seconds
|
2022-10-14 14:45:27 +00:00
|
|
|
for i in sorted(range(30), key=lambda _: random.random()): # nosec B311 - not security related
|
2018-07-12 16:53:10 +01:00
|
|
|
upload_file_name = 'NOTIFY-{}-RSP.TXT'.format((now - timedelta(seconds=i)).strftime('%Y%m%d%H%M%S'))
|
|
|
|
|
if not file_exists(current_app.config['DVLA_RESPONSE_BUCKET_NAME'], upload_file_name):
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError(
|
|
|
|
|
'cant create fake letter response file for {} - too many files for that time already exist on s3'.format(
|
|
|
|
|
reference
|
|
|
|
|
)
|
|
|
|
|
)
|
2018-01-26 13:52:13 +00:00
|
|
|
|
|
|
|
|
s3upload(
|
|
|
|
|
filedata=dvla_response_data,
|
|
|
|
|
region=current_app.config['AWS_REGION'],
|
|
|
|
|
bucket_name=current_app.config['DVLA_RESPONSE_BUCKET_NAME'],
|
|
|
|
|
file_location=upload_file_name
|
|
|
|
|
)
|
|
|
|
|
current_app.logger.info("Fake DVLA response file {}, content [{}], uploaded to {}, created at {}".format(
|
|
|
|
|
upload_file_name, dvla_response_data, current_app.config['DVLA_RESPONSE_BUCKET_NAME'], now))
|
|
|
|
|
|
|
|
|
|
# on development we can't trigger SNS callbacks so we need to manually hit the DVLA callback endpoint
|
|
|
|
|
if current_app.config['NOTIFY_ENVIRONMENT'] == 'development':
|
|
|
|
|
make_request('letter', 'dvla', _fake_sns_s3_callback(upload_file_name), None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _fake_sns_s3_callback(filename):
|
|
|
|
|
message_contents = '{"Records":[{"s3":{"object":{"key":"%s"}}}]}' % (filename) # noqa
|
|
|
|
|
return json.dumps({
|
|
|
|
|
"Type": "Notification",
|
|
|
|
|
"MessageId": "some-message-id",
|
|
|
|
|
"Message": message_contents
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2016-05-31 16:55:26 +01:00
|
|
|
def ses_notification_callback(reference):
|
2017-11-17 14:25:59 +00:00
|
|
|
ses_message_body = {
|
|
|
|
|
'delivery': {
|
|
|
|
|
'processingTimeMillis': 2003,
|
|
|
|
|
'recipients': ['success@simulator.amazonses.com'],
|
|
|
|
|
'remoteMtaIp': '123.123.123.123',
|
2022-06-13 13:16:32 -07:00
|
|
|
'reportingMTA': 'a7-32.smtp-out.us-west-2.amazonses.com',
|
2017-11-17 14:25:59 +00:00
|
|
|
'smtpResponse': '250 2.6.0 Message received',
|
|
|
|
|
'timestamp': '2017-11-17T12:14:03.646Z'
|
|
|
|
|
},
|
|
|
|
|
'mail': {
|
|
|
|
|
'commonHeaders': {
|
|
|
|
|
'from': ['TEST <TEST@notify.works>'],
|
|
|
|
|
'subject': 'lambda test',
|
|
|
|
|
'to': ['success@simulator.amazonses.com']
|
|
|
|
|
},
|
|
|
|
|
'destination': ['success@simulator.amazonses.com'],
|
|
|
|
|
'headers': [
|
|
|
|
|
{
|
|
|
|
|
'name': 'From',
|
|
|
|
|
'value': 'TEST <TEST@notify.works>'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'To',
|
|
|
|
|
'value': 'success@simulator.amazonses.com'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'Subject',
|
|
|
|
|
'value': 'lambda test'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'MIME-Version',
|
|
|
|
|
'value': '1.0'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'Content-Type',
|
|
|
|
|
'value': 'multipart/alternative; boundary="----=_Part_617203_1627511946.1510920841645"'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
'headersTruncated': False,
|
|
|
|
|
'messageId': reference,
|
|
|
|
|
'sendingAccountId': '12341234',
|
|
|
|
|
'source': '"TEST" <TEST@notify.works>',
|
2022-06-13 13:16:32 -07:00
|
|
|
'sourceArn': 'arn:aws:ses:us-west-2:12341234:identity/notify.works',
|
2017-11-17 14:25:59 +00:00
|
|
|
'sourceIp': '0.0.0.1',
|
|
|
|
|
'timestamp': '2017-11-17T12:14:01.643Z'
|
|
|
|
|
},
|
|
|
|
|
'notificationType': 'Delivery'
|
2017-11-17 13:41:45 +00:00
|
|
|
}
|
2016-05-31 16:55:26 +01:00
|
|
|
|
2017-11-17 13:41:45 +00:00
|
|
|
return {
|
|
|
|
|
'Type': 'Notification',
|
2017-11-17 14:25:59 +00:00
|
|
|
'MessageId': '8e83c020-1234-1234-1234-92a8ee9baa0a',
|
2022-06-13 13:16:32 -07:00
|
|
|
'TopicArn': 'arn:aws:sns:us-west-2:12341234:ses_notifications',
|
2017-11-17 14:25:59 +00:00
|
|
|
'Subject': None,
|
|
|
|
|
'Message': json.dumps(ses_message_body),
|
|
|
|
|
'Timestamp': '2017-11-17T12:14:03.710Z',
|
|
|
|
|
'SignatureVersion': '1',
|
|
|
|
|
'Signature': '[REDACTED]',
|
2022-06-13 13:16:32 -07:00
|
|
|
'SigningCertUrl': 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-[REDACTED].pem',
|
|
|
|
|
'UnsubscribeUrl': 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=[REACTED]',
|
2017-11-17 14:25:59 +00:00
|
|
|
'MessageAttributes': {}
|
2017-11-17 13:41:45 +00:00
|
|
|
}
|
2016-05-31 16:55:26 +01:00
|
|
|
|
|
|
|
|
|
2017-11-17 14:25:59 +00:00
|
|
|
def ses_hard_bounce_callback(reference):
|
|
|
|
|
return _ses_bounce_callback(reference, 'Permanent')
|
|
|
|
|
|
|
|
|
|
|
2016-05-31 16:55:26 +01:00
|
|
|
def ses_soft_bounce_callback(reference):
|
2017-11-17 14:25:59 +00:00
|
|
|
return _ses_bounce_callback(reference, 'Temporary')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ses_bounce_callback(reference, bounce_type):
|
|
|
|
|
ses_message_body = {
|
|
|
|
|
'bounce': {
|
|
|
|
|
'bounceSubType': 'General',
|
|
|
|
|
'bounceType': bounce_type,
|
|
|
|
|
'bouncedRecipients': [{
|
|
|
|
|
'action': 'failed',
|
|
|
|
|
'diagnosticCode': 'smtp; 550 5.1.1 user unknown',
|
|
|
|
|
'emailAddress': 'bounce@simulator.amazonses.com',
|
|
|
|
|
'status': '5.1.1'
|
|
|
|
|
}],
|
|
|
|
|
'feedbackId': '0102015fc9e676fb-12341234-1234-1234-1234-9301e86a4fa8-000000',
|
|
|
|
|
'remoteMtaIp': '123.123.123.123',
|
2022-06-13 13:16:32 -07:00
|
|
|
'reportingMTA': 'dsn; a7-31.smtp-out.us-west-2.amazonses.com',
|
2017-11-17 14:25:59 +00:00
|
|
|
'timestamp': '2017-11-17T12:14:05.131Z'
|
|
|
|
|
},
|
|
|
|
|
'mail': {
|
|
|
|
|
'commonHeaders': {
|
|
|
|
|
'from': ['TEST <TEST@notify.works>'],
|
|
|
|
|
'subject': 'ses callback test',
|
|
|
|
|
'to': ['bounce@simulator.amazonses.com']
|
|
|
|
|
},
|
|
|
|
|
'destination': ['bounce@simulator.amazonses.com'],
|
|
|
|
|
'headers': [
|
|
|
|
|
{
|
|
|
|
|
'name': 'From',
|
|
|
|
|
'value': 'TEST <TEST@notify.works>'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'To',
|
|
|
|
|
'value': 'bounce@simulator.amazonses.com'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'Subject',
|
|
|
|
|
'value': 'lambda test'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'MIME-Version',
|
|
|
|
|
'value': '1.0'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
'name': 'Content-Type',
|
|
|
|
|
'value': 'multipart/alternative; boundary="----=_Part_596529_2039165601.1510920843367"'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
'headersTruncated': False,
|
|
|
|
|
'messageId': reference,
|
|
|
|
|
'sendingAccountId': '12341234',
|
|
|
|
|
'source': '"TEST" <TEST@notify.works>',
|
2022-06-13 13:16:32 -07:00
|
|
|
'sourceArn': 'arn:aws:ses:us-west-2:12341234:identity/notify.works',
|
2017-11-17 14:25:59 +00:00
|
|
|
'sourceIp': '0.0.0.1',
|
|
|
|
|
'timestamp': '2017-11-17T12:14:03.000Z'
|
|
|
|
|
},
|
|
|
|
|
'notificationType': 'Bounce'
|
|
|
|
|
}
|
2017-11-17 13:41:45 +00:00
|
|
|
return {
|
|
|
|
|
'Type': 'Notification',
|
2017-11-17 14:25:59 +00:00
|
|
|
'MessageId': '36e67c28-1234-1234-1234-2ea0172aa4a7',
|
2022-06-13 13:16:32 -07:00
|
|
|
'TopicArn': 'arn:aws:sns:us-west-2:12341234:ses_notifications',
|
2017-11-17 14:25:59 +00:00
|
|
|
'Subject': None,
|
|
|
|
|
'Message': json.dumps(ses_message_body),
|
|
|
|
|
'Timestamp': '2017-11-17T12:14:05.149Z',
|
|
|
|
|
'SignatureVersion': '1',
|
|
|
|
|
'Signature': '[REDACTED]', # noqa
|
2022-06-13 13:16:32 -07:00
|
|
|
'SigningCertUrl': 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-[REDACTED]].pem',
|
|
|
|
|
'UnsubscribeUrl': 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=[REDACTED]]',
|
2017-11-17 14:25:59 +00:00
|
|
|
'MessageAttributes': {}
|
2017-11-17 13:41:45 +00:00
|
|
|
}
|