mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-22 18:25:47 +08:00
116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
// 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"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/casdoor/casdoor/util"
|
|
)
|
|
|
|
const AliyunCaptchaVerifyUrl = "http://afs.aliyuncs.com"
|
|
|
|
type captchaSuccessResponse struct {
|
|
Code int `json:"Code"`
|
|
Msg string `json:"Msg"`
|
|
}
|
|
|
|
type captchaFailResponse struct {
|
|
Code string `json:"Code"`
|
|
Message string `json:"Message"`
|
|
}
|
|
|
|
type AliyunCaptchaProvider struct{}
|
|
|
|
func NewAliyunCaptchaProvider() *AliyunCaptchaProvider {
|
|
captcha := &AliyunCaptchaProvider{}
|
|
return captcha
|
|
}
|
|
|
|
func contentEscape(str string) string {
|
|
str = strings.Replace(str, " ", "%20", -1)
|
|
str = url.QueryEscape(str)
|
|
return str
|
|
}
|
|
|
|
func (captcha *AliyunCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
|
|
pathData, err := url.ParseQuery(token)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
pathData["Action"] = []string{"AuthenticateSig"}
|
|
pathData["Format"] = []string{"json"}
|
|
pathData["SignatureMethod"] = []string{"HMAC-SHA1"}
|
|
pathData["SignatureNonce"] = []string{strconv.FormatInt(time.Now().UnixNano(), 10)}
|
|
pathData["SignatureVersion"] = []string{"1.0"}
|
|
pathData["Timestamp"] = []string{time.Now().UTC().Format("2006-01-02T15:04:05Z")}
|
|
pathData["Version"] = []string{"2018-01-12"}
|
|
|
|
var keys []string
|
|
for k := range pathData {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
sortQuery := ""
|
|
for _, k := range keys {
|
|
sortQuery += k + "=" + contentEscape(pathData[k][0]) + "&"
|
|
}
|
|
sortQuery = strings.TrimSuffix(sortQuery, "&")
|
|
|
|
stringToSign := fmt.Sprintf("GET&%s&%s", url.QueryEscape("/"), url.QueryEscape(sortQuery))
|
|
|
|
signature := util.GetHmacSha1(clientSecret+"&", stringToSign)
|
|
|
|
resp, err := http.Get(fmt.Sprintf("%s?%s&Signature=%s", AliyunCaptchaVerifyUrl, sortQuery, url.QueryEscape(signature)))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return handleCaptchaResponse(body)
|
|
}
|
|
|
|
func handleCaptchaResponse(body []byte) (bool, error) {
|
|
captchaResp := &captchaSuccessResponse{}
|
|
err := json.Unmarshal(body, captchaResp)
|
|
if err != nil {
|
|
captchaFailResp := &captchaFailResponse{}
|
|
err = json.Unmarshal(body, captchaFailResp)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return false, errors.New(captchaFailResp.Message)
|
|
}
|
|
|
|
return true, nil
|
|
}
|