Compare commits
278 Commits
70671adac8
...
5a2549ba22
Author | SHA1 | Date | |
---|---|---|---|
5a2549ba22 | |||
6e1f7c6df1 | |||
ab4496f06d | |||
a836e0c9e3 | |||
fc099dbbf7 | |||
deab85289b | |||
d76c8a5fed | |||
ecf18a70a8 | |||
7206ca6203 | |||
b612b39e73 | |||
9462d7aa7f | |||
1d91e6d6ee | |||
ec52ebffa5 | |||
d9f967811f | |||
7d287874cd | |||
6fb8b62e5b | |||
78e4afdc71 | |||
79073f3d92 | |||
11e740ea44 | |||
b9a83a436e | |||
cc995925bb | |||
706ba8409e | |||
757425494f | |||
103093c886 | |||
6d887f1bfd | |||
89e8267a29 | |||
877b191a38 | |||
c85fa69713 | |||
30175355a6 | |||
9bdff0d729 | |||
27a58acc73 | |||
f867022207 | |||
ae31b2592e | |||
b151de39df | |||
94c61f8d8a | |||
80391229a3 | |||
3781e80fc5 | |||
23ddf6601b | |||
1873772167 | |||
a5f8cba71b | |||
957e6f02d6 | |||
58f40e221f | |||
183aeac9ee | |||
973bafcdb2 | |||
d5559c499d | |||
220a378c63 | |||
e1a90d5f64 | |||
d3f116e1ca | |||
72cd18b76f | |||
e2a0bc7b4e | |||
7b2a2ce90c | |||
0f1f79e237 | |||
091fdbe891 | |||
ed6360e7a3 | |||
cc45bf7acd | |||
045f3aec0a | |||
eeaf676ee6 | |||
6d931bdf6c | |||
af9801ac24 | |||
8749c6e590 | |||
df54ca7ff3 | |||
bac083411c | |||
536e1fe426 | |||
920287b7ae | |||
4c5aa66d8e | |||
e9a5e72959 | |||
96cca77b2f | |||
00fb8e13fe | |||
9ea336b5c2 | |||
c462b76cb7 | |||
673ccbcb9c | |||
57e5a21ffa | |||
a5dedc145c | |||
e935524552 | |||
21641ce21f | |||
8d2a84a071 | |||
abe515b586 | |||
f61c12afd1 | |||
7874d3f99f | |||
1b2209d97c | |||
8ccd34611e | |||
9e4e874401 | |||
d0232557bc | |||
a2e05d39e6 | |||
663b976b3b | |||
7150e679c8 | |||
20f580d6a6 | |||
cdd35117bf | |||
2b6b5d8f73 | |||
19521c3f23 | |||
198e2cecb0 | |||
fa43ab1879 | |||
8df4583ee0 | |||
9a5f073170 | |||
2641b3e060 | |||
d2cd8316da | |||
843ed247b6 | |||
de969e0028 | |||
e7077cd193 | |||
2472323103 | |||
d4f59769c6 | |||
5fad0cda1e | |||
fbe19e43f7 | |||
54653e82f2 | |||
9a5e24d362 | |||
cb39592bd3 | |||
372333cd84 | |||
cda7ac480f | |||
352c89d69f | |||
724ffbfdf4 | |||
|
ca1a6efd57 | ||
|
727779f054 | ||
|
8675e78082 | ||
|
1edd25d3ea | ||
cc466f4a20 | |||
529ac35bdb | |||
37ab26e72a | |||
81b3e3a142 | |||
|
039b58709e | ||
|
c8ccd002fa | ||
|
3dc7b1f74b | ||
|
fc765c0177 | ||
eb9ca82cb3 | |||
720de1f2de | |||
cd7005d713 | |||
7d90b6c7a2 | |||
|
d25dc5ed45 | ||
|
14bc50165b | ||
|
9d0ae15f74 | ||
|
bcc9e9c609 | ||
50cff0245f | |||
13b7249f2a | |||
02e4e0dc1c | |||
73c00ac333 | |||
|
7f7a783c8a | ||
|
a7e3a5fe47 | ||
|
88836296b8 | ||
|
36334ef186 | ||
207f748c93 | |||
9b34fb8f73 | |||
8503dc230d | |||
1a290e3bd6 | |||
2c0dcd8661 | |||
3d03fb79a7 | |||
ec1de247c9 | |||
6db6baab50 | |||
05ec62994e | |||
41a7129959 | |||
76d9031cb0 | |||
349dd030d6 | |||
e69c79df52 | |||
8cb4435517 | |||
8a4ae4cb91 | |||
ce31c3e691 | |||
ea4edf71ba | |||
1a20f1ec67 | |||
e4ca12bc0f | |||
f242413911 | |||
ca25159830 | |||
db59e6c85c | |||
cb0e4ed4e6 | |||
79c23471ee | |||
e53d7ef230 | |||
8d76ecb78a | |||
e7da288904 | |||
c4f088f29c | |||
eb6395a793 | |||
0318ddbf21 | |||
cd98763937 | |||
31d7e978f4 | |||
dc934f10ee | |||
486aeb86a2 | |||
7c8308a294 | |||
77267f944b | |||
c00a465410 | |||
e313df57d6 | |||
9e6990e145 | |||
85efd755d8 | |||
81a4d5dbda | |||
ecaa4fa95f | |||
5160935096 | |||
fdb5cc1cf9 | |||
2799190b97 | |||
6331dda37b | |||
eea99b9466 | |||
727fc2d8c0 | |||
2ba8980dd8 | |||
8b2daf400a | |||
85c965bf92 | |||
93bf9e94fb | |||
c7185f24d4 | |||
f97b2c7cbb | |||
5b740768f4 | |||
cca01a6c2f | |||
6b01841529 | |||
56b3e6a2f5 | |||
707398eae2 | |||
4b603b70a0 | |||
c7ca26202e | |||
121dd32bfb | |||
b92b1c7c32 | |||
d890a45f2b | |||
048d06ca14 | |||
9fac4ebd82 | |||
56a351bbb2 | |||
237aabf4ba | |||
f086a6e32b | |||
4d734dbbe8 | |||
0a106cb952 | |||
e69f60d813 | |||
34e82de922 | |||
a0fc1653e7 | |||
40cd1de89f | |||
cf82a85070 | |||
7ba1f22ad7 | |||
4da20115d2 | |||
46604b755b | |||
7e65416f80 | |||
848aa88dac | |||
d1cf44fd18 | |||
4d64f290ad | |||
61ac4c1cb0 | |||
bcafc8f545 | |||
19054a9c67 | |||
8d95b7d795 | |||
e326729ddb | |||
3d274c8189 | |||
fb19b12e7f | |||
9562bd6936 | |||
8a2d81ec23 | |||
2ba5df152a | |||
51f40311e0 | |||
f014d30a11 | |||
779b06b4bf | |||
c57461f118 | |||
f49b2f7df1 | |||
e85c910910 | |||
a4a3b6de1b | |||
3d5939ed9c | |||
636c1fdadb | |||
b1862e2a3f | |||
e7ca3ac0d7 | |||
4c0a1c8f3f | |||
6495904cf1 | |||
794c39ec41 | |||
594354e459 | |||
cc0398f878 | |||
6f57a4b24c | |||
5023aaae75 | |||
2e5c87f0b1 | |||
c1068acbf7 | |||
1f4848cc83 | |||
ac81dc2099 | |||
71b39d467d | |||
eca2165247 | |||
dc0e3bf11c | |||
213a0423d4 | |||
2bd07bf598 | |||
ef7c2f8271 | |||
9e9ceab81f | |||
f934208082 | |||
7c325e7c9e | |||
47e69da60b | |||
6285014938 | |||
d4dbaa4d48 | |||
3cedfcaeaf | |||
96a8c8da6c | |||
fdc68079dc | |||
9906d82261 | |||
3797adfc95 | |||
60b6a462c8 | |||
53cc25b4ce | |||
059dca4a40 | |||
c7252d0f7b | |||
6e463ca588 | |||
0fff71b1fb | |||
e53373ab99 | |||
408aa965fd |
207
ref-test/admin/models/users.py
Normal file
207
ref-test/admin/models/users.py
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
from flask import flash, make_response, Response, session
|
||||||
|
from flask.helpers import url_for
|
||||||
|
from flask.json import jsonify
|
||||||
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
from werkzeug.utils import redirect
|
||||||
|
from flask_mail import Message
|
||||||
|
import secrets
|
||||||
|
|
||||||
|
from common.security import encrypt, decrypt
|
||||||
|
from common.security.database import decrypt_find_one, encrypted_update
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
class User:
|
||||||
|
|
||||||
|
def __init__(self, _id=None, username=None, password=None, email=None, remember=False):
|
||||||
|
self._id = _id
|
||||||
|
self.username = username
|
||||||
|
self.email = email
|
||||||
|
self.password = password
|
||||||
|
self.remember = remember
|
||||||
|
|
||||||
|
def start_session(self, resp:Response):
|
||||||
|
from main import app
|
||||||
|
resp.set_cookie(
|
||||||
|
key = '_id',
|
||||||
|
value = self._id,
|
||||||
|
max_age = timedelta(days=14) if self.remember else None,
|
||||||
|
path = '/',
|
||||||
|
expires = datetime.utcnow() + timedelta(days=14) if self.remember else None,
|
||||||
|
domain = f'.{app.config["SERVER_NAME"]}',
|
||||||
|
secure = True
|
||||||
|
)
|
||||||
|
if self.remember:
|
||||||
|
resp.set_cookie (
|
||||||
|
key = 'remember',
|
||||||
|
value = 'True',
|
||||||
|
max_age = timedelta(days=14),
|
||||||
|
path = '/',
|
||||||
|
expires = datetime.utcnow() + timedelta(days=14),
|
||||||
|
domain = f'.{app.config["SERVER_NAME"]}',
|
||||||
|
secure = True
|
||||||
|
)
|
||||||
|
|
||||||
|
def register(self):
|
||||||
|
from main import db
|
||||||
|
from ..views import get_id_from_cookie
|
||||||
|
user = {
|
||||||
|
'_id': self._id,
|
||||||
|
'email': encrypt(self.email),
|
||||||
|
'password': generate_password_hash(self.password, method='sha256'),
|
||||||
|
'username': encrypt(self.username)
|
||||||
|
}
|
||||||
|
if decrypt_find_one(db.users, { 'username': self.username }):
|
||||||
|
return jsonify({ 'error': f'Username {self.username} is not available.' }), 400
|
||||||
|
if db.users.insert_one(user):
|
||||||
|
flash(f'User {self.username} has been created successfully. You may now use it to log in and administer the tests.', 'success')
|
||||||
|
resp = make_response(jsonify(user), 200)
|
||||||
|
if not get_id_from_cookie:
|
||||||
|
self.start_session(resp)
|
||||||
|
return resp
|
||||||
|
return jsonify({ 'error': f'Registration failed. An error occurred.' }), 400
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
from main import db
|
||||||
|
user = decrypt_find_one( db.users, { 'username': self.username })
|
||||||
|
if not user:
|
||||||
|
return jsonify({ 'error': f'Username {self.username} does not exist.' }), 401
|
||||||
|
if not check_password_hash( user['password'], self.password ):
|
||||||
|
return jsonify({ 'error': f'The password you entered is incorrect.' }), 401
|
||||||
|
response = {
|
||||||
|
'success': f'Successfully logged in user {self.username}.'
|
||||||
|
}
|
||||||
|
if 'prev_page' in session:
|
||||||
|
response['redirect_to'] = session['prev_page']
|
||||||
|
session.pop('prev_page')
|
||||||
|
resp = make_response(jsonify(response), 200)
|
||||||
|
self._id = user['_id']
|
||||||
|
self.start_session(resp)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def logout(self):
|
||||||
|
resp = make_response(redirect(url_for('admin_auth.login')))
|
||||||
|
from main import app
|
||||||
|
resp.set_cookie(
|
||||||
|
key = '_id',
|
||||||
|
value = '',
|
||||||
|
max_age = timedelta(days=-1),
|
||||||
|
path = '/',
|
||||||
|
expires= datetime.utcnow() + timedelta(days=-1),
|
||||||
|
domain = f'.{app.config["SERVER_NAME"]}',
|
||||||
|
secure = True
|
||||||
|
)
|
||||||
|
resp.set_cookie (
|
||||||
|
key = 'cookie_consent',
|
||||||
|
value = 'True',
|
||||||
|
max_age = None,
|
||||||
|
path = '/',
|
||||||
|
expires = None,
|
||||||
|
domain = f'.{app.config["SERVER_NAME"]}',
|
||||||
|
secure = True
|
||||||
|
)
|
||||||
|
resp.set_cookie (
|
||||||
|
key = 'remember',
|
||||||
|
value = 'True',
|
||||||
|
max_age = timedelta(days=-1),
|
||||||
|
path = '/',
|
||||||
|
expires = datetime.utcnow() + timedelta(days=-1),
|
||||||
|
domain = f'.{app.config["SERVER_NAME"]}',
|
||||||
|
secure = True
|
||||||
|
)
|
||||||
|
flash('You have been logged out. All cookies pertaining to your account have been deleted. Have a nice day.', 'alert')
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def reset_password(self):
|
||||||
|
from main import db, mail
|
||||||
|
user = decrypt_find_one(db.users, { 'username': self.username })
|
||||||
|
if not user:
|
||||||
|
return jsonify({ 'error': f'Username {self.username} does not exist.' }), 401
|
||||||
|
if not user['email'] == self.email:
|
||||||
|
return jsonify({ 'error': f'The email address {self.email} does not match the user account {self.username}.' }), 401
|
||||||
|
new_password = secrets.token_hex(12)
|
||||||
|
reset_token = secrets.token_urlsafe(16)
|
||||||
|
verification_token = secrets.token_urlsafe(16)
|
||||||
|
user['password'] = generate_password_hash(new_password, method='sha256')
|
||||||
|
if encrypted_update(db.users, { 'username': self.username }, { '$set': {'password': user['password'], 'reset_token': reset_token, 'verification_token': verification_token } } ):
|
||||||
|
flash(f'Your password has been reset. Instructions to recover your account have been sent to {self.email}. Please be sure to check your spam folder in case you have not received the email.', 'alert')
|
||||||
|
email = Message(
|
||||||
|
subject = 'RefTest | Password Reset',
|
||||||
|
recipients = [self.email],
|
||||||
|
body = f"""
|
||||||
|
Hello {user['username']}, \n\n
|
||||||
|
This email was generated because we received a request to reset the password for your administrator account for the SKA RefTest app.\n\n
|
||||||
|
If you did not make this request, please ignore this email.\n\n
|
||||||
|
If you did make this request, then you have two options to recover your account.\n\n
|
||||||
|
For the time being, your password has been reset to the following:\n\n
|
||||||
|
{new_password}\n\n
|
||||||
|
You may use this to log back in to your account, and subsequently change your password to something more suitable.\n\n
|
||||||
|
Alternatively, you may visit the following private link using your unique token to override your password. Copy and paste the following link in a web browser. Please note that this token is only valid once:\n\n
|
||||||
|
{url_for('admin_auth.reset_gateway', token1 = reset_token, token2 = verification_token, _external = True)}\n\n
|
||||||
|
Have a nice day.
|
||||||
|
""",
|
||||||
|
html = f"""
|
||||||
|
<p>Hello {user['username']},</p>
|
||||||
|
<p>This email was generated because we received a request to reset the password for your administrator account for the SKA RefTest app. </p>
|
||||||
|
<p>If you did not make this request, please ignore this email.</p>
|
||||||
|
<p>If you did make this request, then you have two options to recover your account.</p>
|
||||||
|
<p>For the time being, your password has been reset to the following:</p>
|
||||||
|
<strong>{new_password}</strong>
|
||||||
|
<p>You may use this to log back in to your account, and subsequently change your password to something more suitable.</p>
|
||||||
|
<p>Alternatively, you may visit the following private link using your unique token to override your password. Click on the following link, or copy and paste it into a browser. <strong>Please note that this token is only valid once</strong>:</p>
|
||||||
|
<p><a href='{url_for('admin_auth.reset_gateway', token1 = reset_token, token2 = verification_token, _external = True)}'>{url_for('admin_auth.reset_gateway', token1 = reset_token, token2 = verification_token, _external = True)}</a></p>
|
||||||
|
<p>Have a nice day.</p>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
mail.send(email)
|
||||||
|
return jsonify({ 'success': 'Password reset request has been processed.'}), 200
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
from main import db
|
||||||
|
from ..views import get_id_from_cookie
|
||||||
|
retrieved_user = decrypt_find_one(db.users, { '_id': self._id })
|
||||||
|
if not retrieved_user:
|
||||||
|
return jsonify({ 'error': f'User {retrieved_user["username"]} does not exist.' }), 401
|
||||||
|
user = {}
|
||||||
|
updated = []
|
||||||
|
if not self.email == '' and self.email is not None:
|
||||||
|
user['email'] = self.email
|
||||||
|
updated.append('email')
|
||||||
|
if not self.password == '' and self.password is not None:
|
||||||
|
user['password'] = generate_password_hash(self.password, method='sha256')
|
||||||
|
updated.append('password')
|
||||||
|
output = ''
|
||||||
|
if len(updated) == 0:
|
||||||
|
flash(f'There were no changes requested for your account.', 'alert'), 200
|
||||||
|
return jsonify({'success': 'There were no changes requested for your account.'}), 200
|
||||||
|
elif len(updated) == 1:
|
||||||
|
output = updated[0]
|
||||||
|
elif len(updated) == 2:
|
||||||
|
output = ' and '.join(updated)
|
||||||
|
elif len(updated) > 2:
|
||||||
|
output = updated[0]
|
||||||
|
for index in range(1,len(updated)):
|
||||||
|
if index < len(updated) - 2:
|
||||||
|
output = ', '.join([output, updated[index]])
|
||||||
|
elif index == len(updated) - 2:
|
||||||
|
output = ', and '.join([output, updated[index]])
|
||||||
|
else:
|
||||||
|
output = ''.join([output, updated[index]])
|
||||||
|
encrypted_update(db.users, {'_id': self._id}, { '$set': user })
|
||||||
|
if self._id == get_id_from_cookie():
|
||||||
|
_output = 'Your '
|
||||||
|
elif retrieved_user['username'][-1] == 's':
|
||||||
|
_output = '’'.join([retrieved_user['username'], ''])
|
||||||
|
else:
|
||||||
|
_output = '’'.join([retrieved_user['username'], 's'])
|
||||||
|
_output = f'{_output} {output} {"has" if len(updated) == 1 else "have"} been updated.'
|
||||||
|
flash(_output)
|
||||||
|
return jsonify({'success': _output}), 200
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
from main import db
|
||||||
|
retrieved_user = decrypt_find_one(db.users, { '_id': self._id })
|
||||||
|
if not retrieved_user:
|
||||||
|
return jsonify({ 'error': f'User does not exist.' }), 401
|
||||||
|
db.users.find_one_and_delete({'_id': self._id})
|
||||||
|
flash(f'User {retrieved_user["username"]} has been deleted.')
|
||||||
|
return jsonify({'success': f'User {retrieved_user["username"]} has been deleted.'}), 200
|
Loading…
Reference in New Issue
Block a user