Пример #1
0
    def post(self):
        user = schema_create_user.objectify(self.request.validated)
        user.password = self.request.validated['password']
        user.update_validation_nonce(Purpose.registration,
                                     VALIDATION_EXPIRE_DAYS)

        # directly create the user profile, the document id of the profile
        # is the user id
        lang = user.lang
        user.profile = UserProfile(
            categories=['amateur'],
            locales=[DocumentLocale(lang=lang, title='')])

        DBSession.add(user)
        try:
            DBSession.flush()
        except:
            log.warning('Error persisting user', exc_info=True)
            raise HTTPInternalServerError('Error persisting user')

        # also create a version for the profile
        DocumentRest.create_new_version(user.profile, user.id)

        # The user needs validation
        email_service = get_email_service(self.request)
        nonce = user.validation_nonce
        settings = self.request.registry.settings
        link = settings['mail.validate_register_url_template'] % nonce
        email_service.send_registration_confirmation(user, link)

        return to_json_dict(user, schema_user)
Пример #2
0
    def post(self):
        user = schema_create_user.objectify(self.request.validated)
        user.password = self.request.validated['password']
        user.update_validation_nonce(
                Purpose.registration,
                VALIDATION_EXPIRE_DAYS)

        # directly create the user profile, the document id of the profile
        # is the user id
        lang = user.lang
        user.profile = UserProfile(
            categories=['amateur'],
            locales=[DocumentLocale(lang=lang, title='')]
        )

        DBSession.add(user)
        try:
            DBSession.flush()
        except:
            log.warning('Error persisting user', exc_info=True)
            raise HTTPInternalServerError('Error persisting user')

        # also create a version for the profile
        DocumentRest.create_new_version(user.profile, user.id)

        # The user needs validation
        email_service = get_email_service(self.request)
        nonce = user.validation_nonce
        settings = self.request.registry.settings
        link = settings['mail.validate_register_url_template'] % nonce
        email_service.send_registration_confirmation(user, link)

        return to_json_dict(user, schema_user)
Пример #3
0
    def post(self):
        request = self.request
        user = request.validated['user']

        if user.blocked:
            raise HTTPForbidden('account blocked')

        user.update_validation_nonce(
                Purpose.new_password,
                VALIDATION_EXPIRE_DAYS)

        try:
            DBSession.flush()
        except Exception:
            log.warning('Error persisting user', exc_info=True)
            raise HTTPInternalServerError('Error persisting user')

        email_service = get_email_service(request)
        nonce = user.validation_nonce
        settings = request.registry.settings
        link = settings['mail.request_password_change_url_template'].format(
            '#', nonce)
        email_service.send_request_change_password(user, link)

        return {}
Пример #4
0
    def tween(request):

        log.debug('RATE LIMITING FOR METHOD ' + request.method)

        # Only write requests are considered for rate limiting.
        if request.method not in ['POST', 'PUT', 'DELETE']:
            return handler(request)

        if request.authorization is None:
            # See comment of similar block in jwt_database_validation tween
            return handler(request)

        user = DBSession.query(User).get(request.authenticated_userid)
        if user is None:
            return http_error_handler(HTTPBadRequest('Unknown user'), request)

        now = datetime.datetime.now(pytz.utc)
        if user.ratelimit_reset is None or user.ratelimit_reset < now:
            # No window exists or it is expired: create a new one.
            span = int(registry.settings.get('rate_limiting.window_span'))
            limit = int(
                registry.settings.get(
                    'rate_limiting.limit_robot' if user.
                    robot else 'rate_limiting.limit_moderator' if user.
                    moderator else 'rate_limiting.limit'))
            user.ratelimit_reset = now + datetime.timedelta(seconds=span)
            user.ratelimit_remaining = limit - 1
        elif user.ratelimit_remaining:
            user.ratelimit_remaining -= 1
        else:
            # User is rate limited

            # Count how many windows the user has been rate limited
            # and block them is too many.
            current_window = user.ratelimit_reset
            if user.ratelimit_last_blocked_window != current_window:
                user.ratelimit_last_blocked_window = current_window
                user.ratelimit_times += 1

                max_times = int(
                    registry.settings.get('rate_limiting.max_times'))
                if user.ratelimit_times > max_times:
                    user.blocked = True

                # An alert message is sent to the moderators
                email_service = get_email_service(request)
                email_service.send_rate_limiting_alert(user)

            return http_error_handler(
                HTTPTooManyRequests('Rate limit reached'), request)

        return handler(request)
Пример #5
0
    def post(self):
        request = self.request
        user = request.validated["user"]
        user.update_validation_nonce(Purpose.new_password, VALIDATION_EXPIRE_DAYS)

        try:
            DBSession.flush()
        except:
            log.warning("Error persisting user", exc_info=True)
            raise HTTPInternalServerError("Error persisting user")

        email_service = get_email_service(request)
        nonce = user.validation_nonce
        settings = request.registry.settings
        link = settings["mail.request_password_change_url_template"].format("#", nonce)
        email_service.send_request_change_password(user, link)

        return {}
Пример #6
0
    def post(self):
        user = self.get_user()
        request = self.request
        validated = request.validated

        result = {}

        # Before all, check whether the user knows the current password
        current_password = validated['currentpassword']
        if not user.validate_password(current_password):
            request.errors.add('body', 'currentpassword', 'Invalid password')
            return

        sync_sso = False

        # update password if a new password is provided
        if 'newpassword' in validated:
            user.password = validated['newpassword']

        # start email validation procedure if a new email is provided
        email_link = None
        if 'email' in validated and validated['email'] != user.email:
            user.email_to_validate = validated['email']
            user.update_validation_nonce(
                    Purpose.change_email,
                    VALIDATION_EXPIRE_DAYS)
            email_service = get_email_service(self.request)
            nonce = user.validation_nonce
            settings = request.registry.settings
            link = settings['mail.validate_change_email_url_template'].format(
                '#', nonce)
            email_link = link
            result['email'] = validated['email']
            result['sent_email'] = True
            sync_sso = True

        update_search_index = False
        if 'name' in validated:
            user.name = validated['name']
            result['name'] = user.name
            update_search_index = True
            sync_sso = True

        if 'forum_username' in validated:
            user.forum_username = validated['forum_username']
            result['forum_username'] = user.forum_username
            update_search_index = True
            sync_sso = True

        if 'is_profile_public' in validated:
            user.is_profile_public = validated['is_profile_public']

        # Synchronize everything except the new email (still stored
        # in the email_to_validate attribute while validation is pending).
        if sync_sso:
            try:
                client = get_discourse_client(request.registry.settings)
                client.sync_sso(user)
            except:
                log.error('Error syncing with discourse', exc_info=True)
                raise HTTPInternalServerError('Error with Discourse')

        try:
            DBSession.flush()
        except:
            log.warning('Error persisting user', exc_info=True)
            raise HTTPInternalServerError('Error persisting user')

        if email_link:
            email_service.send_change_email_confirmation(user, link)

        if update_search_index:
            # when user name changes, the search index has to be updated
            notify_es_syncer(self.request.registry.queue_config)

            # also update the cache version of the user profile
            update_cache_version(user.profile)

        return result
Пример #7
0
    def post(self):
        user = self.get_user()
        request = self.request
        validated = request.validated

        result = {}

        # Before all, check whether the user knows the current password
        current_password = validated['currentpassword']
        if not user.validate_password(current_password):
            request.errors.add('body', 'currentpassword', 'Invalid password')
            return

        sync_sso = False

        # update password if a new password is provided
        if 'newpassword' in validated:
            user.password = validated['newpassword']

        # start email validation procedure if a new email is provided
        email_link = None
        if 'email' in validated and validated['email'] != user.email:
            user.email_to_validate = validated['email']
            user.update_validation_nonce(Purpose.change_email,
                                         VALIDATION_EXPIRE_DAYS)
            email_service = get_email_service(self.request)
            nonce = user.validation_nonce
            settings = request.registry.settings
            link = settings['mail.validate_change_email_url_template'].format(
                '#', nonce)
            email_link = link
            result['email'] = validated['email']
            result['sent_email'] = True
            sync_sso = True

        update_search_index = False
        if 'name' in validated:
            user.name = validated['name']
            result['name'] = user.name
            update_search_index = True
            sync_sso = True

        if 'forum_username' in validated:
            user.forum_username = validated['forum_username']
            result['forum_username'] = user.forum_username
            update_search_index = True
            sync_sso = True

        if 'is_profile_public' in validated:
            user.is_profile_public = validated['is_profile_public']

        # Synchronize everything except the new email (still stored
        # in the email_to_validate attribute while validation is pending).
        if sync_sso:
            try:
                client = get_discourse_client(request.registry.settings)
                client.sync_sso(user)
            except Exception:
                log.error('Error syncing with discourse', exc_info=True)
                raise HTTPInternalServerError('Error with Discourse')

        try:
            DBSession.flush()
        except Exception:
            log.warning('Error persisting user', exc_info=True)
            raise HTTPInternalServerError('Error persisting user')

        if email_link:
            email_service.send_change_email_confirmation(user, link)

        if update_search_index:
            # when user name changes, the search index has to be updated
            notify_es_syncer(self.request.registry.queue_config)

            # also update the cache version of the user profile
            update_cache_version(user.profile)

        return result
Пример #8
0
    def tween(request):

        log.debug('RATE LIMITING FOR METHOD ' + request.method)

        # Only write requests are considered for rate limiting.
        if request.method not in ['POST', 'PUT', 'DELETE']:
            return handler(request)

        if request.authorization is None:
            # See comment of similar block in jwt_database_validation tween
            return handler(request)

        user = DBSession.query(User).get(request.authenticated_userid)
        if user is None:
            return http_error_handler(HTTPBadRequest('Unknown user'), request)

        now = datetime.datetime.now(pytz.utc)
        if user.ratelimit_reset is None or user.ratelimit_reset < now:
            # No window exists or it is expired: create a new one.
            span = int(registry.settings.get('rate_limiting.window_span'))
            limit = int(
                registry.settings.get(
                    'rate_limiting.limit_robot' if user.
                    robot else 'rate_limiting.limit_moderator' if user.
                    moderator else 'rate_limiting.limit'))
            user.ratelimit_reset = now + datetime.timedelta(seconds=span)
            user.ratelimit_remaining = limit - 1
            log.debug('RATE LIMITING, CREATE WINDOW SPAN : {}'.format(
                user.ratelimit_reset))

        elif user.ratelimit_remaining:
            user.ratelimit_remaining -= 1
            log.info('RATE LIMITING, REQUESTS REMAINING FOR {} : {}'.format(
                user.id, user.ratelimit_remaining))

        else:
            # User is rate limited
            log.warning('RATE LIMIT REACHED FOR USER {}'.format(user.id))

            # Count how many windows the user has been rate limited
            # and block them if too many.
            current_window = user.ratelimit_reset
            if user.ratelimit_last_blocked_window != current_window:
                user.ratelimit_last_blocked_window = current_window
                user.ratelimit_times += 1

                max_times = int(
                    registry.settings.get('rate_limiting.max_times'))
                if user.ratelimit_times > max_times:
                    log.warning('RATE LIMIT BLOCK USER {}'.format(user.id))
                    user.blocked = True

                # An alert message is sent to the moderators
                email_service = get_email_service(request)
                try:
                    email_service.send_rate_limiting_alert(user)
                except SMTPAuthenticationError:
                    log.error('RATE LIMIT ALERT MAIL : AUTHENTICATION ERROR')

            return http_error_handler(
                HTTPTooManyRequests('Rate limit reached'), request)

        return handler(request)