This commit is contained in:
fatedier
2025-11-18 01:11:44 +08:00
committed by GitHub
parent 66973a03db
commit 15fd19a16d
6 changed files with 35 additions and 19 deletions

View File

@@ -39,6 +39,7 @@ linters:
- G404 - G404
- G501 - G501
- G115 - G115
- G204
severity: low severity: low
confidence: low confidence: low
govet: govet:

View File

@@ -78,7 +78,7 @@ func NewProxyCommand(name string, c v1.ProxyConfigurer, clientCfg *v1.ClientComm
os.Exit(1) os.Exit(1)
} }
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)} unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil { if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
@@ -108,7 +108,7 @@ func NewVisitorCommand(name string, c v1.VisitorConfigurer, clientCfg *v1.Client
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)} unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil { if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

View File

@@ -21,7 +21,6 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"slices"
"sync" "sync"
"syscall" "syscall"
"time" "time"
@@ -37,18 +36,12 @@ import (
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
) )
type UnsafeFeature = string
const (
TokenSourceExec UnsafeFeature = "TokenSourceExec"
)
var ( var (
cfgFile string cfgFile string
cfgDir string cfgDir string
showVersion bool showVersion bool
strictConfigMode bool strictConfigMode bool
allowUnsafe []UnsafeFeature allowUnsafe []string
) )
func init() { func init() {
@@ -56,7 +49,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory") rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc") rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors") rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow_unsafe", "", []string{}, "allowed unsafe features, one or more of: TokenSourceExec") rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow-unsafe", "", []string{}, "allowed unsafe features, one or more of: TokenSourceExec")
} }
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
@@ -68,7 +61,7 @@ var rootCmd = &cobra.Command{
return nil return nil
} }
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)} unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
// If cfgDir is not empty, run multiple frpc service for each config file in cfgDir. // If cfgDir is not empty, run multiple frpc service for each config file in cfgDir.
// Note that it's only designed for testing. It's not guaranteed to be stable. // Note that it's only designed for testing. It's not guaranteed to be stable.

View File

@@ -17,7 +17,6 @@ package sub
import ( import (
"fmt" "fmt"
"os" "os"
"slices"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -44,7 +43,7 @@ var verifyCmd = &cobra.Command{
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)} unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs, unsafeFeatures) warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs, unsafeFeatures)
if warning != nil { if warning != nil {
fmt.Printf("WARNING: %v\n", warning) fmt.Printf("WARNING: %v\n", warning)

View File

@@ -249,6 +249,22 @@ type VirtualNetConfig struct {
Address string `json:"address,omitempty"` Address string `json:"address,omitempty"`
} }
const (
UnsafeFeatureTokenSourceExec = "TokenSourceExec"
)
type UnsafeFeatures struct { type UnsafeFeatures struct {
TokenSourceExec bool features map[string]bool
}
func NewUnsafeFeatures(allowed []string) UnsafeFeatures {
features := make(map[string]bool)
for _, f := range allowed {
features[f] = true
}
return UnsafeFeatures{features: features}
}
func (u UnsafeFeatures) IsEnabled(feature string) bool {
return u.features[feature]
} }

View File

@@ -52,7 +52,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.Unsa
// Validate tokenSource if specified // Validate tokenSource if specified
if c.Auth.TokenSource != nil { if c.Auth.TokenSource != nil {
if c.Auth.TokenSource.Type == "exec" && !unsafeFeatures.TokenSourceExec { if c.Auth.TokenSource.Type == "exec" && !unsafeFeatures.IsEnabled(v1.UnsafeFeatureTokenSourceExec) {
errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.tokenSource.type")) errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.tokenSource.type"))
} }
if err := c.Auth.TokenSource.Validate(); err != nil { if err := c.Auth.TokenSource.Validate(); err != nil {
@@ -62,10 +62,12 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.Unsa
if c.Auth.OIDC.TokenSource != nil { if c.Auth.OIDC.TokenSource != nil {
// Validate oidc.tokenSource mutual exclusivity with other fields of oidc // Validate oidc.tokenSource mutual exclusivity with other fields of oidc
if c.Auth.OIDC.ClientID != "" || c.Auth.OIDC.ClientSecret != "" || c.Auth.OIDC.Audience != "" || c.Auth.OIDC.Scope != "" || c.Auth.OIDC.TokenEndpointURL != "" || len(c.Auth.OIDC.AdditionalEndpointParams) > 0 || c.Auth.OIDC.TrustedCaFile != "" || c.Auth.OIDC.InsecureSkipVerify || c.Auth.OIDC.ProxyURL != "" { if c.Auth.OIDC.ClientID != "" || c.Auth.OIDC.ClientSecret != "" || c.Auth.OIDC.Audience != "" ||
c.Auth.OIDC.Scope != "" || c.Auth.OIDC.TokenEndpointURL != "" || len(c.Auth.OIDC.AdditionalEndpointParams) > 0 ||
c.Auth.OIDC.TrustedCaFile != "" || c.Auth.OIDC.InsecureSkipVerify || c.Auth.OIDC.ProxyURL != "" {
errs = AppendError(errs, fmt.Errorf("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc")) errs = AppendError(errs, fmt.Errorf("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc"))
} }
if c.Auth.OIDC.TokenSource.Type == "exec" && !unsafeFeatures.TokenSourceExec { if c.Auth.OIDC.TokenSource.Type == "exec" && !unsafeFeatures.IsEnabled(v1.UnsafeFeatureTokenSourceExec) {
errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.oidc.tokenSource.type")) errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.oidc.tokenSource.type"))
} }
} }
@@ -114,7 +116,12 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.Unsa
return warnings, errs return warnings, errs
} }
func ValidateAllClientConfig(c *v1.ClientCommonConfig, proxyCfgs []v1.ProxyConfigurer, visitorCfgs []v1.VisitorConfigurer, unsafeFeatures v1.UnsafeFeatures) (Warning, error) { func ValidateAllClientConfig(
c *v1.ClientCommonConfig,
proxyCfgs []v1.ProxyConfigurer,
visitorCfgs []v1.VisitorConfigurer,
unsafeFeatures v1.UnsafeFeatures,
) (Warning, error) {
var warnings Warning var warnings Warning
if c != nil { if c != nil {
warning, err := ValidateClientCommonConfig(c, unsafeFeatures) warning, err := ValidateClientCommonConfig(c, unsafeFeatures)