def user_schema_check_breaches(request: Request) -> UserSchema: """Return a UserSchema that will check the password against breaches. It would probably be good to generalize this function at some point, probably similar to: http://webargs.readthedocs.io/en/latest/advanced.html#reducing-boilerplate """ # pylint: disable=unused-argument return UserSchema(only=("username", "password"), context={"check_breached_passwords": True})
from webargs.pyramidparser import use_kwargs from tildes.enums import CommentLabelOption, CommentTreeSortOption from tildes.lib.datetime import utc_now from tildes.lib.string import separate_string from tildes.models.comment import Comment, CommentLabel, CommentTree from tildes.models.group import Group from tildes.models.topic import Topic from tildes.models.user import User from tildes.schemas.user import ( BIO_MAX_LENGTH, EMAIL_ADDRESS_NOTE_MAX_LENGTH, UserSchema, ) PASSWORD_FIELD = UserSchema(only=("password", )).fields["password"] THEME_OPTIONS = { "white": "White", "solarized-light": "Solarized Light", "solarized-dark": "Solarized Dark", "dracula": "Dracula", "atom-one-dark": "Atom One Dark", "black": "Black", "zenburn": "Zenburn", "gruvbox-light": "Gruvbox Light", "gruvbox-dark": "Gruvbox Dark", "motte": "The Motte", }
request.user = user request.db_session.add(Log(LogEventType.USER_LOG_IN, request)) # only use redirect_url if it's a relative url, so we can't redirect to other sites if redirect_url.startswith("/"): return HTTPFound(location=redirect_url) return HTTPFound(location="/") @view_config( route_name="login", request_method="POST", permission=NO_PERMISSION_REQUIRED ) @use_kwargs( UserSchema( only=("username", "password"), context={"username_trim_whitespace": True} ) ) @use_kwargs({"from_url": String(missing="")}) @not_logged_in @rate_limit_view("login") def post_login( request: Request, username: str, password: str, from_url: str ) -> Response: """Process a log in request.""" incr_counter("logins") # Look up the user for the supplied username user = ( request.query(User) .undefer_all_columns()
# Copyright (c) 2018 Tildes contributors <*****@*****.**> # SPDX-License-Identifier: AGPL-3.0-or-later """Root factories for users.""" from pyramid.request import Request from tildes.models.user import User from tildes.resources import get_resource from tildes.schemas.user import UserSchema from tildes.views.decorators import use_kwargs @use_kwargs(UserSchema(only=("username", )), location="matchdict") def user_by_username(request: Request, username: str) -> User: """Get a user specified by {username} in the route or 404 if not found.""" query = request.query(User).include_deleted().filter( User.username == username) return get_resource(request, query)
from pyramid.response import Response from sqlalchemy.exc import IntegrityError from webargs.pyramidparser import use_kwargs from tildes.enums import LogEventType, TopicSortOption from tildes.lib.string import separate_string from tildes.models.log import Log from tildes.models.user import User, UserInviteCode from tildes.schemas.fields import Enum, ShortTimePeriod from tildes.schemas.topic import TopicSchema from tildes.schemas.user import UserSchema from tildes.views import IC_NOOP from tildes.views.decorators import ic_view_config PASSWORD_FIELD = UserSchema(only=("password",)).fields["password"] @ic_view_config( route_name="user", request_method="PATCH", request_param="ic-trigger-name=password-change", permission="change_password", ) @use_kwargs( { "old_password": PASSWORD_FIELD, "new_password": PASSWORD_FIELD, "new_password_confirm": PASSWORD_FIELD, } )
"""Views related to user settings.""" from pyramid.httpexceptions import HTTPUnprocessableEntity from pyramid.request import Request from pyramid.response import Response from pyramid.view import view_config from webargs.pyramidparser import use_kwargs from tildes.schemas.user import EMAIL_ADDRESS_NOTE_MAX_LENGTH, UserSchema PASSWORD_FIELD = UserSchema(only=('password',)).fields['password'] @view_config(route_name='settings', renderer='settings.jinja2') def get_settings(request: Request) -> dict: """Generate the user settings page.""" current_theme = request.cookies.get('theme', '') theme_options = { '': 'White (default)', 'light': 'Solarized Light', 'dark': 'Solarized Dark', 'black': 'Black', } return {'current_theme': current_theme, 'theme_options': theme_options} @view_config( route_name='settings_account_recovery', renderer='settings_account_recovery.jinja2',
permission=NO_PERMISSION_REQUIRED, ) @not_logged_in def get_login(request: Request) -> dict: """Display the login form.""" # pylint: disable=unused-argument return {} @view_config( route_name='login', request_method='POST', permission=NO_PERMISSION_REQUIRED, ) @use_kwargs( UserSchema(only=('username', 'password'), strict=True), ) @not_logged_in @rate_limit_view('login') def post_login(request: Request, username: str, password: str) -> HTTPFound: """Process a log in request.""" incr_counter('logins') # Look up the user for the supplied username user = (request.query(User).undefer_all_columns().filter( User.username == username).one_or_none()) # If that user doesn't exist or the password was wrong, error out if not user or not user.is_correct_password(password): incr_counter('login_failures') # log the failure - need to manually commit because of the exception
"""Root factories for users.""" from pyramid.request import Request from webargs.pyramidparser import use_kwargs from tildes.models.user import User from tildes.resources import get_resource from tildes.schemas.user import UserSchema @use_kwargs( UserSchema(only=('username', )), locations=('matchdict', ), ) def user_by_username(request: Request, username: str) -> User: """Get a user specified by {username} in the route or 404 if not found.""" query = request.query(User).filter(User.username == username) return get_resource(request, query)
route_name="register", renderer="register.jinja2", permission=NO_PERMISSION_REQUIRED ) @use_kwargs({"code": String(missing="")}) @not_logged_in def get_register(request: Request, code: str) -> dict: """Display the registration form.""" # pylint: disable=unused-argument return {"code": code} @view_config( route_name="register", request_method="POST", permission=NO_PERMISSION_REQUIRED ) @use_kwargs( UserSchema( only=("username", "password"), context={"check_breached_passwords": True} ), location="form", ) @use_kwargs( {"invite_code": String(required=True), "password_confirm": String(required=True)}, location="form", ) @not_logged_in @rate_limit_view("register") def post_register( request: Request, username: str, password: str, password_confirm: str, invite_code: str,
from pyramid.request import Request from pyramid.response import Response from sqlalchemy.exc import IntegrityError from webargs.pyramidparser import use_kwargs from tildes.enums import LogEventType, TopicSortOption from tildes.models.log import Log from tildes.models.user import User, UserInviteCode from tildes.schemas.fields import Enum, ShortTimePeriod from tildes.schemas.topic import TopicSchema from tildes.schemas.user import UserSchema from tildes.views import IC_NOOP from tildes.views.decorators import ic_view_config PASSWORD_FIELD = UserSchema(only=('password',)).fields['password'] @ic_view_config( route_name='user', request_method='PATCH', request_param='ic-trigger-name=password-change', permission='change_password', ) @use_kwargs({ 'old_password': PASSWORD_FIELD, 'new_password': PASSWORD_FIELD, 'new_password_confirm': PASSWORD_FIELD, }) def change_password( request: Request,