chore: baseline snapshot before moderation-strictness feature
Repo .git was damaged (refs/ missing, index truncated, object store near-empty). Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak, then full worktree committed as a rollback baseline.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// Copyright 2022 E99p1ant. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// File is the configuration object.
|
||||
var File *ini.File
|
||||
|
||||
func Init() error {
|
||||
configFile := os.Getenv("NEKOBOX_CONFIG_PATH")
|
||||
if configFile == "" {
|
||||
configFile = "conf/app.ini"
|
||||
}
|
||||
|
||||
var err error
|
||||
File, err = ini.LoadSources(ini.LoadOptions{
|
||||
IgnoreInlineComment: true,
|
||||
}, configFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "parse %q", configFile)
|
||||
}
|
||||
|
||||
if err := File.Section("app").MapTo(&App); err != nil {
|
||||
return errors.Wrap(err, "map 'server'")
|
||||
}
|
||||
|
||||
if App.ExternalURL == "" {
|
||||
return errors.New("app.external_url is required")
|
||||
}
|
||||
App.ExternalURL = strings.TrimRight(App.ExternalURL, "/")
|
||||
|
||||
if err := File.Section("security").MapTo(&Security); err != nil {
|
||||
return errors.Wrap(err, "map 'security'")
|
||||
}
|
||||
|
||||
if err := File.Section("server").MapTo(&Server); err != nil {
|
||||
return errors.Wrap(err, "map 'server'")
|
||||
}
|
||||
|
||||
// XSRFKey 为空会导致 CSRF token 以空密钥生成、可被预测,
|
||||
// 使删题/置顶/拉黑/改密等所有 POST 操作的 CSRF 防护形同虚设。启动时强制校验。
|
||||
if Server.XSRFKey == "" {
|
||||
return errors.New("server.xsrf_key is required (used to generate CSRF tokens, must not be empty)")
|
||||
}
|
||||
|
||||
// Salt 为空会让密码哈希以空盐计算(HmacSha1(password, "")),
|
||||
// 相同密码产生相同哈希且可被离线字典/彩虹表攻击。启动时强制校验。
|
||||
if Server.Salt == "" {
|
||||
return errors.New("server.salt is required (used to hash user passwords, must not be empty)")
|
||||
}
|
||||
|
||||
if err := File.Section("database").MapTo(&Database); err != nil {
|
||||
return errors.Wrap(err, "map 'database'")
|
||||
}
|
||||
|
||||
if err := File.Section("redis").MapTo(&Redis); err != nil {
|
||||
return errors.Wrap(err, "map 'redis'")
|
||||
}
|
||||
|
||||
if err := File.Section("recaptcha").MapTo(&Recaptcha); err != nil {
|
||||
return errors.Wrap(err, "map 'recaptcha'")
|
||||
}
|
||||
|
||||
if err := File.Section("pixel").MapTo(&Pixel); err != nil {
|
||||
return errors.Wrap(err, "map 'pixel'")
|
||||
}
|
||||
|
||||
if err := File.Section("upload").MapTo(&Upload); err != nil {
|
||||
return errors.Wrap(err, "map 'upload'")
|
||||
}
|
||||
|
||||
if err := File.Section("limits").MapTo(&Limits); err != nil {
|
||||
return errors.Wrap(err, "map 'limits'")
|
||||
}
|
||||
// ini 键留空会被 int 解析为 0;<1 的值一律回退内置默认,防止上限被静默置零。
|
||||
sanitizeLimits(&Limits)
|
||||
|
||||
if err := File.Section("mail").MapTo(&Mail); err != nil {
|
||||
return errors.Wrap(err, "map 'mail'")
|
||||
}
|
||||
|
||||
serviceSections := File.Section("service").ChildSections()
|
||||
for _, serviceSection := range serviceSections {
|
||||
serviceSection := serviceSection
|
||||
var backend struct {
|
||||
Prefix string `ini:"prefix"`
|
||||
ForwardURL string `ini:"forward_url"`
|
||||
}
|
||||
if err := serviceSection.MapTo(&backend); err != nil {
|
||||
return errors.Wrapf(err, "map 'service.%s'", serviceSection.Name())
|
||||
}
|
||||
Service.Backends = append(Service.Backends, backend)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user