- 添加管理员端 API,用于获取和更新完整配置。 - 添加公共端 API,用于获取非敏感配置信息。 - 增加本地存储(LocalStorage)、S3(S3Storage)、和 WebDAV(WebDAVStorage)存储类型的实现。 - 支持热更新存储配置和保存配置文件至磁盘。 - 更新 Swagger 文档以包含新接口定义。
116 lines
3.0 KiB
Go
116 lines
3.0 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"FileRelay/internal/config"
|
|
"FileRelay/internal/model"
|
|
"FileRelay/internal/storage"
|
|
"context"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"log"
|
|
"math/big"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var DB *gorm.DB
|
|
|
|
func InitDB() {
|
|
var err error
|
|
dbPath := config.GlobalConfig.Database.Path
|
|
if dbPath == "" {
|
|
dbPath = "file_relay.db"
|
|
}
|
|
|
|
DB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to database: %v", err)
|
|
}
|
|
|
|
// 自动迁移
|
|
err = DB.AutoMigrate(
|
|
&model.FileBatch{},
|
|
&model.FileItem{},
|
|
&model.APIToken{},
|
|
&model.Admin{},
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Failed to migrate database: %v", err)
|
|
}
|
|
|
|
fmt.Println("Database initialized and migrated.")
|
|
|
|
// 初始化存储
|
|
if err := ReloadStorage(); err != nil {
|
|
log.Fatalf("Failed to initialize storage: %v", err)
|
|
}
|
|
|
|
// 初始化管理员 (如果不存在)
|
|
initAdmin()
|
|
}
|
|
|
|
func ReloadStorage() error {
|
|
storageType := config.GlobalConfig.Storage.Type
|
|
switch storageType {
|
|
case "local":
|
|
storage.GlobalStorage = storage.NewLocalStorage(config.GlobalConfig.Storage.Local.Path)
|
|
case "webdav":
|
|
cfg := config.GlobalConfig.Storage.WebDAV
|
|
storage.GlobalStorage = storage.NewWebDAVStorage(cfg.URL, cfg.Username, cfg.Password, cfg.Root)
|
|
case "s3":
|
|
cfg := config.GlobalConfig.Storage.S3
|
|
s3Storage, err := storage.NewS3Storage(context.Background(), cfg.Endpoint, cfg.Region, cfg.AccessKey, cfg.SecretKey, cfg.Bucket, cfg.UseSSL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
storage.GlobalStorage = s3Storage
|
|
default:
|
|
return fmt.Errorf("unsupported storage type: %s", storageType)
|
|
}
|
|
fmt.Printf("Storage initialized with type: %s\n", storageType)
|
|
return nil
|
|
}
|
|
|
|
func initAdmin() {
|
|
var count int64
|
|
DB.Model(&model.Admin{}).Count(&count)
|
|
if count == 0 {
|
|
passwordHash := config.GlobalConfig.Security.AdminPasswordHash
|
|
if passwordHash == "" {
|
|
// 生成随机密码
|
|
password := generateRandomPassword(12)
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
log.Fatalf("Failed to generate password hash: %v", err)
|
|
}
|
|
passwordHash = string(hash)
|
|
fmt.Printf("**************************************************\n")
|
|
fmt.Printf("NO ADMIN PASSWORD CONFIGURED. GENERATED RANDOM PASSWORD:\n")
|
|
fmt.Printf("Password: %s\n", password)
|
|
fmt.Printf("Please save this password or configure admin_password_hash in config.yaml\n")
|
|
fmt.Printf("**************************************************\n")
|
|
}
|
|
|
|
admin := &model.Admin{
|
|
PasswordHash: passwordHash,
|
|
}
|
|
DB.Create(admin)
|
|
fmt.Println("Admin account initialized.")
|
|
}
|
|
}
|
|
|
|
func generateRandomPassword(length int) string {
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
|
b := make([]byte, length)
|
|
for i := range b {
|
|
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
|
if err != nil {
|
|
return "admin123" // 退路
|
|
}
|
|
b[i] = charset[num.Int64()]
|
|
}
|
|
return string(b)
|
|
}
|