Skip to content

Commit cec2443

Browse files
authored
Merge pull request #2 from zy84338719/remove-initwithdb
优化存储结构
2 parents e7097bd + 4be6eba commit cec2443

File tree

125 files changed

+6330
-7792
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+6330
-7792
lines changed

.github/copilot-instructions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ FileCodeBox 是一个高性能的文件快传系统的 Go 实现,基于现代
2020
```go
2121
// 通过 ConfigManager 统一管理所有配置
2222
manager := config.InitManager()
23-
manager.InitWithDB(db) // 数据库驱动的动态配置
23+
manager.SetDB(db) // 注入数据库连接(配置读取现在以 config.yaml 和 环境变量为准)
2424
```
2525

2626
配置分为多个模块:`BaseConfig`, `DatabaseConfig`, `StorageConfig`, `UserSystemConfig`, `MCPConfig`
2727

2828
支持环境变量优先级覆盖、数据库持久化存储、热重载机制:
29-
- **环境变量优先级**:PORT、ADMIN_TOKEN 等关键配置始终优先使用环境变量
29+
- **环境变量优先级**:PORT、DATA_PATH 等关键配置始终优先使用环境变量
3030
- **数据库持久化**:配置自动保存到 key_value 表,支持动态更新
3131
- **热重载机制**:通过 ReloadConfig() 方法实现运行时配置更新
3232
- **配置验证**:每个配置模块都有独立的验证方法
33-
- **分层映射**ToMap() 和 FromMap() 方法支持配置的序列化和反序列化
33+
- **类型安全配置**使用结构体 Clone() 方法和直接字段访问,避免 map 转换开销
3434

3535
### Route Architecture
3636
完全模块化的路由系统 (`internal/routes/`):

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
1+
# FileCodeBox (Go)
2+
3+
轻量且高性能的文件/文本分享服务,使用 Go 实现,支持分片上传、秒传、断点续传与多种存储后端。
4+
5+
核心目标是提供一个易部署、易扩展的文件快传系统,适合自托管与容器化部署场景。
6+
7+
## 主要特性
8+
9+
- 高性能:基于 Go 的并发能力构建,低延迟与内存占用
10+
- 文件/文本分享:支持短链接分享文本和文件
11+
- 分片上传:大文件分片、断点续传、上传校验与秒传支持
12+
- 管理后台:内置管理控制台,可管理文件、配置与用户
13+
- 多存储后端:支持本地、S3、WebDAV、OneDrive(可扩展)
14+
- 容器友好:提供 Docker 与 docker-compose 支持
15+
- 主题系统:前端主题可替换与定制
16+
17+
## 环境要求
18+
19+
开发推荐使用 Go 1.25+。项目默认使用 SQLite 作为开发环境的轻量数据库。生产环境请按需选择存储与资源配置。
20+
21+
## 部署建议(简要)
22+
23+
- 推荐使用 Docker + 反向代理(Nginx)启用 HTTPS
24+
-`data/` 目录做定期备份
25+
- 将服务放入进程管理(systemd / 容器重启策略)
26+
27+
## 开发与扩展
28+
29+
- 新增存储:实现 `storage.StorageInterface` 并在 `storage.NewStorageManager` 注册
30+
- 新增接口:在 `internal/services` 实现业务逻辑,并在 `internal/handlers``internal/routes` 添加路由
31+
32+
运行测试与示例脚本请查看 `tests/` 目录。
33+
34+
---
35+
36+
## 常见问题与排查(示例)
37+
38+
- 检查端口占用:
39+
40+
```bash
41+
lsof -ti:12345
42+
```
43+
44+
- 如果数据库被锁或服务异常,尝试重启服务或检查 `data/` 下的 sqlite 文件权限。
45+
46+
---
47+
48+
## 许可证
49+
50+
MIT
51+
52+
---
53+
54+
如需我继续:
55+
56+
- 将 README 翻译为英文
57+
- 自动生成或更新 Swagger 文档
58+
- 补全详细部署示例(Kubernetes / systemd)
59+
60+
请告诉我接下来要做哪个扩展。
161
<div align="center">
262
<img src="assets/images/logos/logo.svg" alt="FileCodeBox Logo" width="200"/>
363

@@ -72,7 +132,7 @@ docker-compose up -d
72132
- `name`: 站点名称
73133
- `upload_size`: 最大上传大小
74134
- `file_storage`: 存储类型(local/s3/webdav/onedrive)
75-
- `admin_token`: 管理员访问令牌
135+
- 管理员认证改为使用管理员用户名/密码登录并通过 `Authorization: Bearer <token>` 使用 JWT(不再使用静态管理员令牌配置)
76136

77137
## 管理员后台
78138

@@ -93,6 +153,20 @@ docker-compose up -d
93153
3. 设置合适的上传大小限制
94154
4. 配置站点名称和描述信息
95155

156+
### 管理后台静态资源的安全说明
157+
158+
管理后台使用了一组专用静态资源(位于 `themes/<theme>/admin/`),这些文件包含管理界面的 JavaScript、CSS 与模板。
159+
160+
为了避免未授权用户直接访问管理后台页面并读取敏感前端逻辑,服务已将管理专用静态资源改为仅在管理员认证后提供:
161+
162+
- 管理前端入口 `GET /admin/` 需要有效的管理员 JWT(通过 `Authorization: Bearer <token>` 方式传递)。
163+
- 管理专用静态路径(例如 `/admin/js/*`, `/admin/css/*`, `/admin/templates/*`, `/admin/assets/*`, `/admin/components/*`)也仅在认证通过后提供。
164+
- 公共资源(用户前端和通用资源)仍通过 `/js/*`, `/css/*`, `/assets/*`, `/components/*` 对外公开,以支持用户页面和登录流程。
165+
166+
部署注意:如果你的生产环境在前面放了 Nginx、CDN 或其它反向代理,请确保对 `/admin/*` 不做缓存并`不要`将 admin 静态事先缓存到代理上,否则可能绕过后端认证。建议在代理上为 `/admin/*` 添加 `Cache-Control: no-store` 或根据代理文档设置不缓存规则。
167+
168+
如果需要把少量引导或 favicon 等资产在未认证时可用,请将这些文件放入主题的 `assets/` 目录(由 `/assets/*` 提供),不要将管理专用目录下的文件放到公共路径。
169+
96170
## API接口
97171

98172
### 分享文本

admin-test.html

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<!DOCTYPE html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>管理员API测试</title>
7+
</head>
8+
<body>
9+
<h1>管理员API测试</h1>
10+
11+
<div>
12+
<h2>1. 登录测试</h2>
13+
<button onclick="testLogin()">测试登录</button>
14+
<div id="login-result"></div>
15+
</div>
16+
17+
<div>
18+
<h2>2. 仪表板API测试</h2>
19+
<button onclick="testDashboard()">测试仪表板</button>
20+
<div id="dashboard-result"></div>
21+
</div>
22+
23+
<div>
24+
<h2>3. 用户列表API测试</h2>
25+
<button onclick="testUsers()">测试用户列表</button>
26+
<div id="users-result"></div>
27+
</div>
28+
29+
<script>
30+
let authToken = null;
31+
32+
async function testLogin() {
33+
try {
34+
const response = await fetch('/admin/login', {
35+
method: 'POST',
36+
headers: {
37+
'Content-Type': 'application/json'
38+
},
39+
body: JSON.stringify({
40+
username: 'testadmin',
41+
password: 'admin123'
42+
})
43+
});
44+
45+
const result = await response.json();
46+
47+
if (result.code === 200) {
48+
authToken = result.data.token;
49+
localStorage.setItem('user_token', authToken);
50+
document.getElementById('login-result').innerHTML =
51+
'<span style="color: green;">登录成功!Token: ' + authToken.substring(0, 50) + '...</span>';
52+
} else {
53+
document.getElementById('login-result').innerHTML =
54+
'<span style="color: red;">登录失败: ' + result.message + '</span>';
55+
}
56+
} catch (error) {
57+
document.getElementById('login-result').innerHTML =
58+
'<span style="color: red;">请求失败: ' + error.message + '</span>';
59+
}
60+
}
61+
62+
async function testDashboard() {
63+
if (!authToken) {
64+
authToken = localStorage.getItem('user_token');
65+
}
66+
67+
if (!authToken) {
68+
document.getElementById('dashboard-result').innerHTML =
69+
'<span style="color: red;">请先登录</span>';
70+
return;
71+
}
72+
73+
try {
74+
const response = await fetch('/admin/dashboard', {
75+
headers: {
76+
'Authorization': 'Bearer ' + authToken
77+
}
78+
});
79+
80+
const result = await response.json();
81+
82+
document.getElementById('dashboard-result').innerHTML =
83+
'<pre>' + JSON.stringify(result, null, 2) + '</pre>';
84+
} catch (error) {
85+
document.getElementById('dashboard-result').innerHTML =
86+
'<span style="color: red;">请求失败: ' + error.message + '</span>';
87+
}
88+
}
89+
90+
async function testUsers() {
91+
if (!authToken) {
92+
authToken = localStorage.getItem('user_token');
93+
}
94+
95+
if (!authToken) {
96+
document.getElementById('users-result').innerHTML =
97+
'<span style="color: red;">请先登录</span>';
98+
return;
99+
}
100+
101+
try {
102+
const response = await fetch('/admin/users', {
103+
headers: {
104+
'Authorization': 'Bearer ' + authToken
105+
}
106+
});
107+
108+
const result = await response.json();
109+
110+
document.getElementById('users-result').innerHTML =
111+
'<pre>' + JSON.stringify(result, null, 2) + '</pre>';
112+
} catch (error) {
113+
document.getElementById('users-result').innerHTML =
114+
'<span style="color: red;">请求失败: ' + error.message + '</span>';
115+
}
116+
}
117+
</script>
118+
</body>
119+
</html>

config.generated.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
base:
2+
data_path: /tmp/filecodebox_test
3+
description: 开箱即用的文件快传系统
4+
host: 0.0.0.0
5+
name: FileCodeBox
6+
port: 12346
7+
production: false
8+
database:
9+
host: ""
10+
name: ./data/filecodebox.db
11+
port: 0
12+
ssl: disable
13+
type: sqlite
14+
user: ""
15+
mcp:
16+
host: 0.0.0.0
17+
port: 8081
18+
storage: {}
19+
ui:
20+
allow_user_registration: 0
21+
background: ""
22+
chunk_size: 2097152
23+
download_timeout: 300
24+
enable_chunk: 0
25+
enable_concurrent_download: 1
26+
enable_mcp_server: 0
27+
error_count: 1
28+
error_minute: 1
29+
file_storage: local
30+
jwt_secret: FileCodeBox2025JWT
31+
keywords: FileCodeBox, 文件快递柜, 口令传送箱, 匿名口令分享文本, 文件
32+
max_concurrent_downloads: 10
33+
max_save_seconds: 0
34+
max_sessions_per_user: 5
35+
notify_content: "欢迎使用 FileCodeBox,本程序开源于 <a href=\"https://github.com/zy84338719/FileCodeBox\" target=\"_blank\">Github</a> ,欢迎Star和Fork。"
36+
notify_title: 系统通知
37+
opacity: 0
38+
open_upload: 1
39+
page_explain: "请勿上传或分享违法内容。根据《中华人民共和国网络安全法》、《中华人民共和国刑法》、《中华人民共和国治安管理处罚法》等相关规定。 传播或存储违法、违规内容,会受到相关处罚,严重者将承担刑事责任。本站坚决配合相关部门,确保网络内容的安全,和谐,打造绿色网络环境。"
40+
require_email_verify: 0
41+
robots_text: |-
42+
User-agent: *
43+
Disallow: /
44+
session_expiry_hours: 168
45+
show_admin_address: 0
46+
storage_path: ""
47+
sys_start: 1757914992279
48+
themes_select: themes/2025
49+
upload_count: 10
50+
upload_minute: 1
51+
upload_size: 100
52+
user_storage_quota: 1073741824
53+
user_upload_size: 52428800
54+
user: {}

config.yaml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
base:
2+
name: FileCodeBox
3+
description: 开箱即用的文件快传系统
4+
keywords: ""
5+
port: 12346
6+
host: 0.0.0.0
7+
datapath: /Users/zhangyi/zy/FileCodeBox/data
8+
production: false
9+
database:
10+
type: sqlite
11+
host: ""
12+
port: 0
13+
name: ./data/filecodebox.db
14+
user: ""
15+
pass: ""
16+
ssl: disable
17+
transfer:
18+
upload:
19+
openupload: 1
20+
uploadsize: 10485760
21+
enablechunk: 0
22+
chunksize: 2097152
23+
maxsaveseconds: 0
24+
download:
25+
enableconcurrentdownload: 1
26+
maxconcurrentdownloads: 10
27+
downloadtimeout: 300
28+
storage:
29+
type: ""
30+
storagepath: ""
31+
s3: null
32+
webdav: null
33+
onedrive: null
34+
nfs: null
35+
user:
36+
allowuserregistration: 1
37+
requireemailverify: 0
38+
useruploadsize: 52428800
39+
userstoragequota: 1073741824
40+
sessionexpiryhours: 168
41+
maxsessionsperuser: 5
42+
jwtsecret: FileCodeBox2025JWT
43+
mcp:
44+
enablemcpserver: 0
45+
mcpport: ""
46+
mcphost: ""
47+
notifytitle: ""
48+
notifycontent: ""
49+
ui:
50+
themes_select: themes/2025
51+
background: ""
52+
page_explain: 请勿上传或分享违法内容。根据《中华人民共和国网络安全法》、《中华人民共和国刑法》、《中华人民共和国治安管理处罚法》等相关规定。 传播或存储违法、违规内容,会受到相关处罚,严重者将承担刑事责任。本站坚决配合相关部门,确保网络内容的安全,和谐,打造绿色网络环境。
53+
robots_text: |-
54+
User-agent: *
55+
Disallow: /
56+
show_admin_addr: 0
57+
opacity: 0
58+
themes_select: themes/2025
59+
robots_text: |-
60+
User-agent: *
61+
Disallow: /
62+
page_explain: 请勿上传或分享违法内容。根据《中华人民共和国网络安全法》、《中华人民共和国刑法》、《中华人民共和国治安管理处罚法》等相关规定。 传播或存储违法、违规内容,会受到相关处罚,严重者将承担刑事责任。本站坚决配合相关部门,确保网络内容的安全,和谐,打造绿色网络环境。
63+
show_admin_addr: 0
64+
opacity: 0
65+
background: ""
66+
sys_start: ""
67+
upload_minute: 0
68+
upload_count: 0
69+
error_minute: 0
70+
error_count: 0
71+
expire_style: []

docs/ADMIN_AUTH_401_FIX_REPORT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ combinedAuthMiddleware := func(c *gin.Context) {
6464
if tokenParts[1] == cfg.AdminToken {
6565
c.Set("is_admin", true)
6666
c.Set("role", "admin")
67-
c.Set("auth_type", "admin_token")
67+
c.Set("auth_type", "jwt")
6868
c.Next()
6969
return
7070
}
@@ -97,7 +97,7 @@ combinedAuthMiddleware := func(c *gin.Context) {
9797
**管理员Token认证**
9898
- `is_admin`: true
9999
- `role`: "admin"
100-
- `auth_type`: "admin_token"
100+
- `auth_type`: "jwt"
101101

102102
## 测试验证
103103

0 commit comments

Comments
 (0)