def post(self):
        self._require_login("/account/register")
        self._require_registration("/account/register")

        # Check to make sure that they aren't trying to edit another user
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get("account_id")
        if target_account_id == current_user_account_id:
            url = self.request.get("url")
            secret_key = self.request.get("secret")
            query = MobileClient.query(
                MobileClient.messaging_id == url, ancestor=ndb.Key(Account, current_user_account_id)
            )
            if query.count() == 0:
                # Webhook doesn't exist, add it
                verification_key = NotificationHelper.verify_webhook(url, secret_key)
                client = MobileClient(
                    parent=self.user_bundle.account.key,
                    user_id=current_user_account_id,
                    messaging_id=url,
                    display_name=self.request.get("name"),
                    secret=secret_key,
                    client_type=ClientType.WEBHOOK,
                    verified=False,
                    verification_code=verification_key,
                )
                client.put()
            else:
                # Webhook already exists. Update the secret
                current = query.fetch()[0]
                current.secret = secret_key
                current.put()
            self.redirect("/account")
        else:
            self.redirect("/")
Beispiel #2
0
    def test_clients_type(self):
        clients = [MobileClient(
                    parent=ndb.Key(Account, 'user_id'),
                    user_id='user_id',
                    messaging_id='messaging_id_{}'.format(client_type),
                    client_type=client_type) for client_type in ClientType.names.keys()]
        for client in clients:
            client.put()

        self.assertEqual([client.messaging_id for client in MobileClient.clients(['user_id'], client_types=[ClientType.OS_ANDROID])], ['messaging_id_0'])
        self.assertEqual([client.messaging_id for client in MobileClient.clients(['user_id'], client_types=ClientType.FCM_CLIENTS)], ['messaging_id_1', 'messaging_id_3'])
        self.assertEqual([client.messaging_id for client in MobileClient.clients(['user_id'], client_types=[ClientType.WEBHOOK])], ['messaging_id_2'])
    def _send(cls, users, notification):
        # Send to FCM clients
        fcm_clients = MobileClient.clients(users,
                                           client_types=ClientType.FCM_CLIENTS)
        if fcm_clients:
            cls._defer_fcm(fcm_clients, notification)

        # Send to webhooks
        webhook_clients = MobileClient.clients(
            users, client_types=[ClientType.WEBHOOK])
        if webhook_clients:
            cls._defer_webhook(webhook_clients, notification)
    def test_fcm_messaging_ids_unsupported_type(self):
        user_id = 'user_id'

        for (token, os) in [('a', ClientType.OS_ANDROID), ('b', ClientType.OS_IOS), ('c', ClientType.WEBHOOK), ('d', ClientType.WEB)]:
            MobileClient(
                parent=ndb.Key(Account, user_id),
                user_id=user_id,
                messaging_id=token,
                client_type=os,
                device_uuid=token,
                display_name=token).put()

        self.assertEqual(MobileClient.fcm_messaging_ids(user_id), ['b', 'd'])
Beispiel #5
0
    def ping_client(self, request):
        user_id = get_current_user_id(self.headers)
        if user_id is None:
            return BaseResponse(code=401,
                                message="Unauthorized to ping client")

        gcm_id = request.mobile_id

        # Find a Client for the current user with the passed GCM ID
        clients = MobileClient.query(MobileClient.messaging_id == gcm_id,
                                     ancestor=ndb.Key(Account,
                                                      user_id)).fetch(1)
        if len(clients) == 0:
            # No Client for user with that push token - bailing
            return BaseResponse(code=404,
                                message="Invalid push token for user")
        else:
            client = clients[0]
            response = NotificationHelper.send_ping(client)
            # If we got a response from the send_ping method, it was sent via TBANS
            # We'll bubble up any errors we got back
            if response:
                if response.code == 200:
                    return BaseResponse(code=200, message="Ping sent")
                else:
                    return BaseResponse(
                        code=response.code,
                        message="Error pinging client - {}".format(
                            response.message))
            else:
                return BaseResponse(code=200, message="Ping sent")
Beispiel #6
0
    def get(self):
        self._require_admin()

        all_clients = MobileClient.query()
        android = all_clients.filter(MobileClient.client_type == ClientType.OS_ANDROID).count()
        ios = all_clients.filter(MobileClient.client_type == ClientType.OS_IOS).count()
        webhook = all_clients.filter(MobileClient.client_type == ClientType.WEBHOOK).count()

        var = Sitevar.get_by_id('notifications.enable')
        if var is None or not var.values_json == "true":
            push_enabled = False
        else:
            push_enabled = True

        self.template_values.update({
            'mobile_users': all_clients.count(),
            'android_users': android,
            'ios_users': ios,
            'webhooks': webhook,
            'broadcast_success': self.request.get('broadcast_success'),
            'push_enabled': push_enabled,
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/mobile_dashboard.html')
        self.response.out.write(template.render(path, self.template_values))
    def register_client(self, request):
        user_id = get_current_user_id(self.headers)
        if user_id is None:
            return BaseResponse(code=401, message="Unauthorized to register")
        gcm_id = request.mobile_id
        os = ClientType.enums[request.operating_system]
        name = request.name
        uuid = request.device_uuid

        query = MobileClient.query(
                MobileClient.user_id == user_id,
                MobileClient.device_uuid == uuid,
                MobileClient.client_type == os)
        # trying to figure out an elusive dupe bug
        logging.info("DEBUGGING")
        logging.info("User ID: {}".format(user_id))
        logging.info("UUID: {}".format(uuid))
        logging.info("Count: {}".format(query.count()))
        if query.count() == 0:
            # Record doesn't exist yet, so add it
            MobileClient(
                parent=ndb.Key(Account, user_id),
                user_id=user_id,
                messaging_id=gcm_id,
                client_type=os,
                device_uuid=uuid,
                display_name=name).put()
            return BaseResponse(code=200, message="Registration successful")
        else:
            # Record already exists, update it
            client = query.fetch(1)[0]
            client.messaging_id = gcm_id
            client.display_name = name
            client.put()
            return BaseResponse(code=304, message="Client already exists")
    def post(self):
        if not self.user_bundle.user:
            self.response.set_status(401)
            return

        user_id = self.user_bundle.user.user_id()
        fcm_token = self.request.get('fcm_token')
        uuid = self.request.get('uuid')
        display_name = self.request.get('display_name')
        client_type = ClientType.WEB

        query = MobileClient.query(
                MobileClient.user_id == user_id,
                MobileClient.device_uuid == uuid,
                MobileClient.client_type == client_type)
        if query.count() == 0:
            # Record doesn't exist yet, so add it
            MobileClient(
                parent=ndb.Key(Account, user_id),
                user_id=user_id,
                messaging_id=fcm_token,
                client_type=client_type,
                device_uuid=uuid,
                display_name=display_name).put()
        else:
            # Record already exists, update it
            client = query.fetch(1)[0]
            client.messaging_id = fcm_token
            client.display_name = display_name
            client.put()
    def ping_client(self, request):
        current_user = endpoints.get_current_user()
        if current_user is None:
            return BaseResponse(code=401, message="Unauthorized to ping client")

        user_id = PushHelper.user_email_to_id(current_user.email())
        gcm_id = request.mobile_id

        # Find a Client for the current user with the passed GCM ID
        clients = MobileClient.query(MobileClient.messaging_id == gcm_id, ancestor=ndb.Key(Account, user_id)).fetch(1)
        if len(clients) == 0:
            # No Client for user with that push token - bailing
            return BaseResponse(code=404, message="Invalid push token for user")
        else:
            client = clients[0]
            response = NotificationHelper.send_ping(client)
            # If we got a response from the send_ping method, it was sent via TBANS
            # We'll bubble up any errors we got back
            if response:
                if response.code == 200:
                    return BaseResponse(code=200, message="Ping sent")
                else:
                    return BaseResponse(code=response.code, message="Error pinging client - {}".format(response.message))
            else:
                return BaseResponse(code=200, message="Ping sent")
Beispiel #10
0
    def post(self, client_id):
        self._require_login()
        self._require_registration()

        # Check to make sure the user isn't trying to impersonate another
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            verification = self.request.get('code')
            webhook = MobileClient.get_by_id(int(client_id),
                                             parent=ndb.Key(
                                                 Account,
                                                 current_user_account_id))
            if webhook.client_type == ClientType.WEBHOOK and current_user_account_id == webhook.user_id:
                if verification == webhook.verification_code:
                    logging.info("webhook verified")
                    webhook.verified = True
                    webhook.put()
                    self.redirect('/account?webhook_verification_success=1')
                    return
                else:  # Verification failed
                    # Redirect back to the verification page
                    self.redirect('/webhooks/verify/{}?error=1'.format(
                        webhook.key.id()))
                    return
        self.redirect('/')
Beispiel #11
0
    def post(self):
        self._require_login()
        self._require_registration()

        # Check to make sure that they aren't trying to edit another user
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            client_id = self.request.get('client_id')
            client = MobileClient.get_by_id(int(client_id),
                                            parent=ndb.Key(
                                                Account,
                                                current_user_account_id))
            if client is not None:
                # This makes sure that the client actually exists and that this user owns it
                if client.client_type == ClientType.WEBHOOK:
                    keys = {
                        client.client_type:
                        [(client.messaging_id, client.secret)]
                    }
                else:
                    keys = {client.client_type: [client.messaging_id]}
                notification = PingNotification()
                notification.send(keys)
            self.redirect('/account')
        else:
            self.redirect('/')
    def get(self):
        self._require_admin()

        all_clients = MobileClient.query()
        android = all_clients.filter(
            MobileClient.client_type == ClientType.OS_ANDROID).count()
        ios = all_clients.filter(
            MobileClient.client_type == ClientType.OS_IOS).count()
        web = all_clients.filter(
            MobileClient.client_type == ClientType.WEB).count()
        webhook = all_clients.filter(
            MobileClient.client_type == ClientType.WEBHOOK).count()
        push_enabled = NotificationsEnable.notifications_enabled()

        self.template_values.update({
            'mobile_users':
            all_clients.count(),
            'android_users':
            android,
            'ios_users':
            ios,
            'web_users':
            web,
            'webhooks':
            webhook,
            'broadcast_success':
            self.request.get('broadcast_success'),
            'push_enabled':
            push_enabled,
        })

        path = os.path.join(os.path.dirname(__file__),
                            '../../templates/admin/mobile_dashboard.html')
        self.response.out.write(template.render(path, self.template_values))
Beispiel #13
0
    def post(self):
        self._require_login()
        self._require_registration()

        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            client_id = self.request.get('client_id')
            webhook = MobileClient.get_by_id(int(client_id),
                                             parent=ndb.Key(
                                                 Account,
                                                 current_user_account_id))
            if webhook.client_type == ClientType.WEBHOOK and current_user_account_id == webhook.user_id:
                verification_key = NotificationHelper.verify_webhook(
                    webhook.messaging_id, webhook.secret)
                webhook.verification_code = verification_key
                webhook.verified = False
                webhook.put()
                self.redirect('/account')
                return
            else:
                logging.warning("Not webhook, or wrong owner")
        else:
            logging.warning("Users don't match. " + current_user_account_id +
                            "/" + target_account_id)
        self.redirect('/')
Beispiel #14
0
 def get_client_ids_for_users(cls, os_type, user_list):
     output = []
     for user in user_list:
         client_list = MobileClient.query(MobileClient.user_id == user, MobileClient.client_type == ClientType.enums[os_type]).fetch()
         for client in client_list:
             output.append(client.messaging_id)
     return output
Beispiel #15
0
    def ping_client(self, request):
        current_user = endpoints.get_current_user()
        if current_user is None:
            return BaseResponse(code=401,
                                message="Unauthorized to ping client")

        user_id = PushHelper.user_email_to_id(current_user.email())
        gcm_id = request.mobile_id

        # Find a Client for the current user with the passed GCM ID
        clients = MobileClient.query(MobileClient.messaging_id == gcm_id,
                                     ancestor=ndb.Key(Account,
                                                      user_id)).fetch(1)
        if len(clients) == 0:
            # No Client for user with that push token - bailing
            return BaseResponse(code=404,
                                message="Invalid push token for user")
        else:
            client = clients[0]
            from helpers.tbans_helper import TBANSHelper
            success = TBANSHelper.ping(client)
            if success:
                return BaseResponse(code=200, message="Ping sent")
            else:
                return BaseResponse(code=500, message="Failed to ping client")
 def get_all_mobile_clients(cls, client_types=[]):
     output = []
     if client_types == []:
         return output
     clients = MobileClient.query(MobileClient.client_type.IN(client_types))
     for user in clients:
         output.append(user.user_id)
     return output
 def get_all_mobile_clients(cls, client_types=[]):
     output = []
     if client_types == []:
         return output
     clients = MobileClient.query(MobileClient.client_type.IN(client_types))
     for user in clients:
         output.append(user.user_id)
     return output
    def test_defer_webhook(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='messaging_id',
                              client_type=ClientType.WEBHOOK)
        client.put()
        notification = MockNotification()
        TBANSHelper._defer_webhook([client], notification)

        # Make sure we'll send to FCM clients
        tasks = self.taskqueue_stub.get_filtered_tasks(
            queue_names='push-notifications')
        self.assertEqual(len(tasks), 1)

        # Make sure our taskqueue tasks execute what we expect
        with patch.object(TBANSHelper, '_send_webhook') as mock_send_webhook:
            deferred.run(tasks[0].payload)
            mock_send_webhook.assert_called_once_with([client], ANY)
Beispiel #19
0
    def get_client_ids_for_users(cls, user_list, os_types=None):
        if not user_list:
            return defaultdict(list)

        if os_types is None:
            os_types = ClientType.names.keys()
        clients = MobileClient.query(MobileClient.user_id.IN(user_list),
                                     MobileClient.client_type.IN(os_types),
                                     MobileClient.verified == True).fetch()
        return cls.get_client_ids_for_clients(clients)
 def get_client_ids_for_users(cls, user_list, os_types=None):
     if os_types is None:
         os_types = ClientType.names.keys()
     output = defaultdict(list)
     clients = MobileClient.query(MobileClient.user_id.IN(user_list), MobileClient.client_type.IN(os_types), MobileClient.verified == True).fetch()
     for client in clients:
         if client.client_type == ClientType.WEBHOOK:
             output[client.client_type].append((client.messaging_id, client.secret))
         else:
             output[client.client_type].append(client.messaging_id)
     return output
Beispiel #21
0
    def get(self):
        self._require_admin()

        webhooks = MobileClient.query(MobileClient.client_type == ClientType.WEBHOOK).fetch()

        self.template_values.update({
            'webhooks': webhooks,
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/mobile_webhooks_dashboard.html')
        self.response.out.write(template.render(path, self.template_values))
    def test_ping_fcm_unsupported(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='token',
                              client_type=-1,
                              device_uuid='uuid',
                              display_name='Phone')

        with self.assertRaises(Exception,
                               msg='Unsupported FCM client type: -1'):
            TBANSHelper._ping_client(client)
    def test_broadcast_android(self):
        client_type = ClientType.OS_ANDROID
        messaging_id = 'token'

        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id=messaging_id,
                              client_type=client_type,
                              device_uuid='uuid',
                              display_name='Phone')
        client.put()

        from notifications.broadcast import BroadcastNotification
        with patch.object(BroadcastNotification, 'send') as mock_send:
            TBANSHelper.broadcast([client_type], 'Broadcast', 'Test broadcast')
            mock_send.assert_called_once_with({client_type: [messaging_id]})

        # Make sure we didn't send to FCM or webhooks
        tasks = self.taskqueue_stub.GetTasks('push-notifications')
        self.assertEqual(len(tasks), 0)
    def test_send_webhook_filter_webhook_clients_verified(self):
        clients = [
            MobileClient(parent=ndb.Key(Account, 'user_id'),
                         user_id='user_id',
                         messaging_id='unverified',
                         client_type=ClientType.WEBHOOK,
                         verified=False),
            MobileClient(parent=ndb.Key(Account, 'user_id'),
                         user_id='user_id',
                         messaging_id='verified',
                         client_type=ClientType.WEBHOOK,
                         verified=True)
        ]

        with patch(
                'models.notifications.requests.webhook_request.WebhookRequest',
                autospec=True) as mock_init:
            exit_code = TBANSHelper._send_webhook(clients, MockNotification())
            mock_init.assert_called_once_with(ANY, 'verified', ANY)
            self.assertEqual(exit_code, 0)
    def test_send_fcm_unhandled_error(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='messaging_id',
                              client_type=ClientType.OS_IOS)
        client.put()

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        batch_response = messaging.BatchResponse(
            [messaging.SendResponse(None, FirebaseError('code', 'message'))])
        with patch.object(FCMRequest, 'send',
                          return_value=batch_response), patch(
                              'logging.error') as mock_error:
            exit_code = TBANSHelper._send_fcm([client], MockNotification())
            self.assertEqual(exit_code, 0)
            mock_error.assert_called_once_with(
                'Unhandled FCM error for messaging_id - code / message')

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        # Check that we didn't queue for a retry
        tasks = self.taskqueue_stub.get_filtered_tasks(
            queue_names='push-notifications')
        self.assertEqual(len(tasks), 0)
    def test_send_fcm_invalid_argument_error(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='messaging_id',
                              client_type=ClientType.OS_IOS)
        client.put()

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        batch_response = messaging.BatchResponse([
            messaging.SendResponse(None,
                                   InvalidArgumentError('code', 'message'))
        ])
        with patch.object(FCMRequest, 'send',
                          return_value=batch_response), patch(
                              'logging.critical') as mock_critical:
            exit_code = TBANSHelper._send_fcm([client], MockNotification())
            self.assertEqual(exit_code, 0)
            mock_critical.assert_called_once_with(
                'Invalid argument when sending to FCM - code')

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        # Make sure we haven't queued for a retry
        tasks = self.taskqueue_stub.get_filtered_tasks(
            queue_names='push-notifications')
        self.assertEqual(len(tasks), 0)
    def test_send_fcm_sender_id_mismatch_error(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='messaging_id',
                              client_type=ClientType.OS_IOS)
        client.put()

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        batch_response = messaging.BatchResponse([
            messaging.SendResponse(None,
                                   SenderIdMismatchError('code', 'message'))
        ])
        with patch.object(FCMRequest, 'send', return_value=batch_response), \
            patch.object(MobileClient, 'delete_for_messaging_id', wraps=MobileClient.delete_for_messaging_id) as mock_delete, \
                patch('logging.info') as mock_info:
            exit_code = TBANSHelper._send_fcm([client], MockNotification())
            mock_delete.assert_called_once_with('messaging_id')
            self.assertEqual(exit_code, 0)
            mock_info.assert_called_with(
                'Deleting mismatched client with ID: messaging_id')

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'), [])

        # Make sure we haven't queued for a retry
        tasks = self.taskqueue_stub.get_filtered_tasks(
            queue_names='push-notifications')
        self.assertEqual(len(tasks), 0)
    def post(self):
        self._require_registration()
        self._require_request_user_is_bundle_user()

        # Name and URL must be non-None
        url = self.request.get('url', None)
        name = self.request.get('name', None)
        if not url or not name:
            return self.redirect('/webhooks/add?error=1')

        # Secret may be none - but we'll generate a secret for the user
        secret = self.request.get('secret', None)
        if not secret:
            import uuid
            secret = uuid.uuid4().hex

        current_user_account_id = self.user_bundle.account.key.id()
        query = MobileClient.query(MobileClient.messaging_id == url, ancestor=ndb.Key(Account, current_user_account_id))
        if query.count() == 0:
            # Webhook doesn't exist, add it
            from helpers.tbans_helper import TBANSHelper
            response = TBANSHelper.verify_webhook(url, secret)

            client = MobileClient(
                parent=self.user_bundle.account.key,
                user_id=current_user_account_id,
                messaging_id=url,
                display_name=name,
                secret=secret,
                client_type=ClientType.WEBHOOK,
                verified=False,
                verification_code=response.verification_key)
            client.put()
        else:
            # Webhook already exists. Update the secret
            current = query.fetch()[0]
            current.secret = secret
            current.put()

        self.redirect('/account')
    def test_send_fcm_unavailable_error(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='messaging_id',
                              client_type=ClientType.OS_IOS)
        client.put()

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        batch_response = messaging.BatchResponse([
            messaging.SendResponse(None, UnavailableError('code', 'message'))
        ])
        with patch.object(FCMRequest, 'send',
                          return_value=batch_response), patch(
                              'logging.error') as mock_error:
            exit_code = TBANSHelper._send_fcm([client], MockNotification())
            self.assertEqual(exit_code, 0)
            mock_error.assert_called_once_with(
                'FCM unavailable - retrying client...')

        # Sanity check
        self.assertEqual(MobileClient.fcm_messaging_ids('user_id'),
                         ['messaging_id'])

        # Check that we queue'd for a retry
        tasks = self.taskqueue_stub.get_filtered_tasks(
            queue_names='push-notifications')
        self.assertEqual(len(tasks), 1)

        # Make sure our taskqueue tasks execute what we expect
        with patch.object(TBANSHelper, '_send_fcm') as mock_send_fcm:
            deferred.run(tasks[0].payload)
            mock_send_fcm.assert_called_once_with([client], ANY, 1)
 def unregister_client(self, request):
     user_id = get_current_user_id(self.headers)
     if user_id is None:
         return BaseResponse(code=401, message="Unauthorized to unregister")
     gcm_id = request.mobile_id
     query = MobileClient.query(MobileClient.messaging_id == gcm_id, ancestor=ndb.Key(Account, user_id))\
         .fetch(keys_only=True)
     if len(query) == 0:
         # Record doesn't exist, so we can't remove it
         return BaseResponse(code=404, message="User doesn't exist. Can't remove it")
     else:
         ndb.delete_multi(query)
         return BaseResponse(code=200, message="User deleted")
Beispiel #31
0
 def unregister_client(self, request):
     current_user = endpoints.get_current_user()
     if current_user is None:
         return BaseResponse(code=401, message="Unauthorized to unregister")
     userID = PushHelper.user_email_to_id(current_user.email())
     gcmId = request.mobile_id
     query = MobileClient.query(MobileClient.messaging_id == gcmId, MobileClient.user_id == userID).fetch(keys_only=True)
     if len(query) == 0:
         # Record doesn't exist, so we can't remove it
         return BaseResponse(code=404, message="User doesn't exist. Can't remove it")
     else:
         ndb.delete_multi(query)
         return BaseResponse(code=200, message="User deleted")
 def unregister_client(self, request):
     current_user = endpoints.get_current_user()
     if current_user is None:
         return BaseResponse(code=401, message="Unauthorized to unregister")
     userID = PushHelper.user_email_to_id(current_user.email())
     gcmId = request.mobile_id
     query = MobileClient.query(MobileClient.messaging_id == gcmId, ancestor=ndb.Key(Account, userID)).fetch(keys_only=True)
     if len(query) == 0:
         # Record doesn't exist, so we can't remove it
         return BaseResponse(code=404, message="User doesn't exist. Can't remove it")
     else:
         ndb.delete_multi(query)
         return BaseResponse(code=200, message="User deleted")
    def test_ping_webhook(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='https://thebluealliance.com',
                              client_type=ClientType.WEBHOOK,
                              secret='secret',
                              display_name='Webhook')

        with patch.object(TBANSHelper, '_ping_webhook',
                          return_value=True) as mock_ping_webhook:
            success = TBANSHelper.ping(client)
            mock_ping_webhook.assert_called_once_with(client)
            self.assertTrue(success)
    def test_ping_client(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='token',
                              client_type=ClientType.OS_IOS,
                              device_uuid='uuid',
                              display_name='Phone')

        with patch.object(TBANSHelper, '_ping_client',
                          return_value=True) as mock_ping_client:
            success = TBANSHelper.ping(client)
            mock_ping_client.assert_called_once_with(client)
            self.assertTrue(success)
    def post(self):
        self._require_registration()
        self._require_request_user_is_bundle_user()

        # Name and URL must be non-None
        url = self.request.get('url', None)
        name = self.request.get('name', None)
        if not url or not name:
            return self.redirect('/webhooks/add?error=1')

        # Always generate secret server-side; previously allowed clients to set the secret
        import uuid
        secret = uuid.uuid4().hex

        current_user_account_id = self.user_bundle.account.key.id()
        query = MobileClient.query(MobileClient.messaging_id == url, ancestor=ndb.Key(Account, current_user_account_id))
        if query.count() == 0:
            # Webhook doesn't exist, add it
            from helpers.tbans_helper import TBANSHelper
            verification_key = TBANSHelper.verify_webhook(url, secret)

            client = MobileClient(
                parent=self.user_bundle.account.key,
                user_id=current_user_account_id,
                messaging_id=url,
                display_name=name,
                secret=secret,
                client_type=ClientType.WEBHOOK,
                verified=False,
                verification_code=verification_key)
            client.put()
        else:
            # Webhook already exists. Update the secret
            current = query.fetch()[0]
            current.secret = secret
            current.put()

        self.redirect('/account')
 def get_client_ids_for_users(cls, user_list, os_types=None):
     if os_types is None:
         os_types = ClientType.names.keys()
     output = defaultdict(list)
     clients = MobileClient.query(MobileClient.user_id.IN(user_list),
                                  MobileClient.client_type.IN(os_types),
                                  MobileClient.verified == True).fetch()
     for client in clients:
         if client.client_type == ClientType.WEBHOOK:
             output[client.client_type].append(
                 (client.messaging_id, client.secret))
         else:
             output[client.client_type].append(client.messaging_id)
     return output
    def test_send_webhook_multiple(self):
        clients = [
            MobileClient(parent=ndb.Key(Account, 'user_id'),
                         user_id='user_id',
                         messaging_id='{}'.format(i),
                         client_type=ClientType.WEBHOOK) for i in range(3)
        ]

        batch_response = messaging.BatchResponse([])
        with patch.object(WebhookRequest, 'send',
                          return_value=batch_response) as mock_send:
            exit_code = TBANSHelper._send_webhook(clients, MockNotification())
            self.assertEqual(mock_send.call_count, 3)
            self.assertEqual(exit_code, 0)
    def post(self):
        self._require_registration()

        # Check to make sure that they aren't trying to edit another user
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            client_id = self.request.get('client_id')
            client = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
            if client is not None:
                # This makes sure that the client actually exists and that this user owns it
                NotificationHelper.send_ping(client)
                return self.redirect('/account?ping_sent=1')
        self.redirect('/')
Beispiel #39
0
 def unregister_client(self, request):
     user_id = get_current_user_id(self.headers)
     if user_id is None:
         return BaseResponse(code=401, message="Unauthorized to unregister")
     gcm_id = request.mobile_id
     query = MobileClient.query(MobileClient.messaging_id == gcm_id, ancestor=ndb.Key(Account, user_id))\
         .fetch(keys_only=True)
     if len(query) == 0:
         # Record doesn't exist, so we can't remove it
         return BaseResponse(code=404,
                             message="User doesn't exist. Can't remove it")
     else:
         ndb.delete_multi(query)
         return BaseResponse(code=200, message="User deleted")
    def test_ping_webhook_failure(self):
        client = MobileClient(parent=ndb.Key(Account, 'user_id'),
                              user_id='user_id',
                              messaging_id='https://thebluealliance.com',
                              client_type=ClientType.WEBHOOK,
                              secret='secret',
                              display_name='Webhook')

        from models.notifications.requests.webhook_request import WebhookRequest
        with patch.object(WebhookRequest, 'send',
                          return_value=False) as mock_send:
            success = TBANSHelper._ping_webhook(client)
            mock_send.assert_called_once()
            self.assertFalse(success)
    def test_fcm_messaging_ids(self):
        user_id_one = 'user_id_one'
        token_one = 'token1'
        token_two = 'token2'

        user_id_two = 'user_id_two'
        token_three = 'token3'

        user_id_three = 'user_id_three'

        for (user_id, tokens) in [(user_id_one, [token_one, token_two]), (user_id_two, [token_three])]:
            for token in tokens:
                MobileClient(
                    parent=ndb.Key(Account, user_id),
                    user_id=user_id,
                    messaging_id=token,
                    client_type=ClientType.OS_IOS,
                    device_uuid=token[::-1],
                    display_name='Phone').put()

        self.assertEqual(MobileClient.fcm_messaging_ids(user_id_one), [token_one, token_two])
        self.assertEqual(MobileClient.fcm_messaging_ids(user_id_two), [token_three])
        self.assertEqual(MobileClient.fcm_messaging_ids(user_id_three), [])
Beispiel #42
0
 def register_client(self, request):
     current_user = endpoints.get_current_user()
     if current_user is None:
         return BaseResponse(code=401, message="Unauthorized to register")
     userId = PushHelper.user_email_to_id(current_user.email())
     gcmId = request.mobile_id
     os = ClientType.enums[request.operating_system]
     if MobileClient.query( MobileClient.messaging_id==gcmId ).count() == 0:
         # Record doesn't exist yet, so add it
         MobileClient(   messaging_id = gcmId,
                         user_id = userId,
                         client_type = os ).put()
         return BaseResponse(code=200, message="Registration successful")
     else:
         # Record already exists, don't bother updating it again
         return BaseResponse(code=304, message="Client already exists")
    def get(self):
        webhooks = MobileClient.query(MobileClient.client_type == ClientType.WEBHOOK).fetch()
        failures = []

        for client in webhooks:
            response = TBANSHelper.ping_webhook(client)
            if not response.code == 200:
                failures.append(client.key)

        count = len(failures)
        if failures:
            ndb.delete_multi(failures)
        logging.info("Deleted {} broken webhooks".format(count))

        template_values = {'count': count}
        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/webhooks_clear_do.html')
        self.response.out.write(template.render(path, template_values))
 def get(self):
     clients = MobileClient.query().fetch()
     clients = sorted(clients, key=lambda x: (x.messaging_id, x.updated))
     last = None
     to_remove = []
     last = None
     for client in clients:
         if last is not None and client.messaging_id == last.messaging_id:
             logging.info("Removing")
             to_remove.append(client.key)
         last = client
     count = len(to_remove)
     if to_remove:
         ndb.delete_multi(to_remove)
     logging.info("Removed {} duplicate mobile clients".format(count))
     template_values = {'count': count}
     path = os.path.join(os.path.dirname(__file__), '../../templates/admin/mobile_clear_do.html')
     self.response.out.write(template.render(path, template_values))
    def get(self):
        webhooks = MobileClient.query(MobileClient.client_type == ClientType.WEBHOOK).fetch()
        failures = []

        notification = PingNotification()._render_webhook()

        for key in webhooks:
            if not NotificationSender.send_webhook(notification, [(key.messaging_id, key.secret)]):
                failures.append(key.key)

        count = len(failures)
        if failures:
            ndb.delete_multi(failures)
        logging.info("Deleted {} broken webhooks".format(count))

        template_values = {'count': count}
        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/webhooks_clear_do.html')
        self.response.out.write(template.render(path, template_values))
    def post(self):
        self._require_registration()

        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            client_id = self.request.get('client_id')
            webhook = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
            if webhook.client_type == ClientType.WEBHOOK and current_user_account_id == webhook.user_id:
                verification_key = NotificationHelper.verify_webhook(webhook.messaging_id, webhook.secret)
                webhook.verification_code = verification_key
                webhook.verified = False
                webhook.put()
                self.redirect('/account')
                return
            else:
                logging.warning("Not webhook, or wrong owner")
        else:
            logging.warning("Users don't match. "+current_user_account_id+"/"+target_account_id)
        self.redirect('/')
    def post(self):
        self._require_registration()

        # Check to make sure that they aren't trying to edit another user
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            client_id = self.request.get('client_id')
            client = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
            if client is not None:
                # This makes sure that the client actually exists and that this user owns it
                if client.client_type == ClientType.WEBHOOK:
                    keys = {client.client_type: [(client.messaging_id, client.secret)]}
                else:
                    keys = {client.client_type: [client.messaging_id]}
                notification = PingNotification()
                notification.send(keys)
            self.redirect('/account')
        else:
            self.redirect('/')
    def post(self, client_id):
        self._require_registration()

        # Check to make sure the user isn't trying to impersonate another
        current_user_account_id = self.user_bundle.account.key.id()
        target_account_id = self.request.get('account_id')
        if target_account_id == current_user_account_id:
            verification = self.request.get('code')
            webhook = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
            if webhook.client_type == ClientType.WEBHOOK and current_user_account_id == webhook.user_id:
                if verification == webhook.verification_code:
                    logging.info("webhook verified")
                    webhook.verified = True
                    webhook.put()
                    self.redirect('/account?webhook_verification_success=1')
                    return
                else:  # Verification failed
                    # Redirect back to the verification page
                    self.redirect('/webhooks/verify/{}?error=1'.format(webhook.key.id()))
                    return
        self.redirect('/')
    def post(self, client_id):
        self._require_registration()
        self._require_request_user_is_bundle_user()

        current_user_account_id = self.user_bundle.account.key.id()
        if not current_user_account_id:
            return self.redirect('/')

        verification = self.request.get('code')
        if not verification:
            return self.redirect('/webhooks/verify/{}?error=1'.format(webhook.key.id()))

        webhook = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
        if not webhook or webhook.client_type != ClientType.WEBHOOK or current_user_account_id != webhook.user_id:
            return self.redirect('/')

        if verification == webhook.verification_code:
            webhook.verified = True
            webhook.put()
            return self.redirect('/account?webhook_verification_success=1')
        else:
            # Redirect back to the verification page
            return self.redirect('/webhooks/verify/{}?error=1'.format(webhook.key.id()))
    def post(self):
        self._require_registration()
        self._require_request_user_is_bundle_user()

        current_user_account_id = self.user_bundle.account.key.id()
        if not current_user_account_id:
            return self.redirect('/')

        client_id = self.request.get('client_id')
        if not client_id:
            return self.redirect('/')

        webhook = MobileClient.get_by_id(int(client_id), parent=ndb.Key(Account, current_user_account_id))
        if not webhook or webhook.client_type != ClientType.WEBHOOK or current_user_account_id != webhook.user_id:
            return self.redirect('/')

        from helpers.tbans_helper import TBANSHelper
        response = TBANSHelper.verify_webhook(webhook.messaging_id, webhook.secret)

        webhook.verification_code = response.verification_key
        webhook.verified = False
        webhook.put()

        return self.redirect('/account')
 def mobile_clients(self):
     user_id = self.user.user_id()
     return MobileClient.query(ancestor=ndb.Key(Account, user_id)).fetch()
Beispiel #52
0
 def delete_bad_gcm_token(cls, key):
     logging.info("removing bad GCM token: "+key)
     to_delete = MobileClient.query(MobileClient.messaging_id == key).fetch(keys_only=True)
     ndb.delete_multi(to_delete)
Beispiel #53
0
 def update_token(cls, old, new):
     logging.info("updating token"+old+"\n->"+new)
     to_update = MobileClient.query(MobileClient.messaging_id == old).fetch()
     for model in to_update:
         model.messaging_id = new
         model.put()
 def update_token(cls, old, new):
     to_update = MobileClient.query(MobileClient.messaging_id == old).fetch()
     for model in to_update:
         model.messaging_id = new
         model.put()