HAO-Netdisk 是一款基于 Python Flask 后端 + Tkinter 图形化启动器的个人云存储(网盘)应用。支持双 IPv4/IPv6 协议网络访问,用户可共享文件并创建带密码保护和有效期的共享链接。
当前版本:v1.7.5+
本项目仅供学习参考,请勿用于非法用途,否则后果自负!
- 主进程:Tkinter GUI启动器(
NetdiskLauncher类,使用ttk组件和分区式布局)用于协议/端口选择、邮件配置、服务控制 - Flask 线程:Web 服务器在守护进程线程中运行(
.run(host, port, use_reloader=False))- 为何分离线程? 确保启动器界面响应流畅的同时运行 Flask
- 重要提示: 使用
threading.Event()实现干净关闭;调用os._exit(0)强制终止 - 邮件配置加载:Flask 启动前自动从
mail_config.json加载邮件配置,并在启动时初始化Mail对象
用户 → 文件 (一对多), 目录, 个人简介, 密码哈希, 重置令牌
文件 → 用户ID, 目录ID (可选), 共享链接, 下载链接 (UUID)
目录 → user_id, files (一对多), is_public 标记- 核心模式:文件可独立存在或归属目录
- 共享系统:使用
secrets.token_urlsafe(16)生成有效期1天的高安全性共享链接
uploads/ → 所有用户文件存储于此(单层扁平目录)
static/images/avatar/ → 用户头像存储于 {username}.png 格式
app.log → 应用程序事件日志
site.db → SQLite 数据库
python.exe app.py启动 Tkinter 启动器 →
- 可选填写邮件配置并点击"保存邮件配置"(配置保存到
mail_config.json) - 选择 IPv4/IPv6 协议 → 输入端口(默认 5000)
- 点击"启动服务" → Flask 线程启动 → 自动打开浏览器访问
http://localhost:{port} - 可从启动器复制公网或本地访问链接、查看日志、检查版本、删除文件
- Flask默认运行于
http://localhost:5000 - 首次运行时数据库自动初始化;模式迁移由
check_and_update_database()处理
函数 check_and_update_database()(应用启动时调用):
- 自动创建缺失表
- 通过
ALTER TABLE为现有表添加缺失字段 - 切勿手动编辑数据库 — 请使用 SQLAlchemy 模型
# 验证登录
if ‘user_id’ not in session:
return redirect(url_for(‘login’))
user = db.session.get(User, session[‘user_id’])- 使用 Flask
session(通过 SECRET_KEY 实现服务器端管理) - 不使用 JWT;采用带邮箱/用户名过滤器的纯 SQL 查询登录
采用文件名冲突避免机制上传文件:
counter = 1
while os.path.exists(os.path.join(app.config[‘UPLOAD_FOLDER’], filename)):
filename = f“{base_filename}({counter}){file_extension}”
counter += 1大文件采用分块流式传输:
with open(filepath, ‘wb’) as f:
for chunk in file.stream:
f.write(chunk)所有重要操作通过log_event(event_string)记录:
log_event(f'用户 {session[“username”]} 上传了文件。')日志带时间戳记录于app.log,用于启动器“查看日志”按钮
两级可见性设置:
is_public=True:对所有用户在/files列表中可见is_public=False:仅所有者可见- 数据库查询统一过滤规则:
(query.is_public == True) | (query.user_id == session.get(‘user_id’))
share_link = secrets.token_urlsafe(16)
file.share_expiration = datetime.now(timezone.utc) + timedelta(days=1)- 访问
/share/<share_link>可无需登录直接下载 - 可选密码保护共享链接
- 过期时间由服务器端验证(非强制执行;仅为客户端UI显示返回)
启动器界面包含邮件配置分区(底部),支持以下字段的可视化配置:
- SMTP 服务器:邮件服务提供商的服务器地址(例:
smtp.163.com) - SMTP 端口:服务器端口(例:25、587、465)
- 用户名:登录用户名或邮箱地址
- 密码/授权码:邮件服务授权码(以密文显示)
- 默认发件人:邮箱地址
- 使用 TLS / 使用 SSL:复选框切换连接加密方式
- 保存配置:点击"保存邮件配置"按钮 → 配置以 JSON 格式写入
mail_config.json - 启动器启动时:自动从
mail_config.json加载已保存的配置到 GUI 输入框 - 服务启动时:Flask 调用
load_mail_config()将配置读入app.config,并执行mail.init_app(app)
{
"MAIL_SERVER": "your_smtp.com",
"MAIL_PORT": 587,
"MAIL_USERNAME": "your@example.com",
"MAIL_PASSWORD": "your_auth_code",
"MAIL_DEFAULT_SENDER": "your@example.com",
"MAIL_USE_TLS": true,
"MAIL_USE_SSL": false
}如果 Flask-Mail 因 SSL/TLS 版本不匹配而失败,forgot_password 路由会自动调用 fallback_send_email() 函数,该函数:
- 尝试多种连接方式(SSL 直连、STARTTLS、明文)
- 记录每次尝试的详细日志
- 提高邮件发送成功率,兼容不同 SMTP 服务器配置
- Cropper.js (
static/js/cropperjs.js):图片编辑/裁剪 - Lightbox2:图片图库
- Mammoth.js:DOCX文件预览
- XLSX.js:Excel文件处理
GET /file_list_api→ 用于启动器删除对话框GET /directory_list_api→ 列出所有目录及嵌套文件POST /delete_file,POST /delete_directory→ 管理员通过启动器执行删除
启动器使用 ttk(主题化 Tkinter)和分区式布局提供现代简约的用户体验:
运行设置区
- 协议选择(IPv6 / IPv4)及支持状态检测
- 端口输入框(默认 5000,可自定义)
服务控制区
- 启动服务、停止服务、重启服务(网格式按钮排列)
- 复制公网访问链接、复制本地访问链接(自动打开浏览器)
- 删除文件(弹窗式管理界面)
状态区
- 服务状态指示灯(绿色/红色圆点实时更新)
- 服务运行状态文字提示
- 检查最新版本按钮(连接 Gitee 仓库获取发布信息)
邮件配置区
- SMTP 服务器、端口、用户名、密码、默认发件人输入框
- TLS / SSL 协议选择复选框
- 保存邮件配置按钮
菜单栏(顶部)
- 帮助菜单:关于协议选择、关于端口设置、关于本软件、查看日志、上传文件目录
- 联系我们菜单:发送邮件、我的网站
- 退出菜单
- 使用
ttk.Frame、ttk.LabelFrame、ttk.Button等控件实现一致的主题样式 - 网格布局管理器(
grid)替代传统pack,提供更灵活的响应式设计 - 颜色配置独立,便于后续主题定制
- 采用基于会话的认证 — 安全验证绝不依赖客户端IP或标头
- 过滤数据库查询 — 始终执行可见性/所有权检查
- 流式处理大文件上传 — 避免加载至内存
- 记录所有用户操作 — 通过
log_event()生成审计轨迹 - IOError时使用
db.session.rollback()— 保持事务完整性 - 邮件配置外置化 — 使用
mail_config.json而非硬编码,启动时自动加载 - 启动器 GUI 使用 ttk — 保持现代统一的界面风格
- 邮件发送支持回退机制 — 若 Flask-Mail 失败,自动尝试 smtplib 多种连接方式
- 移除 Flask 中的
use_reloader=False— 导致线程中重复执行 - 在客户端存储绝对文件路径 — 始终在服务器端重建路径
- 认为共享链接已过期 — 始终在服务器端验证
share_expiration - 直接修改数据库模式 — 使用 SQLAlchemy 模型 +
check_and_update_database() - 混用 pack() 和 grid() 布局管理器 — 会导致 Tkinter 错误;启动器使用 grid
- 把邮件凭证硬编码在代码中 — 必须使用
mail_config.json - 移除邮件配置保存/加载逻辑 — 保留启动器邮件配置 GUI 和
load_mail_config()函数
修改功能时:
- 添加至
/file_manager路由进行快速测试(管理员可删除项目) - 检查app.log获取操作日志
- 验证数据库变更是否破坏现有查询(尤其可见性过滤器)
- 修改网络代码时同时测试IPv4和IPv6
- 勿提交密钥(
app.py中的邮箱密码——未来请使用.env文件)
- 移动端应用尚未实现(计划中)
- 暂无性能监控仪表盘
- 共享链接过期机制未强制执行(仅UI层级)
- 仅支持单级上传文件夹(文件系统不支持嵌套目录)
- 邮件密码以明文保存在
mail_config.json