From 91cae5bdebb2240cac31de89aff88cff17b9bb45 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Fri, 22 May 2026 22:35:55 +0800 Subject: [PATCH] fix(auth): redisLoader copy-paste bug, httpLoader.Close leak, reload data wipe, silent parse errors - redisLoader branch used fileLoader instead of redisLoader (copy-paste bug) - Close() was missing httpLoader.Close() (resource leak vs admission pattern) - reload() now preserves kvs on load() error instead of wiping to static-only - load() propagates first loader error, reload() returns early on load failure - parseAuths scanner errors now logged instead of silently discarded - http plugin drains body on non-200 to allow keep-alive connection reuse - Replace manual map-copy loops with maps.Copy --- auth/auth.go | 63 ++++++++++++++++++++++++++++----------------- auth/plugin/http.go | 2 ++ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index 88d7fe68..2efbd080 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "io" + "maps" "strings" "sync" "time" @@ -138,16 +139,15 @@ func (p *authenticator) periodReload(ctx context.Context) error { } } -func (p *authenticator) reload(ctx context.Context) (err error) { +func (p *authenticator) reload(ctx context.Context) error { kvs := make(map[string]string) - for k, v := range p.options.auths { - kvs[k] = v - } + maps.Copy(kvs, p.options.auths) m, err := p.load(ctx) - for k, v := range m { - kvs[k] = v + if err != nil { + return err } + maps.Copy(kvs, m) p.logger.Debugf("load items %d", len(m)) @@ -156,63 +156,75 @@ func (p *authenticator) reload(ctx context.Context) (err error) { p.kvs = kvs - return + return nil } -func (p *authenticator) load(ctx context.Context) (m map[string]string, err error) { - m = make(map[string]string) +func (p *authenticator) load(ctx context.Context) (map[string]string, error) { + m := make(map[string]string) + var loadErr error if p.options.fileLoader != nil { if mapper, ok := p.options.fileLoader.(loader.Mapper); ok { auths, er := mapper.Map(ctx) if er != nil { p.logger.Warnf("file loader: %v", er) + loadErr = er } m = auths } else { r, er := p.options.fileLoader.Load(ctx) if er != nil { p.logger.Warnf("file loader: %v", er) + loadErr = er } - if auths, _ := p.parseAuths(r); auths != nil { + if auths, err := p.parseAuths(r); err == nil { m = auths + } else { + p.logger.Warnf("file loader parse: %v", err) } } } if p.options.redisLoader != nil { - if mapper, ok := p.options.fileLoader.(loader.Mapper); ok { + if mapper, ok := p.options.redisLoader.(loader.Mapper); ok { auths, er := mapper.Map(ctx) if er != nil { - p.logger.Warnf("file loader: %v", er) - } - for k, v := range auths { - m[k] = v + p.logger.Warnf("redis loader: %v", er) + if loadErr == nil { + loadErr = er + } } + maps.Copy(m, auths) } else { r, er := p.options.redisLoader.Load(ctx) if er != nil { p.logger.Warnf("redis loader: %v", er) - } - if auths, _ := p.parseAuths(r); auths != nil { - for k, v := range auths { - m[k] = v + if loadErr == nil { + loadErr = er } } + if auths, err := p.parseAuths(r); err == nil { + maps.Copy(m, auths) + } else { + p.logger.Warnf("redis loader parse: %v", err) + } } } if p.options.httpLoader != nil { r, er := p.options.httpLoader.Load(ctx) if er != nil { p.logger.Warnf("http loader: %v", er) - } - if auths, _ := p.parseAuths(r); auths != nil { - for k, v := range auths { - m[k] = v + if loadErr == nil { + loadErr = er } } + if auths, err := p.parseAuths(r); err == nil { + maps.Copy(m, auths) + } else { + p.logger.Warnf("http loader parse: %v", err) + } } - return + return m, loadErr } func (p *authenticator) parseAuths(r io.Reader) (auths map[string]string, err error) { @@ -254,6 +266,9 @@ func (p *authenticator) Close() error { if p.options.redisLoader != nil { p.options.redisLoader.Close() } + if p.options.httpLoader != nil { + p.options.httpLoader.Close() + } return nil } diff --git a/auth/plugin/http.go b/auth/plugin/http.go index e88c0fec..499aafba 100644 --- a/auth/plugin/http.go +++ b/auth/plugin/http.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "io" "net/http" "github.com/go-gost/core/auth" @@ -91,6 +92,7 @@ func (p *httpPlugin) Authenticate(ctx context.Context, user, password string, op defer resp.Body.Close() if resp.StatusCode != http.StatusOK { + io.Copy(io.Discard, resp.Body) return }