basic implementation of audit logging

This commit is contained in:
azivner 2017-09-28 23:16:36 -04:00
parent 47d296cf12
commit a9698d362f
9 changed files with 65 additions and 11 deletions

View File

@ -1,18 +1,15 @@
#!/usr/bin/python #!/usr/bin/python
import binascii
import getpass
import os
import base64 import base64
import getpass
import hashlib
import os
from Crypto.Cipher import AES
from Crypto.Util import Counter
from builtins import input from builtins import input
import src.config_provider
import src.sql
import src.my_scrypt import src.my_scrypt
from Crypto.Cipher import AES
from Crypto.Util import Counter
import hashlib
config = src.config_provider.getConfig() config = src.config_provider.getConfig()
src.sql.connect(config['Document']['documentPath']) src.sql.connect(config['Document']['documentPath'])

8
src/audit_category.py Normal file
View File

@ -0,0 +1,8 @@
UPDATE_CONTENT = 'CONTENT'
CHANGE_POSITION = 'POSITION'
CREATE_NOTE = 'CREATE'
DELETE_NOTE = 'DELETE'
CHANGE_PARENT = 'PARENT'
ENCRYPTION = 'ENCRYPTION'
CHANGE_PASSWORD = 'PASSWORD'
SETTINGS = 'SETTINGS'

View File

@ -5,9 +5,10 @@ from Crypto.Util import Counter
import sql import sql
import my_scrypt import my_scrypt
import audit_category
def change_password(current_password, new_password): 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.getVerificationHash(current_password))
if current_password_hash != sql.getOption('password_verification_hash'): if current_password_hash != sql.getOption('password_verification_hash'):
@ -49,6 +50,8 @@ def change_password(current_password, new_password):
sql.setOption('password_verification_hash', new_password_verification_key) sql.setOption('password_verification_hash', new_password_verification_key)
sql.addAudit(audit_category.CHANGE_PASSWORD, request)
sql.commit() sql.commit()
return { return {

View File

@ -10,7 +10,9 @@ from flask_login import login_required
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 from sql import getResults, getSingleResult, getOption, addAudit
import audit_category
notes_api = Blueprint('notes_api', __name__) notes_api = Blueprint('notes_api', __name__)
@ -66,6 +68,9 @@ def updateNote(note_id):
now now
]) ])
if note['detail']['encryption'] != detail['encryption']:
addAudit(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'],
note['detail']['note_text'], note['detail']['note_text'],
@ -105,6 +110,8 @@ def deleteNote(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)
commit() commit()
return jsonify({}) return jsonify({})
@ -137,6 +144,8 @@ 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)
now = math.floor(time.time()) now = math.floor(time.time())
insert("notes", { insert("notes", {

View File

@ -1,7 +1,9 @@
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
from flask import request
from flask_login import login_required from flask_login import login_required
from sql import execute, commit import audit_category
from sql import execute, commit, addAudit
from sql import getSingleResult from sql import getSingleResult
notes_move_api = Blueprint('notes_move_api', __name__) notes_move_api = Blueprint('notes_move_api', __name__)
@ -20,6 +22,8 @@ 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)
commit() commit()
return jsonify({}) return jsonify({})
@ -32,6 +36,8 @@ 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)
commit() commit()
return jsonify({}) return jsonify({})
@ -45,6 +51,8 @@ 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)
commit() commit()
return jsonify({}) return jsonify({})
@ -53,5 +61,7 @@ def moveAfterNote(note_id, after_note_id):
def setExpandedNote(note_id, expanded): def setExpandedNote(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
commit() commit()
return jsonify({}) return jsonify({})

View File

@ -2,6 +2,7 @@ from flask import Blueprint, jsonify, request
from flask_login import login_required from flask_login import login_required
import sql import sql
import audit_category
settings_api = Blueprint('settings_api', __name__) settings_api = Blueprint('settings_api', __name__)
@ -25,7 +26,10 @@ 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.setOption(req['name'], req['value']) sql.setOption(req['name'], req['value'])
sql.commit() sql.commit()
return jsonify({}) return jsonify({})

View File

@ -1,6 +1,9 @@
import base64 import base64
import sqlite3 import sqlite3
import math
import time
conn = None conn = None
def dict_factory(cursor, row): def dict_factory(cursor, row):
@ -32,6 +35,17 @@ def setOption(name, value):
def getOption(name): def getOption(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 = math.floor(time.time())
browser_id = None
if request:
browser_id = request.headers['x-browser-id']
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])
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])

View File

@ -1,3 +1,6 @@
import base64
import os
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
from flask_login import login_required from flask_login import login_required
@ -44,5 +47,6 @@ def getTree():
retObject['password_derived_key_salt'] = getOption('password_derived_key_salt') retObject['password_derived_key_salt'] = getOption('password_derived_key_salt')
retObject['encrypted_data_key'] = getOption('encrypted_data_key') retObject['encrypted_data_key'] = getOption('encrypted_data_key')
retObject['encryption_session_timeout'] = getOption('encryption_session_timeout') retObject['encryption_session_timeout'] = getOption('encryption_session_timeout')
retObject['browser_id'] = base64.b64encode(os.urandom(8))
return jsonify(retObject) return jsonify(retObject)

View File

@ -95,6 +95,11 @@ $(function(){
globalEncryptionSessionTimeout = resp.encryption_session_timeout; globalEncryptionSessionTimeout = resp.encryption_session_timeout;
globalEncryptedDataKey = resp.encrypted_data_key; globalEncryptedDataKey = resp.encrypted_data_key;
// add browser ID header to all AJAX requests
$.ajaxSetup({
headers: { 'x-browser-id': resp.browser_id }
});
if (document.location.hash) { if (document.location.hash) {
startNoteId = document.location.hash.substr(1); // strip initial # startNoteId = document.location.hash.substr(1); // strip initial #
} }