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
This commit is contained in:
ginuerzh
2026-05-22 22:35:55 +08:00
parent 3f73c82d00
commit 91cae5bdeb
2 changed files with 41 additions and 24 deletions
+39 -24
View File
@@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"context" "context"
"io" "io"
"maps"
"strings" "strings"
"sync" "sync"
"time" "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) kvs := make(map[string]string)
for k, v := range p.options.auths { maps.Copy(kvs, p.options.auths)
kvs[k] = v
}
m, err := p.load(ctx) m, err := p.load(ctx)
for k, v := range m { if err != nil {
kvs[k] = v return err
} }
maps.Copy(kvs, m)
p.logger.Debugf("load items %d", len(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 p.kvs = kvs
return return nil
} }
func (p *authenticator) load(ctx context.Context) (m map[string]string, err error) { func (p *authenticator) load(ctx context.Context) (map[string]string, error) {
m = make(map[string]string) m := make(map[string]string)
var loadErr error
if p.options.fileLoader != nil { if p.options.fileLoader != nil {
if mapper, ok := p.options.fileLoader.(loader.Mapper); ok { if mapper, ok := p.options.fileLoader.(loader.Mapper); ok {
auths, er := mapper.Map(ctx) auths, er := mapper.Map(ctx)
if er != nil { if er != nil {
p.logger.Warnf("file loader: %v", er) p.logger.Warnf("file loader: %v", er)
loadErr = er
} }
m = auths m = auths
} else { } else {
r, er := p.options.fileLoader.Load(ctx) r, er := p.options.fileLoader.Load(ctx)
if er != nil { if er != nil {
p.logger.Warnf("file loader: %v", er) 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 m = auths
} else {
p.logger.Warnf("file loader parse: %v", err)
} }
} }
} }
if p.options.redisLoader != nil { 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) auths, er := mapper.Map(ctx)
if er != nil { if er != nil {
p.logger.Warnf("file loader: %v", er) p.logger.Warnf("redis loader: %v", er)
} if loadErr == nil {
for k, v := range auths { loadErr = er
m[k] = v }
} }
maps.Copy(m, auths)
} else { } else {
r, er := p.options.redisLoader.Load(ctx) r, er := p.options.redisLoader.Load(ctx)
if er != nil { if er != nil {
p.logger.Warnf("redis loader: %v", er) p.logger.Warnf("redis loader: %v", er)
} if loadErr == nil {
if auths, _ := p.parseAuths(r); auths != nil { loadErr = er
for k, v := range auths {
m[k] = v
} }
} }
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 { if p.options.httpLoader != nil {
r, er := p.options.httpLoader.Load(ctx) r, er := p.options.httpLoader.Load(ctx)
if er != nil { if er != nil {
p.logger.Warnf("http loader: %v", er) p.logger.Warnf("http loader: %v", er)
} if loadErr == nil {
if auths, _ := p.parseAuths(r); auths != nil { loadErr = er
for k, v := range auths {
m[k] = v
} }
} }
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) { 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 { if p.options.redisLoader != nil {
p.options.redisLoader.Close() p.options.redisLoader.Close()
} }
if p.options.httpLoader != nil {
p.options.httpLoader.Close()
}
return nil return nil
} }
+2
View File
@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"io"
"net/http" "net/http"
"github.com/go-gost/core/auth" "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() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
io.Copy(io.Discard, resp.Body)
return return
} }