mirror of
https://github.com/GSA/notifications-api.git
synced 2026-05-27 09:28:03 -04:00
3
.github/workflows/checks.yml
vendored
3
.github/workflows/checks.yml
vendored
@@ -14,8 +14,7 @@ env:
|
||||
WERKZEUG_DEBUG_PIN: off
|
||||
REDIS_ENABLED: 0
|
||||
AWS_REGION: us-west-2
|
||||
AWS_PINPOINT_REGION: us-west-2
|
||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||
AWS_US_TOLL_FREE_NUMBER: "+18446120782"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
3
.github/workflows/daily_checks.yml
vendored
3
.github/workflows/daily_checks.yml
vendored
@@ -19,8 +19,7 @@ env:
|
||||
NOTIFY_EMAIL_DOMAIN: dispostable.com
|
||||
REDIS_ENABLED: 0
|
||||
AWS_REGION: us-west-2
|
||||
AWS_PINPOINT_REGION: us-west-2
|
||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||
AWS_US_TOLL_FREE_NUMBER: "+18446120782"
|
||||
|
||||
jobs:
|
||||
pip-audit:
|
||||
|
||||
4
.github/workflows/deploy-demo.yml
vendored
4
.github/workflows/deploy-demo.yml
vendored
@@ -51,8 +51,6 @@ jobs:
|
||||
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
|
||||
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
|
||||
with:
|
||||
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
|
||||
@@ -64,8 +62,6 @@ jobs:
|
||||
--var DANGEROUS_SALT="$DANGEROUS_SALT"
|
||||
--var SECRET_KEY="$SECRET_KEY"
|
||||
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
|
||||
--var AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
|
||||
--var AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
|
||||
--var NEW_RELIC_LICENSE_KEY="$NEW_RELIC_LICENSE_KEY"
|
||||
|
||||
- name: Check for changes to egress config
|
||||
|
||||
4
.github/workflows/deploy.yml
vendored
4
.github/workflows/deploy.yml
vendored
@@ -56,8 +56,6 @@ jobs:
|
||||
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
|
||||
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
|
||||
with:
|
||||
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
|
||||
@@ -69,8 +67,6 @@ jobs:
|
||||
--var DANGEROUS_SALT="$DANGEROUS_SALT"
|
||||
--var SECRET_KEY="$SECRET_KEY"
|
||||
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
|
||||
--var AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID"
|
||||
--var AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY"
|
||||
--var NEW_RELIC_LICENSE_KEY="$NEW_RELIC_LICENSE_KEY"
|
||||
|
||||
- name: Check for changes to egress config
|
||||
|
||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.9
|
||||
96
Pipfile.lock
generated
96
Pipfile.lock
generated
@@ -277,32 +277,32 @@
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4",
|
||||
"sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f",
|
||||
"sha256:4789d1e3e257965e960232345002262ede4d094d1a19f4d3b52e48d4d8f3b885",
|
||||
"sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502",
|
||||
"sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41",
|
||||
"sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965",
|
||||
"sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e",
|
||||
"sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc",
|
||||
"sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad",
|
||||
"sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505",
|
||||
"sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388",
|
||||
"sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6",
|
||||
"sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2",
|
||||
"sha256:c5caeb8188c24888c90b5108a441c106f7faa4c4c075a2bcae438c6e8ca73cef",
|
||||
"sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac",
|
||||
"sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695",
|
||||
"sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6",
|
||||
"sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336",
|
||||
"sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0",
|
||||
"sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c",
|
||||
"sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106",
|
||||
"sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a",
|
||||
"sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8"
|
||||
"sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1",
|
||||
"sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7",
|
||||
"sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06",
|
||||
"sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84",
|
||||
"sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915",
|
||||
"sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074",
|
||||
"sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5",
|
||||
"sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3",
|
||||
"sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9",
|
||||
"sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3",
|
||||
"sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011",
|
||||
"sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536",
|
||||
"sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a",
|
||||
"sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f",
|
||||
"sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480",
|
||||
"sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac",
|
||||
"sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0",
|
||||
"sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108",
|
||||
"sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828",
|
||||
"sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354",
|
||||
"sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612",
|
||||
"sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3",
|
||||
"sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==39.0.1"
|
||||
"version": "==39.0.2"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
@@ -1604,32 +1604,32 @@
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4",
|
||||
"sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f",
|
||||
"sha256:4789d1e3e257965e960232345002262ede4d094d1a19f4d3b52e48d4d8f3b885",
|
||||
"sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502",
|
||||
"sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41",
|
||||
"sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965",
|
||||
"sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e",
|
||||
"sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc",
|
||||
"sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad",
|
||||
"sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505",
|
||||
"sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388",
|
||||
"sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6",
|
||||
"sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2",
|
||||
"sha256:c5caeb8188c24888c90b5108a441c106f7faa4c4c075a2bcae438c6e8ca73cef",
|
||||
"sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac",
|
||||
"sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695",
|
||||
"sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6",
|
||||
"sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336",
|
||||
"sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0",
|
||||
"sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c",
|
||||
"sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106",
|
||||
"sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a",
|
||||
"sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8"
|
||||
"sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1",
|
||||
"sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7",
|
||||
"sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06",
|
||||
"sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84",
|
||||
"sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915",
|
||||
"sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074",
|
||||
"sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5",
|
||||
"sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3",
|
||||
"sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9",
|
||||
"sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3",
|
||||
"sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011",
|
||||
"sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536",
|
||||
"sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a",
|
||||
"sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f",
|
||||
"sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480",
|
||||
"sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac",
|
||||
"sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0",
|
||||
"sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108",
|
||||
"sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828",
|
||||
"sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354",
|
||||
"sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612",
|
||||
"sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3",
|
||||
"sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==39.0.1"
|
||||
"version": "==39.0.2"
|
||||
},
|
||||
"cyclonedx-python-lib": {
|
||||
"hashes": [
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
import os
|
||||
|
||||
import botocore
|
||||
from boto3 import Session, client
|
||||
from boto3 import Session
|
||||
from flask import current_app
|
||||
|
||||
FILE_LOCATION_STRUCTURE = 'service-{}-notify/{}.csv'
|
||||
|
||||
default_access_key = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
default_secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
default_region = os.environ.get('AWS_REGION')
|
||||
|
||||
|
||||
def get_s3_file(
|
||||
bucket_name, file_location, access_key=default_access_key, secret_key=default_secret_key, region=default_region
|
||||
bucket_name, file_location, access_key, secret_key, region
|
||||
):
|
||||
s3_file = get_s3_object(bucket_name, file_location, access_key, secret_key, region)
|
||||
return s3_file.get()['Body'].read().decode('utf-8')
|
||||
|
||||
|
||||
def get_s3_object(
|
||||
bucket_name, file_location, access_key=default_access_key, secret_key=default_secret_key, region=default_region
|
||||
bucket_name, file_location, access_key, secret_key, region
|
||||
):
|
||||
session = Session(aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region)
|
||||
s3 = session.resource('s3')
|
||||
@@ -27,7 +21,7 @@ def get_s3_object(
|
||||
|
||||
|
||||
def file_exists(
|
||||
bucket_name, file_location, access_key=default_access_key, secret_key=default_secret_key, region=default_region
|
||||
bucket_name, file_location, access_key, secret_key, region
|
||||
):
|
||||
try:
|
||||
# try and access metadata of object
|
||||
@@ -85,28 +79,3 @@ def remove_contact_list_from_s3(service_id, contact_list_id):
|
||||
def remove_s3_object(bucket_name, object_key, access_key, secret_key, region):
|
||||
obj = get_s3_object(bucket_name, object_key, access_key, secret_key, region)
|
||||
return obj.delete()
|
||||
|
||||
|
||||
def get_list_of_files_by_suffix(
|
||||
bucket_name,
|
||||
subfolder='',
|
||||
suffix='',
|
||||
last_modified=None,
|
||||
access_key=default_access_key,
|
||||
secret_key=default_secret_key,
|
||||
region=default_region
|
||||
):
|
||||
s3_client = client('s3', region, aws_access_key_id=access_key, aws_secret_access_key=secret_key)
|
||||
paginator = s3_client.get_paginator('list_objects_v2')
|
||||
|
||||
page_iterator = paginator.paginate(
|
||||
Bucket=bucket_name,
|
||||
Prefix=subfolder
|
||||
)
|
||||
|
||||
for page in page_iterator:
|
||||
for obj in page.get('Contents', []):
|
||||
key = obj['Key']
|
||||
if key.lower().endswith(suffix.lower()):
|
||||
if not last_modified or obj['LastModified'] >= last_modified:
|
||||
yield key
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import re
|
||||
from time import monotonic
|
||||
|
||||
import boto3
|
||||
import botocore
|
||||
import phonenumbers
|
||||
from boto3 import client
|
||||
|
||||
from app.clients.sms import SmsClient
|
||||
from app.cloudfoundry_config import cloud_config
|
||||
|
||||
|
||||
class AwsSnsClient(SmsClient):
|
||||
@@ -14,19 +15,26 @@ class AwsSnsClient(SmsClient):
|
||||
"""
|
||||
|
||||
def init_app(self, current_app, statsd_client, *args, **kwargs):
|
||||
self._client = boto3.client("sns", region_name=current_app.config["AWS_REGION"])
|
||||
self._long_codes_client = boto3.client("sns", region_name=current_app.config["AWS_PINPOINT_REGION"])
|
||||
self._client = client(
|
||||
"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)
|
||||
self.current_app = current_app
|
||||
self.statsd_client = statsd_client
|
||||
self.long_code_regex = re.compile(r"^\+1\d{10}$")
|
||||
self._valid_sender_regex = re.compile(r"^\+?\d{5,14}$")
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return 'sns'
|
||||
|
||||
def get_name(self):
|
||||
return 'sns'
|
||||
return self.name
|
||||
|
||||
def _valid_sender_number(self, sender):
|
||||
return sender and re.match(self._valid_sender_regex, sender)
|
||||
|
||||
def send_sms(self, to, content, reference, sender=None, international=False):
|
||||
matched = False
|
||||
@@ -35,7 +43,6 @@ class AwsSnsClient(SmsClient):
|
||||
matched = True
|
||||
to = phonenumbers.format_number(match.number, phonenumbers.PhoneNumberFormat.E164)
|
||||
|
||||
client = self._client
|
||||
# See documentation
|
||||
# https://docs.aws.amazon.com/sns/latest/dg/sms_publish-to-phone.html#sms_publish_sdk
|
||||
attributes = {
|
||||
@@ -45,20 +52,12 @@ class AwsSnsClient(SmsClient):
|
||||
}
|
||||
}
|
||||
|
||||
# If sending with a long code number, we need to use another AWS region
|
||||
# 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
|
||||
if self._valid_sender_number(sender):
|
||||
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
||||
"DataType": "String",
|
||||
"StringValue": sender,
|
||||
}
|
||||
|
||||
# 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
|
||||
else:
|
||||
attributes["AWS.MM.SMS.OriginationNumber"] = {
|
||||
"DataType": "String",
|
||||
"StringValue": self.current_app.config["AWS_US_TOLL_FREE_NUMBER"],
|
||||
@@ -66,7 +65,7 @@ class AwsSnsClient(SmsClient):
|
||||
|
||||
try:
|
||||
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:
|
||||
self.statsd_client.incr("clients.sns.error")
|
||||
raise str(e)
|
||||
@@ -84,6 +83,3 @@ class AwsSnsClient(SmsClient):
|
||||
self.statsd_client.incr("clients.sns.error")
|
||||
self.current_app.logger.error("No valid numbers found in {}".format(to))
|
||||
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:
|
||||
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
|
||||
def sns_topic_arns(self):
|
||||
try:
|
||||
@@ -73,5 +94,8 @@ class CloudfoundryConfig:
|
||||
def _ses_credentials(self, 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()
|
||||
|
||||
@@ -94,7 +94,6 @@ class Config(object):
|
||||
|
||||
# AWS Settings
|
||||
AWS_REGION = getenv('AWS_REGION')
|
||||
AWS_PINPOINT_REGION = getenv("AWS_PINPOINT_REGION")
|
||||
AWS_US_TOLL_FREE_NUMBER = getenv("AWS_US_TOLL_FREE_NUMBER")
|
||||
# Whether to ignore POSTs from SNS for replies to SMS we sent
|
||||
RECEIVE_INBOUND_SMS = False
|
||||
@@ -153,7 +152,7 @@ class Config(object):
|
||||
MOU_SIGNER_RECEIPT_TEMPLATE_ID = '4fd2e43c-309b-4e50-8fb8-1955852d9d71'
|
||||
MOU_SIGNED_ON_BEHALF_SIGNER_RECEIPT_TEMPLATE_ID = 'c20206d5-bf03-4002-9a90-37d5032d9e84'
|
||||
MOU_SIGNED_ON_BEHALF_ON_BEHALF_RECEIPT_TEMPLATE_ID = '522b6657-5ca5-4368-a294-6b527703bd0b'
|
||||
NOTIFY_INTERNATIONAL_SMS_SENDER = '18446120782'
|
||||
NOTIFY_INTERNATIONAL_SMS_SENDER = getenv('AWS_US_TOLL_FREE_NUMBER')
|
||||
LETTERS_VOLUME_EMAIL_TEMPLATE_ID = '11fad854-fd38-4a7c-bd17-805fb13dfc12'
|
||||
NHS_EMAIL_BRANDING_ID = 'a7dc4e56-660b-4db7-8cff-12c37b12b5ea'
|
||||
# we only need real email in Live environment (production)
|
||||
|
||||
@@ -6,3 +6,4 @@ worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api-demo.app.cloud.gov
|
||||
admin_base_url: https://notify-demo.app.cloud.gov
|
||||
default_toll_free_number: "+18337581259"
|
||||
|
||||
@@ -6,3 +6,4 @@ worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api.app.cloud.gov
|
||||
admin_base_url: https://notify.app.cloud.gov
|
||||
default_toll_free_number: ""
|
||||
|
||||
@@ -9,3 +9,4 @@ admin_base_url: https://notify-sandbox.app.cloud.gov
|
||||
ADMIN_CLIENT_SECRET: sandbox-notify-secret-key
|
||||
DANGEROUS_SALT: sandbox-notify-salt
|
||||
SECRET_KEY: sandbox-notify-secret-key
|
||||
default_toll_free_number: ""
|
||||
|
||||
@@ -6,3 +6,4 @@ worker_memory: 512M
|
||||
scheduler_memory: 256M
|
||||
public_api_route: notify-api-staging.app.cloud.gov
|
||||
admin_base_url: https://notify-staging.app.cloud.gov
|
||||
default_toll_free_number: "+18556438890"
|
||||
|
||||
@@ -60,5 +60,5 @@ Rules for use:
|
||||
1. start a pipenv shell as a shortcut to load `.env` file variables: `$ pipenv shell`
|
||||
1. Deploy the application:
|
||||
```
|
||||
cf push --vars-file deploy-config/sandbox.yml --var AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID --var AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
|
||||
cf push --vars-file deploy-config/sandbox.yml
|
||||
```
|
||||
|
||||
@@ -16,6 +16,7 @@ applications:
|
||||
- name: notify-api-ses-((env))
|
||||
parameters:
|
||||
notification_webhook: "https://((public_api_route))/notifications/email/ses"
|
||||
- notify-api-sns-((env))
|
||||
|
||||
processes:
|
||||
- type: web
|
||||
@@ -47,11 +48,7 @@ applications:
|
||||
INTERNAL_CLIENT_API_KEYS: '{"notify-admin":["((ADMIN_CLIENT_SECRET))"]}'
|
||||
DANGEROUS_SALT: ((DANGEROUS_SALT))
|
||||
SECRET_KEY: ((SECRET_KEY))
|
||||
AWS_ACCESS_KEY_ID: ((AWS_ACCESS_KEY_ID))
|
||||
AWS_SECRET_ACCESS_KEY: ((AWS_SECRET_ACCESS_KEY))
|
||||
AWS_REGION: us-west-2
|
||||
AWS_PINPOINT_REGION: us-west-2
|
||||
AWS_US_TOLL_FREE_NUMBER: +18446120782
|
||||
AWS_US_TOLL_FREE_NUMBER: ((default_toll_free_number))
|
||||
|
||||
REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt"
|
||||
NEW_RELIC_CA_BUNDLE_PATH: "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
@@ -15,12 +15,12 @@ down_revision = '0345_move_broadcast_provider'
|
||||
|
||||
SMS_SENDER_ID = 'd24b830b-57b4-4f14-bd80-02f46f8d54de'
|
||||
NOTIFY_SERVICE_ID = current_app.config['NOTIFY_SERVICE_ID']
|
||||
INBOUND_NUMBER = current_app.config['NOTIFY_INTERNATIONAL_SMS_SENDER']
|
||||
INBOUND_NUMBER = current_app.config['NOTIFY_INTERNATIONAL_SMS_SENDER'].strip('+')
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
sql = f"""INSERT INTO service_sms_senders (id, sms_sender, service_id, is_default, created_at)
|
||||
sql = f"""INSERT INTO service_sms_senders (id, sms_sender, service_id, is_default, created_at)
|
||||
VALUES ('{SMS_SENDER_ID}', '{INBOUND_NUMBER}', '{NOTIFY_SERVICE_ID}',false, now())"""
|
||||
|
||||
op.execute(sql)
|
||||
|
||||
@@ -15,7 +15,7 @@ revision = '0377_add_inbound_sms_number'
|
||||
down_revision = '0376_add_provider_response'
|
||||
|
||||
INBOUND_NUMBER_ID = '9b5bc009-b847-4b1f-8a54-f3b5f95cff18'
|
||||
INBOUND_NUMBER = current_app.config['NOTIFY_INTERNATIONAL_SMS_SENDER']
|
||||
INBOUND_NUMBER = current_app.config['NOTIFY_INTERNATIONAL_SMS_SENDER'].strip('+')
|
||||
DEFAULT_SERVICE_ID = current_app.config['NOTIFY_SERVICE_ID']
|
||||
|
||||
def upgrade():
|
||||
@@ -26,20 +26,20 @@ def upgrade():
|
||||
select_by_col = 'number'
|
||||
select_by_val = INBOUND_NUMBER
|
||||
op.execute(f"delete from {table_name} where {select_by_col} = '{select_by_val}'")
|
||||
|
||||
|
||||
# add the inbound number for the default service to inbound_numbers
|
||||
table_name = 'inbound_numbers'
|
||||
provider = 'sns'
|
||||
active = 'true'
|
||||
op.execute(f"insert into {table_name} (id, number, provider, service_id, active, created_at) VALUES('{INBOUND_NUMBER_ID}', '{INBOUND_NUMBER}', '{provider}','{DEFAULT_SERVICE_ID}', '{active}', 'now()')")
|
||||
|
||||
|
||||
# add the inbound number for the default service to service_sms_senders
|
||||
table_name = 'service_sms_senders'
|
||||
sms_sender = INBOUND_NUMBER
|
||||
select_by_col = 'id'
|
||||
select_by_val = '286d6176-adbe-7ea7-ba26-b7606ee5e2a4'
|
||||
op.execute(f"update {table_name} set {'sms_sender'}='{sms_sender}' where {select_by_col} = '{select_by_val}'")
|
||||
|
||||
|
||||
# add the inbound number for the default service to inbound_numbers
|
||||
table_name = 'service_permissions'
|
||||
permission = 'inbound_sms'
|
||||
|
||||
31
migrations/versions/0391_update_sms_numbers.py
Normal file
31
migrations/versions/0391_update_sms_numbers.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
|
||||
Revision ID: 0391_update_sms_numbers
|
||||
Revises: 0390_drop_dvla_provider.py
|
||||
Create Date: 2023-03-01 12:36:38.226954
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
from flask import current_app
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = '0391_update_sms_numbers'
|
||||
down_revision = '0390_drop_dvla_provider.py'
|
||||
OLD_SMS_NUMBER = "18446120782"
|
||||
NEW_SMS_NUMBER = current_app.config['NOTIFY_INTERNATIONAL_SMS_SENDER'].strip('+')
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.alter_column("service_sms_senders", "sms_sender", type_=sa.types.String(length=255))
|
||||
op.alter_column("inbound_numbers", "number", type_=sa.types.String(length=255))
|
||||
op.execute(f"UPDATE service_sms_senders SET sms_sender = '+{NEW_SMS_NUMBER}' WHERE sms_sender IN ('{OLD_SMS_NUMBER}', '{NEW_SMS_NUMBER}')")
|
||||
op.execute(f"UPDATE inbound_numbers SET number = '+{NEW_SMS_NUMBER}' WHERE number IN ('{OLD_SMS_NUMBER}', '{NEW_SMS_NUMBER}')")
|
||||
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.execute(f"UPDATE service_sms_senders SET sms_sender = '{OLD_SMS_NUMBER}' WHERE sms_sender = '+{NEW_SMS_NUMBER}'")
|
||||
op.execute(f"UPDATE inbound_numbers SET number = '{OLD_SMS_NUMBER}' WHERE number = '+{NEW_SMS_NUMBER}'")
|
||||
op.alter_column("service_sms_senders", "sms_sender", type_=sa.types.String(length=11))
|
||||
op.alter_column("inbound_numbers", "number", type_=sa.types.String(length=11))
|
||||
@@ -19,7 +19,6 @@
|
||||
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_REGION=us-west-2
|
||||
AWS_PINPOINT_REGION=us-west-2
|
||||
AWS_US_TOLL_FREE_NUMBER=+18446120782
|
||||
|
||||
#############################################################
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from os import getenv
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
from freezegun import freeze_time
|
||||
from app.aws.s3 import get_s3_file
|
||||
|
||||
from app.aws.s3 import (
|
||||
default_access_key,
|
||||
default_region,
|
||||
default_secret_key,
|
||||
get_list_of_files_by_suffix,
|
||||
get_s3_file,
|
||||
)
|
||||
from tests.app.conftest import datetime_in_past
|
||||
default_access_key = getenv('AWS_ACCESS_KEY_ID')
|
||||
default_secret_key = getenv('AWS_SECRET_ACCESS_KEY')
|
||||
default_region = getenv('AWS_REGION')
|
||||
|
||||
|
||||
def single_s3_object_stub(key='foo', last_modified=None):
|
||||
@@ -24,7 +18,7 @@ def single_s3_object_stub(key='foo', last_modified=None):
|
||||
|
||||
def test_get_s3_file_makes_correct_call(notify_api, mocker):
|
||||
get_s3_mock = mocker.patch('app.aws.s3.get_s3_object')
|
||||
get_s3_file('foo-bucket', 'bar-file.txt')
|
||||
get_s3_file('foo-bucket', 'bar-file.txt', default_access_key, default_secret_key, default_region)
|
||||
|
||||
get_s3_mock.assert_called_with(
|
||||
'foo-bucket',
|
||||
@@ -33,52 +27,3 @@ def test_get_s3_file_makes_correct_call(notify_api, mocker):
|
||||
default_secret_key,
|
||||
default_region,
|
||||
)
|
||||
|
||||
|
||||
@freeze_time("2018-01-11 00:00:00")
|
||||
@pytest.mark.parametrize('suffix_str, days_before, returned_no', [
|
||||
('.ACK.txt', None, 1),
|
||||
('.ack.txt', None, 1),
|
||||
('.ACK.TXT', None, 1),
|
||||
('', None, 2),
|
||||
('', 1, 1),
|
||||
])
|
||||
def test_get_list_of_files_by_suffix(notify_api, mocker, suffix_str, days_before, returned_no):
|
||||
paginator_mock = mocker.patch('app.aws.s3.client')
|
||||
multiple_pages_s3_object = [
|
||||
{
|
||||
"Contents": [
|
||||
single_s3_object_stub('bar/foo.ACK.txt', datetime_in_past(1, 0)),
|
||||
]
|
||||
},
|
||||
{
|
||||
"Contents": [
|
||||
single_s3_object_stub('bar/foo1.rs.txt', datetime_in_past(2, 0)),
|
||||
]
|
||||
}
|
||||
]
|
||||
paginator_mock.return_value.get_paginator.return_value.paginate.return_value = multiple_pages_s3_object
|
||||
if (days_before):
|
||||
key = get_list_of_files_by_suffix('foo-bucket', subfolder='bar', suffix=suffix_str,
|
||||
last_modified=datetime.now(tz=pytz.utc) - timedelta(days=days_before))
|
||||
else:
|
||||
key = get_list_of_files_by_suffix('foo-bucket', subfolder='bar', suffix=suffix_str)
|
||||
|
||||
assert sum(1 for x in key) == returned_no
|
||||
for k in key:
|
||||
assert k == 'bar/foo.ACK.txt'
|
||||
|
||||
|
||||
def test_get_list_of_files_by_suffix_empty_contents_return_with_no_error(notify_api, mocker):
|
||||
paginator_mock = mocker.patch('app.aws.s3.client')
|
||||
multiple_pages_s3_object = [
|
||||
{
|
||||
"other_content": [
|
||||
'some_values',
|
||||
]
|
||||
}
|
||||
]
|
||||
paginator_mock.return_value.get_paginator.return_value.paginate.return_value = multiple_pages_s3_object
|
||||
key = get_list_of_files_by_suffix('foo-bucket', subfolder='bar', suffix='.pdf')
|
||||
|
||||
assert sum(1 for x in key) == 0
|
||||
|
||||
@@ -13,7 +13,10 @@ def test_send_sms_successful_returns_aws_sns_response(notify_api, mocker):
|
||||
boto_mock.publish.assert_called_once_with(
|
||||
PhoneNumber="+16135555555",
|
||||
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