amanuensis/amanuensis/user.py

87 lines
2.3 KiB
Python
Raw Normal View History

2020-01-09 06:48:00 +00:00
import os
2020-01-04 01:07:28 +00:00
import re
2020-01-09 06:48:00 +00:00
import time
import uuid
2020-01-13 20:48:37 +00:00
from flask_login import UserMixin
2020-01-09 06:48:00 +00:00
from werkzeug.security import generate_password_hash, check_password_hash
import config
2020-01-04 01:07:28 +00:00
2020-01-13 20:48:37 +00:00
class User(UserMixin):
2020-01-09 06:48:00 +00:00
def __init__(self, uid):
2020-01-09 21:28:15 +00:00
if not os.path.isdir(config.prepend('user', uid)):
raise ValueError("No user with uid {}".format(uid))
2020-01-13 20:48:37 +00:00
self.uid = str(uid)
self.config_path = os.path.join('user', uid, 'config.json')
with config.json_ro(self.config_path) as j:
self.config = j
def __getattr__(self, key):
if key not in self.config:
raise AttributeError(key)
return self.config.get(key)
2020-01-13 20:48:37 +00:00
def get_id(self):
return self.uid
2020-01-09 21:28:15 +00:00
def set_password(self, pw):
h = generate_password_hash(pw)
2020-01-13 20:48:37 +00:00
with config.json_rw(self.config_path) as j:
2020-01-09 21:28:15 +00:00
j['password'] = h
def check_password(self, pw):
2020-01-13 20:48:37 +00:00
with config.json_ro(self.config_path) as j:
2020-01-09 21:28:15 +00:00
return check_password_hash(j['password'], pw)
2020-01-04 01:07:28 +00:00
def valid_username(username):
return re.match(r"^[A-Za-z0-9-_]{3,}$", username) is not None
def valid_email(email):
"""Vaguely RFC2822 email verifier"""
atom = r"[0-9A-Za-z!#$%&'*+-/=?^_`{|}~]{1,}"
dotatom = atom + r"(\." + atom + r")*"
addrspec = "^" + dotatom + "@" + dotatom + "$"
return re.match(addrspec, email)
def create_user(username, displayname, email):
2020-01-13 20:48:37 +00:00
if not valid_username(username):
raise ValueError("Invalid username: '{}'".format(username))
if not valid_email(email):
raise ValueError("Invalid email: '{}'".format(email))
2020-01-09 06:48:00 +00:00
uid = uuid.uuid4().hex
now = int(time.time())
2020-01-12 06:36:39 +00:00
temp_pw = os.urandom(32).hex()
2020-01-09 06:48:00 +00:00
user_json = {
'uid': uid,
'username': username,
'displayname': displayname,
'email': email,
'password': None,
'created': now,
2020-01-12 06:36:39 +00:00
'newPasswordRequired': True,
2020-01-16 01:15:51 +00:00
'admin': False,
2020-01-09 06:48:00 +00:00
}
config.new_user(user_json)
2020-01-12 06:36:39 +00:00
u = User(uid)
u.set_password(temp_pw)
return u, temp_pw
2020-01-09 21:28:15 +00:00
2020-01-13 20:48:37 +00:00
def uid_from_username(username):
"""Gets the internal uid of a user given a username"""
if username is None:
raise ValueError("username must not be None")
if not username:
raise ValueError("username must not be empty")
2020-01-09 21:28:15 +00:00
with config.json_ro('user', 'index.json') as index:
2020-01-13 20:48:37 +00:00
uid = index.get(username)
if uid is None:
config.logger.debug("uid_from_username('{}') returned None".format(username))
return uid
def user_from_uid(uid):
if not os.path.isdir(config.prepend('user', uid)):
config.logger.debug("No user with uid '{}'".format(uid))
return None
return User(uid)