Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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)
Exemple #5
0
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
Exemple #6
0
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)
Exemple #7
0
    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')
Exemple #8
0
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
Exemple #9
0
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))
Exemple #10
0
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()
Exemple #11
0
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()
Exemple #12
0
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()
Exemple #13
0
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()
Exemple #14
0
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()
Exemple #15
0
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()
Exemple #16
0
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
Exemple #17
0
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)
Exemple #18
0
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))
Exemple #19
0
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')
Exemple #20
0
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))
Exemple #21
0
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
Exemple #22
0
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()
Exemple #23
0
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)
Exemple #24
0
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
Exemple #25
0
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
Exemple #26
0
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')
Exemple #27
0
 def __init__(self, *args):
     ArgumentError.__init__(self, *args)
     self.suspend_time = 0
Exemple #28
0
 def __init__(self, *args):
     ArgumentError.__init__(self, *args)
     self.suspend_time = 0
Exemple #29
0
 def __init__(self, *args):
     ArgumentError.__init__(self, *args)
Exemple #30
0
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')
Exemple #31
0
 def __init__(self, *args):
     ArgumentError.__init__(self, *args)
Exemple #32
0
def _check_page_type(page_type):
    if page_type not in TYPES:
        raise ArgumentError(MESSAGE_PAGE_INVALID_TYPE)