Make all responses to email API return a validation response. (#3650)
This commit is contained in:
Родитель
0c43382ca5
Коммит
be18b6cbdf
|
@ -125,7 +125,9 @@ CSP_IMG_SRC += (HTTP_GA_SRC,)
|
|||
CSP_SCRIPT_SRC += (HTTP_GA_SRC, "'self'")
|
||||
|
||||
# Auth token required to authorize inbound email.
|
||||
INBOUND_EMAIL_SECRET_KEY = 'totally-unsecure-string-for-local-development-goodness'
|
||||
INBOUND_EMAIL_SECRET_KEY = 'totally-unsecure-secret-string'
|
||||
# Validation key we need to send in POST response.
|
||||
INBOUND_EMAIL_VALIDATION_KEY = 'totally-unsecure-validation-string'
|
||||
|
||||
# If you have settings you want to overload, put them in a local_settings.py.
|
||||
try:
|
||||
|
|
|
@ -389,19 +389,24 @@ class TestReviewNotesViewSetCreateActivityEmailWaffleOff(TestCase):
|
|||
|
||||
@override_settings(ALLOWED_CLIENTS_EMAIL_API=['10.10.10.10'])
|
||||
@override_settings(INBOUND_EMAIL_SECRET_KEY='SOME SECRET KEY')
|
||||
@override_settings(INBOUND_EMAIL_VALIDATION_KEY='validation key')
|
||||
class TestEmailApi(TestCase):
|
||||
|
||||
def get_request(self, data):
|
||||
datastr = json.dumps(data)
|
||||
req = req_factory_factory(reverse('inbound-email-api'))
|
||||
req = req_factory_factory(reverse('inbound-email-api'), post=True)
|
||||
req.META['REMOTE_ADDR'] = '10.10.10.10'
|
||||
req.META['CONTENT_LENGTH'] = len(datastr)
|
||||
req.META['CONTENT_TYPE'] = 'application/json'
|
||||
req.POST = data
|
||||
req.method = 'POST'
|
||||
req._stream = StringIO.StringIO(datastr)
|
||||
return req
|
||||
|
||||
def get_validation_request(self, data):
|
||||
req = req_factory_factory(
|
||||
url=reverse('inbound-email-api'), post=True, data=data)
|
||||
req.META['REMOTE_ADDR'] = '10.10.10.10'
|
||||
return req
|
||||
|
||||
def test_basic(self):
|
||||
user = user_factory()
|
||||
self.grant_permission(user, '*:*')
|
||||
|
@ -414,6 +419,8 @@ class TestEmailApi(TestCase):
|
|||
|
||||
res = inbound_email(req)
|
||||
assert res.status_code == 201
|
||||
res.render()
|
||||
assert res.content == '"validation key"'
|
||||
logs = ActivityLog.objects.for_addons(addon)
|
||||
assert logs.count() == 1
|
||||
assert logs.get(action=amo.LOG.REVIEWER_REPLY_VERSION.id)
|
||||
|
@ -442,8 +449,28 @@ class TestEmailApi(TestCase):
|
|||
res = inbound_email(req)
|
||||
_mock.assert_called_with(('something',))
|
||||
assert res.status_code == 201
|
||||
res.render()
|
||||
assert res.content == '"validation key"'
|
||||
|
||||
def test_bad_request(self):
|
||||
"""Test with no email body."""
|
||||
res = inbound_email(self.get_request({'SecretKey': 'SOME SECRET KEY'}))
|
||||
assert res.status_code == 400
|
||||
|
||||
@mock.patch('olympia.activity.tasks.process_email.apply_async')
|
||||
def test_validation_response(self, _mock):
|
||||
req = self.get_validation_request(
|
||||
{'SecretKey': 'SOME SECRET KEY', 'Type': 'Validation'})
|
||||
res = inbound_email(req)
|
||||
assert not _mock.called
|
||||
assert res.status_code == 200
|
||||
res.render()
|
||||
assert res.content == '"validation key"'
|
||||
|
||||
@mock.patch('olympia.activity.tasks.process_email.apply_async')
|
||||
def test_validation_response_wrong_secret(self, _mock):
|
||||
req = self.get_validation_request(
|
||||
{'SecretKey': 'WRONG SECRET', 'Type': 'Validation'})
|
||||
res = inbound_email(req)
|
||||
assert not _mock.called
|
||||
assert res.status_code == 403
|
||||
|
|
|
@ -82,11 +82,13 @@ class EmailCreationPermission(object):
|
|||
# request.data isn't available at this point.
|
||||
data = json.loads(request.body)
|
||||
except ValueError:
|
||||
data = {}
|
||||
# Verification checks don't send JSON, but do send the key as POST.
|
||||
data = request.POST
|
||||
|
||||
secret_key = data.get('SecretKey', '')
|
||||
if not secret_key == settings.INBOUND_EMAIL_SECRET_KEY:
|
||||
log.info('Invalid secret key [%s] provided' % (secret_key,))
|
||||
log.info('Invalid secret key [%s] provided; data [%s]' % (
|
||||
secret_key, data))
|
||||
return False
|
||||
|
||||
remote_ip = request.META.get('REMOTE_ADDR', '')
|
||||
|
@ -102,10 +104,17 @@ class EmailCreationPermission(object):
|
|||
@authentication_classes(())
|
||||
@permission_classes((EmailCreationPermission,))
|
||||
def inbound_email(request):
|
||||
validation_response = settings.INBOUND_EMAIL_VALIDATION_KEY
|
||||
if request.data.get('Type', '') == 'Validation':
|
||||
# Its just a verification check that the end-point is working.
|
||||
return Response(data=validation_response,
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
message = request.data.get('Message', None)
|
||||
if not message:
|
||||
raise ParseError(
|
||||
detail='Message not present in the POST data.')
|
||||
|
||||
process_email.apply_async((message,))
|
||||
return Response(status=status.HTTP_201_CREATED)
|
||||
return Response(data=validation_response,
|
||||
status=status.HTTP_201_CREATED)
|
||||
|
|
|
@ -16,5 +16,5 @@ urlpatterns = patterns(
|
|||
url(r'^v3/internal/', include('olympia.internal_tools.urls')),
|
||||
url(r'^v3/', include('olympia.signing.urls')),
|
||||
url(r'^v3/statistics/', include('olympia.stats.api_urls')),
|
||||
url(r'^v3/activity', include('olympia.activity.urls')),
|
||||
url(r'^v3/activity/', include('olympia.activity.urls')),
|
||||
)
|
||||
|
|
|
@ -33,6 +33,15 @@ EMAIL_HOST_USER = EMAIL_URL['EMAIL_HOST_USER']
|
|||
EMAIL_HOST_PASSWORD = EMAIL_URL['EMAIL_HOST_PASSWORD']
|
||||
EMAIL_QA_WHITELIST = env.list('EMAIL_QA_WHITELIST')
|
||||
|
||||
# Filter IP addresses of allowed clients that can post email through the API.
|
||||
ALLOWED_CLIENTS_EMAIL_API = env.list('ALLOWED_CLIENTS_EMAIL_API', default=[])
|
||||
# Auth token required to authorize inbound email.
|
||||
INBOUND_EMAIL_SECRET_KEY = env('INBOUND_EMAIL_SECRET_KEY', default='')
|
||||
# Validation key we need to send in POST response.
|
||||
INBOUND_EMAIL_VALIDATION_KEY = env('INBOUND_EMAIL_VALIDATION_KEY', default='')
|
||||
# Domain emails should be sent to.
|
||||
INBOUND_EMAIL_DOMAIN = env('INBOUND_EMAIL_DOMAIN', default=DOMAIN)
|
||||
|
||||
ENV = env('ENV')
|
||||
DEBUG = False
|
||||
DEBUG_PROPAGATE_EXCEPTIONS = False
|
||||
|
|
|
@ -20,6 +20,15 @@ EMAIL_BLACKLIST = env.list('EMAIL_BLACKLIST')
|
|||
|
||||
SEND_REAL_EMAIL = True
|
||||
|
||||
# Filter IP addresses of allowed clients that can post email through the API.
|
||||
ALLOWED_CLIENTS_EMAIL_API = env.list('ALLOWED_CLIENTS_EMAIL_API', default=[])
|
||||
# Auth token required to authorize inbound email.
|
||||
INBOUND_EMAIL_SECRET_KEY = env('INBOUND_EMAIL_SECRET_KEY', default='')
|
||||
# Validation key we need to send in POST response.
|
||||
INBOUND_EMAIL_VALIDATION_KEY = env('INBOUND_EMAIL_VALIDATION_KEY', default='')
|
||||
# Domain emails should be sent to.
|
||||
INBOUND_EMAIL_DOMAIN = env('INBOUND_EMAIL_DOMAIN', default=DOMAIN)
|
||||
|
||||
ENV = env('ENV')
|
||||
DEBUG = False
|
||||
DEBUG_PROPAGATE_EXCEPTIONS = False
|
||||
|
|
|
@ -32,6 +32,16 @@ EMAIL_HOST_USER = EMAIL_URL['EMAIL_HOST_USER']
|
|||
EMAIL_HOST_PASSWORD = EMAIL_URL['EMAIL_HOST_PASSWORD']
|
||||
EMAIL_QA_WHITELIST = env.list('EMAIL_QA_WHITELIST')
|
||||
|
||||
# Filter IP addresses of allowed clients that can post email through the API.
|
||||
ALLOWED_CLIENTS_EMAIL_API = env.list('ALLOWED_CLIENTS_EMAIL_API', default=[])
|
||||
# Auth token required to authorize inbound email.
|
||||
INBOUND_EMAIL_SECRET_KEY = env('INBOUND_EMAIL_SECRET_KEY', default='')
|
||||
# Validation key we need to send in POST response.
|
||||
INBOUND_EMAIL_VALIDATION_KEY = env('INBOUND_EMAIL_VALIDATION_KEY', default='')
|
||||
# Domain emails should be sent to.
|
||||
INBOUND_EMAIL_DOMAIN = env('INBOUND_EMAIL_DOMAIN', default=DOMAIN)
|
||||
|
||||
|
||||
ENV = env('ENV')
|
||||
DEBUG = False
|
||||
DEBUG_PROPAGATE_EXCEPTIONS = False
|
||||
|
|
|
@ -217,14 +217,14 @@ MOBILE_DOMAIN = 'm.%s' % DOMAIN
|
|||
# The full url of the mobile site.
|
||||
MOBILE_SITE_URL = 'http://%s' % MOBILE_DOMAIN
|
||||
|
||||
# Filter IP addresses of the allowed clients that can post email
|
||||
# through the API.
|
||||
# Filter IP addresses of allowed clients that can post email through the API.
|
||||
ALLOWED_CLIENTS_EMAIL_API = env.list('ALLOWED_CLIENTS_EMAIL_API', default=[])
|
||||
|
||||
# Auth token required to authorize inbound email.
|
||||
INBOUND_EMAIL_SECRET_KEY = env('INBOUND_EMAIL_SECRET_KEY', default='')
|
||||
|
||||
INBOUND_EMAIL_DOMAIN = DOMAIN
|
||||
# Validation key we need to send in POST response.
|
||||
INBOUND_EMAIL_VALIDATION_KEY = env('INBOUND_EMAIL_VALIDATION_KEY', default='')
|
||||
# Domain emails should be sent to.
|
||||
INBOUND_EMAIL_DOMAIN = env('INBOUND_EMAIL_DOMAIN', default=DOMAIN)
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
|
|
Загрузка…
Ссылка в новой задаче