Explorar el Código

hash passwords in database

Eren Yilmaz hace 6 años
padre
commit
653c12b4b8
Se han modificado 6 ficheros con 95 adiciones y 43 borrados
  1. 32 12
      client_controller.py
  2. 3 16
      cool_query.py
  3. 7 0
      hash_all_users_passwords.py
  4. 43 9
      model.py
  5. 8 6
      server_controller.py
  6. 2 0
      util.py

+ 32 - 12
client_controller.py

@@ -39,7 +39,7 @@ def login(username=None, password=None):
             print('Login failed.')
 
 
-def register(username=None, password=None, game_key=''):
+def register(username=None, game_key='', password=None, retype_password=None):
     if connection.session_id is not None:
         connection.session_id = None
         fake_loading_bar('Signing out', duration=0.7)
@@ -49,9 +49,22 @@ def register(username=None, password=None, game_key=''):
 
     if password is None:
         if sys.stdin.isatty():
-            password = getpass('Password: ')
+            password = getpass('New password: ')
+            retype_password = getpass('Retype password: ')
         else:
-            password = input('Password: ')
+            password = input('New password: ')
+            retype_password = input('Retype password: ')
+        if password != retype_password:
+            print('Passwords do not match.')
+            return
+    elif retype_password is None:
+        if sys.stdin.isatty():
+            retype_password = getpass('Retype password: ')
+        else:
+            retype_password = input('Retype password: ')
+        if password != retype_password:
+            print('Passwords do not match.')
+            return
 
     if not debug:
         if game_key == '':
@@ -82,16 +95,23 @@ def change_password(password=None, retype_password=None):
     if password != retype_password:
         password = None
     if password is None:
-        while True:
-            if sys.stdin.isatty():
-                password = getpass('New password: ')
-                retype_password = getpass('Retype password: ')
-            else:
-                password = input('New password: ')
-                retype_password = getpass('Retype password: ')
-            if password == retype_password:
-                break
+        if sys.stdin.isatty():
+            password = getpass('New password: ')
+            retype_password = getpass('Retype password: ')
+        else:
+            password = input('New password: ')
+            retype_password = input('Retype password: ')
+        if password != retype_password:
+            print('Passwords do not match.')
+            return
+    elif retype_password is None:
+        if sys.stdin.isatty():
+            retype_password = getpass('Retype password: ')
+        else:
+            retype_password = input('Retype password: ')
+        if password != retype_password:
             print('Passwords do not match.')
+            return
 
     fake_loading_bar('Validating password', duration=1.2)
     fake_loading_bar('Changing password', duration=5.2)

+ 3 - 16
cool_query.py

@@ -2,21 +2,8 @@ import model
 
 model.connect()
 model.cursor.execute('''
-        SELECT 
-            username, 
-            SUM(CASE -- sum score for each of the users ownables
-                WHEN ownership.ownable_id = ? THEN ownership.amount
-                ELSE ownership.amount * (SELECT price 
-                                         FROM transactions
-                                         WHERE ownable_id = ownership.ownable_id 
-                                         ORDER BY dt DESC 
-                                         LIMIT 1)
-                END
-            ) score
-        FROM users, ownership
-        WHERE ownership.user_id = users.rowid
-        AND users.username != 'bank'
-        GROUP BY users.rowid
-        ''', (model.currency_id(),))
+        SELECT * FROM users 
+                WHERE username = ?
+        ''',('u',))
 
 print(model.cursor.fetchall())

+ 7 - 0
hash_all_users_passwords.py

@@ -0,0 +1,7 @@
+import model
+from admin_console import cleanup
+
+if __name__ == '__main__':
+    if input('Are you sure you want to hash all users passwords? (type in "yes" or something else):') == 'yes':
+        model.hash_all_users_passwords()
+        cleanup()

+ 43 - 9
model.py

@@ -6,9 +6,11 @@ import uuid
 from datetime import timedelta, datetime
 from math import floor
 
+from passlib.handlers.sha2_crypt import sha256_crypt
+
 import db_setup
 from game import CURRENCY_NAME
-from util import random_chars
+from util import random_chars, salt
 from debug import debug
 
 # connection: db.Connection = None
@@ -89,13 +91,17 @@ def login(username, password):
         return None
 
     cursor.execute('''
-                SELECT rowid
+                SELECT rowid, password
                 FROM users
                 WHERE username = ?
-                AND password = ?
-                ''', (username, password))
-    user_id = cursor.fetchone()
-    if user_id:
+                ''', (username,))
+    data = cursor.fetchone()
+    if not data:
+        return None
+    hashed_password = data[1]
+    user_id = data[0]
+    # if a ValueError occurs here, then most likely a password that was stored as plain text
+    if sha256_crypt.verify(password + salt, hashed_password):
         return new_session(user_id)
     else:
         return None
@@ -185,7 +191,7 @@ def new_session(user_id):
                 INSERT INTO SESSIONS 
                 (user_id, session_id)
                 VALUES (? , ?)
-                ''', (user_id[0], session_id))
+                ''', (user_id, session_id))
 
     return session_id
 
@@ -298,9 +304,9 @@ def get_user_ownership(user_id):
              AND NOT stop_loss) AS ask
         FROM ownership, ownables
         WHERE user_id = ?
-        AND ownership.amount > 0
+        AND (ownership.amount > 0 OR ownership.ownable_id = ?)
         AND ownership.ownable_id = ownables.rowid
-        ''', (currency_id(), user_id,))
+        ''', (currency_id(), user_id, currency_id(),))
 
     return cursor.fetchall()
 
@@ -973,3 +979,31 @@ def delete_ownable(ownable_id):
         DELETE FROM ownables
         WHERE rowid = ?
         ''', (ownable_id,))
+
+
+def hash_all_users_passwords():
+    connect()
+
+    cursor.execute('''
+        SELECT rowid, password 
+        FROM users
+        ''')
+
+    users = cursor.fetchall()
+
+    for user in users:
+        user_id = user[0]
+        pw = user[1]
+        valid_hash = True
+        try:
+            sha256_crypt.verify('password' + salt, pw)
+        except ValueError:
+            valid_hash = False
+        if valid_hash:
+            raise AssertionError('There is already a hashed password in the database! Be careful what you are doing!')
+        pw = sha256_crypt.encrypt(pw + salt)
+        cursor.execute('''
+            UPDATE users
+            SET password = ?
+            WHERE rowid = ?
+            ''', (pw, user_id,))

+ 8 - 6
server_controller.py

@@ -1,9 +1,10 @@
 import json
-
 from bottle import request, response
-
 import model
 from debug import debug
+from passlib.hash import sha256_crypt
+
+from util import salt
 
 
 def missing_attributes(attributes):
@@ -45,7 +46,7 @@ def register():
     if missing:
         return bad_request(missing)
     username = request.json['username']
-    password = request.json['password']
+    hashed_password = sha256_crypt.encrypt(request.json['password'] + salt)
     if model.user_exists(username):
         return forbidden('User already exists.')
     game_key = ''
@@ -53,7 +54,7 @@ def register():
         game_key = request.json['game_key'].strip().upper()
         if game_key != '' and game_key not in model.unused_keys():
             return bad_request('Game key is not valid.')
-    if model.register(username, password, game_key):
+    if model.register(username, hashed_password, game_key):
         return {'message': "successfully registered user"}
     else:
         return bad_request('registration not successful')
@@ -186,9 +187,10 @@ def change_password():
     missing = missing_attributes(['session_id', 'password'])
     if missing:
         return bad_request(missing)
-    model.change_password(request.json['session_id'], request.json['password'])
+    hashed_password = sha256_crypt.encrypt(request.json['password'] + salt)
+    model.change_password(request.json['session_id'], hashed_password)
     model.sign_out_user(request.json['session_id'])
-    return {'message': "Successfully deleted order"}
+    return {'message': "Successfully changed password"}
 
 
 def news():

+ 2 - 0
util.py

@@ -1,5 +1,7 @@
 from random import random
 
+salt = 'orderer_is_a_cool_application_]{][{²$%WT§$%GV§$%SF$%&S$%FGGFHBDHJZIF254325'
+
 chars = [str(d) for d in range(1, 10)]
 
 ps = [2. for _ in chars]