-
Notifications
You must be signed in to change notification settings - Fork 1
从分支添加密码功能 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
从分支添加密码功能 #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,6 +16,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| - 📥 **导入/导出**:支持 Chrome、Firefox、HTML 和 JSON 格式 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 🎲 **盲盒功能**:随机书签发现功能 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 📚 **历史记录**:跟踪访问过的书签 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 🔒 **密码保护**:使用密码验证保护您的书签安全 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 🔒 **编辑锁定模式**:防止意外修改 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 🌍 **多语言支持**:支持中文、英文、日文、德文、法文、韩文和西班牙文 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 💾 **自动备份**:自动数据备份和恢复 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -60,12 +61,17 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 基本操作 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. 添加书签 :点击"添加"按钮或从浏览器拖拽 URL | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. 创建文件夹 :在侧边栏右键点击创建新文件夹 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. 搜索 :使用 Ctrl+F 或点击搜索图标 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4. 导入/导出 :通过文件菜单访问 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 5. 开魔盒:也叫开盲盒,通过点击右上角的圆形魔盒按钮打开。可直接选择数字(1-5)或输入数字(>5)随机浏览。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 详细说明请参阅 用户指南 。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. **添加书签**:点击"添加"按钮或从浏览器拖拽 URL | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. **创建文件夹**:在侧边栏右键点击创建新文件夹 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. **搜索**:使用 Ctrl+F 或点击搜索图标 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4. **导入/导出**:通过文件菜单访问 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 5. **密码保护**:在设置 → 密码设置中配置密码保护 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 启用密码保护并设置密码 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 配置密保问题用于密码恢复 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 下次启动时将需要输入密码 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 6. **开魔盒**:也叫开盲盒,通过点击右上角的圆形魔盒按钮打开。可直接选择数字(1-5)或输入数字(>5)随机浏览。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
63
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding a space after the colon in each list item for better readability.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 详细说明请参阅 用户指南。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## 🛠️ 开发 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -108,7 +114,7 @@ url-navigator/ | |||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 下载体验版 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| [URL Navigator单EXE体验版](https://github.com/yihufree/URL-Navigator/releases/download/V0.60/URLNav_20250611.zip) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [URL Navigator单EXE体验版](https://github.com/yihufree/URL-Navigator/releases/download/V0.51/URLNav_20250611v0.51.zip) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## 🌐 国际化 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: utf-8 -*- | ||
|
|
||
| import os | ||
| import sys | ||
| import shutil | ||
| import subprocess | ||
| import platform | ||
| import datetime | ||
|
|
||
| def build_exe(): | ||
| """构建EXE文件""" | ||
| print("开始构建EXE文件...") | ||
|
|
||
| # 清理旧的构建文件 | ||
| if os.path.exists("build"): | ||
| shutil.rmtree("build") | ||
| if os.path.exists("dist"): | ||
| shutil.rmtree("dist") | ||
|
|
||
| # 确保资源文件夹存在 | ||
| if not os.path.exists("resources"): | ||
| print("错误: 资源文件夹不存在!") | ||
| return | ||
|
|
||
| # 获取版本日期 | ||
| version_date = datetime.datetime.now().strftime("%Y%m%d") | ||
| output_filename = f"URLNav_{version_date}" | ||
|
|
||
| # 构建命令 | ||
| cmd = [ | ||
| "pyinstaller", | ||
| f"--name={output_filename}", | ||
| "--windowed", # 无控制台窗口 | ||
| "--onefile", # 单个EXE文件 | ||
| "--clean", # 清理临时文件 | ||
| "--icon=resources/icons/app_icon.ico", # 应用图标 | ||
| "--add-data=resources;resources", # 添加整个资源目录 | ||
| "--add-data=languages;languages", # 添加语言文件目录 | ||
| "--noconfirm", # 不显示确认对话框 | ||
| "main.py" # 主程序入口 | ||
| ] | ||
|
|
||
| # 根据操作系统调整路径分隔符 | ||
| if platform.system() != "Windows": | ||
| # 对于Unix系统使用冒号分隔符 | ||
| for i in range(len(cmd)): | ||
| if "--add-data=" in cmd[i]: | ||
| cmd[i] = cmd[i].replace(";", ":") | ||
|
|
||
| print(f"运行命令: {' '.join(cmd)}") | ||
|
|
||
| # 执行构建 | ||
| try: | ||
| subprocess.call(cmd, shell=False) # 明确禁用shell以防止命令注入 | ||
|
|
||
| # 检查是否成功创建EXE文件 | ||
| exe_path = os.path.join("dist", f"{output_filename}.exe") | ||
| if os.path.exists(exe_path): | ||
| print(f"构建成功!EXE文件大小: {os.path.getsize(exe_path) / (1024*1024):.2f} MB") | ||
| print(f"EXE文件位置: {os.path.abspath(exe_path)}") | ||
| else: | ||
| print("构建似乎完成,但找不到EXE文件") | ||
|
|
||
| except Exception as e: | ||
| print(f"构建过程中出错: {e}") | ||
| return | ||
|
|
||
| def resource_path(relative_path): | ||
| """获取资源文件的绝对路径,兼容开发环境和打包后环境""" | ||
| if hasattr(sys, '_MEIPASS'): | ||
| return os.path.join(sys._MEIPASS, relative_path) | ||
| return os.path.join(os.path.abspath("."), relative_path) | ||
|
|
||
| if __name__ == "__main__": | ||
| build_exe() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| 检查密码设置状态 | ||
| """ | ||
|
|
||
| from PyQt5.QtCore import QSettings | ||
|
|
||
| def main(): | ||
| settings = QSettings("URL Navigator", "URL Navigator") | ||
|
|
||
| # 检查各项设置 | ||
| password_enabled = settings.value("security/password_enabled", False) | ||
| password_hash = settings.value("security/password_hash", "") | ||
| password_salt = settings.value("security/password_salt", "") | ||
| security_question = settings.value("security/security_question", "") | ||
|
|
||
| print(f"密码保护启用: {password_enabled}") | ||
| print(f"密码哈希: {'存在' if password_hash else '不存在'}") | ||
| print(f"密码盐值: {'存在' if password_salt else '不存在'}") | ||
| print(f"密保问题: {security_question if security_question else '未设置'}") | ||
|
|
||
| # 如果启用了密码保护但没有密码数据,说明有问题 | ||
| if password_enabled and (not password_hash or not password_salt): | ||
| print("\n问题: 密码保护已启用但密码数据缺失!") | ||
| print("建议: 运行 reset_password_protection.py 重置设置") | ||
| elif password_enabled: | ||
| print("\n状态: 密码保护正常") | ||
| else: | ||
| print("\n状态: 密码保护未启用") | ||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| #!/usr/bin/env python3 | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| URLNav 密码问题快速修复工具 | ||
|
|
||
| 这个工具用于解决首次启动时要求输入密码但不知道密码的问题。 | ||
| """ | ||
|
|
||
| import sys | ||
| import os | ||
| from PyQt5.QtCore import QSettings | ||
| from PyQt5.QtWidgets import QApplication, QMessageBox | ||
|
|
||
| def clear_all_password_settings(): | ||
| """清除所有密码相关设置""" | ||
| try: | ||
| # 尝试不同的组织名和应用名组合 | ||
| settings_combinations = [ | ||
| ("URL Navigator", "URL Navigator"), | ||
| ("URLNav", "URLNav"), | ||
| ("", "URLNav"), | ||
| ("", "URL Navigator") | ||
| ] | ||
|
|
||
| cleared_any = False | ||
|
|
||
| for org, app in settings_combinations: | ||
| settings = QSettings(org, app) | ||
|
|
||
| # 检查是否有密码相关设置 | ||
| keys_to_check = [ | ||
| "security/password_enabled", | ||
| "security/password_hash", | ||
| "security/password_salt", | ||
| "security/security_question", | ||
| "security/security_answer_hash", | ||
| "security/security_answer_salt" | ||
| ] | ||
|
|
||
| has_settings = any(settings.contains(key) for key in keys_to_check) | ||
|
|
||
| if has_settings: | ||
| print(f"发现密码设置在: 组织='{org}', 应用='{app}'") | ||
|
|
||
| # 清除所有密码相关设置 | ||
| for key in keys_to_check: | ||
| if settings.contains(key): | ||
| settings.remove(key) | ||
| print(f" 已清除: {key}") | ||
|
|
||
| settings.sync() | ||
| cleared_any = True | ||
|
|
||
| return cleared_any | ||
|
|
||
| except Exception as e: | ||
| print(f"清除设置时出错: {e}") | ||
| return False | ||
|
|
||
| def main(): | ||
| print("URLNav 密码问题快速修复工具") | ||
| print("=" * 40) | ||
|
|
||
| # 创建临时应用(不显示界面) | ||
| app = QApplication(sys.argv) if not QApplication.instance() else QApplication.instance() | ||
|
|
||
| print("正在检查和清除密码设置...") | ||
|
|
||
| if clear_all_password_settings(): | ||
| print("\n✅ 已成功清除所有密码设置") | ||
| print("\n现在您可以正常启动 URLNav 应用程序了。") | ||
| print("如果需要重新设置密码保护,请在应用程序的设置中进行配置。") | ||
| else: | ||
| print("\n❓ 未找到任何密码设置") | ||
| print("\n如果仍然遇到密码提示问题,可能的原因:") | ||
| print("1. 配置文件位置不同") | ||
| print("2. 应用程序代码中有其他问题") | ||
| print("\n建议联系开发者获取进一步帮助。") | ||
|
|
||
| print("\n修复工具执行完成。") | ||
|
|
||
| # 不需要显示GUI,直接退出 | ||
| sys.exit(0) | ||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,6 +16,8 @@ | |||||||||
| import json | ||||||||||
| from logging.handlers import RotatingFileHandler | ||||||||||
| from threading import Lock | ||||||||||
| from utils.password_manager import PasswordManager | ||||||||||
| from ui.password_dialogs import PasswordInputDialog | ||||||||||
|
|
||||||||||
| # 配置日志 | ||||||||||
| def setup_logging(): | ||||||||||
|
|
@@ -54,6 +56,52 @@ def setup_logging(): | |||||||||
|
|
||||||||||
| logger = logging.getLogger(__name__) | ||||||||||
|
|
||||||||||
| def verify_password(): | ||||||||||
| """验证密码""" | ||||||||||
| try: | ||||||||||
| password_manager = PasswordManager() | ||||||||||
|
|
||||||||||
| # 如果未启用密码保护,直接返回True | ||||||||||
| if not password_manager.is_password_enabled(): | ||||||||||
| logger.info("密码保护未启用,跳过验证") | ||||||||||
| return True | ||||||||||
|
|
||||||||||
| logger.info("密码保护已启用,需要验证密码") | ||||||||||
|
|
||||||||||
| # 创建临时应用程序实例用于显示对话框 | ||||||||||
| temp_app = None | ||||||||||
| if not QApplication.instance(): | ||||||||||
| temp_app = QApplication(sys.argv) | ||||||||||
|
|
||||||||||
| # 显示密码输入对话框 | ||||||||||
| from utils.language_manager import language_manager | ||||||||||
| dialog = PasswordInputDialog( | ||||||||||
| parent=None, | ||||||||||
| language_manager=language_manager, | ||||||||||
| password_manager=password_manager | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| # 执行对话框 | ||||||||||
| result = dialog.exec_() | ||||||||||
|
|
||||||||||
| # 清理临时应用程序 | ||||||||||
| if temp_app: | ||||||||||
| temp_app.quit() | ||||||||||
|
|
||||||||||
| if result == QDialog.Accepted: | ||||||||||
| logger.info("密码验证成功") | ||||||||||
| return True | ||||||||||
| else: | ||||||||||
| logger.info("用户取消密码验证") | ||||||||||
| return False | ||||||||||
|
|
||||||||||
| except Exception as e: | ||||||||||
| logger.error(f"密码验证过程中发生错误: {e}") | ||||||||||
| import traceback | ||||||||||
| traceback.print_exc() | ||||||||||
|
Comment on lines
+100
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using
Suggested change
|
||||||||||
| # 如果验证过程出错,为了安全起见,拒绝访问 | ||||||||||
| return False | ||||||||||
|
|
||||||||||
| def main(): | ||||||||||
| try: | ||||||||||
| # 设置日志 | ||||||||||
|
|
@@ -84,6 +132,11 @@ def main(): | |||||||||
| with open(style_path, "r", encoding="utf-8") as f: | ||||||||||
| app.setStyleSheet(f.read()) | ||||||||||
|
|
||||||||||
| # 密码验证 | ||||||||||
| if not verify_password(): | ||||||||||
| logger.info("密码验证失败,程序退出") | ||||||||||
| sys.exit(0) | ||||||||||
|
|
||||||||||
| # 创建并显示主窗口 | ||||||||||
| window = UrlNavigatorApp() | ||||||||||
| window.show() | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a space after the colon in each list item for better readability.