Skip to content

Commit

Permalink
feat: add cloudflare turnstile captcha (casdoor#1327)
Browse files Browse the repository at this point in the history
* feat: add cloudflare turnstile captcha

* fix: rename turnstile to cloudflare turnstile
  • Loading branch information
YiNNx authored Nov 26, 2022
1 parent b7cd598 commit 5bb7a41
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
2 changes: 2 additions & 0 deletions captcha/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return NewAliyunCaptchaProvider()
} else if captchaType == "GEETEST" {
return NewGEETESTCaptchaProvider()
} else if captchaType == "Cloudflare Turnstile" {
return NewCloudflareTurnstileProvider()
}
return nil
}
Expand Down
66 changes: 66 additions & 0 deletions captcha/turnstile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package captcha

import (
"encoding/json"
"errors"
"io"
"net/http"
"net/url"
"strings"
)

const CloudflareTurnstileVerifyUrl = "https://challenges.cloudflare.com/turnstile/v0/siteverify"

type CloudflareTurnstileProvider struct{}

func NewCloudflareTurnstileProvider() *CloudflareTurnstileProvider {
captcha := &CloudflareTurnstileProvider{}
return captcha
}

func (captcha *CloudflareTurnstileProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
reqData := url.Values{
"secret": {clientSecret},
"response": {token},
}
resp, err := http.PostForm(CloudflareTurnstileVerifyUrl, reqData)
if err != nil {
return false, err
}

defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}

type captchaResponse struct {
Success bool `json:"success"`
ErrorCodes []string `json:"error-codes"`
}
captchaResp := &captchaResponse{}
err = json.Unmarshal(body, captchaResp)
if err != nil {
return false, err
}

if len(captchaResp.ErrorCodes) > 0 {
return false, errors.New(strings.Join(captchaResp.ErrorCodes, ","))
}

return captchaResp.Success, nil
}
5 changes: 5 additions & 0 deletions web/src/Setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_geetest.png`,
url: "https://www.geetest.com",
},
"Cloudflare Turnstile": {
logo: `${StaticBaseUrl}/img/social_cloudflare.png`,
url: "https://www.cloudflare.com/products/turnstile/",
},
},
};

Expand Down Expand Up @@ -695,6 +699,7 @@ export function getProviderTypeOptions(category) {
{id: "hCaptcha", name: "hCaptcha"},
{id: "Aliyun Captcha", name: "Aliyun Captcha"},
{id: "GEETEST", name: "GEETEST"},
{id: "Cloudflare Turnstile", name: "Cloudflare Turnstile"},
]);
} else {
return [];
Expand Down
15 changes: 15 additions & 0 deletions web/src/common/CaptchaWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ export const CaptchaWidget = ({captchaType, subType, siteKey, clientSecret, onCh
}, 500);
break;
}
case "Cloudflare Turnstile": {
const tTimer = setInterval(() => {
if (!window.turnstile) {
loadScript("https://challenges.cloudflare.com/turnstile/v0/api.js");
}
if (window.turnstile && window.turnstile.render) {
window.turnstile.render("#captcha", {
sitekey: siteKey,
callback: onChange,
});
clearInterval(tTimer);
}
}, 300);
break;
}
default:
break;
}
Expand Down

0 comments on commit 5bb7a41

Please sign in to comment.