85 lines
3.3 KiB
Go
85 lines
3.3 KiB
Go
package onboarding
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"data-terminal-cloud/internal/config"
|
||
|
|
"errors"
|
||
|
|
captcha "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/captcha/v20190722"
|
||
|
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||
|
|
"net/http/httptest"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
type fakeCaptchaAPI struct {
|
||
|
|
web, mini int
|
||
|
|
result int64
|
||
|
|
err error
|
||
|
|
t *testing.T
|
||
|
|
}
|
||
|
|
|
||
|
|
func (f *fakeCaptchaAPI) DescribeCaptchaResultWithContext(_ context.Context, r *captcha.DescribeCaptchaResultRequest) (*captcha.DescribeCaptchaResultResponse, error) {
|
||
|
|
f.web++
|
||
|
|
if *r.CaptchaAppId != 123 || *r.AppSecretKey != "web-secret-123456" || *r.Randstr != "random" || *r.CaptchaType != 9 {
|
||
|
|
f.t.Fatal("wrong web request")
|
||
|
|
}
|
||
|
|
return &captcha.DescribeCaptchaResultResponse{Response: &captcha.DescribeCaptchaResultResponseParams{CaptchaCode: common.Int64Ptr(f.result)}}, f.err
|
||
|
|
}
|
||
|
|
func (f *fakeCaptchaAPI) DescribeCaptchaMiniResultWithContext(_ context.Context, r *captcha.DescribeCaptchaMiniResultRequest) (*captcha.DescribeCaptchaMiniResultResponse, error) {
|
||
|
|
f.mini++
|
||
|
|
if *r.CaptchaAppId != 456 || *r.AppSecretKey != "mini-secret-12345" || *r.CaptchaType != 9 {
|
||
|
|
f.t.Fatal("wrong mini request")
|
||
|
|
}
|
||
|
|
return &captcha.DescribeCaptchaMiniResultResponse{Response: &captcha.DescribeCaptchaMiniResultResponseParams{CaptchaCode: common.Int64Ptr(f.result)}}, f.err
|
||
|
|
}
|
||
|
|
func TestTencentCaptchaProviderSeparatesClientsAndFailsClosed(t *testing.T) {
|
||
|
|
f := &fakeCaptchaAPI{t: t, result: 1}
|
||
|
|
p := &tencentCaptchaProvider{api: f, config: config.TencentCaptchaConfig{SaaS: config.CaptchaClientConfig{AppID: "123", AppSecretKey: "web-secret-123456"}, Mini: config.CaptchaClientConfig{AppID: "456", AppSecretKey: "mini-secret-12345"}}}
|
||
|
|
ctx := context.Background()
|
||
|
|
if err := p.Verify(ctx, "saas", "ticket", "random", "203.0.113.1"); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if err := p.Verify(ctx, "mini_program", "ticket", "", "203.0.113.1"); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if f.web != 1 || f.mini != 1 {
|
||
|
|
t.Fatal("wrong API")
|
||
|
|
}
|
||
|
|
for _, code := range []int64{0, 7, 8, 9, 21, 100} {
|
||
|
|
f.result = code
|
||
|
|
if p.Verify(ctx, "saas", "ticket", "random", "203.0.113.1") == nil {
|
||
|
|
t.Fatal("rejection accepted", code)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
f.result = 1
|
||
|
|
f.err = errors.New("contains-secret-value")
|
||
|
|
if err := p.Verify(ctx, "saas", "ticket", "random", "203.0.113.1"); err == nil || strings.Contains(err.Error(), "secret-value") {
|
||
|
|
t.Fatal("error must be closed and sanitized")
|
||
|
|
}
|
||
|
|
before := f.web
|
||
|
|
for _, ticket := range []string{"", "trerror_123", strings.Repeat("x", 4097)} {
|
||
|
|
if p.Verify(ctx, "saas", ticket, "random", "203.0.113.1") == nil {
|
||
|
|
t.Fatal("bad ticket accepted")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if f.web != before {
|
||
|
|
t.Fatal("bad ticket caused API call")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
func TestCaptchaClientIPTrustBoundary(t *testing.T) {
|
||
|
|
s := &Service{options: Options{TrustedProxyCIDRs: []string{"172.18.0.0/16"}}}
|
||
|
|
for _, tc := range []struct{ remote, forwarded, want string }{
|
||
|
|
{"203.0.113.9:123", "1.1.1.1", "203.0.113.9"},
|
||
|
|
{"172.18.0.4:123", "1.1.1.1, 203.0.113.9", "203.0.113.9"},
|
||
|
|
{"172.18.0.4:123", "203.0.113.9, 172.18.0.3", "203.0.113.9"},
|
||
|
|
{"[2001:db8::1]:123", "1.1.1.1", "2001:db8::1"},
|
||
|
|
} {
|
||
|
|
r := httptest.NewRequest("POST", "https://example.test", nil)
|
||
|
|
r.RemoteAddr = tc.remote
|
||
|
|
r.Header.Set("X-Forwarded-For", tc.forwarded)
|
||
|
|
if got := s.clientIP(r); got != tc.want {
|
||
|
|
t.Fatalf("ip %s want %s", got, tc.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|