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())
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)
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
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 } }
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)
def test_b64e_none(self): self.assertEqual('', utils.b64e(None))
def test_b64e_blank(self): self.assertEqual('', utils.b64e(''))
def test_b64e(self): self.assertEqual(self.b64, utils.b64e(self.plain))
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)
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)}
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
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
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)