mirror of
https://github.com/karust/openserp.git
synced 2026-08-12 11:53:29 +08:00
fix(captcha): exit non-zero on misconfig, tighten solver gate tests
This commit is contained in:
24
cmd/captcha_config.go
Normal file
24
cmd/captcha_config.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func resolveCaptchaSolverConfig() (bool, string, error) {
|
||||
apiKey := strings.TrimSpace(config.Config2Capcha.ApiKey)
|
||||
if !config.Captcha.SolverEnabled {
|
||||
if apiKey != "" {
|
||||
logrus.Warn("2captcha.apikey is set but captcha.solver_enabled=false; solver will not run")
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return false, "", fmt.Errorf("captcha solver is enabled (captcha.solver_enabled=true) but 2captcha.apikey is empty")
|
||||
}
|
||||
|
||||
return true, apiKey, nil
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
defaultConfigFilename = "config"
|
||||
envPrefix = "OPENSERP"
|
||||
)
|
||||
@@ -27,6 +27,7 @@ type Config struct {
|
||||
Resilience ResilienceConfig `mapstructure:"resilience"`
|
||||
CircuitBreaker CircuitBreakerConfig `mapstructure:"circuit_breaker"`
|
||||
CORS CORSConfig `mapstructure:"cors"`
|
||||
Captcha CaptchaConfig `mapstructure:"captcha"`
|
||||
Config2Capcha Config2Captcha `mapstructure:"2captcha"`
|
||||
GoogleConfig EngineConfig `mapstructure:"google"`
|
||||
YandexConfig EngineConfig `mapstructure:"yandex"`
|
||||
@@ -87,6 +88,10 @@ type CORSConfig struct {
|
||||
MaxAge int `mapstructure:"max_age"`
|
||||
}
|
||||
|
||||
type CaptchaConfig struct {
|
||||
SolverEnabled bool `mapstructure:"solver_enabled"`
|
||||
}
|
||||
|
||||
var config = Config{}
|
||||
|
||||
var flagToConfigKey = map[string]string{
|
||||
@@ -322,6 +327,7 @@ func setConfigDefaults(v *viper.Viper) {
|
||||
v.SetDefault("cors.allow_methods", "GET, POST, OPTIONS")
|
||||
v.SetDefault("cors.allow_headers", "Origin, Content-Type, Accept, Authorization, X-Use-Proxy")
|
||||
v.SetDefault("cors.max_age", 86400)
|
||||
v.SetDefault("captcha.solver_enabled", false)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -34,6 +35,12 @@ func search(cmd *cobra.Command, args []string) {
|
||||
Insecure: config.Server.Insecure,
|
||||
}
|
||||
|
||||
captchaSolverEnabled, captchaSolverAPIKey, err := resolveCaptchaSolverConfig()
|
||||
if err != nil {
|
||||
logrus.Errorf("Error validating captcha solver config: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
proxyRuntime := core.ProxyRuntimeBrowser
|
||||
if config.Server.IsRawRequests {
|
||||
proxyRuntime = core.ProxyRuntimeRaw
|
||||
@@ -65,7 +72,7 @@ func search(cmd *cobra.Command, args []string) {
|
||||
results, err = searchRaw(engineType, query)
|
||||
} else {
|
||||
logrus.Infof("Using browser mode for %s search", engineType)
|
||||
results, err = searchBrowser(engineType, query, selectedProxy)
|
||||
results, err = searchBrowser(engineType, query, selectedProxy, captchaSolverEnabled, captchaSolverAPIKey)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -84,7 +91,7 @@ func search(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
func searchBrowser(engineType string, query core.Query, browserProxyURL string) ([]core.SearchResult, error) {
|
||||
func searchBrowser(engineType string, query core.Query, browserProxyURL string, captchaSolverEnabled bool, captchaSolverAPIKey string) ([]core.SearchResult, error) {
|
||||
var engine core.SearchEngine
|
||||
if core.IsAuthenticatedSocksProxyURL(browserProxyURL) {
|
||||
return nil, fmt.Errorf(
|
||||
@@ -95,15 +102,16 @@ func searchBrowser(engineType string, query core.Query, browserProxyURL string)
|
||||
}
|
||||
|
||||
opts := core.BrowserOpts{
|
||||
IsHeadless: !config.App.IsBrowserHead,
|
||||
IsLeakless: config.App.IsLeakless,
|
||||
Timeout: time.Second * time.Duration(config.App.Timeout),
|
||||
LeavePageOpen: config.App.IsLeaveHead,
|
||||
CaptchaSolverApiKey: config.Config2Capcha.ApiKey,
|
||||
BrowserPath: config.App.BrowserPath,
|
||||
ProxyURL: browserProxyURL,
|
||||
Insecure: config.Server.Insecure,
|
||||
UseStealth: config.App.IsStealth,
|
||||
IsHeadless: !config.App.IsBrowserHead,
|
||||
IsLeakless: config.App.IsLeakless,
|
||||
Timeout: time.Second * time.Duration(config.App.Timeout),
|
||||
LeavePageOpen: config.App.IsLeaveHead,
|
||||
CaptchaSolverEnabled: captchaSolverEnabled,
|
||||
CaptchaSolverApiKey: captchaSolverAPIKey,
|
||||
BrowserPath: config.App.BrowserPath,
|
||||
ProxyURL: browserProxyURL,
|
||||
Insecure: config.Server.Insecure,
|
||||
UseStealth: config.App.IsStealth,
|
||||
}
|
||||
|
||||
if config.Server.IsDebug {
|
||||
|
||||
24
cmd/serve.go
24
cmd/serve.go
@@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -70,6 +71,12 @@ func serve(cmd *cobra.Command, args []string) {
|
||||
corsCfg.AllowHeaders = config.CORS.AllowHeaders
|
||||
corsCfg.MaxAge = config.CORS.MaxAge
|
||||
|
||||
captchaSolverEnabled, captchaSolverAPIKey, err := resolveCaptchaSolverConfig()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
proxyRuntime := core.ProxyRuntimeBrowser
|
||||
if config.Server.IsRawRequests {
|
||||
proxyRuntime = core.ProxyRuntimeRaw
|
||||
@@ -96,14 +103,15 @@ func serve(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
baseOpts := core.BrowserOpts{
|
||||
IsHeadless: !config.App.IsBrowserHead,
|
||||
IsLeakless: config.App.IsLeakless,
|
||||
Timeout: time.Second * time.Duration(config.App.Timeout),
|
||||
LeavePageOpen: config.App.IsLeaveHead,
|
||||
CaptchaSolverApiKey: config.Config2Capcha.ApiKey,
|
||||
BrowserPath: config.App.BrowserPath,
|
||||
Insecure: config.Server.Insecure,
|
||||
UseStealth: config.App.IsStealth,
|
||||
IsHeadless: !config.App.IsBrowserHead,
|
||||
IsLeakless: config.App.IsLeakless,
|
||||
Timeout: time.Second * time.Duration(config.App.Timeout),
|
||||
LeavePageOpen: config.App.IsLeaveHead,
|
||||
CaptchaSolverEnabled: captchaSolverEnabled,
|
||||
CaptchaSolverApiKey: captchaSolverAPIKey,
|
||||
BrowserPath: config.App.BrowserPath,
|
||||
Insecure: config.Server.Insecure,
|
||||
UseStealth: config.App.IsStealth,
|
||||
}
|
||||
if config.Server.IsDebug {
|
||||
baseOpts.IsHeadless = false
|
||||
|
||||
@@ -103,3 +103,69 @@ func TestValidateBrowserProxyPolicyRejectsTaggedAuthenticatedSocksInPool(t *test
|
||||
t.Fatalf("expected explicit authenticated SOCKS error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCaptchaSolverConfigDisabledWithoutKey(t *testing.T) {
|
||||
origEnabled := config.Captcha.SolverEnabled
|
||||
origKey := config.Config2Capcha.ApiKey
|
||||
defer func() {
|
||||
config.Captcha.SolverEnabled = origEnabled
|
||||
config.Config2Capcha.ApiKey = origKey
|
||||
}()
|
||||
|
||||
config.Captcha.SolverEnabled = false
|
||||
config.Config2Capcha.ApiKey = ""
|
||||
|
||||
enabled, key, err := resolveCaptchaSolverConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if enabled {
|
||||
t.Fatal("expected solver to be disabled")
|
||||
}
|
||||
if key != "" {
|
||||
t.Fatalf("expected empty solver key when disabled, got %q", key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCaptchaSolverConfigEnabledWithoutKeyFails(t *testing.T) {
|
||||
origEnabled := config.Captcha.SolverEnabled
|
||||
origKey := config.Config2Capcha.ApiKey
|
||||
defer func() {
|
||||
config.Captcha.SolverEnabled = origEnabled
|
||||
config.Config2Capcha.ApiKey = origKey
|
||||
}()
|
||||
|
||||
config.Captcha.SolverEnabled = true
|
||||
config.Config2Capcha.ApiKey = ""
|
||||
|
||||
_, _, err := resolveCaptchaSolverConfig()
|
||||
if err == nil {
|
||||
t.Fatal("expected missing API key error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "captcha solver is enabled") {
|
||||
t.Fatalf("expected clear startup error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCaptchaSolverConfigEnabledWithKey(t *testing.T) {
|
||||
origEnabled := config.Captcha.SolverEnabled
|
||||
origKey := config.Config2Capcha.ApiKey
|
||||
defer func() {
|
||||
config.Captcha.SolverEnabled = origEnabled
|
||||
config.Config2Capcha.ApiKey = origKey
|
||||
}()
|
||||
|
||||
config.Captcha.SolverEnabled = true
|
||||
config.Config2Capcha.ApiKey = "api-key"
|
||||
|
||||
enabled, key, err := resolveCaptchaSolverConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if !enabled {
|
||||
t.Fatal("expected solver to be enabled")
|
||||
}
|
||||
if key != "api-key" {
|
||||
t.Fatalf("expected configured API key, got %q", key)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user