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)
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)
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 {}
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)
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 {}
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
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
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)