Example #1
0
    def async_post(self, json):
        logger.debug('POST request: %s' % str(json))

        if 'content' not in json:
            raise RuntimeError('no key [content] in json message')

        msg_content = json.get('content')
        if msg_content is None or len(msg_content.strip()) == 0:
            raise RuntimeError('content may not be blank')
        if not utils.is_base64(msg_content):
            raise RuntimeError('content in json message must be base64')

        user_id = str(json.get('user_id', 0))
        user_name = utils.b64d(json.get('user_name', utils.b64e('admin')))
        object_type = json.get('object_type')
        target_id = str(json.get('target_id'))
        namespace = json.get('namespace', '/ws')
        target_name = json.get('target_name')

        data = utils.activity_for_message(user_id, user_name)
        data['target'] = {
            'objectType': object_type,
            'id': target_id,
            'displayName': target_name,
            'url': namespace
        }
        data['object'] = {
            'content': msg_content
        }

        if not environ.env.cache.user_is_in_multicast(target_id):
            logger.info('user {} is offline, dropping message: {}'.format(target_id, str(json)))
            return

        try:
            environ.env.out_of_scope_emit('message', data, room=target_id, json=True, namespace='/ws', broadcast=True)
        except Exception as e:
            logger.error('could not /send message to target {}: {}'.format(target_id, str(e)))
            logger.exception(traceback.format_exc())
            environ.env.capture_exception(sys.exc_info())
Example #2
0
def send_broadcast():
    form = request.get_json()
    verb = form['verb']
    content = form['content']

    message = {}
    if is_blank(verb):
        message['verb'] = 'Verb may not be empty.'
    if is_blank(content):
        message['content'] = 'Content may not be empty.'

    if len(message):
        return api_response(400, message=message)

    try:
        content = utils.b64e(content)
        broadcast_manager.send(content, verb)
    except Exception as e:
        logger.error('Could not send broadcast: %s' % str(e))
        logger.exception(traceback.format_exc())
        return api_response(400, message='Could not send broadcast')
    return api_response(200)
Example #3
0
    def activity_for_login(self, skip: set=None):
        data = {
            'actor': {
                'id': BaseTest.USER_ID,
                'displayName': b64e(BaseTest.USER_NAME),
                'image': {
                    'url': 'http://some-url.com/image.jpg',
                    'width': '120',
                    'height': '120'
                },
                'attachments': list()
            },
            'verb': 'login'
        }

        if skip is not None:
            if 'user_id' in skip:
                del data['actor']['id']
            if 'user_name' in skip:
                del data['actor']['displayName']
            if 'image' in skip:
                del data['actor']['image']

        infos = {
            'gender': BaseTest.GENDER,
            'age': BaseTest.AGE,
            'membership': BaseTest.MEMBERSHIP,
            'fake_checked': BaseTest.FAKE_CHECKED,
            'has_webcam': BaseTest.HAS_WEBCAM,
            'country': BaseTest.COUNTRY,
            'city': BaseTest.CITY,
            'token': '66968fad-2336-40c9-bc6d-0ecbcd91f4da'
        }

        for key, val in infos.items():
            if skip is None or key not in skip:
                data['actor']['attachments'].append({'objectType': key, 'content': val})

        return data
Example #4
0
 def activity_for_message(self,
                          msg: str = 'test message',
                          object_type: str = 'room'):
     return {
         'actor': {
             'id': BaseTest.USER_ID,
             'url': BaseTest.ROOM_ID
         },
         'provider': {
             'url': BaseTest.CHANNEL_ID
         },
         'verb': 'send',
         'target': {
             'id': BaseTest.ROOM_ID,
             'objectType': object_type
         },
         'id': str(uuid()),
         'published':
         datetime.utcnow().strftime(ConfigKeys.DEFAULT_DATE_FORMAT),
         'object': {
             'content': b64e(msg),
             'url': BaseTest.CHANNEL_ID
         }
     }
Example #5
0
 def test_multiple_whisper_ok(self):
     act = self.act()
     act.object.content = b64e('{"text":" -kenobi -anakin Hello there!"}')
     is_valid, code, msg = self.validator.on_message(act)
     self.assertTrue(is_valid)
Example #6
0
 def test_b64e_none(self):
     self.assertEqual('', utils.b64e(None))
Example #7
0
 def test_b64e_blank(self):
     self.assertEqual('', utils.b64e(''))
Example #8
0
 def test_b64e(self):
     self.assertEqual(self.b64, utils.b64e(self.plain))
Example #9
0
    def ban_user(self,
                 user_id: str,
                 target_id: str,
                 duration: str,
                 target_type: str,
                 reason: str = None,
                 banner_id: str = None,
                 user_name: str = None) -> None:
        target_name = None

        if target_type == 'global':
            pass
        elif target_type == 'channel':
            target_name = self.env.db.get_channel_name(target_id)
        elif target_type == 'room':
            target_name = self.env.db.get_room_name(target_id)
        else:
            raise UnknownBanTypeException(target_type)

        try:
            user_name = utils.b64e(self.env.db.get_user_name(user_id))
        except NoSuchUserException:
            logger.info(
                'when processing ban request: user %s does not exist, will create'
                % user_id)
            user_name = user_name or user_id
            self.env.db.create_user(user_id, user_name)

        ban_activity = {
            'actor': {
                'id': '0',
                'displayName': utils.b64e('admin')
            },
            'verb': 'ban',
            'object': {
                'id':
                user_id,
                'displayName':
                user_name,
                'summary':
                duration,
                'updated':
                utils.ban_duration_to_datetime(duration).strftime(
                    ConfigKeys.DEFAULT_DATE_FORMAT)
            },
            'target': {
                'url': '/ws',
                'objectType': target_type
            },
            'published':
            datetime.utcnow().strftime(ConfigKeys.DEFAULT_DATE_FORMAT),
            'id': str(uuid())
        }

        if reason is not None:
            ban_activity['object']['content'] = reason
        if banner_id is not None:
            ban_activity['actor']['id'] = banner_id
        if target_name is not None:
            ban_activity['target']['id'] = target_id
            ban_activity['target']['displayName'] = utils.b64e(target_name)

        self.env.publish(ban_activity)
Example #10
0
 def get_user(self, user_id: str) -> dict:
     user_name = self.env.db.get_user_name(user_id)
     return {'uuid': user_id, 'name': utils.b64e(user_name)}
Example #11
0
    def get_bans_for_user(self, user_id: str, session=None) -> dict:
        def _to_date(_timestamp):
            return datetime.fromtimestamp(int(_timestamp)).strftime(ConfigKeys.DEFAULT_DATE_FORMAT)

        now = datetime.utcnow()
        all_channels = self.redis.hgetall(RedisKeys.channels())
        channel_ids = list()
        room_ids = list()

        output = {
            'global': dict(),
            'room': dict(),
            'channel': dict()
        }

        for channel_id, _ in all_channels.items():
            channel_ids.append(str(channel_id, 'utf-8'))

        for channel_id in channel_ids:
            all_rooms = self.redis.hgetall(RedisKeys.rooms(channel_id))

            for room_id, _ in all_rooms.items():
                room_ids.append(str(room_id, 'utf-8'))

        for channel_id in channel_ids:
            r_key = RedisKeys.banned_users_channel(channel_id)
            if not self.redis.hexists(r_key, user_id):
                continue

            ban_info = self.redis.hget(RedisKeys, r_key)
            ban_duration, ban_timestamp, _ = ban_info.split('|', 2)
            if datetime.fromtimestamp(int(ban_timestamp)) < now:
                self.redis.hdel(r_key, user_id)
                continue

            output['channel'][channel_id] = {
                'name': b64e(self.get_channel_name(channel_id)),
                'duration': ban_duration,
                'timestamp': _to_date(ban_timestamp)
            }

        for room_id in room_ids:
            r_key = RedisKeys.banned_users(room_id)
            if not self.redis.hexists(r_key, user_id):
                continue

            ban_info = self.redis.hget(RedisKeys, r_key)
            ban_duration, ban_timestamp, _ = ban_info.split('|', 2)
            if datetime.fromtimestamp(int(ban_timestamp)) < now:
                self.redis.hdel(r_key, user_id)
                continue

            output['room'][room_id] = {
                'name': b64e(self.get_room_name(room_id)),
                'duration': ban_duration,
                'timestamp': _to_date(ban_timestamp)
            }

        r_key = RedisKeys.banned_users()
        if self.redis.hexists(r_key, user_id):
            ban_info = self.redis.hget(RedisKeys.banned_users(), user_id)
            ban_duration, ban_timestamp, _ = ban_info.split('|', 2)
            if datetime.fromtimestamp(int(ban_timestamp)) < now:
                self.redis.hdel(r_key, user_id)
            else:
                output['global'] = {
                    'duration': ban_duration,
                    'timestamp': _to_date(ban_timestamp)
                }
        return output
Example #12
0
            def _pre_process(*args, **kwargs):
                if not hasattr(validation.request, validation_name):
                    raise RuntimeError(
                        'no such attribute on validation.request: %s' %
                        validation_name)

                try:
                    data = args[0]
                    if 'actor' not in data:
                        data['actor'] = dict()

                    # let the server determine the publishing time of the event, not the client
                    # use default time format, since activity streams only accept RFC3339 format
                    data['published'] = datetime.utcnow().strftime(
                        ConfigKeys.DEFAULT_DATE_FORMAT)
                    data['id'] = str(uuid())

                    if should_validate_request:
                        data['actor']['id'] = str(
                            environ.env.session.get(SessionKeys.user_id.value))
                        user_name = environ.env.session.get(
                            SessionKeys.user_name.value)
                        if user_name is None or len(user_name.strip()) == 0:
                            try:
                                user_name = utils.get_user_name_for(
                                    data['actor']['id'])
                            except NoSuchUserException:
                                error_msg = '[%s] no user found for user_id "%s" in session' % \
                                            (validation_name, str(data['actor']['id']))
                                logger.error(error_msg)
                                return ErrorCodes.NO_USER_IN_SESSION, error_msg
                        data['actor']['displayName'] = utils.b64e(user_name)

                    activity = as_parser.parse(data)

                    # the login request will not have user id in session yet, which this would check
                    if should_validate_request:
                        is_valid, error_msg = validation.request.validate_request(
                            activity)
                        if not is_valid:
                            logger.error(
                                '[%s] validation failed, error message: %s' %
                                (validation_name, str(error_msg)))
                            return ErrorCodes.VALIDATION_ERROR, error_msg

                    is_valid, status_code, message = getattr(
                        validation.request, validation_name)(activity)
                    if is_valid:
                        all_ok = True
                        if validation_name in environ.env.event_validator_map:
                            for validator in environ.env.event_validator_map[
                                    validation_name]:
                                all_ok, status_code, msg = validator(
                                    data, activity)
                                if not all_ok:
                                    logger.warning(
                                        '[%s] validator "%s" failed: %s' %
                                        (validation_name, str(validator),
                                         str(msg)))
                                    break

                        if all_ok:
                            args = (data, activity)
                            status_code, message = view_func(*args, **kwargs)

                except Exception as e:
                    logger.error('%s: %s' % (validation_name, str(e)))
                    logger.exception(traceback.format_exc())
                    environ.env.stats.incr('event.' + validation_name +
                                           '.exception')
                    environ.env.capture_exception(sys.exc_info())
                    return ErrorCodes.UNKNOWN_ERROR, str(e)

                if status_code == 200:
                    environ.env.stats.incr('event.' + validation_name +
                                           '.count')
                else:
                    environ.env.stats.incr('event.' + validation_name +
                                           '.error')
                    logger.warning(
                        'in decorator for %s, status_code: %s, message: %s' %
                        (validation_name, status_code, str(message)))
                return status_code, message
Example #13
0
 def test_create_restricted_name(self):
     activity = self.activity_for_create()
     activity['target']['displayName'] = b64e('admins')
     is_valid, code, msg = request.on_create(as_parser(activity))
     self.assertFalse(is_valid)
     self.assertEqual(code, ErrorCodes.ROOM_NAME_RESTRICTED)