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
|
||||
Reference in New Issue
Block a user