realms-wiki/realms/modules/auth/models.py

112 lines
2.9 KiB
Python
Raw Normal View History

2014-10-22 00:06:27 +03:00
from flask import current_app
2014-08-30 18:06:12 +03:00
from flask.ext.login import UserMixin, logout_user, login_user, AnonymousUserMixin
2014-10-22 00:06:27 +03:00
from realms import login_manager, db
2014-08-30 18:06:12 +03:00
from realms.lib.model import Model
from realms.lib.util import gravatar_url
2014-08-20 18:28:25 +03:00
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
import bcrypt
@login_manager.user_loader
def load_user(user_id):
2014-08-30 18:06:12 +03:00
return User.get_by_id(user_id)
2014-08-20 18:28:25 +03:00
@login_manager.token_loader
def load_token(token):
# Load unsafe because payload is needed for sig
2014-10-22 00:06:27 +03:00
sig_okay, payload = URLSafeSerializer(current_app.config['SECRET_KEY']).loads_unsafe(token)
2014-08-20 18:28:25 +03:00
if not payload:
2014-09-18 18:42:32 +03:00
return None
2014-08-20 18:28:25 +03:00
# User key *could* be stored in payload to avoid user lookup in db
2014-08-30 18:06:12 +03:00
user = User.get_by_id(payload.get('id'))
2014-08-20 18:28:25 +03:00
if not user:
2014-09-18 18:42:32 +03:00
return None
2014-08-20 18:28:25 +03:00
try:
if User.signer(sha256(user.password).hexdigest()).loads(token):
return user
else:
2014-09-18 18:42:32 +03:00
return None
2014-08-20 18:28:25 +03:00
except BadSignature:
2014-09-18 18:42:32 +03:00
return None
2014-08-20 18:28:25 +03:00
2014-08-30 18:06:12 +03:00
class AnonUser(AnonymousUserMixin):
username = 'Anon'
email = ''
admin = False
2014-08-30 18:06:12 +03:00
2014-08-20 18:28:25 +03:00
2014-08-30 18:06:12 +03:00
class User(Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(128), unique=True)
email = db.Column(db.String(128), unique=True)
password = db.Column(db.String(60))
admin = False
2014-08-20 18:28:25 +03:00
2014-08-30 18:06:12 +03:00
hidden_fields = ['password']
readonly_fields = ['email', 'password']
2014-08-20 18:28:25 +03:00
def get_auth_token(self):
key = sha256(self.password).hexdigest()
2014-08-30 18:06:12 +03:00
return User.signer(key).dumps(dict(id=self.id))
@property
def avatar(self):
return gravatar_url(self.email)
2014-08-20 18:28:25 +03:00
@staticmethod
def create(username, email, password):
2014-08-30 18:06:12 +03:00
u = User()
u.username = username
u.email = email
u.password = User.hash_password(password)
u.save()
2014-08-20 18:28:25 +03:00
@staticmethod
2014-08-30 18:06:12 +03:00
def get_by_username(username):
2014-10-31 00:59:19 +02:00
return User.query().filter_by(username=username).first()
2014-08-20 18:28:25 +03:00
@staticmethod
2014-08-30 18:06:12 +03:00
def get_by_email(email):
2014-10-31 00:59:19 +02:00
return User.query().filter_by(email=email).first()
2014-08-20 18:28:25 +03:00
@staticmethod
2014-08-30 18:06:12 +03:00
def signer(salt):
2014-10-22 00:06:27 +03:00
return URLSafeSerializer(current_app.config['SECRET_KEY'] + salt)
2014-08-20 18:28:25 +03:00
@staticmethod
def auth(email, password):
2014-10-31 00:59:19 +02:00
user = User.get_by_email(email)
2014-08-20 18:28:25 +03:00
if not user:
2014-08-30 18:06:12 +03:00
# User doesn't exist
2014-08-20 18:28:25 +03:00
return False
2014-08-30 18:06:12 +03:00
if User.check_password(password, user.password):
# Password is good, log in user
2014-08-20 18:28:25 +03:00
login_user(user, remember=True)
return user
else:
2014-08-30 18:06:12 +03:00
# Password check failed
2014-08-20 18:28:25 +03:00
return False
@staticmethod
2014-08-30 18:06:12 +03:00
def hash_password(password):
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12))
@staticmethod
def check_password(password, hashed):
return bcrypt.hashpw(password.encode('utf-8'), hashed.encode('utf-8')) == hashed
2014-08-20 18:28:25 +03:00
@classmethod
def logout(cls):
logout_user()
2014-08-30 18:06:12 +03:00
login_manager.anonymous_user = AnonUser