Repository: fossasia/open-event-server

Issue:
Perform a check on the server side for the Current password of a user.
**I'm submitting a ...**  (check one with "x")
- [ ] bug report
- [x] feature request
- [ ] support request => Please do not submit support requests here, instead ask your query in out Gitter channel at https://gitter.im/fossasia/open-event-orga-server

**Current behavior:**
Currently, we are having something like:
![password](https://user-images.githubusercontent.com/17925669/29180618-f7842b90-7e15-11e7-912d-53c3671d3556.png)
where the user can update his password. Now since, we are not having the password field in user response(which will never be), we will have to perform a check server side while updating a password.

Expected:
Perform a check and return the response if the check was successful. Else return error.


Discussion:
@shubham-padia @poush @enigmaeth @magdalenesuo Can you take a look at this? I mean should we have a separate endpoint for this so that the old password can be send in request body and checked on the server side since we cannot check it on client side.
If you just want to verify if the old password is correct then I guess you can also try hitting the login API.
Say user enters, "123" as password, you hit the login API with email and password and if it success then it is the correct one and then you can compare it with the new password entered.
Although if there is something to be developed in Orga Server then I guess the comparison between old and new password at USER patch request should be the one.
@fossasia/open-event-server-devs  views? 
> Say user enters, "123" as password, you hit the login API with email and password and if it success then it is the correct one and then you can compare it with the new password entered.

Sounds good :+1: 

> Although if there is something to be developed in Orga Server then I guess the comparison between old and new password at USER patch request should be the one.

@poush Can you elaborate on this, did not quite get it :sweat_smile: 
@poush Yeah I also dint get the later part.
Was saying that the other option is to send User PATCH request with old password as well in request body and the old and new password will be compared in this same request first before saving the new password. Other than this no separate endpoint should be built for this and of course, it is impossible to send the password from API to frontend and impractical to do even if it is possible.
I feel there can be two different checks in this reset password API. 
- [ ] The hash of the old password entered matches the entry in the db
- [ ] The old password is not same as new password ( Done in most websites )
@SaptakS Reset password API is for forgot password. This should be done is User PATCH.
@poush well according to the screenshot if it is for forgot password I don't think there should be a current password field.
Password change should require old password at a server level. The FE shouldn't handle checking of old password validity. We don't want someone to directly use the API and change a password without knowing the old password. (Lets say some one got hold of a valid auth token for example)
@niranjan94 Is there will be a separate endpoint or it will be done in USER Patch request?
Separate endpoint should be better. Something like how we discussed in the `/auth/*` namespace

Resolving patch:
diff --git a/app/api/auth.py b/app/api/auth.py
--- a/app/api/auth.py
+++ b/app/api/auth.py
@@ -1,5 +1,6 @@
 import base64
 from flask import request, jsonify, abort, make_response, Blueprint
+from flask_jwt import current_identity as current_user, jwt_required
 from sqlalchemy.orm.exc import NoResultFound
 
 from app import get_settings
@@ -73,3 +74,31 @@ def reset_password_patch():
         "email": user.email,
         "name": user.name if user.get('name') else None
     })
+
+
+@auth_routes.route('/change-password', methods=['POST'])
+@jwt_required()
+def change_password():
+    old_password = request.json['data']['old-password']
+    new_password = request.json['data']['new-password']
+
+    try:
+        user = User.query.filter_by(id=current_user.id).one()
+    except NoResultFound:
+        return abort(
+            make_response(jsonify(error="User not found"), 404)
+        )
+    else:
+        if user.is_correct_password(old_password):
+
+            user.password = new_password
+            save_to_db(user)
+        else:
+            return make_response(jsonify(error="Wrong Password"), 400)
+
+    return jsonify({
+        "id": user.id,
+        "email": user.email,
+        "name": user.fullname if user.fullname else None,
+        "password_changed": True
+    })
diff --git a/app/models/user.py b/app/models/user.py
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -263,6 +263,13 @@ def is_anonymous(self):
     def get_id(self):
         return self.id
 
+    def is_correct_password(self, password):
+        salt = self.salt
+        password = generate_password_hash(password, salt)
+        if password == self._password:
+            return True
+        return False
+
     @property
     def is_staff(self):
         return self.is_super_admin or self.is_admin
@@ -325,8 +332,8 @@ def update_lat(self):
 
     @property
     def fullname(self):
-        firstname = self.firstname if self.firstname else ''
-        lastname = self.lastname if self.lastname else ''
+        firstname = self.first_name if self.first_name else ''
+        lastname = self.last_name if self.last_name else ''
         if firstname and lastname:
             return u'{} {}'.format(firstname, lastname)
         else:


Test patch: