Remediate the 2026-09-03 feature-test findings

This commit is contained in:
2026-09-03 17:15:03 -04:00
parent cf95daf3bb
commit fd513c08eb
112 changed files with 5182 additions and 857 deletions

View File

@@ -187,9 +187,28 @@ def update_user(userid: int):
user.failedlogins = 0
changes['unlocked'] = {'old': True, 'new': False}
# Password change
# Password change.
#
# An ADMIN may set one here - that is how a temporary password is issued,
# and mustchangepassword forces the holder to replace it at next login.
# Somebody changing their OWN password may not: this route asks for no
# current password and enforces no length, so it was a way around
# /api/auth/change-password, which requires both. The two rules have to
# agree or the weaker one is the real one.
if 'password' in data and data['password']:
if not current_user.hasrole('admin'):
return error_response(
ErrorCodes.FORBIDDEN,
'Change your own password at /api/auth/change-password, which '
'requires your current one.',
http_code=403)
if len(data['password']) < 8:
return error_response(
ErrorCodes.VALIDATION_ERROR,
'Password must be at least 8 characters')
user.passwordhash = generate_password_hash(data['password'])
# Issued by somebody else, so it is temporary by definition.
user.mustchangepassword = True
changes['password'] = {'old': '***', 'new': '***'}
if changes: