refactored naming to conform to PEP 8

This commit is contained in:
azivner 2017-10-09 19:48:10 -04:00
parent 8a5ff3968b
commit c9322465a5
17 changed files with 155 additions and 125 deletions

View File

@ -33,7 +33,7 @@ if password1 == password2:
src.sql.setOption('password_verification_salt', base64.b64encode(os.urandom(32))) src.sql.setOption('password_verification_salt', base64.b64encode(os.urandom(32)))
src.sql.setOption('password_derived_key_salt', base64.b64encode(os.urandom(32))) src.sql.setOption('password_derived_key_salt', base64.b64encode(os.urandom(32)))
password_derived_key = src.my_scrypt.getPasswordDerivedKey(password1) password_derived_key = src.my_scrypt.get_password_derived_key(password1)
aes = AES.new(password_derived_key, AES.MODE_CTR, counter=Counter.new(128, initial_value=5)) aes = AES.new(password_derived_key, AES.MODE_CTR, counter=Counter.new(128, initial_value=5))
@ -44,7 +44,7 @@ if password1 == password2:
src.sql.setOption('encrypted_data_key', base64.b64encode(encrypted_data_key)) src.sql.setOption('encrypted_data_key', base64.b64encode(encrypted_data_key))
verification_hash = src.my_scrypt.getVerificationHash(password1) verification_hash = src.my_scrypt.get_verification_hash(password1)
src.sql.setOption('username', username) src.sql.setOption('username', username)
src.sql.setOption('password_verification_hash', base64.b64encode(verification_hash)) src.sql.setOption('password_verification_hash', base64.b64encode(verification_hash))

View File

@ -10,15 +10,15 @@ from notes_history_api import notes_history_api
from notes_move_api import notes_move_api from notes_move_api import notes_move_api
from password_api import password_api from password_api import password_api
from settings_api import settings_api from settings_api import settings_api
from sql import connect, getOption from sql import connect, get_option
from tree_api import tree_api from tree_api import tree_api
config = config_provider.getConfig() config = config_provider.get_config()
documentPath = config['Document']['documentPath'] documentPath = config['Document']['documentPath']
connect(documentPath) connect(documentPath)
flask_secret_key = getOption("flask_secret_key") flask_secret_key = get_option("flask_secret_key")
if not flask_secret_key: if not flask_secret_key:
print("Application has not been setup yet. Run 'python setup.py' to finish setup.") print("Application has not been setup yet. Run 'python setup.py' to finish setup.")

View File

@ -6,9 +6,10 @@ from sql import getSingleResult
audit_api = Blueprint('audit_api', __name__) audit_api = Blueprint('audit_api', __name__)
@audit_api.route('/api/audit/<int:full_load_time>', methods = ['GET']) @audit_api.route('/api/audit/<int:full_load_time>', methods = ['GET'])
@login_required @login_required
def getNote(full_load_time): def get_note(full_load_time):
browser_id = request.headers['x-browser-id'] browser_id = request.headers['x-browser-id']
count = getSingleResult("SELECT COUNT(*) AS 'count' FROM audit_log WHERE browser_id != ? AND date_modified >= ?", [browser_id, full_load_time])['count'] count = getSingleResult("SELECT COUNT(*) AS 'count' FROM audit_log WHERE browser_id != ? AND date_modified >= ?", [browser_id, full_load_time])['count']

View File

@ -1,25 +1,27 @@
from datetime import datetime
import utils
from sql import getOption, setOption, commit
import config_provider
from shutil import copyfile
import os import os
import re import re
from datetime import datetime
from shutil import copyfile
import config_provider
import utils
from sql import get_option, set_option, commit
def regular_backup(): def regular_backup():
now = utils.nowTimestamp() now = utils.now_timestamp()
last_backup_date = int(getOption('last_backup_date')) last_backup_date = int(get_option('last_backup_date'))
if now - last_backup_date > 43200: if now - last_backup_date > 43200:
backup_now() backup_now()
cleanup_old_backups() cleanup_old_backups()
def backup_now():
now = utils.nowTimestamp()
config = config_provider.getConfig() def backup_now():
now = utils.now_timestamp()
config = config_provider.get_config()
document_path = config['Document']['documentPath'] document_path = config['Document']['documentPath']
backup_directory = config['Backup']['backupDirectory'] backup_directory = config['Backup']['backupDirectory']
@ -28,12 +30,13 @@ def backup_now():
copyfile(document_path, backup_directory + "/" + "backup-" + date_str + ".db") copyfile(document_path, backup_directory + "/" + "backup-" + date_str + ".db")
setOption('last_backup_date', now) set_option('last_backup_date', now)
commit() commit()
def cleanup_old_backups(): def cleanup_old_backups():
now = datetime.utcnow() now = datetime.utcnow()
config = config_provider.getConfig() config = config_provider.get_config()
backup_directory = config['Backup']['backupDirectory'] backup_directory = config['Backup']['backupDirectory']
for file in os.listdir(backup_directory): for file in os.listdir(backup_directory):

View File

@ -3,24 +3,24 @@ import hashlib
from Crypto.Cipher import AES from Crypto.Cipher import AES
from Crypto.Util import Counter from Crypto.Util import Counter
import sql
import my_scrypt
import audit_category import audit_category
import my_scrypt
import sql
def change_password(current_password, new_password, request = None): def change_password(current_password, new_password, request = None):
current_password_hash = base64.b64encode(my_scrypt.getVerificationHash(current_password)) current_password_hash = base64.b64encode(my_scrypt.get_verification_hash(current_password))
if current_password_hash != sql.getOption('password_verification_hash'): if current_password_hash != sql.get_option('password_verification_hash'):
return { return {
'success': False, 'success': False,
'message': "Given current password doesn't match hash" 'message': "Given current password doesn't match hash"
} }
current_password_derived_key = my_scrypt.getPasswordDerivedKey(current_password) current_password_derived_key = my_scrypt.get_password_derived_key(current_password)
new_password_verification_key = base64.b64encode(my_scrypt.getVerificationHash(new_password)) new_password_verification_key = base64.b64encode(my_scrypt.get_verification_hash(new_password))
new_password_encryption_key = my_scrypt.getPasswordDerivedKey(new_password) new_password_encryption_key = my_scrypt.get_password_derived_key(new_password)
def decrypt(encrypted_base64): def decrypt(encrypted_base64):
encrypted_bytes = base64.b64decode(encrypted_base64) encrypted_bytes = base64.b64decode(encrypted_base64)
@ -40,17 +40,17 @@ def change_password(current_password, new_password, request = None):
def get_aes(key): def get_aes(key):
return AES.new(key, AES.MODE_CTR, counter=Counter.new(128, initial_value=5)) return AES.new(key, AES.MODE_CTR, counter=Counter.new(128, initial_value=5))
encrypted_data_key = sql.getOption('encrypted_data_key') encrypted_data_key = sql.get_option('encrypted_data_key')
decrypted_data_key = decrypt(encrypted_data_key) decrypted_data_key = decrypt(encrypted_data_key)
new_encrypted_data_key = encrypt(decrypted_data_key) new_encrypted_data_key = encrypt(decrypted_data_key)
sql.setOption('encrypted_data_key', new_encrypted_data_key) sql.set_option('encrypted_data_key', new_encrypted_data_key)
sql.setOption('password_verification_hash', new_password_verification_key) sql.set_option('password_verification_hash', new_password_verification_key)
sql.addAudit(audit_category.CHANGE_PASSWORD, request) sql.add_audit(audit_category.CHANGE_PASSWORD, request)
sql.commit() sql.commit()

View File

@ -1,6 +1,6 @@
import configparser import configparser
def getConfig(): def get_config():
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read('config.ini') config.read('config.ini')

View File

@ -6,7 +6,7 @@ import traceback
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
from flask_login import login_required from flask_login import login_required
from sql import getOption, setOption, commit, execute_script from sql import get_option, set_option, commit, execute_script
import backup import backup
@ -16,22 +16,24 @@ MIGRATIONS_DIR = "src/migrations"
migration_api = Blueprint('migration_api', __name__) migration_api = Blueprint('migration_api', __name__)
@migration_api.route('/api/migration', methods = ['GET']) @migration_api.route('/api/migration', methods = ['GET'])
@login_required @login_required
def getMigrationInfo(): def get_migration_info():
return jsonify({ return jsonify({
'db_version': int(getOption('db_version')), 'db_version': int(get_option('db_version')),
'app_db_version': APP_DB_VERSION 'app_db_version': APP_DB_VERSION
}) })
@migration_api.route('/api/migration', methods = ['POST']) @migration_api.route('/api/migration', methods = ['POST'])
@login_required @login_required
def runMigration(): def run_migration():
migrations = [] migrations = []
backup.backup_now() backup.backup_now()
current_db_version = int(getOption('db_version')) current_db_version = int(get_option('db_version'))
for file in os.listdir(MIGRATIONS_DIR): for file in os.listdir(MIGRATIONS_DIR):
match = re.search(r"([0-9]{4})__([a-zA-Z0-9_ ]+)\.sql", file) match = re.search(r"([0-9]{4})__([a-zA-Z0-9_ ]+)\.sql", file)
@ -55,7 +57,7 @@ def runMigration():
try: try:
execute_script(sql) execute_script(sql)
setOption('db_version', db_version) set_option('db_version', db_version)
commit() commit()
migration_record['success'] = True migration_record['success'] = True

View File

@ -1,17 +1,21 @@
import scrypt # pip install scrypt import scrypt # pip install scrypt
import sql import sql
def getVerificationHash(password):
salt = sql.getOption('password_verification_salt')
return getScryptHash(password, salt) def get_verification_hash(password):
salt = sql.get_option('password_verification_salt')
def getPasswordDerivedKey(password): return get_scrypt_hash(password, salt)
salt = sql.getOption('password_derived_key_salt')
return getScryptHash(password, salt)
def getScryptHash(password, salt): def get_password_derived_key(password):
salt = sql.get_option('password_derived_key_salt')
return get_scrypt_hash(password, salt)
def get_scrypt_hash(password, salt):
# scrypt doesn't like unicode strings # scrypt doesn't like unicode strings
password = password.encode('ascii', 'ignore') password = password.encode('ascii', 'ignore')
salt = salt.encode('ascii', 'ignore') salt = salt.encode('ascii', 'ignore')

View File

@ -1,25 +1,23 @@
import base64 import base64
import math
import random import random
import string import string
import time
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
from flask import request from flask import request
from flask_login import login_required from flask_login import login_required
import audit_category
import utils
from sql import delete from sql import delete
from sql import execute, insert, commit from sql import execute, insert, commit
from sql import getResults, getSingleResult, getOption, addAudit, deleteRecentAudits from sql import getResults, getSingleResult, get_option, add_audit, deleteRecentAudits
import utils
import audit_category
notes_api = Blueprint('notes_api', __name__) notes_api = Blueprint('notes_api', __name__)
@notes_api.route('/api/notes/<string:note_id>', methods = ['GET']) @notes_api.route('/api/notes/<string:note_id>', methods = ['GET'])
@login_required @login_required
def getNote(note_id): def get_note(note_id):
execute("update options set opt_value = ? where opt_name = 'start_node'", [note_id]) execute("update options set opt_value = ? where opt_name = 'start_node'", [note_id])
detail = getSingleResult("select * from notes where note_id = ?", [note_id]) detail = getSingleResult("select * from notes where note_id = ?", [note_id])
@ -35,9 +33,10 @@ def getNote(note_id):
'images': getResults("select * from images where note_id = ? order by note_offset", [note_id]) 'images': getResults("select * from images where note_id = ? order by note_offset", [note_id])
}) })
@notes_api.route('/api/notes/<string:note_id>', methods = ['PUT']) @notes_api.route('/api/notes/<string:note_id>', methods = ['PUT'])
@login_required @login_required
def updateNote(note_id): def update_note(note_id):
detail = getSingleResult("select * from notes where note_id = ?", [note_id]) detail = getSingleResult("select * from notes where note_id = ?", [note_id])
if detail['note_clone_id']: if detail['note_clone_id']:
@ -45,9 +44,9 @@ def updateNote(note_id):
note = request.get_json(force=True) note = request.get_json(force=True)
now = utils.nowTimestamp() now = utils.now_timestamp()
history_snapshot_time_interval = float(getOption('history_snapshot_time_interval')) history_snapshot_time_interval = float(get_option('history_snapshot_time_interval'))
history_cutoff = now - history_snapshot_time_interval history_cutoff = now - history_snapshot_time_interval
@ -71,14 +70,14 @@ def updateNote(note_id):
if note['detail']['note_title'] != detail['note_title']: if note['detail']['note_title'] != detail['note_title']:
deleteRecentAudits(audit_category.UPDATE_TITLE, request, note_id) deleteRecentAudits(audit_category.UPDATE_TITLE, request, note_id)
addAudit(audit_category.UPDATE_TITLE, request, note_id) add_audit(audit_category.UPDATE_TITLE, request, note_id)
if note['detail']['note_text'] != detail['note_text']: if note['detail']['note_text'] != detail['note_text']:
deleteRecentAudits(audit_category.UPDATE_CONTENT, request, note_id) deleteRecentAudits(audit_category.UPDATE_CONTENT, request, note_id)
addAudit(audit_category.UPDATE_CONTENT, request, note_id) add_audit(audit_category.UPDATE_CONTENT, request, note_id)
if note['detail']['encryption'] != detail['encryption']: if note['detail']['encryption'] != detail['encryption']:
addAudit(audit_category.ENCRYPTION, request, note_id, detail['encryption'], note['detail']['encryption']) add_audit(audit_category.ENCRYPTION, request, note_id, detail['encryption'], note['detail']['encryption'])
execute("update notes set note_title = ?, note_text = ?, encryption = ?, date_modified = ? where note_id = ?", [ execute("update notes set note_title = ?, note_text = ?, encryption = ?, date_modified = ? where note_id = ?", [
note['detail']['note_title'], note['detail']['note_title'],
@ -108,25 +107,27 @@ def updateNote(note_id):
return jsonify({}) return jsonify({})
@notes_api.route('/api/notes/<string:note_id>', methods = ['DELETE']) @notes_api.route('/api/notes/<string:note_id>', methods = ['DELETE'])
@login_required @login_required
def deleteNote(note_id): def delete_note(note_id):
children = getResults("select note_id from notes_tree where note_pid = ?", [note_id]) children = getResults("select note_id from notes_tree where note_pid = ?", [note_id])
for child in children: for child in children:
deleteNote(child['note_id']) delete_note(child['note_id'])
delete("notes_tree", note_id) delete("notes_tree", note_id)
delete("notes", note_id) delete("notes", note_id)
addAudit(audit_category.DELETE_NOTE, request, note_id) add_audit(audit_category.DELETE_NOTE, request, note_id)
commit() commit()
return jsonify({}) return jsonify({})
@notes_api.route('/api/notes/<string:parent_note_id>/children', methods = ['POST']) @notes_api.route('/api/notes/<string:parent_note_id>/children', methods = ['POST'])
@login_required @login_required
def createChild(parent_note_id): def create_child(parent_note_id):
note = request.get_json(force=True) note = request.get_json(force=True)
noteId = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(22)) noteId = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(22))
@ -153,9 +154,9 @@ def createChild(parent_note_id):
else: else:
raise Exception('Unknown target: ' + note['target']) raise Exception('Unknown target: ' + note['target'])
addAudit(audit_category.CREATE_NOTE, request, noteId) add_audit(audit_category.CREATE_NOTE, request, noteId)
now = utils.nowTimestamp() now = utils.now_timestamp()
insert("notes", { insert("notes", {
'note_id': noteId, 'note_id': noteId,
@ -182,9 +183,10 @@ def createChild(parent_note_id):
'note_id': noteId 'note_id': noteId
}) })
@notes_api.route('/api/notes', methods = ['GET']) @notes_api.route('/api/notes', methods = ['GET'])
@login_required @login_required
def searchNotes(): def search_notes():
search = '%' + request.args['search'] + '%' search = '%' + request.args['search'] + '%'
result = getResults("select note_id from notes where note_title like ? or note_text like ?", [search, search]) result = getResults("select note_id from notes where note_title like ? or note_text like ?", [search, search])

View File

@ -5,16 +5,18 @@ from sql import getResults
notes_history_api = Blueprint('notes_history_api', __name__) notes_history_api = Blueprint('notes_history_api', __name__)
@notes_history_api.route('/api/notes-history/<string:note_id>', methods = ['GET']) @notes_history_api.route('/api/notes-history/<string:note_id>', methods = ['GET'])
@login_required @login_required
def getNoteHistory(note_id): def get_note_history(note_id):
history = getResults("select * from notes_history where note_id = ? order by date_modified desc", [note_id]) history = getResults("select * from notes_history where note_id = ? order by date_modified desc", [note_id])
return jsonify(history) return jsonify(history)
@notes_history_api.route('/api/recent-changes/', methods = ['GET']) @notes_history_api.route('/api/recent-changes/', methods = ['GET'])
@login_required @login_required
def getRecentChanges(): def get_recent_changes():
recent_changes = getResults("select * from notes_history order by date_modified desc limit 1000") recent_changes = getResults("select * from notes_history order by date_modified desc limit 1000")
return jsonify(recent_changes) return jsonify(recent_changes)

View File

@ -3,14 +3,14 @@ from flask import request
from flask_login import login_required from flask_login import login_required
import audit_category import audit_category
from sql import execute, commit, addAudit from sql import execute, commit, add_audit
from sql import getSingleResult from sql import getSingleResult
notes_move_api = Blueprint('notes_move_api', __name__) notes_move_api = Blueprint('notes_move_api', __name__)
@notes_move_api.route('/api/notes/<string:note_id>/moveTo/<string:parent_id>', methods = ['PUT']) @notes_move_api.route('/api/notes/<string:note_id>/moveTo/<string:parent_id>', methods = ['PUT'])
@login_required @login_required
def moveToNote(note_id, parent_id): def move_to_note(note_id, parent_id):
res = getSingleResult('select max(note_pos) as max_note_pos from notes_tree where note_pid = ?', [parent_id]) res = getSingleResult('select max(note_pos) as max_note_pos from notes_tree where note_pid = ?', [parent_id])
max_note_pos = res['max_note_pos'] max_note_pos = res['max_note_pos']
new_note_pos = 0 new_note_pos = 0
@ -22,13 +22,14 @@ def moveToNote(note_id, parent_id):
execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [parent_id, new_note_pos, note_id]) execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [parent_id, new_note_pos, note_id])
addAudit(audit_category.CHANGE_PARENT, request, note_id) add_audit(audit_category.CHANGE_PARENT, request, note_id)
commit() commit()
return jsonify({}) return jsonify({})
@notes_move_api.route('/api/notes/<string:note_id>/moveBefore/<string:before_note_id>', methods = ['PUT']) @notes_move_api.route('/api/notes/<string:note_id>/moveBefore/<string:before_note_id>', methods = ['PUT'])
def moveBeforeNote(note_id, before_note_id): def move_before_note(note_id, before_note_id):
before_note = getSingleResult("select * from notes_tree where note_id = ?", [before_note_id]) before_note = getSingleResult("select * from notes_tree where note_id = ?", [before_note_id])
if before_note <> None: if before_note <> None:
@ -36,14 +37,15 @@ def moveBeforeNote(note_id, before_note_id):
execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [before_note['note_pid'], before_note['note_pos'], note_id]) execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [before_note['note_pid'], before_note['note_pos'], note_id])
addAudit(audit_category.CHANGE_POSITION, request, note_id) add_audit(audit_category.CHANGE_POSITION, request, note_id)
commit() commit()
return jsonify({}) return jsonify({})
@notes_move_api.route('/api/notes/<string:note_id>/moveAfter/<string:after_note_id>', methods = ['PUT']) @notes_move_api.route('/api/notes/<string:note_id>/moveAfter/<string:after_note_id>', methods = ['PUT'])
def moveAfterNote(note_id, after_note_id): def move_after_note(note_id, after_note_id):
after_note = getSingleResult("select * from notes_tree where note_id = ?", [after_note_id]) after_note = getSingleResult("select * from notes_tree where note_id = ?", [after_note_id])
if after_note <> None: if after_note <> None:
@ -51,14 +53,15 @@ def moveAfterNote(note_id, after_note_id):
execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [after_note['note_pid'], after_note['note_pos'] + 1, note_id]) execute("update notes_tree set note_pid = ?, note_pos = ? where note_id = ?", [after_note['note_pid'], after_note['note_pos'] + 1, note_id])
addAudit(audit_category.CHANGE_POSITION, request, note_id) add_audit(audit_category.CHANGE_POSITION, request, note_id)
commit() commit()
return jsonify({}) return jsonify({})
@notes_move_api.route('/api/notes/<string:note_id>/expanded/<int:expanded>', methods = ['PUT']) @notes_move_api.route('/api/notes/<string:note_id>/expanded/<int:expanded>', methods = ['PUT'])
def setExpandedNote(note_id, expanded): def set_expanded_note(note_id, expanded):
execute("update notes_tree set is_expanded = ? where note_id = ?", [expanded, note_id]) execute("update notes_tree set is_expanded = ? where note_id = ?", [expanded, note_id])
# no audit here, not really important # no audit here, not really important

View File

@ -1,15 +1,14 @@
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
from flask_login import login_required from flask_login import login_required
import hashlib
import binascii
import sql
import change_password import change_password
password_api = Blueprint('password_api', __name__) password_api = Blueprint('password_api', __name__)
@password_api.route('/api/password/change', methods = ['POST']) @password_api.route('/api/password/change', methods = ['POST'])
@login_required @login_required
def changePassword(): def change_password():
req = request.get_json(force=True) req = request.get_json(force=True)
result = change_password.change_password(req['current_password'], req['new_password']) result = change_password.change_password(req['current_password'], req['new_password'])

View File

@ -8,7 +8,7 @@ from flask_login import login_required
import my_scrypt import my_scrypt
from migration_api import APP_DB_VERSION from migration_api import APP_DB_VERSION
from sql import getOption from sql import get_option
class User(UserMixin): class User(UserMixin):
@ -23,7 +23,7 @@ def init(app):
login_manager.init_app(app) login_manager.init_app(app)
login_manager.login_view = 'login_form' login_manager.login_view = 'login_form'
user.id = getOption('username') user.id = get_option('username')
routes = Blueprint('routes', __name__) routes = Blueprint('routes', __name__)
@ -37,7 +37,7 @@ def login_form():
@routes.route('/app', methods=['GET']) @routes.route('/app', methods=['GET'])
@login_required @login_required
def show_app(): def show_app():
db_version = int(getOption('db_version')) db_version = int(get_option('db_version'))
if db_version < APP_DB_VERSION: if db_version < APP_DB_VERSION:
return redirect('migration') return redirect('migration')
@ -59,9 +59,9 @@ def logout():
def verify_password(guessed_password): def verify_password(guessed_password):
hashed_password = base64.b64decode(getOption('password_verification_hash')) hashed_password = base64.b64decode(get_option('password_verification_hash'))
guess_hashed = my_scrypt.getVerificationHash(guessed_password) guess_hashed = my_scrypt.get_verification_hash(guessed_password)
return guess_hashed == hashed_password return guess_hashed == hashed_password

View File

@ -6,29 +6,31 @@ import audit_category
settings_api = Blueprint('settings_api', __name__) settings_api = Blueprint('settings_api', __name__)
allowed_options = [ 'encryption_session_timeout', 'history_snapshot_time_interval' ] ALLOWED_OPTIONS = ['encryption_session_timeout', 'history_snapshot_time_interval']
@settings_api.route('/api/settings', methods = ['GET']) @settings_api.route('/api/settings', methods = ['GET'])
@login_required @login_required
def get_settings(): def get_settings():
dict = {} dict = {}
settings = sql.getResults("SELECT opt_name, opt_value FROM options WHERE opt_name IN (%s)" % ',' . join('?'*len(allowed_options)), allowed_options) settings = sql.getResults("SELECT opt_name, opt_value FROM options WHERE opt_name IN (%s)" % ',' . join('?' * len(ALLOWED_OPTIONS)), ALLOWED_OPTIONS)
for set in settings: for set in settings:
dict[set['opt_name']] = set['opt_value'] dict[set['opt_name']] = set['opt_value']
return jsonify(dict) return jsonify(dict)
@settings_api.route('/api/settings', methods = ['POST']) @settings_api.route('/api/settings', methods = ['POST'])
@login_required @login_required
def set_settings(): def set_settings():
req = request.get_json(force=True) req = request.get_json(force=True)
if req['name'] in allowed_options: if req['name'] in ALLOWED_OPTIONS:
sql.addAudit(audit_category.SETTINGS, request, None, sql.getOption(req['name']), req['value'], req['name']) sql.add_audit(audit_category.SETTINGS, request, None, sql.get_option(req['name']), req['value'], req['name'])
sql.setOption(req['name'], req['value']) sql.set_option(req['name'], req['value'])
sql.commit() sql.commit()

View File

@ -1,13 +1,11 @@
import base64 import base64
import sqlite3 import sqlite3
import math
import time
import utils import utils
conn = None conn = None
def dict_factory(cursor, row): def dict_factory(cursor, row):
d = {} d = {}
for idx, col in enumerate(cursor.description): for idx, col in enumerate(cursor.description):
@ -18,27 +16,32 @@ def dict_factory(cursor, row):
return d return d
def connect(documentPath):
def connect(document_path):
global conn global conn
conn = sqlite3.connect(documentPath) conn = sqlite3.connect(document_path)
conn.row_factory = dict_factory conn.row_factory = dict_factory
def insert(tablename, rec):
def insert(table_name, rec):
# FIXME: SQL injection! # FIXME: SQL injection!
keys = ','.join(rec.keys()) keys = ','.join(rec.keys())
question_marks = ','.join(list('?' * len(rec))) question_marks = ','.join(list('?' * len(rec)))
values = tuple(rec.values()) values = tuple(rec.values())
cursor = execute('INSERT INTO '+tablename+' ('+keys+') VALUES ('+question_marks+')', values) cursor = execute('INSERT INTO ' + table_name + ' (' + keys + ') VALUES (' + question_marks + ')', values)
return cursor.lastrowid return cursor.lastrowid
def setOption(name, value):
def set_option(name, value):
execute("UPDATE options SET opt_value = ? WHERE opt_name = ?", [value, name]) execute("UPDATE options SET opt_value = ? WHERE opt_name = ?", [value, name])
def getOption(name):
def get_option(name):
return getSingleResult("SELECT opt_value FROM options WHERE opt_name = ?", [name])['opt_value'] return getSingleResult("SELECT opt_value FROM options WHERE opt_name = ?", [name])['opt_value']
def addAudit(category, request = None, note_id = None, change_from = None, change_to = None, comment = None):
now = utils.nowTimestamp() def add_audit(category, request=None, note_id=None, change_from=None, change_to=None, comment=None):
now = utils.now_timestamp()
browser_id = None browser_id = None
@ -48,36 +51,43 @@ def addAudit(category, request = None, note_id = None, change_from = None, chang
execute("INSERT INTO audit_log (date_modified, category, browser_id, note_id, change_from, change_to, comment)" execute("INSERT INTO audit_log (date_modified, category, browser_id, note_id, change_from, change_to, comment)"
" VALUES (?, ?, ?, ?, ?, ?, ?)", [now, category, browser_id, note_id, change_from, change_to, comment]) " VALUES (?, ?, ?, ?, ?, ?, ?)", [now, category, browser_id, note_id, change_from, change_to, comment])
def deleteRecentAudits(category, request, note_id): def deleteRecentAudits(category, request, note_id):
browser_id = request.headers['x-browser-id'] browser_id = request.headers['x-browser-id']
delete_cutoff = utils.nowTimestamp() - 10 * 60; delete_cutoff = utils.now_timestamp() - 10 * 60;
execute("DELETE FROM audit_log WHERE category = ? AND browser_id = ? AND note_id = ? AND date_modified > ?", execute("DELETE FROM audit_log WHERE category = ? AND browser_id = ? AND note_id = ? AND date_modified > ?",
[category, browser_id, note_id, delete_cutoff]) [category, browser_id, note_id, delete_cutoff])
def delete(tablename, note_id): def delete(tablename, note_id):
execute("DELETE FROM " + tablename + " WHERE note_id = ?", [note_id]) execute("DELETE FROM " + tablename + " WHERE note_id = ?", [note_id])
def execute(sql, params=[]): def execute(sql, params=[]):
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(sql, params) cursor.execute(sql, params)
return cursor return cursor
def execute_script(sql): def execute_script(sql):
cursor = conn.cursor() cursor = conn.cursor()
cursor.executescript(sql) cursor.executescript(sql)
return cursor return cursor
def getResults(sql, params=[]): def getResults(sql, params=[]):
cursor = conn.cursor() cursor = conn.cursor()
query = cursor.execute(sql, params) query = cursor.execute(sql, params)
return query.fetchall() return query.fetchall()
def getSingleResult(sql, params=()): def getSingleResult(sql, params=()):
cursor = conn.cursor() cursor = conn.cursor()
query = cursor.execute(sql, params) query = cursor.execute(sql, params)
return query.fetchone() return query.fetchone()
def commit(): def commit():
conn.commit() conn.commit()

View File

@ -4,15 +4,16 @@ import os
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
from flask_login import login_required from flask_login import login_required
from sql import getResults, getSingleResult, getOption from sql import getResults, getSingleResult, get_option
import utils import utils
import backup import backup
tree_api = Blueprint('tree_api', __name__) tree_api = Blueprint('tree_api', __name__)
@tree_api.route('/api/tree', methods = ['GET']) @tree_api.route('/api/tree', methods = ['GET'])
@login_required @login_required
def getTree(): def get_tree():
backup.regular_backup() backup.regular_backup()
notes = getResults("select " notes = getResults("select "
@ -26,32 +27,32 @@ def getTree():
"left join notes as clone on notes.note_clone_id = clone.note_id " "left join notes as clone on notes.note_clone_id = clone.note_id "
"order by note_pid, note_pos") "order by note_pid, note_pos")
rootNotes = [] root_notes = []
notesMap = {} notes_map = {}
for note in notes: for note in notes:
note['children'] = [] note['children'] = []
if not note['note_pid']: if not note['note_pid']:
rootNotes.append(note) root_notes.append(note)
notesMap[note['note_id']] = note notes_map[note['note_id']] = note
for note in notes: for note in notes:
if note['note_pid'] != "": if note['note_pid'] != "":
parent = notesMap[note['note_pid']] parent = notes_map[note['note_pid']]
parent['children'].append(note) parent['children'].append(note)
parent['folder'] = True parent['folder'] = True
retObject = {} ret_object = {
retObject['notes'] = rootNotes 'notes': root_notes,
retObject['start_note_id'] = getSingleResult('select * from options where opt_name = "start_node"')['opt_value']; 'start_note_id': getSingleResult('select * from options where opt_name = "start_node"')['opt_value'],
retObject['password_verification_salt'] = getOption('password_verification_salt') 'password_verification_salt': get_option('password_verification_salt'),
retObject['password_derived_key_salt'] = getOption('password_derived_key_salt') 'password_derived_key_salt': get_option('password_derived_key_salt'),
retObject['encrypted_data_key'] = getOption('encrypted_data_key') 'encrypted_data_key': get_option('encrypted_data_key'),
retObject['encryption_session_timeout'] = getOption('encryption_session_timeout') 'encryption_session_timeout': get_option('encryption_session_timeout'),
retObject['browser_id'] = base64.b64encode(os.urandom(8)) 'browser_id': base64.b64encode(os.urandom(8)), 'full_load_time': utils.now_timestamp()
retObject['full_load_time'] = utils.nowTimestamp() }
return jsonify(retObject) return jsonify(ret_object)

View File

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import time import time
def nowTimestamp():
def now_timestamp():
return int(time.mktime(datetime.utcnow().timetuple())) return int(time.mktime(datetime.utcnow().timetuple()))