Add ability to change the key
This commit is contained in:
parent
0caf0efeef
commit
f778afd268
4 changed files with 50 additions and 4 deletions
|
|
@ -31,7 +31,6 @@ There is deliberately no network connectivity or syncing intended.
|
||||||
|
|
||||||
* Search
|
* Search
|
||||||
* Taxonomy/tagging
|
* Taxonomy/tagging
|
||||||
* Ability to change the SQLCipher key
|
|
||||||
* Export to other formats (plaintext, json, sql etc)
|
* Export to other formats (plaintext, json, sql etc)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,25 @@ class DBManager:
|
||||||
cur.execute("PRAGMA user_version = 1;")
|
cur.execute("PRAGMA user_version = 1;")
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
|
def rekey(self, new_key: str) -> None:
|
||||||
|
"""
|
||||||
|
Change the SQLCipher passphrase in-place, then reopen the connection
|
||||||
|
with the new key to verify.
|
||||||
|
"""
|
||||||
|
if self.conn is None:
|
||||||
|
raise RuntimeError("Database is not connected")
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
# Change the encryption key of the currently open database
|
||||||
|
cur.execute(f"PRAGMA rekey = '{new_key}';")
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
# Close and reopen with the new key to verify and restore PRAGMAs
|
||||||
|
self.conn.close()
|
||||||
|
self.conn = None
|
||||||
|
self.cfg.key = new_key
|
||||||
|
if not self.connect():
|
||||||
|
raise sqlite.Error("Re-open failed after rekey")
|
||||||
|
|
||||||
def get_entry(self, date_iso: str) -> str:
|
def get_entry(self, date_iso: str) -> str:
|
||||||
cur = self.conn.cursor()
|
cur = self.conn.cursor()
|
||||||
cur.execute("SELECT content FROM entries WHERE date = ?;", (date_iso,))
|
cur.execute("SELECT content FROM entries WHERE date = ?;", (date_iso,))
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ class MainWindow(QMainWindow):
|
||||||
self._save_date(self._current_date_iso(), explicit)
|
self._save_date(self._current_date_iso(), explicit)
|
||||||
|
|
||||||
def _open_settings(self):
|
def _open_settings(self):
|
||||||
dlg = SettingsDialog(self.cfg, self)
|
dlg = SettingsDialog(self.cfg, self.db, self)
|
||||||
if dlg.exec() == QDialog.Accepted:
|
if dlg.exec() == QDialog.Accepted:
|
||||||
new_cfg = dlg.config
|
new_cfg = dlg.config
|
||||||
if new_cfg.path != self.cfg.path:
|
if new_cfg.path != self.cfg.path:
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,20 @@ from PySide6.QtWidgets import (
|
||||||
QFileDialog,
|
QFileDialog,
|
||||||
QDialogButtonBox,
|
QDialogButtonBox,
|
||||||
QSizePolicy,
|
QSizePolicy,
|
||||||
|
QMessageBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .db import DBConfig
|
from .db import DBConfig, DBManager
|
||||||
from .settings import save_db_config
|
from .settings import save_db_config
|
||||||
|
from .key_prompt import KeyPrompt
|
||||||
|
|
||||||
|
|
||||||
class SettingsDialog(QDialog):
|
class SettingsDialog(QDialog):
|
||||||
def __init__(self, cfg: DBConfig, parent=None):
|
def __init__(self, cfg: DBConfig, db: DBManager, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setWindowTitle("Settings")
|
self.setWindowTitle("Settings")
|
||||||
self._cfg = DBConfig(path=cfg.path, key="")
|
self._cfg = DBConfig(path=cfg.path, key="")
|
||||||
|
self._db = db
|
||||||
|
|
||||||
form = QFormLayout()
|
form = QFormLayout()
|
||||||
form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
|
form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
|
||||||
|
|
@ -44,12 +47,17 @@ class SettingsDialog(QDialog):
|
||||||
h.setStretch(1, 0)
|
h.setStretch(1, 0)
|
||||||
form.addRow("Database path", path_row)
|
form.addRow("Database path", path_row)
|
||||||
|
|
||||||
|
# Change key button
|
||||||
|
self.rekey_btn = QPushButton("Change key")
|
||||||
|
self.rekey_btn.clicked.connect(self._change_key)
|
||||||
|
|
||||||
bb = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
|
bb = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel)
|
||||||
bb.accepted.connect(self._save)
|
bb.accepted.connect(self._save)
|
||||||
bb.rejected.connect(self.reject)
|
bb.rejected.connect(self.reject)
|
||||||
|
|
||||||
v = QVBoxLayout(self)
|
v = QVBoxLayout(self)
|
||||||
v.addLayout(form)
|
v.addLayout(form)
|
||||||
|
v.addWidget(self.rekey_btn)
|
||||||
v.addWidget(bb)
|
v.addWidget(bb)
|
||||||
|
|
||||||
def _browse(self):
|
def _browse(self):
|
||||||
|
|
@ -67,6 +75,26 @@ class SettingsDialog(QDialog):
|
||||||
save_db_config(self._cfg)
|
save_db_config(self._cfg)
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
def _change_key(self):
|
||||||
|
p1 = KeyPrompt(self, title="Change key", message="Enter new key")
|
||||||
|
if p1.exec() != QDialog.Accepted:
|
||||||
|
return
|
||||||
|
new_key = p1.key()
|
||||||
|
p2 = KeyPrompt(self, title="Change key", message="Re-enter new key")
|
||||||
|
if p2.exec() != QDialog.Accepted:
|
||||||
|
return
|
||||||
|
if new_key != p2.key():
|
||||||
|
QMessageBox.warning(self, "Key mismatch", "The two entries did not match.")
|
||||||
|
return
|
||||||
|
if not new_key:
|
||||||
|
QMessageBox.warning(self, "Empty key", "Key cannot be empty.")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self._db.rekey(new_key)
|
||||||
|
QMessageBox.information(self, "Key changed", "The database key was updated.")
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Error", f"Could not change key:\n{e}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def config(self) -> DBConfig:
|
def config(self) -> DBConfig:
|
||||||
return self._cfg
|
return self._cfg
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue