mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 12:20:52 +08:00
feat(watcher): log auth field changes on reload
Cache parsed auth contents and compute redacted diffs for prefix, proxy_url, and disabled when auth files are added or updated.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@@ -15,6 +16,7 @@ import (
|
|||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/diff"
|
||||||
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@@ -72,6 +74,7 @@ func (w *Watcher) reloadClients(rescanAuth bool, affectedOAuthProviders []string
|
|||||||
w.clientsMutex.Lock()
|
w.clientsMutex.Lock()
|
||||||
|
|
||||||
w.lastAuthHashes = make(map[string]string)
|
w.lastAuthHashes = make(map[string]string)
|
||||||
|
w.lastAuthContents = make(map[string]*coreauth.Auth)
|
||||||
if resolvedAuthDir, errResolveAuthDir := util.ResolveAuthDir(cfg.AuthDir); errResolveAuthDir != nil {
|
if resolvedAuthDir, errResolveAuthDir := util.ResolveAuthDir(cfg.AuthDir); errResolveAuthDir != nil {
|
||||||
log.Errorf("failed to resolve auth directory for hash cache: %v", errResolveAuthDir)
|
log.Errorf("failed to resolve auth directory for hash cache: %v", errResolveAuthDir)
|
||||||
} else if resolvedAuthDir != "" {
|
} else if resolvedAuthDir != "" {
|
||||||
@@ -84,6 +87,11 @@ func (w *Watcher) reloadClients(rescanAuth bool, affectedOAuthProviders []string
|
|||||||
sum := sha256.Sum256(data)
|
sum := sha256.Sum256(data)
|
||||||
normalizedPath := w.normalizeAuthPath(path)
|
normalizedPath := w.normalizeAuthPath(path)
|
||||||
w.lastAuthHashes[normalizedPath] = hex.EncodeToString(sum[:])
|
w.lastAuthHashes[normalizedPath] = hex.EncodeToString(sum[:])
|
||||||
|
// Parse and cache auth content for future diff comparisons
|
||||||
|
var auth coreauth.Auth
|
||||||
|
if errParse := json.Unmarshal(data, &auth); errParse == nil {
|
||||||
|
w.lastAuthContents[normalizedPath] = &auth
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -127,6 +135,13 @@ func (w *Watcher) addOrUpdateClient(path string) {
|
|||||||
curHash := hex.EncodeToString(sum[:])
|
curHash := hex.EncodeToString(sum[:])
|
||||||
normalized := w.normalizeAuthPath(path)
|
normalized := w.normalizeAuthPath(path)
|
||||||
|
|
||||||
|
// Parse new auth content for diff comparison
|
||||||
|
var newAuth coreauth.Auth
|
||||||
|
if errParse := json.Unmarshal(data, &newAuth); errParse != nil {
|
||||||
|
log.Errorf("failed to parse auth file %s: %v", filepath.Base(path), errParse)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.clientsMutex.Lock()
|
w.clientsMutex.Lock()
|
||||||
|
|
||||||
cfg := w.config
|
cfg := w.config
|
||||||
@@ -141,7 +156,26 @@ func (w *Watcher) addOrUpdateClient(path string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get old auth for diff comparison
|
||||||
|
var oldAuth *coreauth.Auth
|
||||||
|
if w.lastAuthContents != nil {
|
||||||
|
oldAuth = w.lastAuthContents[normalized]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute and log field changes
|
||||||
|
if changes := diff.BuildAuthChangeDetails(oldAuth, &newAuth); len(changes) > 0 {
|
||||||
|
log.Debugf("auth field changes for %s:", filepath.Base(path))
|
||||||
|
for _, c := range changes {
|
||||||
|
log.Debugf(" %s", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update caches
|
||||||
w.lastAuthHashes[normalized] = curHash
|
w.lastAuthHashes[normalized] = curHash
|
||||||
|
if w.lastAuthContents == nil {
|
||||||
|
w.lastAuthContents = make(map[string]*coreauth.Auth)
|
||||||
|
}
|
||||||
|
w.lastAuthContents[normalized] = &newAuth
|
||||||
|
|
||||||
w.clientsMutex.Unlock() // Unlock before the callback
|
w.clientsMutex.Unlock() // Unlock before the callback
|
||||||
|
|
||||||
@@ -160,6 +194,7 @@ func (w *Watcher) removeClient(path string) {
|
|||||||
|
|
||||||
cfg := w.config
|
cfg := w.config
|
||||||
delete(w.lastAuthHashes, normalized)
|
delete(w.lastAuthHashes, normalized)
|
||||||
|
delete(w.lastAuthContents, normalized)
|
||||||
|
|
||||||
w.clientsMutex.Unlock() // Release the lock before the callback
|
w.clientsMutex.Unlock() // Release the lock before the callback
|
||||||
|
|
||||||
|
|||||||
44
internal/watcher/diff/auth_diff.go
Normal file
44
internal/watcher/diff/auth_diff.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// auth_diff.go computes human-readable diffs for auth file field changes.
|
||||||
|
package diff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildAuthChangeDetails computes a redacted, human-readable list of auth field changes.
|
||||||
|
// Only prefix, proxy_url, and disabled fields are tracked; sensitive data is never printed.
|
||||||
|
func BuildAuthChangeDetails(oldAuth, newAuth *coreauth.Auth) []string {
|
||||||
|
changes := make([]string, 0, 3)
|
||||||
|
|
||||||
|
// Handle nil cases by using empty Auth as default
|
||||||
|
if oldAuth == nil {
|
||||||
|
oldAuth = &coreauth.Auth{}
|
||||||
|
}
|
||||||
|
if newAuth == nil {
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare prefix
|
||||||
|
oldPrefix := strings.TrimSpace(oldAuth.Prefix)
|
||||||
|
newPrefix := strings.TrimSpace(newAuth.Prefix)
|
||||||
|
if oldPrefix != newPrefix {
|
||||||
|
changes = append(changes, fmt.Sprintf("prefix: %s -> %s", oldPrefix, newPrefix))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare proxy_url (redacted)
|
||||||
|
oldProxy := strings.TrimSpace(oldAuth.ProxyURL)
|
||||||
|
newProxy := strings.TrimSpace(newAuth.ProxyURL)
|
||||||
|
if oldProxy != newProxy {
|
||||||
|
changes = append(changes, fmt.Sprintf("proxy_url: %s -> %s", formatProxyURL(oldProxy), formatProxyURL(newProxy)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare disabled
|
||||||
|
if oldAuth.Disabled != newAuth.Disabled {
|
||||||
|
changes = append(changes, fmt.Sprintf("disabled: %t -> %t", oldAuth.Disabled, newAuth.Disabled))
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ type Watcher struct {
|
|||||||
reloadCallback func(*config.Config)
|
reloadCallback func(*config.Config)
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
lastAuthHashes map[string]string
|
lastAuthHashes map[string]string
|
||||||
|
lastAuthContents map[string]*coreauth.Auth
|
||||||
lastRemoveTimes map[string]time.Time
|
lastRemoveTimes map[string]time.Time
|
||||||
lastConfigHash string
|
lastConfigHash string
|
||||||
authQueue chan<- AuthUpdate
|
authQueue chan<- AuthUpdate
|
||||||
|
|||||||
Reference in New Issue
Block a user