mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-04 02:11:11 -05:00
Use sns credentials from VCAP_SERVICES
This commit is contained in:
1
.github/workflows/checks.yml
vendored
1
.github/workflows/checks.yml
vendored
@@ -14,7 +14,6 @@ env:
|
|||||||
WERKZEUG_DEBUG_PIN: off
|
WERKZEUG_DEBUG_PIN: off
|
||||||
REDIS_ENABLED: 0
|
REDIS_ENABLED: 0
|
||||||
AWS_REGION: us-west-2
|
AWS_REGION: us-west-2
|
||||||
AWS_PINPOINT_REGION: us-west-2
|
|
||||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
1
.github/workflows/daily_checks.yml
vendored
1
.github/workflows/daily_checks.yml
vendored
@@ -19,7 +19,6 @@ env:
|
|||||||
NOTIFY_EMAIL_DOMAIN: dispostable.com
|
NOTIFY_EMAIL_DOMAIN: dispostable.com
|
||||||
REDIS_ENABLED: 0
|
REDIS_ENABLED: 0
|
||||||
AWS_REGION: us-west-2
|
AWS_REGION: us-west-2
|
||||||
AWS_PINPOINT_REGION: us-west-2
|
|
||||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import re
|
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
|
|
||||||
import boto3
|
|
||||||
import botocore
|
import botocore
|
||||||
import phonenumbers
|
import phonenumbers
|
||||||
|
from boto3 import client
|
||||||
|
|
||||||
from app.clients.sms import SmsClient
|
from app.clients.sms import SmsClient
|
||||||
|
from app.cloudfoundry_config import cloud_config
|
||||||
|
|
||||||
|
|
||||||
class AwsSnsClient(SmsClient):
|
class AwsSnsClient(SmsClient):
|
||||||
@@ -14,19 +14,22 @@ class AwsSnsClient(SmsClient):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def init_app(self, current_app, statsd_client, *args, **kwargs):
|
def init_app(self, current_app, statsd_client, *args, **kwargs):
|
||||||
self._client = boto3.client("sns", region_name=current_app.config["AWS_REGION"])
|
self._client = client(
|
||||||
self._long_codes_client = boto3.client("sns", region_name=current_app.config["AWS_PINPOINT_REGION"])
|
"sns",
|
||||||
|
region_name=cloud_config.sns_region,
|
||||||
|
aws_access_key_id=cloud_config.sns_access_key,
|
||||||
|
aws_secret_access_key=cloud_config.sns_secret_key
|
||||||
|
)
|
||||||
super(SmsClient, self).__init__(*args, **kwargs)
|
super(SmsClient, self).__init__(*args, **kwargs)
|
||||||
self.current_app = current_app
|
self.current_app = current_app
|
||||||
self.statsd_client = statsd_client
|
self.statsd_client = statsd_client
|
||||||
self.long_code_regex = re.compile(r"^\+1\d{10}$")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return 'sns'
|
return 'sns'
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
return 'sns'
|
return self.name
|
||||||
|
|
||||||
def send_sms(self, to, content, reference, sender=None, international=False):
|
def send_sms(self, to, content, reference, sender=None, international=False):
|
||||||
matched = False
|
matched = False
|
||||||
@@ -35,7 +38,6 @@ class AwsSnsClient(SmsClient):
|
|||||||
matched = True
|
matched = True
|
||||||
to = phonenumbers.format_number(match.number, phonenumbers.PhoneNumberFormat.E164)
|
to = phonenumbers.format_number(match.number, phonenumbers.PhoneNumberFormat.E164)
|
||||||
|
|
||||||
client = self._client
|
|
||||||
# See documentation
|
# See documentation
|
||||||
# https://docs.aws.amazon.com/sns/latest/dg/sms_publish-to-phone.html#sms_publish_sdk
|
# https://docs.aws.amazon.com/sns/latest/dg/sms_publish-to-phone.html#sms_publish_sdk
|
||||||
attributes = {
|
attributes = {
|
||||||
@@ -45,20 +47,12 @@ class AwsSnsClient(SmsClient):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# If sending with a long code number, we need to use another AWS region
|
if sender:
|
||||||
# and specify the phone number we want to use as the origination number
|
|
||||||
send_with_dedicated_phone_number = self._send_with_dedicated_phone_number(sender)
|
|
||||||
if send_with_dedicated_phone_number:
|
|
||||||
client = self._long_codes_client
|
|
||||||
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
||||||
"DataType": "String",
|
"DataType": "String",
|
||||||
"StringValue": sender,
|
"StringValue": sender,
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
# If the number is US based, we must use a US Toll Free number to send the message
|
|
||||||
country = phonenumbers.region_code_for_number(match.number)
|
|
||||||
if country == "US":
|
|
||||||
client = self._long_codes_client
|
|
||||||
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
||||||
"DataType": "String",
|
"DataType": "String",
|
||||||
"StringValue": self.current_app.config["AWS_US_TOLL_FREE_NUMBER"],
|
"StringValue": self.current_app.config["AWS_US_TOLL_FREE_NUMBER"],
|
||||||
@@ -66,7 +60,7 @@ class AwsSnsClient(SmsClient):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
start_time = monotonic()
|
start_time = monotonic()
|
||||||
response = client.publish(PhoneNumber=to, Message=content, MessageAttributes=attributes)
|
response = self._client.publish(PhoneNumber=to, Message=content, MessageAttributes=attributes)
|
||||||
except botocore.exceptions.ClientError as e:
|
except botocore.exceptions.ClientError as e:
|
||||||
self.statsd_client.incr("clients.sns.error")
|
self.statsd_client.incr("clients.sns.error")
|
||||||
raise str(e)
|
raise str(e)
|
||||||
@@ -84,6 +78,3 @@ class AwsSnsClient(SmsClient):
|
|||||||
self.statsd_client.incr("clients.sns.error")
|
self.statsd_client.incr("clients.sns.error")
|
||||||
self.current_app.logger.error("No valid numbers found in {}".format(to))
|
self.current_app.logger.error("No valid numbers found in {}".format(to))
|
||||||
raise ValueError("No valid numbers found for SMS delivery")
|
raise ValueError("No valid numbers found for SMS delivery")
|
||||||
|
|
||||||
def _send_with_dedicated_phone_number(self, sender):
|
|
||||||
return sender and re.match(self.long_code_regex, sender)
|
|
||||||
|
|||||||
@@ -59,6 +59,27 @@ class CloudfoundryConfig:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return getenv('AWS_SECRET_ACCESS_KEY')
|
return getenv('AWS_SECRET_ACCESS_KEY')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sns_access_key(self):
|
||||||
|
try:
|
||||||
|
return self._sns_credentials('aws_access_key_id')
|
||||||
|
except KeyError:
|
||||||
|
return getenv('AWS_ACCESS_KEY_ID')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sns_secret_key(self):
|
||||||
|
try:
|
||||||
|
return self._sns_credentials('aws_secret_access_key')
|
||||||
|
except KeyError:
|
||||||
|
return getenv('AWS_SECRET_ACCESS_KEY')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sns_region(self):
|
||||||
|
try:
|
||||||
|
return self._sns_credentials('region')
|
||||||
|
except KeyError:
|
||||||
|
return getenv('AWS_REGION')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sns_topic_arns(self):
|
def sns_topic_arns(self):
|
||||||
try:
|
try:
|
||||||
@@ -73,5 +94,8 @@ class CloudfoundryConfig:
|
|||||||
def _ses_credentials(self, key):
|
def _ses_credentials(self, key):
|
||||||
return self.parsed_services['datagov-smtp'][0]['credentials'][key]
|
return self.parsed_services['datagov-smtp'][0]['credentials'][key]
|
||||||
|
|
||||||
|
def _sns_credentials(self, key):
|
||||||
|
return self.parsed_services['ttsnotify-sms'][0]['credentials'][key]
|
||||||
|
|
||||||
|
|
||||||
cloud_config = CloudfoundryConfig()
|
cloud_config = CloudfoundryConfig()
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ class Config(object):
|
|||||||
|
|
||||||
# AWS Settings
|
# AWS Settings
|
||||||
AWS_REGION = getenv('AWS_REGION')
|
AWS_REGION = getenv('AWS_REGION')
|
||||||
AWS_PINPOINT_REGION = getenv("AWS_PINPOINT_REGION")
|
|
||||||
AWS_US_TOLL_FREE_NUMBER = getenv("AWS_US_TOLL_FREE_NUMBER")
|
AWS_US_TOLL_FREE_NUMBER = getenv("AWS_US_TOLL_FREE_NUMBER")
|
||||||
# Whether to ignore POSTs from SNS for replies to SMS we sent
|
# Whether to ignore POSTs from SNS for replies to SMS we sent
|
||||||
RECEIVE_INBOUND_SMS = False
|
RECEIVE_INBOUND_SMS = False
|
||||||
|
|||||||
@@ -50,8 +50,6 @@ applications:
|
|||||||
SECRET_KEY: ((SECRET_KEY))
|
SECRET_KEY: ((SECRET_KEY))
|
||||||
AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
|
AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
|
||||||
AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
|
AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
|
||||||
AWS_REGION: us-west-2
|
|
||||||
AWS_PINPOINT_REGION: us-west-2
|
|
||||||
AWS_US_TOLL_FREE_NUMBER: ((default_toll_free_number))
|
AWS_US_TOLL_FREE_NUMBER: ((default_toll_free_number))
|
||||||
|
|
||||||
REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt"
|
REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
AWS_ACCESS_KEY_ID="don't write secrets to the sample file"
|
AWS_ACCESS_KEY_ID="don't write secrets to the sample file"
|
||||||
AWS_SECRET_ACCESS_KEY="don't write secrets to the sample file"
|
AWS_SECRET_ACCESS_KEY="don't write secrets to the sample file"
|
||||||
AWS_REGION=us-west-2
|
AWS_REGION=us-west-2
|
||||||
AWS_PINPOINT_REGION=us-west-2
|
|
||||||
AWS_US_TOLL_FREE_NUMBER=+18446120782
|
AWS_US_TOLL_FREE_NUMBER=+18446120782
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ def test_send_sms_successful_returns_aws_sns_response(notify_api, mocker):
|
|||||||
boto_mock.publish.assert_called_once_with(
|
boto_mock.publish.assert_called_once_with(
|
||||||
PhoneNumber="+16135555555",
|
PhoneNumber="+16135555555",
|
||||||
Message=content,
|
Message=content,
|
||||||
MessageAttributes={'AWS.SNS.SMS.SMSType': {'DataType': 'String', 'StringValue': 'Transactional'}}
|
MessageAttributes={
|
||||||
|
'AWS.SNS.SMS.SMSType': {'DataType': 'String', 'StringValue': 'Transactional'},
|
||||||
|
'AWS.MM.SMS.OriginationNumber': {'DataType': 'String', 'StringValue': '+18446120782'}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user