]>
git.gir.st - subscriptionfeed.git/blob - app/common/user.py
1 from werkzeug
.security
import generate_password_hash
, check_password_hash
4 from flask_login
import LoginManager
, UserMixin
, login_user
, logout_user
, login_required
, current_user
5 from flask
import Blueprint
, flash
, redirect
, render_template
, url_for
, request
7 class User(UserMixin
): # TODO: to common
8 def __init__(self
, id, name
, passwd
, token
):
15 def set_password(self
, passwd
):
16 self
.passwd
= generate_password_hash(passwd
)
17 with sqlite3
.connect(cf
['global']['database']) as conn
:
19 c
.execute("UPDATE users SET password = ? where id = ?", (self
.passwd
, self
.id,))
20 def check_password(self
, passwd
):
21 return check_password_hash(self
.passwd
, passwd
)
23 def from_id(self
, id):
24 with sqlite3
.connect(cf
['global']['database']) as conn
:
26 c
.execute("SELECT name,password,token FROM users WHERE id = ?", (id,))
28 name
, passwd
, token
= c
.fetchone()
29 except: return None # todo: ugly
30 return User(id, name
, passwd
, token
)
32 def from_name(self
, name
):
33 with sqlite3
.connect(cf
['global']['database']) as conn
:
35 c
.execute("SELECT id,password,token FROM users WHERE name=?", (name
,))
37 id, passwd
, token
= c
.fetchone()
38 except: return None # todo: ugly
39 return User(id, name
, passwd
, token
)
41 def from_token(self
, token
):
42 with sqlite3
.connect(cf
['global']['database']) as conn
:
44 c
.execute("SELECT id,name,password FROM users WHERE token=?", (token
,))
46 id, name
, passwd
, = c
.fetchone()
47 except: return None # todo: ugly
48 return User(id, name
, passwd
, token
)
52 login
= LoginManager()
53 login
.login_view
= 'usermgmt.login_form'
58 # in the future tokens will be invalidable by users. -> https://flask-login.readthedocs.io/en/latest/#alternative-tokens
59 return User
.from_token(token
)
62 def querytoken_auth(request
):
63 if request
.args
.get('token'):
64 user
= User
.from_token(request
.args
.get('token'))
70 usermgmt
= Blueprint('usermgmt', __name__
,
71 template_folder
='templates',
72 static_folder
='static',
73 static_url_path
='/static/usermgmt')
75 @usermgmt.route('/login')
77 return render_template('login.html.j2')
79 @usermgmt.route('/login', methods
=['POST'])
81 action
= request
.form
.get('action')
83 user
= User
.from_name(request
.form
.get('user'))
84 if user
and user
.check_password(request
.form
.get('password')):
85 login_user(user
, remember
=request
.form
.get('remember'))
86 return redirect(request
.args
.get('next','/')) # xxx: non-exploitable open redirect!
87 flash('wrong username and/or password', 'error')
88 elif action
== 'register':
89 flash("open registration currently closed. ask <i>girst</i> on irc://chat.freenode.net/#invidious if you want an account.", 'info')
90 elif action
== 'logout':
92 return redirect(request
.args
.get('next','/')) # xxx: non-exploitable open redirect!
94 flash('unsupported action', 'error')
95 return redirect(url_for('usermgmt.login_form'))
97 @usermgmt.route('/manage/account')
98 def account_manager():
99 return render_template('account_mgmt.html.j2')
101 @usermgmt.route('/manage/account', methods
=['POST'])
103 def manage_account():
104 token
= current_user
.token
105 action
= request
.form
.get('action')
106 if action
== 'chpwd':
107 if not current_user
.check_password(request
.form
.get('oldpasswd')):
108 flash('current password incorrect.', 'error')
110 current_user
.set_password(request
.form
.get('newpasswd'))
111 flash('password updated.', 'info')
113 flash('unsupported action', 'error')
115 return redirect(url_for('usermgmt.account_manager'))
117 # NOTE: only register blueprint _after_ adding routes!
118 app
.register_blueprint(usermgmt
)