def create_user( username, password, email, auto_verify=False, email_required=True, prompts=tuple(), is_possible_abuser=False, ): """ Creates a regular user, if allowed. """ if not validate_password(password): raise InvalidPasswordException(INVALID_PASSWORD_MESSAGE) created = create_user_noverify( username, email, email_required=email_required, prompts=prompts, is_possible_abuser=is_possible_abuser, ) created.password_hash = hash_password(password).decode("ascii") created.verified = auto_verify created.save() return created
def change_personal_info(db): """ A resource for changing user info. Update request can contain 0 or more fields to change the user. Missing fields will not be updated. JSON body with all fields is: { "username": <string>, "password": <string>, "first_name": <string>, "last_name": <string>, } :param db: The database session :returns: Error JSON on failure or updated user JSON on success. """ # Get User info from request environment. user = request.environ.get('user_info') if user is None: raise RuntimeError('change_personal_info should always have user_info') # Get Update JSON from body. Return unchanged user if no body. data = request.json if data is None: return UserJSON.from_db(user).json # Validate JSON body try: if 'username' in data and not validate_username(data['username']): raise ValueError if 'password' in data and not validate_password(data['username']): raise ValueError if 'first_name' in data and not validate_name(data['first_name']): raise ValueError if 'last_name' in data and not validate_name(data['last_name']): raise ValueError except ValueError: response.status = 400 return Error("Update contains invalid data").json # Check username for originality if changing username = data.get('username', user.username) if username != user.username: count = db.query(User).filter(User.username == username).count() if count != 0: response.status = 400 return Error("'%s' already exists" % username).json # Update fields and send to database user.username = username user.password_hash = data.get('password', user.password_hash) user.first_name = data.get('first_name', user.first_name) user.last_name = data.get('last_name', user.last_name) db.commit() return UserJSON.from_db(user).json
def create_new_user(db): """ Create a new User. JSON must include all fields. JSON body with all fields is: { "username": <string>, "password": <string>, "first_name": <string>, "last_name": <string>, } :param db: The database session :returns: JSON containing the created user info if successful Otherwise, returns error information in JSON format. """ try: # Access and validate new user info from JSON body data = request.json if data is None: raise ValueError if 'username' not in data or not validate_username(data['username']): raise ValueError if 'password' not in data or not validate_password(data['username']): raise ValueError if 'first_name' not in data or not validate_name(data['first_name']): raise ValueError if 'last_name' not in data or not validate_name(data['last_name']): raise ValueError username = data['username'] password = data['password'] first_name = data['first_name'] last_name = data['last_name'] except ValueError: response.status = 400 # Bad Request return Error("Missing JSON with valid username, password, " + "first_name, last_name").json # Check that the username doesn't already exist count = db.query(User).filter(User.username == username).count() if count != 0: response.status = 400 return Error("'%s' already exists" % username).json # Insert User into database user = User(username=username, password_hash=password, first_name=first_name, last_name=last_name) db.add(user) db.commit() return UserJSON.from_db(user).json
def change_password(user, new_password): if not validate_password(new_password): raise InvalidPasswordException(INVALID_PASSWORD_MESSAGE) pw_hash = hash_password(new_password) user.invalid_login_attempts = 0 user.password_hash = pw_hash.decode("ascii") invalidate_all_sessions(user) # Remove any password required notifications for the user. notification.delete_notifications_by_kind(user, "password_required")
def login(db): """ Generate a session with the server. Session generation performed according to the following steps. 1. Client presents username and password 2. Server authenticates username and password. 3. Server generates cryptographically secure random token if session doesn't already exist and send to client. 4. Server sends previously generated random token if session already exists. This session token must be provided with each future request in an HTTP header called 'Authentication'. Login request must contain JSON body: { "username": <string>, "password": <string>, } :param db: The database session :returns: Error JSON on fail or Session token JSON on success. """ try: data = request.json if data is None: raise ValueError # validate data if 'username' not in data or not validate_username(data['username']): raise ValueError if 'password' not in data or not validate_password(data['password']): raise ValueError username = data['username'] password = data['password'] except ValueError: response.status = 400 return Error("Missing valid username or password").json # Verify username/password combo with database try: user = db.query(User) \ .filter(User.username == username, User.password_hash == password) \ .one() except NoResultFound: response.status = 401 return Error("Username/Password combo is invalid").json except MultipleResultsFound: response.status = 500 return Error( "Somehow multiple users exist with that username/password") try: # Try to revieve old session token session = db.query(Session) \ .filter(Session.user_id == user.id) \ .one() except NoResultFound: # No previous session so generate new token while True: # Make sure session token doesn't already exist. token = generate_token() if db.query(Session) \ .filter(Session.session_hash == token).count() == 0: break session = Session(session_hash=token, user_id=user.id, expires=datetime.now() + timedelta(weeks=2)) db.add(session) return Token(session.session_hash).json