Files
CHFS-NG/chfs-ng/internal/config/config.go
T

178 lines
3.8 KiB
Go

package config
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type AccountConfig struct {
Username string
Password string
Default string
None []string
Read []string
Write []string
Delete []string
}
type Config struct {
Path []string
Port int
Allow string
Rules []string
Log string
FileRemove int
ImagePreview bool
FolderDownload string
SessionTimeout int
HTMLTitle string
HTMLNotice string
SSLCert string
SSLKey string
Accounts []AccountConfig
}
func Default() Config {
return Config{Path: []string{"."}, Port: 80, FileRemove: 1, ImagePreview: true, FolderDownload: "enable", SessionTimeout: 30}
}
func Load(path string) (Config, error) {
c := Default()
f, err := os.Open(path)
if err != nil {
return c, err
}
defer f.Close()
s := bufio.NewScanner(f)
var section *AccountConfig
for s.Scan() {
line := strings.TrimSpace(s.Text())
if line == "" || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
name := strings.TrimSpace(line[1 : len(line)-1])
if name != "" {
c.Accounts = append(c.Accounts, AccountConfig{Username: name})
section = &c.Accounts[len(c.Accounts)-1]
} else {
section = nil
}
continue
}
i := strings.IndexByte(line, '=')
if i < 0 {
continue
}
key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
val = strings.Trim(val, "\\\"")
if section != nil {
switch strings.ToLower(key) {
case "password":
section.Password = val
case "rule.default":
section.Default = val
case "rule.none":
section.None = appendNonEmpty(section.None, val)
case "rule.r":
section.Read = appendNonEmpty(section.Read, val)
case "rule.w":
section.Write = appendNonEmpty(section.Write, val)
case "rule.d":
section.Delete = appendNonEmpty(section.Delete, val)
}
continue
}
switch strings.ToLower(key) {
case "path":
c.Path = splitPath(val)
case "port":
if n, e := strconv.Atoi(val); e == nil && n > 0 && n < 65536 {
c.Port = n
}
case "allow":
c.Allow = val
case "rule":
if val != "" {
c.Rules = append(c.Rules, val)
}
case "log":
c.Log = val
case "file.remove":
if n, e := strconv.Atoi(val); e == nil {
c.FileRemove = n
}
case "image.preview":
c.ImagePreview = parseBool(val, c.ImagePreview)
case "folder.download":
c.FolderDownload = strings.ToLower(val)
case "folder.leaf.download":
if parseBool(val, false) {
c.FolderDownload = "leaf"
}
case "session.timeout":
if n, e := strconv.Atoi(val); e == nil && n > 0 {
c.SessionTimeout = n
}
case "html.title":
c.HTMLTitle = val
case "html.notice":
c.HTMLNotice = val
case "ssl.cert":
c.SSLCert = val
case "ssl.key":
c.SSLKey = val
}
}
if err := s.Err(); err != nil {
return c, err
}
return c, nil
}
func splitPath(v string) []string {
var out []string
for _, p := range strings.Split(v, "|") {
p = strings.TrimSpace(strings.Trim(p, "\\\""))
if p != "" {
out = append(out, p)
}
}
if len(out) == 0 {
return []string{"."}
}
return out
}
func parseBool(v string, d bool) bool {
switch strings.ToLower(strings.TrimSpace(v)) {
case "true", "1", "yes", "on":
return true
case "false", "0", "no", "off":
return false
}
return d
}
func (c Config) Validate() error {
if len(c.Path) == 0 {
return fmt.Errorf("path is empty")
}
if c.Port < 1 || c.Port > 65535 {
return fmt.Errorf("invalid port")
}
return nil
}
func appendNonEmpty(dst []string, value string) []string {
for _, item := range strings.Split(value, "|") {
item = strings.TrimSpace(item)
if item != "" {
dst = append(dst, item)
}
}
return dst
}