from base64 import b85encode from functools import wraps from os import urandom from flask_login import current_user from flask_login import login_required from scrypt import hash as shash from sqlalchemy.exc import IntegrityError from config import TRACKER_PASSWORD_LENGTH_MIN from tracker import db from tracker import login_manager from tracker.model.user import Guest from tracker.model.user import User from tracker.model.user import UserRole login_manager.anonymous_user = Guest def random_string(length=TRACKER_PASSWORD_LENGTH_MIN): salt = b85encode(urandom(length)) return salt.decode() def hash_password(password, salt): hashed = b85encode(shash(password, salt[:User.SALT_LENGTH])) return hashed.decode()[:User.PASSWORD_LENGTH] @login_manager.user_loader def load_user(session_token): if not session_token: return Guest() user = User.query.filter_by(token=session_token).first() if not user: return Guest() user.is_authenticated = True return user def permission_required(permission): def decorator(func): @wraps(func) def decorated_view(*args, **kwargs): if not permission.fget(current_user.role): from tracker.view.error import forbidden return forbidden() return func(*args, **kwargs) return login_required(decorated_view) return decorator def reporter_required(func): return permission_required(UserRole.is_reporter)(func) def security_team_required(func): return permission_required(UserRole.is_security_team)(func) def administrator_required(func): return permission_required(UserRole.is_administrator)(func) def user_can_edit_issue(advisories=[]): role = current_user.role if not role.is_reporter: return False if role.is_security_team: return True return 0 == len(advisories) def user_can_delete_issue(advisories=[]): role = current_user.role if not role.is_reporter: return False return 0 == len(advisories) def user_can_edit_group(advisories=[]): return user_can_edit_issue(advisories) def user_can_delete_group(advisories=[]): return user_can_delete_issue(advisories) def user_can_handle_advisory(): return current_user.role.is_security_team def user_can_watch_log(): return True def user_can_watch_user_log(): return current_user.role.is_reporter def user_invalidate(user): user.token = None user.is_authenticated = False def user_assign_new_token(user, max_tries=32): def assign_token(token): user.token = token return user return user_generate_new_token(assign_token, max_tries) def user_generate_new_token(callback, max_tries=32): failed = 0 while failed < max_tries: try: token = random_string(User.TOKEN_LENGTH) token_owners = User.query.filter_by(token=token).count() if 0 != token_owners: failed += 1 continue user = callback(token) db.session.commit() return user except IntegrityError: db.session.rollback() failed += 1 raise Exception('Failed to obtain unique token within {} tries'.format(max_tries))