def create_with_password(moderator: ModeratorModel, password: str): """ Create a moderator account. The password is given unhashed. :param moderator: filled in moderator model :param password: password to create moderator with :raises ArgumentError if the username or password doesn't fit the requirements. See {USERNAME,PASSWORD}_{MIN,MAX}_LENGTH and {USERNAME,PASSWORD}_ALLOWED_CHARS :raises ArgumentError if the username is already in use. Username checking is done case-insensitively """ if not validation.check_username_validity(moderator.username): raise ArgumentError(MESSAGE_INVALID_USERNAME) if not validation.check_password_validity(password): raise ArgumentError(MESSAGE_INVALID_PASSWORD) if find_by_username_case_insensitive(moderator.username) is not None: raise ArgumentError(MESSAGE_USERNAME_IN_USE) with session() as s: orm_moderator = moderator.to_orm_model() orm_moderator.password = _hash_password(password) s.add(orm_moderator) s.flush() moderator = ModeratorModel.from_orm_model(orm_moderator) s.commit() return moderator
def user_remove_moderator(moderator: ModeratorModel, board: BoardModel, username: str): member = find_moderator_username(username) if not member: raise ArgumentError('Moderator not found') if has_any_of_board_roles(member, board, [roles.BOARD_ROLE_CREATOR]): raise ArgumentError('Cannot remove creator') if moderator.id == member.id: action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.MODERATOR_REMOVE_SELF) board_service.remove_moderator(board, member) log(ModeratorLogType.MODERATOR_REMOVE, moderator, board, 'Removed self') return True else: action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.MODERATOR_REMOVE) board_service.remove_moderator(board, member) log(ModeratorLogType.MODERATOR_REMOVE, moderator, board, 'Removed {}'.format(member.username)) return False
def add_ban(ban: BanModel) -> BanModel: if ban.length > MAX_BAN_TIME: raise ArgumentError(MESSAGE_BAN_TOO_LONG) if ban.ip4_end is not None and ban.ip4_end <= ban.ip4: raise ArgumentError(MESSAGE_IP4_ILLEGAL_RANGE) if ban.board: board = board_service.find_board(ban.board) if not board: raise ArgumentError(MESSAGE_BOARD_NOT_FOUND) if ban.reason and len(ban.reason) > MAX_REASON_LENGTH: raise ArgumentError(MESSAGE_BAN_TEXT_TOO_LONG) ban.date = now() ban = bans.create_ban(ban) for_board_text = ' on {}'.format(ban.board) if ban.board else '' ip4_end_text = ip4_to_str(ban.ip4_end) if ban.ip4_end is not None else '-' f = 'ban add {} from {} to {}{} for {} hours reason {}' text = f.format(ban.id, ip4_to_str(ban.ip4), ip4_end_text, for_board_text, ban.length / 60 / 60 / 1000, ban.reason) mod_log(text) return ban
def check_password_match(moderator: ModeratorModel, password: str): if not validation.check_password_validity(password): raise ArgumentError(MESSAGE_INVALID_PASSWORD) with session() as s: moderator_orm_model = s.query(ModeratorOrmModel).filter_by( id=moderator.id).one() moderator_hashed_password = moderator_orm_model.password s.commit() if not bcrypt.checkpw(password.encode(), moderator_hashed_password): raise ArgumentError(MESSAGE_PASSWORD_INCORRECT)
def request_moderator() -> ModeratorModel: # Cache for the request if not hasattr(flaskg, 'authed_moderator'): if not get_authed(): raise ArgumentError('Not authed') mod = moderator_service.find_moderator_id(session['mod_auth_id']) if mod is None: raise ArgumentError('Mod not found') flaskg.authed_moderator = mod return mod return flaskg.authed_moderator
def _validate(page: PageModel): _check_page_type(page.type) if not validation.check_page_title_validity(page.title): raise ArgumentError(MESSAGE_PAGE_INVALID_TITLE) if not validation.check_page_link_name_validity(page.link_name): raise ArgumentError(MESSAGE_PAGE_INVALID_LINK) if not validation.check_page_content_validity(page.content): raise ArgumentError(MESSAGE_PAGE_INVALID_CONTENT) if page.order < 0 or page.order > 1000: raise ArgumentError(MESSAGE_PAGE_INVALID_ORDER)
def verify_request(self, request): form = request.form response = form.get('g-recaptcha-response', None) if not response: raise ArgumentError('Please fill in the captcha') try: valid = self.verify(response) except Exception: logger.exception('Verify exception') raise ArgumentError('Error contacting recaptcha service') if not valid: raise ArgumentError('Captcha invalid')
def get_request_ip4(request=None): try: ip4 = parse_ip4(get_request_ip4_str(request)) except ValueError: logger.exception('Failed to parse request ip4') raise ArgumentError('Invalid request') return ip4
def user_update_roles(moderator: ModeratorModel, board: BoardModel, username: str, new_roles: 'List[str]'): action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.ROLES_UPDATE) subject = find_moderator_username(username) if not subject: raise ArgumentError('Moderator not found') if moderator.id == subject.id: # and not has_role(moderator, roles.ROLE_ADMIN): raise ArgumentError('Cannot change self') board_moderator = board_moderators.get_board_moderator(board, subject) if not board_moderator: raise ArgumentError('Not a mod of that board') changed = set(new_roles) ^ set(board_moderator.roles) # creator is unchangeable if roles.BOARD_ROLE_CREATOR in changed: changed.remove(roles.BOARD_ROLE_CREATOR) if changed: added_roles = [] removed_roles = [] for i in changed: if i not in board_moderator.roles: added_roles.append(i) else: removed_roles.append(i) for add in added_roles: action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.ROLE_ADD, (subject, add)) add_board_role(subject, board, add) log(ModeratorLogType.MODERATOR_ROLE_ADD, moderator, board, 'Added role {} to {}'.format(add, subject.username)) for remove in removed_roles: action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.ROLE_REMOVE, (subject, remove)) remove_board_role(subject, board, remove) log(ModeratorLogType.MODERATOR_ROLE_REMOVE, moderator, board, 'Removed role {} from {}'.format(remove, subject.username))
def board_remove_moderator(board: BoardModel, moderator: ModeratorModel): with session() as s: bm = s.query(BoardModeratorOrmModel).filter_by( board_id=board.id, moderator_id=moderator.id).one_or_none() if not bm: raise ArgumentError(MESSAGE_BOARD_NOT_ADDED) s.delete(bm) s.commit()
def remove_board_role(moderator: ModeratorModel, board: BoardModel, role: str): _check_board_roles([role]) with session() as s: board_moderator = s.query(BoardModeratorOrmModel).filter_by( moderator_id=moderator.id, board_id=board.id).one() if role not in board_moderator.roles: raise ArgumentError('Role not added') board_moderator.roles.remove(role) s.commit()
def board_add_moderator(board: BoardModel, moderator: ModeratorModel): with session() as s: bm = s.query(BoardModeratorOrmModel).filter_by( moderator_id=moderator.id, board_id=board.id).one_or_none() if bm: raise ArgumentError(MESSAGE_BOARD_ALREADY_ADDED) m = s.query(ModeratorOrmModel).filter_by(id=moderator.id).one() b = s.query(BoardOrmModel).filter_by(id=board.id).one() b.moderators.append(m) s.commit()
def remove_role(moderator: ModeratorModel, role: str): _check_roles([role]) with session() as s: moderator_orm_model = s.query(ModeratorOrmModel).filter_by( id=moderator.id).one() if role not in moderator_orm_model.roles: raise ArgumentError('Role not added') moderator_orm_model.roles.remove(role) s.commit()
def add_role(moderator: ModeratorModel, role: str): _check_roles([role]) with session() as s: moderator_orm_model = s.query(ModeratorOrmModel).filter_by( id=moderator.id).one() if role in moderator_orm_model.roles: raise ArgumentError('Role already added') moderator_orm_model.roles.append(role) s.commit()
def update(page: PageModel): _validate(page) with session() as s: existing = s.query(PageOrmModel).filter_by(id=page.id).one_or_none() if not existing: raise ArgumentError(MESSAGE_PAGE_NOT_FOUND) s.merge(page.to_orm_model()) _cache_page(s, page) s.commit()
def find_by_username_case_insensitive(username: str) -> ModeratorModel: if not validation.check_username_validity(username): raise ArgumentError(MESSAGE_INVALID_USERNAME) with session() as s: # Username chars are safe because it is checked above m = s.query(ModeratorOrmModel).filter( ModeratorOrmModel.username.ilike(username)).one_or_none() res = None if m: res = ModeratorModel.from_orm_model(m) s.commit() return res
def handle_manage_report(manage_report_details): report = reports.find_by_id(manage_report_details.report_id) if not report: raise ArgumentError(MESSAGE_REPORT_NOT_FOUND) moderator = moderator_service.find_moderator_id( manage_report_details.mod_id) if not moderator: raise ArgumentError(MESSAGE_MODERATOR_NOT_FOUND) post = report.post board = post.thread.board if manage_report_details.mode == ManageReportDetails.CLEAR: action_authorizer.authorize_report_action(moderator, board, report, ReportAction.REPORT_CLEAR) delete_report(report) message = 'Cleared report id {}'.format(report.id) moderator_service.log(ModeratorLogType.REPORT_CLEAR, moderator, board, message) elif manage_report_details.mode == ManageReportDetails.DELETE_POST: action_authorizer.authorize_post_action(moderator, PostAction.POST_DELETE, post) # Report gets deleted with a cascade posts_service.delete_post(post) message = 'Post id {}'.format(post.id) moderator_service.log(ModeratorLogType.REPORT_POST_DELETE, moderator, board, message) elif manage_report_details.mode == ManageReportDetails.DELETE_FILE: action_authorizer.authorize_post_action(moderator, PostAction.POST_DELETE_FILE, post) posts_service.delete_file(post) message = 'Post id {}'.format(post.id) moderator_service.log(ModeratorLogType.REPORT_POST_DELETE_FILE, moderator, board, message)
def user_invite_moderator(moderator: ModeratorModel, board: BoardModel, username: str): action_authorizer.authorize_board_action( moderator, board, action_authorizer.ModeratorBoardAction.MODERATOR_ADD) invitee = find_moderator_username(username) if not invitee: raise ArgumentError('Moderator not found') board_service.add_moderator(board, invitee) log(ModeratorLogType.MODERATOR_INVITE, moderator, board, 'Invited {}'.format(invitee.username))
def process_and_generate_thumbnail(local_path, thumbnail_path, thumbnail_size): try: file_size = os.stat(local_path).st_size image = Image.open(local_path) if image.format not in ALLOWED_FORMATS: raise ArgumentError('Invalid file format') width, height = image.size if width > MAX_IMAGE_WIDTH or height > MAX_IMAGE_HEIGHT: raise ArgumentError('Image size too big') image.thumbnail((thumbnail_size, thumbnail_size)) thumbnail_width, thumbnail_height = image.size if image.mode != 'RGB': image = image.convert('RGB') image.save(thumbnail_path, 'JPEG') return width, height, file_size, thumbnail_width, thumbnail_height except (IOError, OSError): logger.exception('Error processing image') raise ArgumentError('Invalid file')
def _check_post_details(post_details: PostDetails, thread: ThreadModel, board: BoardModel): plugin_manager.execute_hook('on_handle_post_check', post_details) # Get moderator if mod_id was set moderator = None if post_details.mod_id is not None: moderator = moderator_service.find_moderator_id(post_details.mod_id) if moderator is None: raise Exception(MESSAGE_MODERATOR_NOT_FOUND) if thread and thread.locked: raise ArgumentError(MESSAGE_THREAD_LOCKED) action_authorizer.authorize_post_action(moderator, PostAction.POST_CREATE, post_details=post_details, board=board, thread=thread) if post_details.has_file and not board.config.file_posting: raise ArgumentError(MESSAGE_FILE_POSTING_DISABLED) # Allow no text when an image is attached if (not post_details.text or not post_details.text.strip()) and not post_details.has_file: raise ArgumentError(MESSAGE_POST_NO_TEXT) if post_details.text is not None: if len(post_details.text) > MAX_TEXT_LENGTH: raise ArgumentError(MESSAGE_POST_TEXT_TOO_LONG) if len(post_details.text.splitlines()) > MAX_TEXT_LINES: raise ArgumentError(MESSAGE_POST_TEXT_TOO_MANY_LINES) if post_details.name is not None and len( post_details.name) > MAX_NAME_LENGTH: raise ArgumentError(MESSAGE_POST_NAME_TOO_LONG) if post_details.password is not None: if len(post_details.password) < MIN_PASSWORD_LENGTH: raise ArgumentError( MESSAGE_PASSWORD_TOO_SHORT.format(MIN_PASSWORD_LENGTH)) if len(post_details.password) > MAX_PASSWORD_LENGTH: raise ArgumentError( MESSAGE_PASSWORD_TOO_LONG.format(MAX_PASSWORD_LENGTH))
def prepare_upload(file, thumbnail_size): user_file_name = file.filename if not user_file_name: raise ArgumentError('Invalid file name') extension = _get_extension(user_file_name) if not extension: raise ArgumentError('Invalid file format') # truncate filename if too long user_file_name = user_file_name[:MAX_FILE_NAME_LENGTH] filename, extension = _get_filename(extension) image_name = filename + '.' + extension thumbnail_name = filename + THUMBNAIL_POSTFIX + '.jpg' image_output = os.path.join(upload_queue_path, image_name) thumbnail_output = os.path.join(upload_queue_path, thumbnail_name) os.makedirs(upload_queue_path, exist_ok=True) # Save the file from the user to the upload queue dir file.save(image_output) # Get image params and generate thumbnail width, height, size, thumbnail_width, thumbnail_height = \ process_and_generate_thumbnail(image_output, thumbnail_output, thumbnail_size) # Ready to be send to the worker to be inserted into the db uploaded_file = UploadedFile(image_name, thumbnail_name, user_file_name, width, height, size, thumbnail_width, thumbnail_height) upload_queue_files = UploadQueueFiles(image_output, image_name, thumbnail_output, thumbnail_name) return uploaded_file, upload_queue_files
def update_password(moderator: ModeratorModel, password: str): """ Update a moderator password. The password is given unhashed. :param moderator: moderator to change password on. :param password: new password :raises ArgumentError if the password doesn't fit the requirements. See PASSWORD_{MIN,MAX}_LENGTH and PASSWORD_ALLOWED_CHARS """ if not validation.check_password_validity(password): raise ArgumentError(MESSAGE_INVALID_PASSWORD) with session() as s: moderator_orm_model = s.query(ModeratorOrmModel).filter_by( id=moderator.id).one() moderator_orm_model.password = _hash_password(password) s.commit()
def delete_post_file(post: PostModel): if post.file is None: raise ArgumentError(MESSAGE_POST_HAS_NO_FILE) with session() as s: file_orm_model = s.query(FileOrmModel).filter_by(id=post.file.id).one() s.delete(file_orm_model) s.commit() thread = post.thread _invalidate_thread_cache(s, thread, thread.board) _invalidate_board_pages_catalog_cache(s, thread.board) document_cache.purge_thread(thread.board, thread) document_cache.purge_board(thread.board)
def create(page: PageModel) -> PageModel: _validate(page) with session() as s: existing = s.query(PageOrmModel).filter_by( link_name=page.link_name).one_or_none() if existing: raise ArgumentError(MESSAGE_PAGE_DUPLICATE_LINK) orm_model = page.to_orm_model() s.add(orm_model) s.flush() m = PageModel.from_orm_model(orm_model) _cache_page(s, m) s.commit() return m
def user_register(username: str, password: str, password_repeat: str): """ Register a moderator with the given passwords. The created moderator has no roles and no relationships to boards. :param username: username to register with :param password: password to register with :param password_repeat: repeated version of password, used for the error message. :raises ArgumentError if the two passwords don't match. :raises ArgumentError any error defined in :meth:`uchan.lib.repository.moderators.create_with_password` :return: the created moderator """ if password != password_repeat: raise ArgumentError(MESSAGE_PASSWORD_INCORRECT) moderator = ModeratorModel.from_username(username) moderator = moderators.create_with_password(moderator, password) mod_log('User {} registered'.format(username)) return moderator
def authorize_action(actor: ModeratorModel, action: ModeratorAction): if has_role(actor, roles.ROLE_ADMIN): return if action is ModeratorAction.BOARD_CREATE: creator_roles = 0 for board_moderator in moderator_service.get_all_board_moderators_by_moderator( actor): if roles.BOARD_ROLE_CREATOR in board_moderator.roles: creator_roles += 1 max = configuration.app.max_boards_per_moderator if creator_roles >= max: raise ArgumentError('Max boards limit reached ({})'.format(max)) elif action is ModeratorAction.BOARD_DELETE: # must be admin raise NoPermissionError() elif action is ModeratorAction.BAN: # must be admin raise NoPermissionError() else: raise Exception('Unknown action')
def __init__(self, *args): ArgumentError.__init__(self, *args) self.suspend_time = 0
def __init__(self, *args): ArgumentError.__init__(self, *args)
def _check_roles(role_list: 'List[str]'): if not all(role is not None and role in roles.ALL_ROLES for role in role_list): raise ArgumentError('Invalid role')
def _check_page_type(page_type): if page_type not in TYPES: raise ArgumentError(MESSAGE_PAGE_INVALID_TYPE)