Safer handling of uploaded database files during full sync.

Before overwriting its version of a user's collection database file with one uploaded by the client, the server now performs a basic integrity check using SQLite's 'pragma integrity_check'.
This commit is contained in:
Christoph Mack 2015-10-08 21:41:04 +02:00 committed by flan
parent f3788fc2c8
commit 2cb5871ba3

View File

@ -31,6 +31,7 @@ import zipfile
import ankisyncd import ankisyncd
import anki import anki
from anki.db import DB
from anki.sync import Syncer, MediaSyncer from anki.sync import Syncer, MediaSyncer
from anki.utils import intTime, checksum, isMac from anki.utils import intTime, checksum, isMac
from anki.consts import SYNC_ZIP_SIZE, SYNC_ZIP_COUNT from anki.consts import SYNC_ZIP_SIZE, SYNC_ZIP_COUNT
@ -405,23 +406,31 @@ class SyncApp(object):
return data return data
def operation_upload(self, col, data, session): def operation_upload(self, col, data, session):
col.close() # Verify integrity of the received database file before replacing our
# existing db.
temp_db_path = session.get_collection_path() + ".tmp"
with open(temp_db_path, 'wb') as f:
f.write(data)
# TODO: we should verify the database integrity before perminantly overwriting
# (ie. use a temporary file) and declaring this a success!
#
# d = DB(path)
# assert d.scalar("pragma integrity_check") == "ok"
# d.close()
#
try: try:
with open(session.get_collection_path(), 'wb') as fd: test_db = DB(temp_db_path)
fd.write(data) if test_db.scalar("pragma integrity_check") != "ok":
raise HTTPBadRequest("Integrity check failed for uploaded "
"collection database file.")
test_db.close()
except sqlite.Error as e:
raise HTTPBadRequest("Uploaded collection database file is "
"corrupt.")
# Overwrite existing db.
col.close()
try:
os.rename(temp_db_path, session.get_collection_path())
finally: finally:
col.reopen() col.reopen()
col.load() col.load()
# run hook_upload if one is defined # If everything went fine, run hook_upload if one is defined.
if self.hook_upload is not None: if self.hook_upload is not None:
self.hook_upload(col, session) self.hook_upload(col, session)