first commit
This commit is contained in:
commit
fccfe2a4c8
26 files changed
+1819
No files matched your search
@@ -0,0 +1,161 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ListenAddr string
|
||||
AppSecret string
|
||||
HTTPSOnly bool
|
||||
FrameAncestors []string
|
||||
TrustedProxies []*net.IPNet
|
||||
TSQueryHost string
|
||||
TSQueryPort int
|
||||
TSVoiceHost string
|
||||
TSVoicePort int
|
||||
TSQueryUser string
|
||||
TSQueryPassword string
|
||||
TSChannelAdminGID int
|
||||
TSQueryTimeout time.Duration
|
||||
RRDTool string
|
||||
RRDPath string
|
||||
GraphDir string
|
||||
StatsInterval time.Duration
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
var c Config
|
||||
c.ListenAddr = env("LISTEN_ADDR", "127.0.0.1:8080")
|
||||
c.AppSecret = os.Getenv("APP_SECRET")
|
||||
if len(c.AppSecret) < 32 {
|
||||
return c, errors.New("APP_SECRET must contain at least 32 characters")
|
||||
}
|
||||
c.HTTPSOnly = envBool("HTTPS_ONLY", true)
|
||||
|
||||
var err error
|
||||
c.FrameAncestors, err = frameAncestors(os.Getenv("FRAME_ANCESTORS"))
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
c.TrustedProxies, err = cidrs(os.Getenv("TRUSTED_PROXIES"))
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
c.TSQueryHost = env("TS_QUERY_HOST", "127.0.0.1")
|
||||
c.TSQueryPort, err = envInt("TS_QUERY_PORT", 10011)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
c.TSVoiceHost = env("TS_VOICE_HOST", "linuxiarz.pl")
|
||||
c.TSVoicePort, err = envInt("TS_VOICE_PORT", 9987)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
c.TSQueryUser = os.Getenv("TS_QUERY_USER")
|
||||
c.TSQueryPassword = os.Getenv("TS_QUERY_PASSWORD")
|
||||
if c.TSQueryUser == "" || c.TSQueryPassword == "" {
|
||||
return c, errors.New("TS_QUERY_USER and TS_QUERY_PASSWORD are required")
|
||||
}
|
||||
c.TSChannelAdminGID, err = envInt("TS_CHANNEL_ADMIN_GID", 5)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
c.TSQueryTimeout, err = envDuration("TS_QUERY_TIMEOUT", 3*time.Second)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
c.RRDTool = env("RRDTOOL", "rrdtool")
|
||||
c.RRDPath = env("RRD_PATH", "/var/lib/ts3monolith/linuxiarz.rrd")
|
||||
c.GraphDir = env("GRAPH_DIR", "/var/lib/ts3monolith/graphs")
|
||||
c.StatsInterval, err = envDuration("STATS_INTERVAL", time.Minute)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
if c.StatsInterval < 10*time.Second {
|
||||
return c, errors.New("STATS_INTERVAL must be at least 10s")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func env(k, d string) string {
|
||||
if v := strings.TrimSpace(os.Getenv(k)); v != "" {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func envBool(k string, d bool) bool {
|
||||
v := strings.TrimSpace(os.Getenv(k))
|
||||
if v == "" {
|
||||
return d
|
||||
}
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return d
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func envInt(k string, d int) (int, error) {
|
||||
v := strings.TrimSpace(os.Getenv(k))
|
||||
if v == "" {
|
||||
return d, nil
|
||||
}
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil || n < 1 || n > 65535 {
|
||||
return 0, fmt.Errorf("invalid %s", k)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func envDuration(k string, d time.Duration) (time.Duration, error) {
|
||||
v := strings.TrimSpace(os.Getenv(k))
|
||||
if v == "" {
|
||||
return d, nil
|
||||
}
|
||||
x, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid %s: %w", k, err)
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func frameAncestors(raw string) ([]string, error) {
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return []string{"'self'"}, nil
|
||||
}
|
||||
out := []string{"'self'"}
|
||||
for _, part := range strings.Fields(raw) {
|
||||
u, err := url.Parse(part)
|
||||
if err != nil || (u.Scheme != "https" && u.Scheme != "http") || u.Host == "" || u.Path != "" || u.RawQuery != "" || u.Fragment != "" {
|
||||
return nil, fmt.Errorf("invalid FRAME_ANCESTORS origin: %q", part)
|
||||
}
|
||||
out = append(out, u.Scheme+"://"+u.Host)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func cidrs(raw string) ([]*net.IPNet, error) {
|
||||
var out []*net.IPNet
|
||||
for _, part := range strings.FieldsFunc(raw, func(r rune) bool { return r == ',' || r == ' ' || r == '\t' || r == '\n' }) {
|
||||
if strings.TrimSpace(part) == "" {
|
||||
continue
|
||||
}
|
||||
_, n, err := net.ParseCIDR(strings.TrimSpace(part))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid TRUSTED_PROXIES entry %q", part)
|
||||
}
|
||||
out = append(out, n)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
Reference in new issue
Block a user