diff --git a/change-password.py b/change-password.py index 06d652101..0945423b2 100644 --- a/change-password.py +++ b/change-password.py @@ -7,15 +7,17 @@ import getpass from Crypto.Cipher import AES from Crypto.Util import Counter import binascii -import src.password_provider import src.my_scrypt +config = src.config_provider.getConfig() +src.sql.connect(config['Document']['documentPath']) + currentPassword = getpass.getpass(prompt="Enter current password: ") currentPasswordHash = binascii.hexlify(src.my_scrypt.getVerificationHash(currentPassword)) -if currentPasswordHash != src.password_provider.getPasswordHash(): +if currentPasswordHash != src.sql.getOption('password'): print("Given password doesn't match hash") exit(-1) @@ -31,9 +33,6 @@ if newPassword1 != newPassword2: newPasswordVerificationKey = binascii.hexlify(src.my_scrypt.getVerificationHash(newPassword1)) newPasswordEncryptionKey = src.my_scrypt.getEncryptionHash(newPassword1) -config = src.config_provider.getConfig() -src.sql.connect(config['Document']['documentPath']) - encryptedNotes = src.sql.getResults("select note_id, note_title, note_text from notes where encryption = 1") def decrypt(encryptedBase64): @@ -63,10 +62,7 @@ for note in encryptedNotes: print("Note " + note['note_id'] + " re-encrypted with new password") -src.password_provider.setPasswordHash(newPasswordVerificationKey) - -print("New password has been saved into password.txt") - +src.sql.setOption('password', newPasswordVerificationKey) src.sql.commit() print("Changes committed. All encrypted notes were re-encrypted successfully with new password key.") diff --git a/config-sample.ini b/config-sample.ini index e0964a735..b5bc9fa0a 100644 --- a/config-sample.ini +++ b/config-sample.ini @@ -1,10 +1,6 @@ [Document] documentPath=demo.ncdb -[Security] -# run "python generate-secret-key.py" and paste the result below -flaskSecretKey= - [Network] port=5000 # true for TLS/SSL/HTTPS (secure), false for HTTP (unsecure). @@ -12,7 +8,3 @@ https=true # path to certificate (run "bash generate-cert.sh" to generate self-signed certificate). Relevant only if https=true certPath=cert.crt certKeyPath=cert.key - -[Login] -# Enter below credentials with with which you want to authenticate to Notecase web app -username=your_username diff --git a/generate-password.py b/generate-password.py deleted file mode 100644 index ca8bb7a33..000000000 --- a/generate-password.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/python - -import getpass -import src.my_scrypt -import binascii -import src.password_provider - -password1 = getpass.getpass() -password2 = getpass.getpass(prompt='Repeat the same password:') - -if password1 == password2: - hash = src.my_scrypt.getVerificationHash(password1) - - src.password_provider.setPasswordHash(binascii.hexlify(hash)) - - print('Password has been generated and saved into password.txt. You can now login.') -else: - print('Entered passwords are not identical!') \ No newline at end of file diff --git a/generate-secret-key.py b/generate-secret-key.py deleted file mode 100644 index 8f810abf2..000000000 --- a/generate-secret-key.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/python -import os -import base64 - -print(base64.b64encode(os.urandom(24))) \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..b4b474ae1 --- /dev/null +++ b/setup.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +import binascii +import getpass +import os +import base64 + +from builtins import input + +import src.config_provider +import src.sql +import src.my_scrypt + +config = src.config_provider.getConfig() +src.sql.connect(config['Document']['documentPath']) + +username = src.sql.getOption("username") + +if username: + print("Application has been already set up.") + exit(1) + +print("Please provide your desired login credentials") + +username = input("Username: ") + +password1 = getpass.getpass() +password2 = getpass.getpass(prompt='Repeat the same password: ') + +if password1 == password2: + hash = src.my_scrypt.getVerificationHash(password1) + + src.sql.setOption('username', username) + src.sql.setOption('password', binascii.hexlify(hash)) + + # urandom is secure enough, see https://docs.python.org/2/library/os.html + src.sql.setOption('flask_secret_key', base64.b64encode(os.urandom(24))) + src.sql.setOption('verification_salt', base64.b64encode(os.urandom(24))) + src.sql.setOption('encryption_salt', base64.b64encode(os.urandom(24))) + + src.sql.commit() + + print('Application has been set up. You can now login.') +else: + print('Entered passwords are not identical!') \ No newline at end of file diff --git a/src/app.py b/src/app.py index c7ac71a99..5959428a7 100644 --- a/src/app.py +++ b/src/app.py @@ -7,18 +7,26 @@ from flask_cors import CORS from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user from notes_api import notes_api -from sql import connect +from sql import connect, getOption from tree_api import tree_api from notes_move_api import notes_move_api from password_api import password_api import config_provider import my_scrypt -import password_provider config = config_provider.getConfig() +documentPath = config['Document']['documentPath'] +connect(documentPath) + +flask_secret_key = getOption("flask_secret_key") + +if not flask_secret_key: + print("Application has not been setup yet. Run 'python setup.py' to finish setup.") + exit(1) + app = Flask(__name__) -app.secret_key = config['Security']['flaskSecretKey'] +app.secret_key = flask_secret_key app.register_blueprint(tree_api) app.register_blueprint(notes_api) app.register_blueprint(notes_move_api) @@ -43,19 +51,15 @@ def logout(): return redirect('login') user = User() -user.id = config['Login']['username'] +user.id = getOption('username') port = config['Network']['port'] https = config['Network']['https'] certPath = config['Network']['certPath'] certKeyPath = config['Network']['certKeyPath'] -documentPath = config['Document']['documentPath'] - -connect(documentPath) - def verify_password(guessed_password): - hashed_password = binascii.unhexlify(password_provider.getPasswordHash()) + hashed_password = binascii.unhexlify(getOption('password')) guess_hashed = my_scrypt.getVerificationHash(guessed_password) diff --git a/src/password_api.py b/src/password_api.py index 83cb8ea7b..bd17fc9a8 100644 --- a/src/password_api.py +++ b/src/password_api.py @@ -2,7 +2,7 @@ from flask import Blueprint, jsonify, request from flask_login import login_required import hashlib import binascii -import password_provider +import sql password_api = Blueprint('password_api', __name__) @@ -11,7 +11,7 @@ password_api = Blueprint('password_api', __name__) def verifyPassword(): req = request.get_json(force=True) - hashedPassword = password_provider.getPasswordHash() + hashedPassword = sql.getOption('password') hashedPasswordBytes = binascii.unhexlify(hashedPassword) hashedPasswordSha = hashlib.sha256(hashedPasswordBytes).hexdigest() diff --git a/src/password_provider.py b/src/password_provider.py deleted file mode 100644 index 65aff814d..000000000 --- a/src/password_provider.py +++ /dev/null @@ -1,7 +0,0 @@ -def getPasswordHash(): - with open('password.txt') as file: - return file.readline() - -def setPasswordHash(newPasswordHash): - with open('password.txt', 'w') as file: - file.write(newPasswordHash) diff --git a/src/sql.py b/src/sql.py index c007e302a..1a59a0af7 100644 --- a/src/sql.py +++ b/src/sql.py @@ -26,6 +26,12 @@ def insert(tablename, rec): cursor = execute('INSERT INTO '+tablename+' ('+keys+') VALUES ('+question_marks+')', values) return cursor.lastrowid +def setOption(name, value): + execute("UPDATE options SET opt_value = ? WHERE opt_name = ?", [value, name]) + +def getOption(name): + return getSingleResult("SELECT opt_value FROM options WHERE opt_name = ?", [name])['opt_value'] + def delete(tablename, note_id): execute("DELETE FROM " + tablename + " WHERE note_id = ?", [note_id])