dev: 支持加密数据
This commit is contained in:
@@ -71,12 +71,11 @@ class DaEntryInfo(QtWidgets.QDialog):
|
||||
def __init__(
|
||||
self,
|
||||
entry_id: int,
|
||||
config: dict,
|
||||
sqh: Sqlite3Worker,
|
||||
parent: QtWidgets.QWidget = None
|
||||
):
|
||||
super().__init__(parent)
|
||||
_, results = sqh.select(config["table_name"], all_columns,
|
||||
_, results = sqh.select("entries", all_columns,
|
||||
where=Operand(entry_id_col).equal_to(entry_id))
|
||||
|
||||
entry = results[0]
|
||||
@@ -88,5 +87,3 @@ class DaEntryInfo(QtWidgets.QDialog):
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(640, 360)
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# coding: utf8
|
||||
from PySide6 import QtWidgets, QtCore, QtGui
|
||||
from pykeepass import PyKeePass
|
||||
from pykeepass.exceptions import HeaderChecksumError, CredentialsError
|
||||
|
||||
|
||||
class DaTargetLogin(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("目标文件")
|
||||
class UiDaTargetLogin(object):
|
||||
def __init__(self, window: QtWidgets.QWidget):
|
||||
window.setWindowTitle("目标文件")
|
||||
self.vly_m = QtWidgets.QVBoxLayout()
|
||||
self.setLayout(self.vly_m)
|
||||
window.setLayout(self.vly_m)
|
||||
|
||||
icon_ellipsis = QtGui.QIcon(":/asset/img/ellipsis.svg")
|
||||
self.icon_eye = QtGui.QIcon(":/asset/img/eye.svg")
|
||||
@@ -15,61 +16,77 @@ class DaTargetLogin(QtWidgets.QDialog):
|
||||
|
||||
self.hly_path = QtWidgets.QHBoxLayout()
|
||||
self.vly_m.addLayout(self.hly_path)
|
||||
self.lb_path = QtWidgets.QLabel("路径:", self)
|
||||
self.lne_path = QtWidgets.QLineEdit(self)
|
||||
self.pbn_browse = QtWidgets.QPushButton(icon=icon_ellipsis, parent=self)
|
||||
self.lb_path = QtWidgets.QLabel("路径:", window)
|
||||
self.lne_path = QtWidgets.QLineEdit(window)
|
||||
self.pbn_browse = QtWidgets.QPushButton(icon=icon_ellipsis, parent=window)
|
||||
self.hly_path.addWidget(self.lb_path)
|
||||
self.hly_path.addWidget(self.lne_path)
|
||||
self.hly_path.addWidget(self.pbn_browse)
|
||||
|
||||
self.hly_password = QtWidgets.QHBoxLayout()
|
||||
self.vly_m.addLayout(self.hly_password)
|
||||
self.lb_password = QtWidgets.QLabel("密码:", self)
|
||||
self.lne_password = QtWidgets.QLineEdit(self)
|
||||
self.lb_password = QtWidgets.QLabel("密码:", window)
|
||||
self.lne_password = QtWidgets.QLineEdit(window)
|
||||
self.lne_password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
||||
self.pbn_eye = QtWidgets.QPushButton(icon=self.icon_eye_off, parent=self)
|
||||
self.pbn_eye = QtWidgets.QPushButton(icon=self.icon_eye_off, parent=window)
|
||||
self.hly_password.addWidget(self.lb_password)
|
||||
self.hly_password.addWidget(self.lne_password)
|
||||
self.hly_password.addWidget(self.pbn_eye)
|
||||
|
||||
self.hly_bottom = QtWidgets.QHBoxLayout()
|
||||
self.vly_m.addLayout(self.hly_bottom)
|
||||
self.pbn_ok = QtWidgets.QPushButton("确定", self)
|
||||
self.pbn_cancel = QtWidgets.QPushButton("取消", self)
|
||||
self.pbn_ok = QtWidgets.QPushButton("确定", window)
|
||||
self.pbn_cancel = QtWidgets.QPushButton("取消", window)
|
||||
self.hly_bottom.addStretch(1)
|
||||
self.hly_bottom.addWidget(self.pbn_ok)
|
||||
self.hly_bottom.addWidget(self.pbn_cancel)
|
||||
|
||||
self.vly_m.addStretch(1)
|
||||
|
||||
self.pbn_browse.clicked.connect(self.on_pbn_browse_clicked)
|
||||
self.pbn_eye.clicked.connect(self.on_pbn_eye_clicked)
|
||||
self.pbn_ok.clicked.connect(self.on_pbn_ok_clicked)
|
||||
self.pbn_cancel.clicked.connect(self.on_pbn_cancel_clicked)
|
||||
self.pbn_ok.setFocus()
|
||||
|
||||
|
||||
class DaTargetLogin(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.ui = UiDaTargetLogin(self)
|
||||
self.tar_kp: PyKeePass | None = None
|
||||
|
||||
self.ui.pbn_browse.clicked.connect(self.on_pbn_browse_clicked)
|
||||
self.ui.pbn_eye.clicked.connect(self.on_pbn_eye_clicked)
|
||||
self.ui.pbn_ok.clicked.connect(self.on_pbn_ok_clicked)
|
||||
self.ui.pbn_cancel.clicked.connect(self.on_pbn_cancel_clicked)
|
||||
|
||||
def on_pbn_browse_clicked(self):
|
||||
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择", "../",
|
||||
filter="KeePass 2 数据库 (*.kdbx);;所有文件 (*)")
|
||||
if len(filename) == 0:
|
||||
return
|
||||
self.lne_path.setText(filename)
|
||||
self.ui.lne_path.setText(filename)
|
||||
|
||||
def on_pbn_eye_clicked(self):
|
||||
if self.lne_password.echoMode() == QtWidgets.QLineEdit.EchoMode.Password:
|
||||
self.lne_password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal)
|
||||
self.pbn_eye.setIcon(self.icon_eye)
|
||||
if self.ui.lne_password.echoMode() == QtWidgets.QLineEdit.EchoMode.Password:
|
||||
self.ui.lne_password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal)
|
||||
self.ui.pbn_eye.setIcon(self.ui.icon_eye)
|
||||
else:
|
||||
self.lne_password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
||||
self.pbn_eye.setIcon(self.icon_eye_off)
|
||||
self.ui.lne_password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
||||
self.ui.pbn_eye.setIcon(self.ui.icon_eye_off)
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(540, 40)
|
||||
|
||||
def on_pbn_ok_clicked(self):
|
||||
try:
|
||||
self.tar_kp = PyKeePass(self.ui.lne_path.text(), self.ui.lne_password.text())
|
||||
except CredentialsError:
|
||||
QtWidgets.QMessageBox.critical(self, "错误", "keepass 密码错误")
|
||||
return
|
||||
except (FileNotFoundError, HeaderChecksumError):
|
||||
QtWidgets.QMessageBox.critical(self, "错误", "文件不存在或不是 keepass 文件")
|
||||
return
|
||||
|
||||
self.accept()
|
||||
|
||||
def on_pbn_cancel_clicked(self):
|
||||
self.tar_kp = None
|
||||
self.reject()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class GbxKpsLogin(QtWidgets.QGroupBox):
|
||||
kp = read_kps_to_db(
|
||||
kps_file=self.lne_path.text(),
|
||||
password=self.lne_password.text(),
|
||||
table_name=self.config["table_name"],
|
||||
table_name="entries",
|
||||
sqh=self.sqh
|
||||
)
|
||||
except CredentialsError:
|
||||
|
||||
@@ -10,7 +10,7 @@ from .cmbx_styles import StyleComboBox
|
||||
from lib.Sqlite3Helper import Sqlite3Worker
|
||||
from lib.db_columns_def import all_columns
|
||||
from lib.sec_db_columns_def import sec_all_columns
|
||||
from lib.config_utils import write_config
|
||||
from lib.config_utils import write_config, get_or_generate_key
|
||||
|
||||
|
||||
class UiKpsUnifier(object):
|
||||
@@ -78,10 +78,15 @@ class KpsUnifier(QtWidgets.QMainWindow):
|
||||
db_path: str,
|
||||
secrets_path: str,
|
||||
config: dict,
|
||||
org_name: str,
|
||||
app_name: str,
|
||||
version: str,
|
||||
parent: QtWidgets.QWidget = None,
|
||||
):
|
||||
super().__init__(parent)
|
||||
self.org_name = org_name
|
||||
self.app_name = app_name
|
||||
|
||||
self.db_path = db_path
|
||||
self.secrets_path = secrets_path
|
||||
self.config = config
|
||||
@@ -103,18 +108,23 @@ class KpsUnifier(QtWidgets.QMainWindow):
|
||||
|
||||
def __del__(self):
|
||||
self.config["last_db_path"] = self.db_path
|
||||
write_config(self.config,
|
||||
QtWidgets.QApplication.organizationName(),
|
||||
QtWidgets.QApplication.applicationName())
|
||||
write_config(self.config, self.org_name, self.app_name)
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(860, 640)
|
||||
|
||||
def init_db(self) -> Sqlite3Worker:
|
||||
sqh = Sqlite3Worker(self.db_path)
|
||||
sqh.create_table(self.config["table_name"], all_columns, if_not_exists=True)
|
||||
key = get_or_generate_key(self.db_path, self.org_name, self.app_name)
|
||||
sqh = Sqlite3Worker(self.db_path, key)
|
||||
sqh.create_table("entries", all_columns, if_not_exists=True)
|
||||
return sqh
|
||||
|
||||
def init_secrets_db(self) -> Sqlite3Worker:
|
||||
key = get_or_generate_key(self.secrets_path, self.org_name, self.app_name)
|
||||
sec_sqh = Sqlite3Worker(self.secrets_path, key)
|
||||
sec_sqh.create_table("secrets", sec_all_columns, if_not_exists=True)
|
||||
return sec_sqh
|
||||
|
||||
def update_db(self, filename: str):
|
||||
self.db_path = filename
|
||||
self.sqh = self.init_db()
|
||||
@@ -153,8 +163,3 @@ class KpsUnifier(QtWidgets.QMainWindow):
|
||||
|
||||
def on_act_about_qt_triggered(self):
|
||||
QtWidgets.QMessageBox.aboutQt(self, "关于 Qt")
|
||||
|
||||
def init_secrets_db(self) -> Sqlite3Worker:
|
||||
sec_sqh = Sqlite3Worker(self.secrets_path)
|
||||
sec_sqh.create_table("secrets", sec_all_columns, if_not_exists=True)
|
||||
return sec_sqh
|
||||
|
||||
@@ -5,7 +5,8 @@ from PySide6 import QtWidgets
|
||||
from pykeepass import PyKeePass
|
||||
|
||||
from .gbx_kps_login import GbxKpsLogin
|
||||
from .utils import accept_warning
|
||||
from .da_target_login import DaTargetLogin
|
||||
from .utils import accept_warning, HorizontalLine
|
||||
from lib.Sqlite3Helper import Sqlite3Worker
|
||||
|
||||
|
||||
@@ -81,6 +82,15 @@ class PageLoad(QtWidgets.QWidget):
|
||||
self.vly_left = QtWidgets.QVBoxLayout()
|
||||
self.hly_m.addLayout(self.vly_left)
|
||||
|
||||
self.pbn_set_target = QtWidgets.QPushButton("设置目标文件", self)
|
||||
# 暂时没用
|
||||
self.pbn_set_target.setDisabled(True)
|
||||
self.pbn_set_target.setMinimumWidth(config["button_min_width"])
|
||||
self.vly_left.addWidget(self.pbn_set_target)
|
||||
|
||||
self.hln_1 = HorizontalLine(self)
|
||||
self.vly_left.addWidget(self.hln_1)
|
||||
|
||||
self.pbn_add_kps = QtWidgets.QPushButton("添加 KPS", self)
|
||||
self.pbn_add_kps.setMinimumWidth(config["button_min_width"])
|
||||
self.vly_left.addWidget(self.pbn_add_kps)
|
||||
@@ -101,6 +111,8 @@ class PageLoad(QtWidgets.QWidget):
|
||||
self.wg_sa = WgLoadKps(config, file_kp, sqh, sec_sqh, self.sa_m)
|
||||
self.sa_m.setWidget(self.wg_sa)
|
||||
|
||||
self.pbn_set_target.clicked.connect(self.on_pbn_set_target_clicked)
|
||||
|
||||
self.pbn_add_kps.clicked.connect(self.on_pbn_add_kps_clicked)
|
||||
self.pbn_clear_db.clicked.connect(self.on_pbn_clear_db_clicked)
|
||||
self.pbn_clear_loaded_mem.clicked.connect(self.on_pbn_clear_loaded_mem_clicked)
|
||||
@@ -121,7 +133,7 @@ class PageLoad(QtWidgets.QWidget):
|
||||
return
|
||||
|
||||
try:
|
||||
self.sqh.delete_from(self.config["table_name"])
|
||||
self.sqh.delete_from("entries")
|
||||
except sqlite3.OperationalError as e:
|
||||
QtWidgets.QMessageBox.critical(self, "错误", f"清空数据库失败:\n{e}")
|
||||
else:
|
||||
@@ -148,3 +160,7 @@ class PageLoad(QtWidgets.QWidget):
|
||||
# 更新kps加载状态
|
||||
for wg in self.wg_sa.kps_wgs:
|
||||
self.wg_sa.update_load_status(wg)
|
||||
|
||||
def on_pbn_set_target_clicked(self):
|
||||
da_target_login = DaTargetLogin(self)
|
||||
da_target_login.exec()
|
||||
|
||||
@@ -5,7 +5,6 @@ from PySide6 import QtWidgets, QtCore, QtGui
|
||||
from pykeepass import PyKeePass
|
||||
|
||||
from .da_entry_info import DaEntryInfo
|
||||
from .da_target_login import DaTargetLogin
|
||||
from .utils import HorizontalLine, get_filepath_uuids_map, accept_warning
|
||||
from lib.Sqlite3Helper import Sqlite3Worker, Expression, Operand
|
||||
from lib.db_columns_def import (
|
||||
@@ -18,7 +17,7 @@ from lib.kps_operations import blob_fy
|
||||
|
||||
class QueryTableModel(QtCore.QAbstractTableModel):
|
||||
|
||||
def __init__(self, query_results: list[tuple], parent=None):
|
||||
def __init__(self, query_results: list[list], parent=None):
|
||||
super().__init__(parent)
|
||||
self.query_results = query_results
|
||||
self.headers = ["序号", "标题", "用户名", "URL"]
|
||||
@@ -98,10 +97,6 @@ class UiPageQuery(object):
|
||||
self.pbn_execute.setMinimumWidth(config["button_min_width"])
|
||||
self.vly_sa_wg.addWidget(self.pbn_execute)
|
||||
|
||||
self.pbn_set_target = QtWidgets.QPushButton("目标文件", window)
|
||||
self.pbn_set_target.setMinimumWidth(config["button_min_width"])
|
||||
self.vly_sa_wg.addWidget(self.pbn_set_target)
|
||||
|
||||
self.hln_1 = HorizontalLine(window)
|
||||
self.vly_sa_wg.addWidget(self.hln_1)
|
||||
|
||||
@@ -147,7 +142,6 @@ class PageQuery(QtWidgets.QWidget):
|
||||
self.ui.act_delete.triggered_with_str.connect(self.on_act_mark_triggered_with_str)
|
||||
|
||||
self.ui.pbn_execute.clicked.connect(self.on_pbn_execute_clicked)
|
||||
self.ui.pbn_set_target.clicked.connect(self.on_pbn_set_target_clicked)
|
||||
|
||||
self.ui.pbn_all.clicked.connect(self.on_pbn_all_clicked)
|
||||
self.ui.pbn_deleted.clicked.connect(self.on_pbn_deleted_clicked)
|
||||
@@ -169,7 +163,7 @@ class PageQuery(QtWidgets.QWidget):
|
||||
},
|
||||
{
|
||||
"name": "谷歌文档",
|
||||
"where": "url LIKE 'https://docs.google.com/%' or url LIKE 'https://drive.google.com/%'"
|
||||
"where": "(url LIKE 'https://docs.google.com/%' OR url LIKE 'https://drive.google.com/%')"
|
||||
},
|
||||
]
|
||||
for fil in default_filters:
|
||||
@@ -193,7 +187,7 @@ class PageQuery(QtWidgets.QWidget):
|
||||
self.set_filter_button(fil)
|
||||
|
||||
def on_custom_filters_clicked_with_data(self, data: dict):
|
||||
_, results = self.sqh.select(self.config["table_name"], query_columns,
|
||||
_, results = self.sqh.select("entries", query_columns,
|
||||
where=Expression(data["where"]).and_(Operand(deleted_col).equal_to(0)))
|
||||
model = QueryTableModel(results, self)
|
||||
self.ui.trv_m.setModel(model)
|
||||
@@ -202,20 +196,20 @@ class PageQuery(QtWidgets.QWidget):
|
||||
self.sqh = sqh
|
||||
|
||||
def on_pbn_all_clicked(self):
|
||||
_, results = self.sqh.select(self.config["table_name"], query_columns,
|
||||
_, results = self.sqh.select("entries", query_columns,
|
||||
where=Operand(deleted_col).equal_to(0))
|
||||
model = QueryTableModel(results, self)
|
||||
self.ui.trv_m.setModel(model)
|
||||
|
||||
def on_pbn_deleted_clicked(self):
|
||||
_, results = self.sqh.select(self.config["table_name"], query_columns,
|
||||
_, results = self.sqh.select("entries", query_columns,
|
||||
where=Operand(deleted_col).equal_to(1))
|
||||
model = QueryTableModel(results, self)
|
||||
self.ui.trv_m.setModel(model)
|
||||
|
||||
def on_trv_m_double_clicked(self, index: QtCore.QModelIndex):
|
||||
entry_id = index.siblingAtColumn(0).data(QtCore.Qt.ItemDataRole.DisplayRole)
|
||||
da_entry_info = DaEntryInfo(entry_id, self.config, self.sqh, self)
|
||||
da_entry_info = DaEntryInfo(entry_id, self.sqh, self)
|
||||
da_entry_info.exec()
|
||||
|
||||
def on_trv_m_custom_context_menu_requested(self, pos: QtCore.QPoint):
|
||||
@@ -228,7 +222,7 @@ class PageQuery(QtWidgets.QWidget):
|
||||
for index in indexes if index.column() == 0
|
||||
]
|
||||
|
||||
self.sqh.update(self.config["table_name"], [(status_col, info)],
|
||||
self.sqh.update("entries", [(status_col, info)],
|
||||
where=Operand(entry_id_col).in_(entry_ids))
|
||||
|
||||
def on_pbn_execute_clicked(self):
|
||||
@@ -236,7 +230,7 @@ class PageQuery(QtWidgets.QWidget):
|
||||
return
|
||||
|
||||
# 删除功能
|
||||
_, results = self.sqh.select(self.config["table_name"], sim_columns,
|
||||
_, results = self.sqh.select("entries", sim_columns,
|
||||
where=Operand(status_col).equal_to("delete"))
|
||||
file_uuids = get_filepath_uuids_map(results)
|
||||
|
||||
@@ -252,7 +246,7 @@ class PageQuery(QtWidgets.QWidget):
|
||||
|
||||
for u in file_uuids[file]:
|
||||
total += 1
|
||||
self.sqh.update(self.config["table_name"], [(deleted_col, 1)],
|
||||
self.sqh.update("entries", [(deleted_col, 1)],
|
||||
where=Operand(uuid_col).equal_to(u).and_(
|
||||
Operand(filepath_col).equal_to(blob_fy(file))))
|
||||
|
||||
@@ -269,10 +263,6 @@ class PageQuery(QtWidgets.QWidget):
|
||||
QtWidgets.QMessageBox.information(self, "提示",
|
||||
f"共 {total} 条标记的条目,已删除 {success} 条,无效 {invalid} 条。")
|
||||
|
||||
def on_pbn_set_target_clicked(self):
|
||||
da_target_login = DaTargetLogin(self)
|
||||
da_target_login.exec()
|
||||
|
||||
|
||||
class PushButtonWithData(QtWidgets.QPushButton):
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# coding: utf8
|
||||
from itertools import combinations
|
||||
from uuid import UUID
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from PySide6.QtCore import QAbstractTableModel
|
||||
|
||||
@@ -70,7 +69,7 @@ class PageSimilar(QtWidgets.QWidget):
|
||||
self.pbn_delete_invalid_data.clicked.connect(self.on_pbn_delete_invalid_data_clicked)
|
||||
|
||||
def on_pbn_read_db_clicked(self):
|
||||
_, results = self.sqh.select(self.config["table_name"], sim_columns)
|
||||
_, results = self.sqh.select("entries", sim_columns)
|
||||
file_uuids = get_filepath_uuids_map(results)
|
||||
|
||||
files = file_uuids.keys()
|
||||
@@ -98,11 +97,11 @@ class PageSimilar(QtWidgets.QWidget):
|
||||
if accept_warning(self, True, "警告", "你确定要从数据库删除无效文件的记录吗?"):
|
||||
return
|
||||
|
||||
_, filepaths = self.sqh.select(self.config["table_name"], [filepath_col,])
|
||||
_, filepaths = self.sqh.select("entries", [filepath_col,])
|
||||
unique_filepaths = set([p[0].decode("utf8") for p in filepaths])
|
||||
invalid_filepaths = [p for p in unique_filepaths if path_not_exist(p)]
|
||||
for path in invalid_filepaths:
|
||||
self.sqh.delete_from(self.config["table_name"],
|
||||
self.sqh.delete_from("entries",
|
||||
where=Operand(filepath_col).equal_to(blob_fy(path)),
|
||||
commit=False)
|
||||
self.sqh.commit()
|
||||
|
||||
@@ -19,7 +19,7 @@ class HorizontalLine(QtWidgets.QFrame):
|
||||
self.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
|
||||
|
||||
|
||||
def get_filepath_uuids_map(query_results: list[tuple]) -> dict[str, list[str]]:
|
||||
def get_filepath_uuids_map(query_results: list[list]) -> dict[str, list[str]]:
|
||||
file_uuids: dict[str, list[str]] = {}
|
||||
for u, filepath in query_results:
|
||||
filepath = filepath.decode("utf8")
|
||||
|
||||
Reference in New Issue
Block a user