Filtering of synchronized secrets on collection, organization, and/or folder (#12)

* Filtering feature, minor logic changes
+: Add IP validation (to properly log IP even when trusted proxy is missing)
+: Added synchronization of decrypted organization, collection, and folder names (for filtering purposes)
+: Changed sync behavior to prevent collapsing multiple logins with the same name
+: Added possibility to filter logins based on organization, collection, and folder name/id in GetSecret
+: Added support for space character in secret name validation (it is also properly URL-decoded)

* Update README

* Fixes related to issues reported by CodeRabbit:
+: Changed british use of organisations in README
+: Reduced line count in parseSecretFilters by including helper function for filter dimensions resolution
+: Added comment clarifying absence of existence checking on dimension IDs as opposed to names
+: Removed efensive comma split logic on IPs (redundant due to IPValidation setting on Fiber)
+: Changed Query validator to align with name validator (mainly removing hard-coded values)
+: Added comments to decryptVaultLabel for clarity
+: Change empty SyncNameMaps instance with emptySyncNameMaps helper for consistency
+: Add lexical sort for lookupIDByName for deterministic result in case of multiple matches

* Bumped logging to warn and added entity metadata in log

* Unit tests:
+: Added unit tests for every newly introduced or changed function
+: Rewrote NewClient constructor to accept optional preloaded data (so it can be used in test scenarios)

* Changes requested by CodeRabbit
This commit is contained in:
Jethro Young authored and GitHub committed 2026-05-20 23:26:29 +02:00
1 parent cac042a5c4
commit 76b82d4dba
11 files changed
+1174 -88

No files matched your search

+10 -23
View File
@@ -10,18 +10,18 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/Turbootzz/vaultwarden-api/pkg/logger"
"github.com/gofiber/fiber/v2"
)
// IPWhitelist manages IP-based access control
type IPWhitelist struct {
mu sync.RWMutex
allowedIPs map[string]bool
allowedCIDRs []*net.IPNet
githubIPRanges []*net.IPNet
enableGitHub bool
lastGitHubUpdate time.Time
mu sync.RWMutex
allowedIPs map[string]bool
allowedCIDRs []*net.IPNet
githubIPRanges []*net.IPNet
enableGitHub bool
lastGitHubUpdate time.Time
}
// GitHubMeta represents GitHub's API response for IP ranges
@@ -86,27 +86,14 @@ func (wl *IPWhitelist) Middleware() fiber.Handler {
return c.Next()
}
// Get client IP from Fiber
clientIP := c.IP()
// If c.IP() returns comma-separated IPs, parse them manually
// This happens when Fiber doesn't parse X-Forwarded-For despite TrustedProxies config
// We take the FIRST IP (leftmost = original client, rightmost = trusted proxy)
var realClientIP string
if strings.Contains(clientIP, ",") {
ips := strings.Split(clientIP, ",")
// Take first IP (original client before any proxies)
realClientIP = strings.TrimSpace(ips[0])
} else {
realClientIP = clientIP
}
if wl.IsAllowed(realClientIP) {
logger.Debug.Printf("IP allowed: %s", realClientIP)
if wl.IsAllowed(clientIP) {
logger.Debug.Printf("IP allowed: %s", clientIP)
return c.Next()
}
logger.Warn.Printf("IP blocked (not whitelisted): %s on %s %s", realClientIP, c.Method(), c.Path())
logger.Warn.Printf("IP blocked (not whitelisted): %s on %s %s", clientIP, c.Method(), c.Path())
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "access denied: IP not whitelisted",
})