Compare commits
278
Commits
| 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 |
@@ -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