push_notifications: Verify that token types are valid.

We only have two types of push notification tokens, so we should
validate that in the bouncer code path.
This commit is contained in:
Tim Abbott 2017-07-07 09:29:45 -07:00
parent 40425044c4
commit 0606ba88df
2 changed files with 22 additions and 12 deletions

View File

@ -141,6 +141,10 @@ class PushBouncerNotificationTest(BouncerTestCase):
'token': token}, 'token': token},
**self.api_auth(self.example_email("hamlet"))) **self.api_auth(self.example_email("hamlet")))
self.assert_json_error(result, "Must validate with valid Zulip server API key") self.assert_json_error(result, "Must validate with valid Zulip server API key")
result = self.client_post(endpoint, {'user_id': user_id, 'token': token,
'token_kind': 17},
**self.get_auth())
self.assert_json_error(result, "Invalid token type")
def test_remote_push_user_endpoints(self): def test_remote_push_user_endpoints(self):
# type: () -> None # type: () -> None
@ -196,26 +200,29 @@ class PushBouncerNotificationTest(BouncerTestCase):
server = RemoteZulipServer.objects.get(uuid=self.server_uuid) server = RemoteZulipServer.objects.get(uuid=self.server_uuid)
endpoints = [ endpoints = [
('/json/users/me/apns_device_token', 'apple-tokenaz'), ('/json/users/me/apns_device_token', 'apple-tokenaz', RemotePushDeviceToken.APNS),
('/json/users/me/android_gcm_reg_id', 'android-token'), ('/json/users/me/android_gcm_reg_id', 'android-token', RemotePushDeviceToken.GCM),
] ]
# Test error handling # Test error handling
for endpoint, _ in endpoints: for endpoint, _, kind in endpoints:
# Try adding/removing tokens that are too big... # Try adding/removing tokens that are too big...
broken_token = "a" * 5000 # too big broken_token = "a" * 5000 # too big
result = self.client_post(endpoint, {'token': broken_token}) result = self.client_post(endpoint, {'token': broken_token,
'token_kind': kind})
self.assert_json_error(result, 'Empty or invalid length token') self.assert_json_error(result, 'Empty or invalid length token')
result = self.client_delete(endpoint, {'token': broken_token}) result = self.client_delete(endpoint, {'token': broken_token,
'token_kind': kind})
self.assert_json_error(result, 'Empty or invalid length token') self.assert_json_error(result, 'Empty or invalid length token')
# Try to remove a non-existent token... # Try to remove a non-existent token...
result = self.client_delete(endpoint, {'token': 'abcd1234'}) result = self.client_delete(endpoint, {'token': 'abcd1234',
'token_kind': kind})
self.assert_json_error(result, 'Token does not exist') self.assert_json_error(result, 'Token does not exist')
# Add tokens # Add tokens
for endpoint, token in endpoints: for endpoint, token, kind in endpoints:
# Test that we can push twice # Test that we can push twice
result = self.client_post(endpoint, {'token': token}) result = self.client_post(endpoint, {'token': token})
self.assert_json_success(result) self.assert_json_success(result)
@ -234,8 +241,9 @@ class PushBouncerNotificationTest(BouncerTestCase):
self.assertEqual(len(tokens), 2) self.assertEqual(len(tokens), 2)
# Remove tokens # Remove tokens
for endpoint, token in endpoints: for endpoint, token, kind in endpoints:
result = self.client_delete(endpoint, {'token': token}) result = self.client_delete(endpoint, {'token': token,
'token_kind': kind})
self.assert_json_success(result) self.assert_json_success(result)
tokens = list(RemotePushDeviceToken.objects.filter(user_id=user.id, token=token, tokens = list(RemotePushDeviceToken.objects.filter(user_id=user.id, token=token,
server=server)) server=server))

View File

@ -12,7 +12,7 @@ from zerver.lib.push_notifications import send_android_push_notification, \
send_apple_push_notification send_apple_push_notification
from zerver.lib.request import JsonableError from zerver.lib.request import JsonableError
from zerver.lib.response import json_error, json_success from zerver.lib.response import json_error, json_success
from zerver.lib.validator import check_dict from zerver.lib.validator import check_dict, check_int
from zerver.models import UserProfile, PushDeviceToken, Realm from zerver.models import UserProfile, PushDeviceToken, Realm
from zerver.views.push_notifications import validate_token from zerver.views.push_notifications import validate_token
@ -25,6 +25,8 @@ def validate_entity(entity):
def validate_bouncer_token_request(entity, token, kind): def validate_bouncer_token_request(entity, token, kind):
# type: (Union[UserProfile, RemoteZulipServer], str, int) -> None # type: (Union[UserProfile, RemoteZulipServer], str, int) -> None
if kind not in [RemotePushDeviceToken.APNS, RemotePushDeviceToken.GCM]:
raise JsonableError(_("Invalid token type"))
validate_entity(entity) validate_entity(entity)
validate_token(token, kind) validate_token(token, kind)
@ -35,7 +37,7 @@ def report_error(request, deployment, type=REQ(), report=REQ(validator=check_dic
@has_request_variables @has_request_variables
def remote_server_register_push(request, entity, user_id=REQ(), def remote_server_register_push(request, entity, user_id=REQ(),
token=REQ(), token_kind=REQ(), ios_app_id=None): token=REQ(), token_kind=REQ(validator=check_int), ios_app_id=None):
# type: (HttpRequest, Union[UserProfile, RemoteZulipServer], int, str, int, Optional[Text]) -> HttpResponse # type: (HttpRequest, Union[UserProfile, RemoteZulipServer], int, str, int, Optional[Text]) -> HttpResponse
validate_bouncer_token_request(entity, token, token_kind) validate_bouncer_token_request(entity, token, token_kind)
server = cast(RemoteZulipServer, entity) server = cast(RemoteZulipServer, entity)
@ -60,7 +62,7 @@ def remote_server_register_push(request, entity, user_id=REQ(),
@has_request_variables @has_request_variables
def remote_server_unregister_push(request, entity, token=REQ(), def remote_server_unregister_push(request, entity, token=REQ(),
token_kind=REQ(), ios_app_id=None): token_kind=REQ(validator=check_int), ios_app_id=None):
# type: (HttpRequest, Union[UserProfile, RemoteZulipServer], str, int, Optional[Text]) -> HttpResponse # type: (HttpRequest, Union[UserProfile, RemoteZulipServer], str, int, Optional[Text]) -> HttpResponse
validate_bouncer_token_request(entity, token, token_kind) validate_bouncer_token_request(entity, token, token_kind)
server = cast(RemoteZulipServer, entity) server = cast(RemoteZulipServer, entity)