add support to encrypt database

This commit is contained in:
2022-01-26 18:30:11 +08:00
parent 84f2cb1fea
commit ccb61741ee
6 changed files with 96 additions and 10 deletions

View File

@@ -1,7 +1,13 @@
from sqlite3 import connect
from getpass import getpass
from os import close
from os.path import join
from typing import List, Union
from shutil import move
from sqlite3 import connect, Connection, DatabaseError
from tempfile import mkstemp
from threading import Lock
from typing import List, Union
from game_backuper.cml import Opts
from game_backuper.config import Config
from game_backuper.file import File, hydrate_file_if_needed
from game_backuper.filetype import FileType
@@ -56,17 +62,64 @@ class Db:
self.db.execute(FILETYPE_TABLE)
self.db.commit()
def __init__(self, loc: str, optimize_db: bool = False):
fn = join(loc, "data.db")
def __init__(self, config: Config, opts: Opts):
self._cfg = config
self._opt = opts
fn = join(config.dest, "data.db")
hydrate_file_if_needed(fn)
self.db = connect(fn, check_same_thread=False)
if optimize_db:
if config.encrypt_db:
passpharse = getpass('Please input the password of the database:')
if not self.encrypted:
tfn = mkstemp()
close(tfn[0])
tfn = tfn[1]
db = connect(tfn)
self.__set_encrypt_key(passpharse, db)
for q in self.db.iterdump():
db.execute(q)
self.db.close()
db.close()
move(tfn, fn)
self.db = connect(fn, check_same_thread=False)
elif opts.change_key:
self.__set_encrypt_key(passpharse)
passpharse = getpass('Please input new password of the database:') # noqa: E501
tfn = mkstemp()
close(tfn[0])
tfn = tfn[1]
db = connect(tfn)
self.__set_encrypt_key(passpharse, db)
for q in self.db.iterdump():
db.execute(q)
self.db.close()
db.close()
move(tfn, fn)
self.db = connect(fn, check_same_thread=False)
self.__set_encrypt_key(passpharse)
else:
if self.encrypted:
passpharse = getpass('Please input the password of the database:') # noqa: E501
self.__set_encrypt_key(passpharse)
tfn = mkstemp()
close(tfn[0])
tfn = tfn[1]
db = connect(tfn)
for q in self.db.iterdump():
db.execute(q)
self.db.close()
db.close()
move(tfn, fn)
self.db = connect(fn, check_same_thread=False)
if opts.optimize_db:
self.db.execute('VACUUM;')
self.db.commit()
ok = self.__check_database()
if not ok:
self.__create_table()
self._lock = Lock()
if config.encrypt_db and not self.encrypted:
print('Warning: Current library do not support encryption.')
def __read_version(self) -> List[int]:
if 'version' not in self._exist_table:
@@ -75,6 +128,12 @@ class Db:
for i in cur:
return [k for k in i if isinstance(k, int)]
def __set_encrypt_key(self, key: str, db: Connection = None):
if db is None:
db = self.db
db.execute('PRAGMA cipher_salt = "x\'2d506b1d2c3e7b075518f9db81039657\'";') # noqa: E501
db.execute('PRAGMA key = \'%s\';' % (key.replace("'", "\\'")))
def __updateExistsTable(self):
cur = self.db.execute('SELECT * FROM main.sqlite_master;')
self._exist_table = {}
@@ -105,6 +164,17 @@ class Db:
(i[0], f.type))
self.db.commit()
@property
def encrypted(self):
try:
con = connect(join(self._cfg.dest, 'data.db'))
con.execute('SELECT count(*) FROM sqlite_master;')
con.close()
return False
except DatabaseError:
con.close()
return True
def get_file(self, prog: str, file: str) -> File:
with self._lock:
cur = self.db.execute(