config: use scfg unmarshaler
This commit is contained in:
parent
c5d07658ab
commit
ef8a9caff4
177
config/config.go
177
config/config.go
|
@ -109,145 +109,150 @@ func Defaults() *Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(path string) (*Server, error) {
|
func Load(path string) (*Server, error) {
|
||||||
cfg, err := scfg.Load(path)
|
var raw struct {
|
||||||
|
Listen []struct {
|
||||||
|
Addr string `scfg:",param"`
|
||||||
|
} `scfg:"listen"`
|
||||||
|
Hostname string `scfg:"hostname"`
|
||||||
|
Title string `scfg:"title"`
|
||||||
|
MOTD string `scfg:"motd"`
|
||||||
|
TLS *[2]string `scfg:"tls"`
|
||||||
|
DB *[2]string `scfg:"db"`
|
||||||
|
MessageStore []string `scfg:"message-store"`
|
||||||
|
Log []string `scfg:"log"`
|
||||||
|
Auth []string `scfg:"auth"`
|
||||||
|
HTTPOrigin []string `scfg:"http-origin"`
|
||||||
|
AcceptProxyIP []string `scfg:"accept-proxy-ip"`
|
||||||
|
MaxUserNetworks int `scfg:"max-user-networks"`
|
||||||
|
UpstreamUserIP []string `scfg:"upstream-user-ip"`
|
||||||
|
DisableInactiveUser string `scfg:"disable-inactive-user"`
|
||||||
|
EnableUserOnAuth string `scfg:"enable-user-on-auth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return parse(cfg)
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := scfg.NewDecoder(f).Decode(&raw); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse(cfg scfg.Block) (*Server, error) {
|
|
||||||
srv := Defaults()
|
srv := Defaults()
|
||||||
for _, d := range cfg {
|
|
||||||
switch d.Name {
|
for _, listen := range raw.Listen {
|
||||||
case "listen":
|
srv.Listen = append(srv.Listen, listen.Addr)
|
||||||
var uri string
|
}
|
||||||
if err := d.ParseParams(&uri); err != nil {
|
if raw.Hostname != "" {
|
||||||
|
srv.Hostname = raw.Hostname
|
||||||
|
}
|
||||||
|
srv.Title = raw.Title
|
||||||
|
srv.MOTDPath = raw.MOTD
|
||||||
|
if raw.TLS != nil {
|
||||||
|
srv.TLS = &TLS{CertPath: raw.TLS[0], KeyPath: raw.TLS[1]}
|
||||||
|
}
|
||||||
|
if raw.DB != nil {
|
||||||
|
srv.DB = DB{Driver: raw.DB[0], Source: raw.DB[1]}
|
||||||
|
}
|
||||||
|
if raw.MessageStore == nil {
|
||||||
|
raw.MessageStore = raw.Log
|
||||||
|
}
|
||||||
|
if raw.MessageStore != nil {
|
||||||
|
driver, source, err := parseDriverSource("message-store", raw.MessageStore)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
srv.Listen = append(srv.Listen, uri)
|
switch driver {
|
||||||
case "hostname":
|
|
||||||
if err := d.ParseParams(&srv.Hostname); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case "title":
|
|
||||||
if err := d.ParseParams(&srv.Title); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case "motd":
|
|
||||||
if err := d.ParseParams(&srv.MOTDPath); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case "tls":
|
|
||||||
tls := &TLS{}
|
|
||||||
if err := d.ParseParams(&tls.CertPath, &tls.KeyPath); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
srv.TLS = tls
|
|
||||||
case "db":
|
|
||||||
if err := d.ParseParams(&srv.DB.Driver, &srv.DB.Source); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case "message-store", "log":
|
|
||||||
if err := d.ParseParams(&srv.MsgStore.Driver); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch srv.MsgStore.Driver {
|
|
||||||
case "memory", "db":
|
case "memory", "db":
|
||||||
|
// nothing to do
|
||||||
case "fs":
|
case "fs":
|
||||||
if err := d.ParseParams(nil, &srv.MsgStore.Source); err != nil {
|
if source == "" {
|
||||||
return nil, err
|
return nil, fmt.Errorf("directive message-store: driver %q requires a source", driver)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("directive %q: unknown driver %q", d.Name, srv.MsgStore.Driver)
|
return nil, fmt.Errorf("directive message-store: unknown driver %q", driver)
|
||||||
}
|
}
|
||||||
case "auth":
|
srv.MsgStore = MsgStore{driver, source}
|
||||||
if err := d.ParseParams(&srv.Auth.Driver); err != nil {
|
}
|
||||||
|
if raw.Auth != nil {
|
||||||
|
driver, source, err := parseDriverSource("auth", raw.Auth)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch srv.Auth.Driver {
|
switch driver {
|
||||||
case "internal", "pam":
|
case "internal", "pam":
|
||||||
srv.Auth.Source = ""
|
// nothing to do
|
||||||
case "oauth2":
|
case "oauth2":
|
||||||
if err := d.ParseParams(nil, &srv.Auth.Source); err != nil {
|
if source == "" {
|
||||||
return nil, err
|
return nil, fmt.Errorf("directive auth: driver %q requires a source", driver)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("directive %q: unknown driver %q", d.Name, srv.Auth.Driver)
|
return nil, fmt.Errorf("directive auth: unknown driver %q", driver)
|
||||||
}
|
}
|
||||||
case "http-origin":
|
srv.Auth = Auth{driver, source}
|
||||||
srv.HTTPOrigins = d.Params
|
}
|
||||||
case "accept-proxy-ip":
|
srv.HTTPOrigins = raw.HTTPOrigin
|
||||||
srv.AcceptProxyIPs = nil
|
for _, s := range raw.AcceptProxyIP {
|
||||||
for _, s := range d.Params {
|
|
||||||
if s == "localhost" {
|
if s == "localhost" {
|
||||||
srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, loopbackIPs...)
|
srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, loopbackIPs...)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, n, err := net.ParseCIDR(s)
|
_, n, err := net.ParseCIDR(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("directive %q: failed to parse CIDR: %v", d.Name, err)
|
return nil, fmt.Errorf("directive accept-proxy-ip: failed to parse CIDR: %v", err)
|
||||||
}
|
}
|
||||||
srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, n)
|
srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, n)
|
||||||
}
|
}
|
||||||
case "max-user-networks":
|
srv.MaxUserNetworks = raw.MaxUserNetworks
|
||||||
var max string
|
|
||||||
if err := d.ParseParams(&max); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
if srv.MaxUserNetworks, err = strconv.Atoi(max); err != nil {
|
|
||||||
return nil, fmt.Errorf("directive %q: %v", d.Name, err)
|
|
||||||
}
|
|
||||||
case "upstream-user-ip":
|
|
||||||
if len(srv.UpstreamUserIPs) > 0 {
|
|
||||||
return nil, fmt.Errorf("directive %q: can only be specified once", d.Name)
|
|
||||||
}
|
|
||||||
var hasIPv4, hasIPv6 bool
|
var hasIPv4, hasIPv6 bool
|
||||||
for _, s := range d.Params {
|
for _, s := range raw.UpstreamUserIP {
|
||||||
_, n, err := net.ParseCIDR(s)
|
_, n, err := net.ParseCIDR(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("directive %q: failed to parse CIDR: %v", d.Name, err)
|
return nil, fmt.Errorf("directive upstream-user-ip: failed to parse CIDR: %v", err)
|
||||||
}
|
}
|
||||||
if n.IP.To4() == nil {
|
if n.IP.To4() == nil {
|
||||||
if hasIPv6 {
|
if hasIPv6 {
|
||||||
return nil, fmt.Errorf("directive %q: found two IPv6 CIDRs", d.Name)
|
return nil, fmt.Errorf("directive upstream-user-ip: found two IPv6 CIDRs")
|
||||||
}
|
}
|
||||||
hasIPv6 = true
|
hasIPv6 = true
|
||||||
} else {
|
} else {
|
||||||
if hasIPv4 {
|
if hasIPv4 {
|
||||||
return nil, fmt.Errorf("directive %q: found two IPv4 CIDRs", d.Name)
|
return nil, fmt.Errorf("directive upstream-user-ip: found two IPv4 CIDRs")
|
||||||
}
|
}
|
||||||
hasIPv4 = true
|
hasIPv4 = true
|
||||||
}
|
}
|
||||||
srv.UpstreamUserIPs = append(srv.UpstreamUserIPs, n)
|
srv.UpstreamUserIPs = append(srv.UpstreamUserIPs, n)
|
||||||
}
|
}
|
||||||
case "disable-inactive-user":
|
if raw.DisableInactiveUser != "" {
|
||||||
var durStr string
|
dur, err := parseDuration(raw.DisableInactiveUser)
|
||||||
if err := d.ParseParams(&durStr); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dur, err := parseDuration(durStr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("directive %q: %v", d.Name, err)
|
return nil, fmt.Errorf("directive disable-inactive-user: %v", err)
|
||||||
} else if dur < 0 {
|
} else if dur < 0 {
|
||||||
return nil, fmt.Errorf("directive %q: duration must be positive", d.Name)
|
return nil, fmt.Errorf("directive disable-inactive-user: duration must be positive")
|
||||||
}
|
}
|
||||||
srv.DisableInactiveUsersDelay = dur
|
srv.DisableInactiveUsersDelay = dur
|
||||||
case "enable-user-on-auth":
|
|
||||||
var s string
|
|
||||||
if err := d.ParseParams(&s); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
b, err := strconv.ParseBool(s)
|
if raw.EnableUserOnAuth != "" {
|
||||||
|
b, err := strconv.ParseBool(raw.EnableUserOnAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("directive %q: %v", d.Name, err)
|
return nil, fmt.Errorf("directive enable-user-on-auth: %v", err)
|
||||||
}
|
}
|
||||||
srv.EnableUsersOnAuth = b
|
srv.EnableUsersOnAuth = b
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown directive %q", d.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return srv, nil
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseDriverSource(name string, params []string) (driver, source string, err error) {
|
||||||
|
switch len(params) {
|
||||||
|
case 2:
|
||||||
|
source = params[1]
|
||||||
|
fallthrough
|
||||||
|
case 1:
|
||||||
|
driver = params[0]
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("directive %v requires exactly 1 or 2 parameters", name)
|
||||||
|
}
|
||||||
|
return driver, source, err
|
||||||
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.sr.ht/~emersion/soju
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b
|
git.sr.ht/~emersion/go-scfg v0.0.0-20231211181832-0b4e72d8ec3c
|
||||||
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc
|
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc
|
||||||
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9
|
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9
|
||||||
github.com/SherClockHolmes/webpush-go v1.3.0
|
github.com/SherClockHolmes/webpush-go v1.3.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
||||||
git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b h1:Lf4oYBOJVmbYzrfqWfXUvSpXQPNMgnbN0efn5A7bH3M=
|
git.sr.ht/~emersion/go-scfg v0.0.0-20231211181832-0b4e72d8ec3c h1:Cjy9/qASF8hogbKbWXgEQZxbYHrM9ksl76sGzsP8Zqo=
|
||||||
git.sr.ht/~emersion/go-scfg v0.0.0-20231004133111-9dce55c8d63b/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
|
git.sr.ht/~emersion/go-scfg v0.0.0-20231211181832-0b4e72d8ec3c/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
|
||||||
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc h1:+y3OijpLl4rgbFsqMBmYUTCsGCkxQUWpWaqfS8j9Ygc=
|
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc h1:+y3OijpLl4rgbFsqMBmYUTCsGCkxQUWpWaqfS8j9Ygc=
|
||||||
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc/go.mod h1:PCl1xjl7iC6x35TKKubKRyo/3TT0dGI66jyNI6vmYnU=
|
git.sr.ht/~emersion/go-sqlite3-fts5 v0.0.0-20230217131031-f2c8767594fc/go.mod h1:PCl1xjl7iC6x35TKKubKRyo/3TT0dGI66jyNI6vmYnU=
|
||||||
git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
|
git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
|
||||||
|
|
Loading…
Reference in a new issue