def request_password_reset(email, user_language) : user_obj = db.users.find_one({'profile.email': email}) if user_obj is None : raise UserError('EMAIL_NOT_EXIST') reset_key = random_bytes_str(16) rdb.set('passreset-' + reset_key, email) send_noreply(email, '找回密码', '点击下方的链接重置密码:\n%s%s' % ('https://patchyvideo.com/resetpassword?key=', reset_key))
def require_session(session_type): # TODO: add challenge code to redis if session_type not in ['LOGIN', 'SIGNUP']: raise UserError('INCORRECT_SESSION_TYPE') sid = binascii.hexlify(bytearray(random_bytes(16))).decode() rdb.set(sid, session_type, ex=UserConfig.SESSION_EXPIRE_TIME) log(obj={'sid': sid}) return sid
def _updateUserRedisValue(user_id, updater) : redis_user_key_lookup_key = f"user-{str(user_id)}" redis_user_key_ttl = rdb.ttl(redis_user_key_lookup_key) redis_user_key = rdb.get(redis_user_key_lookup_key) if redis_user_key : redis_user_obj_json = rdb.get(redis_user_key) if redis_user_obj_json : redis_user_obj = loads(redis_user_obj_json) redis_user_obj = updater(redis_user_obj) rdb.set(redis_user_key, dumps(redis_user_obj), ex = redis_user_key_ttl)
def require_session(session_type, **kwargs) : # TODO: add challenge code to redis if session_type not in ['LOGIN', 'SIGNUP', 'LOGIN_OR_SIGNUP_OPENID_QQ'] : raise UserError('INCORRECT_SESSION_TYPE') sid = binascii.hexlify(bytearray(random_bytes(16))).decode() session_obj = { 'type': session_type, 'openid_qq': kwargs['openid_qq'] if session_type == 'LOGIN_OR_SIGNUP_OPENID_QQ' else '' } rdb.set(sid, dumps(session_obj), ex = UserConfig.SESSION_EXPIRE_TIME) log(obj = {'sid': sid}) return sid
def request_password_reset(email, user_language) : user_obj = db.users.find_one({'profile.email': email}) if user_obj is None : raise UserError('EMAIL_NOT_EXIST') reset_key = random_bytes_str(16) rdb.set('passreset-' + reset_key, email) if user_language not in ['CHS', 'ENG'] : user_language = 'ENG' template_file = f'PatchyVideo-passreset-{user_language}.html' title = get_template_attribute(template_file, 'get_title') html_doc = render_template(template_file, key = reset_key) send_noreply(email, str(title()), html_doc, mime = 'html')
async def upload_image(request): data = await request.post() try: file_field = data['file'] type_field = data['type'] if type_field == 'cover': resolution = (320, 200) dst = _COVER_PATH elif type_field == 'userphoto': resolution = (256, 256) dst = _USERPHOTO_PATH else: return web.json_response( makeResponseFailed('INCORRECT_UPLOAD_TYPE'), dumps=dumps) content = file_field.file.read() except: return web.json_response(makeResponseFailed('INCORRECT_REQUEST'), dumps=dumps) if len(content) > UploadConfig.MAX_UPLOAD_SIZE: return web.json_response(makeResponseFailed('FILE_TOO_LARGE'), dumps=dumps) try: img = Image.open(io.BytesIO(content)) if img is None: raise Exception() except: return web.json_response(makeResponseFailed('UNRECOGNIZED_IMAGE_FILE'), dumps=dumps) if isinstance(img, PIL.GifImagePlugin.GifImageFile): filename = random_bytes_str(24) + ".gif" frames = ImageSequence.Iterator(img) frames = _gif_thumbnails(frames, resolution) om = next(frames) # Handle first frame separately om.info = img.info # Copy sequence info om.save(dst + filename, save_all=True, append_images=list(frames), loop=0) else: filename = random_bytes_str(24) + ".png" img.thumbnail(resolution, Image.ANTIALIAS) img.save(dst + filename) file_key = "upload-image-" + random_bytes_str(16) rdb.set(file_key, filename) log('fe_upload_image', obj={ 'filename': filename, 'file_key': file_key, 'size': len(content) }) return web.json_response(makeResponseSuccess({'file_key': file_key}), dumps=dumps)
async def upload_image_url(request): data = await request.json() try: url = data['url'] if data['type'] == 'cover': resolution = (320, 200) dst = _COVER_PATH elif data['type'] == 'userphoto': resolution = (256, 256) dst = _USERPHOTO_PATH else: return web.json_response( makeResponseFailed('INCORRECT_UPLOAD_TYPE'), dumps=dumps) except: return web.json_response(makeResponseFailed('INCORRECT_REQUEST'), dumps=dumps) async with ClientSession() as session: async with session.get(url) as resp: if resp.status == 200: try: img = Image.open(io.BytesIO(await resp.read())) if isinstance(img, PIL.GifImagePlugin.GifImageFile): filename = random_bytes_str(24) + ".gif" frames = ImageSequence.Iterator(img) frames = _gif_thumbnails(frames, resolution) om = next(frames) # Handle first frame separately om.info = img.info # Copy sequence info om.save(dst + filename, save_all=True, append_images=list(frames), loop=0) else: filename = random_bytes_str(24) + ".png" img.thumbnail(resolution, Image.ANTIALIAS) img.save(dst + filename) except: return web.json_response( makeResponseFailed('INCORRECT_UPLOAD_TYPE'), dumps=dumps) else: return web.json_response( makeResponseFailed('INCORRECT_UPLOAD_TYPE'), dumps=dumps) file_key = "upload-image-" + random_bytes_str(16) rdb.set(file_key, filename) log('fe_upload_image_url', obj={ 'filename': filename, 'file_key': file_key }) return web.json_response(makeResponseSuccess({'file_key': file_key}), dumps=dumps)
def login(username, password, challenge, login_session_id) : log(obj = {'username': username, 'challenge': challenge, 'login_session_id': login_session_id}) if len(username) > UserConfig.MAX_USERNAME_LENGTH : raise UserError('USERNAME_TOO_LONG') if len(username) < UserConfig.MIN_USERNAME_LENGTH : raise UserError('USERNAME_TOO_SHORT') if len(password) > UserConfig.MAX_PASSWORD_LENGTH : raise UserError('PASSWORD_TOO_LONG') if len(password) < UserConfig.MIN_PASSWORD_LENGTH : raise UserError('PASSWORD_TOO_SHORT') if verify_session(login_session_id, 'LOGIN') : user_obj = db.users.find_one({'profile.username': username}) if not user_obj : log(level = 'SEC', obj = {'msg': 'USER_NOT_EXIST'}) raise UserError('INCORRECT_LOGIN') if not verify_password_PBKDF2(password, user_obj['crypto']['salt1'], user_obj['crypto']['password_hashed']) : log(level = 'SEC', obj = {'msg': 'WRONG_PASSWORD'}) raise UserError('INCORRECT_LOGIN') user_id = str(user_obj['_id']) redis_user_key_lookup_key = f"user-{user_id}" redis_user_key = rdb.get(redis_user_key_lookup_key) logged_in = False if redis_user_key : # user already logged in on some other machines redis_user_obj_json_str = rdb.get(redis_user_key) if redis_user_obj_json_str : logged_in = True # reset expire time rdb.set(redis_user_key, redis_user_obj_json_str, ex = UserConfig.LOGIN_EXPIRE_TIME) rdb.set(redis_user_key_lookup_key, redis_user_key, ex = UserConfig.LOGIN_EXPIRE_TIME) if logged_in : return redis_user_key, user_obj['profile'] common_user_obj = { '_id': user_obj['_id'], 'profile': { 'username': user_obj['profile']['username'], 'image': user_obj['profile']['image'], 'desc': user_obj['profile']['desc'] }, 'access_control': user_obj['access_control'], 'settings': user_obj['settings'] } redis_user_value = dumps(common_user_obj) redis_user_key = binascii.hexlify(bytearray(random_bytes(16))).decode() redis_user_key_lookup_key = f"user-{user_obj['_id']}" rdb.set(redis_user_key, redis_user_value, ex = UserConfig.LOGIN_EXPIRE_TIME) rdb.set(redis_user_key_lookup_key, redis_user_key, ex = UserConfig.LOGIN_EXPIRE_TIME) log(obj = {'redis_user_key': redis_user_key, 'user': common_user_obj}) return redis_user_key, common_user_obj['profile'] raise UserError('INCORRECT_SESSION')
async def put_task(queue, param_json): task_id = random_bytes_str(16) param_json_for_user = copy.deepcopy(param_json) del param_json_for_user['user'] del param_json_for_user['event_id'] log_e(param_json['event_id'], param_json['user'], op='put_task', obj={'task_id': task_id}) ret_json = dumps({ 'finished': False, 'key': task_id, 'data': None, 'params': param_json_for_user }) rdb.set(f'task-playlist-{task_id}', ret_json) key = 'post-playlist-tasks-' + str(param_json['user']['_id']) rdb.lpush(key, task_id) await queue.put((param_json, task_id)) return task_id
def do_login(user_obj) : user_id = str(user_obj['_id']) redis_user_key_lookup_key = f"user-{user_id}" redis_user_key = rdb.get(redis_user_key_lookup_key) logged_in = False if redis_user_key : # user already logged in on some other machines redis_user_obj_json_str = rdb.get(redis_user_key) if redis_user_obj_json_str : logged_in = True # reset expire time rdb.set(redis_user_key, redis_user_obj_json_str, ex = UserConfig.LOGIN_EXPIRE_TIME) rdb.set(redis_user_key_lookup_key, redis_user_key, ex = UserConfig.LOGIN_EXPIRE_TIME) if logged_in : profile = user_obj['profile'] profile['access_control_status'] = user_obj['access_control']['status'] return redis_user_key, profile openid_qq = user_obj['profile']['openid_qq'] if 'openid_qq' in user_obj['profile'] else None common_user_obj = { '_id': user_obj['_id'], 'profile': { 'uid': str(user_obj['_id']), 'username': user_obj['profile']['username'], 'image': user_obj['profile']['image'], 'desc': user_obj['profile']['desc'], 'email': user_obj['profile']['email'], 'bind_qq': True if openid_qq else False }, 'access_control': user_obj['access_control'], 'settings': user_obj['settings'] } redis_user_value = dumps(common_user_obj) redis_user_key = binascii.hexlify(bytearray(random_bytes(16))).decode() redis_user_key_lookup_key = f"user-{user_obj['_id']}" rdb.set(redis_user_key, redis_user_value, ex = UserConfig.LOGIN_EXPIRE_TIME) rdb.set(redis_user_key_lookup_key, redis_user_key, ex = UserConfig.LOGIN_EXPIRE_TIME) log(obj = {'redis_user_key': redis_user_key, 'user': common_user_obj}) profile = common_user_obj['profile'] profile['access_control_status'] = user_obj['access_control']['status'] return redis_user_key, profile
async def _add_to_playlist(self, dst_playlist, event_id, user_global): if self.playlist_map[dst_playlist]: dst_rank = self.playlist_map[dst_playlist]['rank'] playlist_ordered = self.playlist_map[dst_playlist]['all'] try: # fast method async with RedisLockAsync( rdb, "playlistEdit:" + dst_playlist), MongoTransaction(client) as s: cur_rank = 0 playlist = playlist_db.retrive_item(dst_playlist, session=s()) if playlist is None: raise UserError('PLAYLIST_NOT_EXIST') if playlist["item"]["videos"] + len( self.playlist_map[dst_playlist] ['succeed']) > PlaylistConfig.MAX_VIDEO_PER_PLAYLIST: raise UserError('VIDEO_LIMIT_EXCEEDED') playlist_videos = playlist["item"]['videos'] for unique_id in playlist_ordered: if unique_id in self.playlist_map[dst_playlist][ 'succeed']: (video_id, _, user) = self.playlist_map[ dst_playlist]['succeed'][unique_id] if dst_rank == -1: if filterOperation('editPlaylist', user, playlist, False): if addVideoToPlaylistLockFree( dst_playlist, video_id, user, playlist_videos, session=s()): playlist_videos += 1 else: if filterOperation('editPlaylist', user, playlist, False): if insertIntoPlaylistLockFree(dst_playlist, video_id, dst_rank + cur_rank, user, session=s()): cur_rank += 1 s.mark_succeed() except UserError as ue: # UserError, rereaise to upper level log_e(event_id, user_global, '_add_to_playlist', 'ERR', { 'ex': str(ex), 'tb': traceback.format_exc() }) del self.playlist_map[dst_playlist] rdb.set(f'playlist-batch-post-event-{dst_playlist}', b'done') raise ue except Exception as ex: # if anything goes wrong, fallback to slow method log_e(event_id, user_global, '_add_to_playlist', 'ERR', { 'ex': str(ex), 'tb': traceback.format_exc() }) cur_rank = 0 for unique_id in playlist_ordered: if unique_id in self.playlist_map[dst_playlist]['succeed']: (video_id, _, user) = self.playlist_map[dst_playlist][ 'succeed'][unique_id] # ignore error, add next video try: if dst_rank == -1: addVideoToPlaylist(dst_playlist, video_id, user) else: insertIntoPlaylist(dst_playlist, video_id, dst_rank + cur_rank, user) cur_rank += 1 except: pass log_e( event_id, user_global, '_add_to_playlist', 'MSG', { 'succedd': len(self.playlist_map[dst_playlist]['succeed']), 'all': len(self.playlist_map[dst_playlist]['all']), 'pid': dst_playlist }) del self.playlist_map[dst_playlist] rdb.set(f'playlist-batch-post-event-{dst_playlist}', b'done')