mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-04 17:16:37 +08:00
fix(backend): allow WHMCS API login when captcha is enabled
This commit is contained in:
@@ -219,7 +219,7 @@ func (h *Handler) login(w http.ResponseWriter, r *http.Request) {
|
|||||||
response.WriteJSON(w, response.Err(-2, err.Error()))
|
response.WriteJSON(w, response.Err(-2, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if captchaEnabled {
|
if captchaEnabled && !h.apiClientCaptchaBypassEnabled(r) {
|
||||||
captchaID := strings.TrimSpace(req.CaptchaID)
|
captchaID := strings.TrimSpace(req.CaptchaID)
|
||||||
if captchaID == "" {
|
if captchaID == "" {
|
||||||
response.WriteJSON(w, response.ErrDefault("验证码校验失败"))
|
response.WriteJSON(w, response.ErrDefault("验证码校验失败"))
|
||||||
@@ -988,21 +988,24 @@ func (h *Handler) captchaEnabled() (bool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if cfg == nil || !strings.EqualFold(cfg.Value, "true") {
|
if cfg == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
return strings.EqualFold(cfg.Value, "true"), nil
|
||||||
|
}
|
||||||
|
|
||||||
// captcha_enabled=true, but we need to verify cloudflare_secret_key is configured
|
func (h *Handler) apiClientCaptchaBypassEnabled(r *http.Request) bool {
|
||||||
// If secret key is not configured, treat captcha as disabled to avoid blocking login
|
if r == nil {
|
||||||
secretKey, err := h.repo.GetConfigByName("cloudflare_secret_key")
|
return false
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if secretKey == nil || strings.TrimSpace(secretKey.Value) == "" {
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
client := strings.ToLower(strings.TrimSpace(r.Header.Get("X-FLVX-API-Client")))
|
||||||
|
switch client {
|
||||||
|
case "whmcs", "whmcs-module":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) markCaptchaToken(token string) {
|
func (h *Handler) markCaptchaToken(token string) {
|
||||||
|
|||||||
@@ -45,6 +45,18 @@ func TestCaptchaVerifyLoginContract(t *testing.T) {
|
|||||||
assertCodeMsg(t, resp, -1, "验证码校验失败")
|
assertCodeMsg(t, resp, -1, "验证码校验失败")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("whmcs api client bypasses captcha", func(t *testing.T) {
|
||||||
|
body := bytes.NewBufferString(`{"username":"admin_user","password":"admin_user","captchaId":""}`)
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/user/login", body)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("X-FLVX-API-Client", "whmcs")
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
|
||||||
|
router.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
assertCode(t, resp, 0)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("captcha token is one-time and consumed by login", func(t *testing.T) {
|
t.Run("captcha token is one-time and consumed by login", func(t *testing.T) {
|
||||||
verifyReq := httptest.NewRequest(http.MethodPost, "/api/v1/captcha/verify", bytes.NewBufferString(`{"id":"captcha-token-1","data":"ok"}`))
|
verifyReq := httptest.NewRequest(http.MethodPost, "/api/v1/captcha/verify", bytes.NewBufferString(`{"id":"captcha-token-1","data":"ok"}`))
|
||||||
verifyReq.Header.Set("Content-Type", "application/json")
|
verifyReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|||||||
Reference in New Issue
Block a user