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 | ||||
|  * Taxonomy/tagging | ||||
|  * Ability to change the SQLCipher key | ||||
|  * Export to other formats (plaintext, json, sql etc) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -64,6 +64,25 @@ class DBManager: | |||
|         cur.execute("PRAGMA user_version = 1;") | ||||
|         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: | ||||
|         cur = self.conn.cursor() | ||||
|         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) | ||||
| 
 | ||||
|     def _open_settings(self): | ||||
|         dlg = SettingsDialog(self.cfg, self) | ||||
|         dlg = SettingsDialog(self.cfg, self.db, self) | ||||
|         if dlg.exec() == QDialog.Accepted: | ||||
|             new_cfg = dlg.config | ||||
|             if new_cfg.path != self.cfg.path: | ||||
|  |  | |||
|  | @ -13,17 +13,20 @@ from PySide6.QtWidgets import ( | |||
|     QFileDialog, | ||||
|     QDialogButtonBox, | ||||
|     QSizePolicy, | ||||
|     QMessageBox, | ||||
| ) | ||||
| 
 | ||||
| from .db import DBConfig | ||||
| from .db import DBConfig, DBManager | ||||
| from .settings import save_db_config | ||||
| from .key_prompt import KeyPrompt | ||||
| 
 | ||||
| 
 | ||||
| class SettingsDialog(QDialog): | ||||
|     def __init__(self, cfg: DBConfig, parent=None): | ||||
|     def __init__(self, cfg: DBConfig, db: DBManager, parent=None): | ||||
|         super().__init__(parent) | ||||
|         self.setWindowTitle("Settings") | ||||
|         self._cfg = DBConfig(path=cfg.path, key="") | ||||
|         self._db = db | ||||
| 
 | ||||
|         form = QFormLayout() | ||||
|         form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) | ||||
|  | @ -44,12 +47,17 @@ class SettingsDialog(QDialog): | |||
|         h.setStretch(1, 0) | ||||
|         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.accepted.connect(self._save) | ||||
|         bb.rejected.connect(self.reject) | ||||
| 
 | ||||
|         v = QVBoxLayout(self) | ||||
|         v.addLayout(form) | ||||
|         v.addWidget(self.rekey_btn) | ||||
|         v.addWidget(bb) | ||||
| 
 | ||||
|     def _browse(self): | ||||
|  | @ -67,6 +75,26 @@ class SettingsDialog(QDialog): | |||
|         save_db_config(self._cfg) | ||||
|         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 | ||||
|     def config(self) -> DBConfig: | ||||
|         return self._cfg | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue