Skip to content

Commit

Permalink
Merge branch 'release/v21.5.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-c committed May 7, 2021
2 parents fd6c5fd + 58060c2 commit c8e7d62
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 88 deletions.
2 changes: 1 addition & 1 deletion portal/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class BaseConfig(object):
('assessment_cache_region', 60*60*2),
('reporting_cache_region', 60*60*12)]
SEND_FILE_MAX_AGE_DEFAULT = 60 * 60 # 1 hour, in seconds
ENABLE_2FA = os.environ.get('ENABLE_2FA', None)
ENABLE_2FA = os.environ.get('ENABLE_2FA', 'false').lower() == 'true'

LOG_CACHE_MISS = False
LOG_FOLDER = os.environ.get('LOG_FOLDER')
Expand Down
55 changes: 55 additions & 0 deletions portal/migrations/versions/ebb5fee8122b_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Hide deleted user's identifiers
Revision ID: ebb5fee8122b
Revises: 406484da81af
Create Date: 2021-05-04 12:50:49.638956
"""
from alembic import op
import re
from sqlalchemy.sql import text


# revision identifiers, used by Alembic.
revision = 'ebb5fee8122b'
down_revision = '406484da81af'


def upgrade():
""" Hide unique system identifiers tied to deleted users.
To prevent conflicts, should a second user desire to use an identifier
previously "owned" by a now deleted user, hide the deleted user's
identifier with a suffix.
"""
conn = op.get_bind()

patients = conn.execute(
"SELECT user_id FROM user_identifiers JOIN users ON users.id = user_id "
"WHERE deleted_id IS NOT NULL").fetchall()

fixes = []
for user_id in patients:
ident_id, value = conn.execute(text(
"SELECT identifiers.id, value FROM identifiers JOIN "
"user_identifiers ON identifiers.id = identifier_id WHERE "
"user_id=:user_id"), user_id=user_id[0]).fetchone()
# Only concerned with IDs that match the MR format (nnn-nn-nnn)
match = re.search(r'\d+-\d+-\d+$', value)
if not match:
continue
deleted_value = f"{value}-deleted"
print(f"change {ident_id} {value} to {deleted_value}")
fixes.append((ident_id, deleted_value))

for ident_id, new_value in fixes:
conn.execute(text(
"UPDATE identifiers SET value=:value WHERE id=:id"),
value=new_value,
id=ident_id)


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
15 changes: 10 additions & 5 deletions portal/models/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,22 @@ def login_user(user, auth_method=None):
# log user back out, in case a flow already promoted them
flask_user_logout()

token = user.generate_otp()
code = user.generate_otp()
session['user_needing_2fa'] = user.id
session['pending_auth_method'] = auth_method
current_app.logger.debug(f"OTP for {user.id}: {token}")
current_app.logger.debug(f"2FA OTP for {user.id}: {code}")
email = EmailMessage(
subject=_("TrueNTH Access Token"),
body=_("One Time Authentication Token: %s" % token),
subject=_("TrueNTH Access Code"),
body=_("One-time access code: %(code)06d", code=code),
recipients=user.email,
sender=current_app.config['MAIL_DEFAULT_SENDER'],
user_id=user.id)
email.send_message()
if current_app.config.get("MAIL_SUPPRESS_SEND"):
# Dump to console for easy access
print(email.body)
else:
email.send_message()

db.session.add(email)
db.session.commit()
return
Expand Down
29 changes: 25 additions & 4 deletions portal/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ def current_encounter(
return initiate_encounter(self, auth_method=existing.auth_method)
return existing

TOTP_TOKEN_LEN = 4
TOTP_TOKEN_LEN = 6
TOTP_TOKEN_LIFE = 30*60

def generate_otp(self):
Expand All @@ -495,11 +495,19 @@ def generate_otp(self):

def validate_otp(self, token):
assert(self.otp_secret)
return otp.valid_totp(
valid = otp.valid_totp(
token,
self.otp_secret,
token_length=self.TOTP_TOKEN_LEN,
interval_length=self.TOTP_TOKEN_LIFE)
if valid:
# due to the long timeout window, a second request
# for a code within the first few minutes will generate
# the same code! patch by altering the user's secret
# after a single validation.
self.otp_secret = generate_random_secret()
db.session.commit()
return valid

@property
def locale(self):
Expand Down Expand Up @@ -678,14 +686,26 @@ def mask_email(self, prefix=INVITE_PREFIX):
else:
self._email = prefix

def mask_identifier(self, suffix):
"""Mask identifiers so other user's may re-use
"""
if not self._identifiers:
return

for identifier in self._identifiers:
if identifier.system == TRUENTH_EXTERNAL_STUDY_SYSTEM:
if identifier.value.endswith(suffix):
continue
identifier.value += suffix

def add_identifier(self, identifier):
if identifier.system in internal_identifier_systems:
raise Conflict(
"edits to identifiers with system {} not allowed".format(
identifier.system))
if identifier in self._identifiers:
raise Conflict("{} already assigned to {}".format(
identifier, self))
# Idempotent, ignore multiple request for same
return

# Check (if applicable) that the identifier isn't already
# assigned to another user
Expand Down Expand Up @@ -1928,6 +1948,7 @@ def delete_user(self, acting_user):

self.active = False
self.mask_email(prefix=DELETED_PREFIX.format(time=int(time.time())))
self.mask_identifier(suffix='-deleted')
self.deleted = Audit(user_id=acting_user.id, subject_id=self.id,
comment="marking deleted {}".format(self),
context='account')
Expand Down
20 changes: 20 additions & 0 deletions portal/static/js/flask_user/2fa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
$(document).ready(function() {
var submitForm = function() {
if (!$("#faInput").val()) return;
$(".buttons-container").addClass("loading");
setTimeout(function() {
$("#TwoFAForm").submit();
}, 50);
};
$("#submitValidationCode").on("click", function(e) {
e.stopPropagation();
submitForm();
});
$(document).keypress(function(event) {
if (event.which === 13) {
submitForm();
return false;
}
return true;
});
});
Loading

0 comments on commit c8e7d62

Please sign in to comment.