-
Notifications
You must be signed in to change notification settings - Fork 686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added journalist password change API #3874
base: develop
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,8 @@ | |
from journalist_app import utils | ||
from models import (Journalist, Reply, Source, Submission, | ||
LoginThrottledException, InvalidUsernameException, | ||
BadTokenException, WrongPasswordException) | ||
BadTokenException, WrongPasswordException, | ||
InvalidPasswordLength, NonDicewarePassword) | ||
from store import NotEncrypted | ||
|
||
|
||
|
@@ -279,6 +280,26 @@ def get_current_user(): | |
user = get_user_object(request) | ||
return jsonify(user.to_json()), 200 | ||
|
||
@api.route('/account/new-password', methods=['POST']) | ||
@token_required | ||
def new_password(): | ||
user = get_user_object(request) | ||
new_password = json.loads(request.data)['new_password'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens if (any expectations like this for the request body that might not be valid are good test cases to add) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New commit adds checks for missing request parameters and invalid data types, along with relevant tests. |
||
|
||
try: | ||
user.set_password(new_password) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. on the regular journalist interface for journalist passphrase reset, we have two additional requirements (for defense in depth) which is to provide a valid passphrase and 2FA token before changing the passphrase. additionally, we have the web application generating the diceware passphrases both for sources and journalists (shown only in the session where they are generated/changed). we should do the same here in the API too. recapping - the logic should be:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is dangerous because if a client doesn't finish the read (broken connection), then the client could be locked out. Changing a passphrase should require multiple steps.
Additionally, errors in the client (failure to display passphrase, crash, etc) could mean that at the network level, everything went just fine, but the user is still locked out. Because this is happening over Tor, we have to plan for exceptional robustness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
So, currently, the web interface basically offers a new password suggestion, which doesn't get stored in the database. It's still up to the client to send a new password, which then gets validated against criteria (length / words). |
||
except (InvalidPasswordLength, NonDicewarePassword) as e: | ||
return jsonify({'message': str(e)}), 400 | ||
except Exception as e: | ||
mdrose marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return jsonify({'message': 'An error occurred while setting the password. Password unchanged'}), 500 | ||
|
||
try: | ||
db.session.commit() | ||
except Exception as e: | ||
mdrose marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return jsonify({'message': 'An error occurred on database commit. Password unchanged.'}), 500 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also suggest that all 500 errors on this endpoint use the same string to not give additional information to an attacker. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
return jsonify({'message': 'Password changed successfully'}), 200 | ||
|
||
def _handle_http_exception(error): | ||
# Workaround for no blueprint-level 404/5 error handlers, see: | ||
# https://github.com/pallets/flask/issues/503#issuecomment-71383286 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently we have an
/user
endpoint which gets information about the current user, what about making this new endpoint/user/new-passphrase
instead of/account/new-password
?another thought: we should also add a link to this in the response from the
/user
endpoint:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done