[change] captcha deps
This commit is contained in:
parent
c243498b6a
commit
eb04060ffb
4 changed files with 49 additions and 95 deletions
3
go.mod
3
go.mod
|
|
@ -5,6 +5,7 @@ go 1.19
|
|||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/caarlos0/env/v6 v6.9.1
|
||||
github.com/dchest/captcha v1.0.0
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
|
|
@ -12,7 +13,6 @@ require (
|
|||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mojocn/base64Captcha v1.3.5
|
||||
github.com/pkoukk/tiktoken-go v0.1.0
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3
|
||||
github.com/spf13/cobra v1.2.1
|
||||
|
|
@ -49,7 +49,6 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
|
|
|
|||
7
go.sum
7
go.sum
|
|
@ -74,6 +74,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/captcha v1.0.0 h1:vw+bm/qMFvTgcjQlYVTuQBJkarm5R0YSsDKhm1HZI2o=
|
||||
github.com/dchest/captcha v1.0.0/go.mod h1:7zoElIawLp7GUMLcj54K9kbw+jEyvz2K0FDdRRYhvWo=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
|
||||
|
|
@ -124,8 +126,6 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
|
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
|
@ -304,8 +304,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
|
||||
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU=
|
||||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
|
|
@ -458,7 +456,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/mojocn/base64Captcha"
|
||||
"github.com/dchest/captcha"
|
||||
"github.com/yaoapp/gou/process"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
|
|
@ -12,7 +13,11 @@ import (
|
|||
"github.com/yaoapp/kun/maps"
|
||||
)
|
||||
|
||||
var captchaStore = base64Captcha.DefaultMemStore
|
||||
var store = captcha.NewMemoryStore(1024, 10*time.Minute)
|
||||
|
||||
func init() {
|
||||
captcha.SetCustomStore(store)
|
||||
}
|
||||
|
||||
// CaptchaOption 验证码配置
|
||||
type CaptchaOption struct {
|
||||
|
|
@ -29,7 +34,7 @@ func NewCaptchaOption() CaptchaOption {
|
|||
return CaptchaOption{
|
||||
Width: 240,
|
||||
Height: 80,
|
||||
Length: 4,
|
||||
Length: 6,
|
||||
Lang: "zh",
|
||||
Background: "#FFFFFF",
|
||||
}
|
||||
|
|
@ -47,95 +52,43 @@ func CaptchaMake(option CaptchaOption) (string, string) {
|
|||
}
|
||||
|
||||
if option.Length == 0 {
|
||||
option.Length = 4
|
||||
option.Length = 6
|
||||
}
|
||||
|
||||
if option.Lang == "" {
|
||||
option.Lang = "zh"
|
||||
}
|
||||
|
||||
var driver base64Captcha.Driver
|
||||
id := captcha.NewLen(option.Length)
|
||||
var data []byte
|
||||
var buff = bytes.NewBuffer(data)
|
||||
switch option.Type {
|
||||
|
||||
case "audio":
|
||||
driver = base64Captcha.NewDriverAudio(option.Length, option.Lang)
|
||||
break
|
||||
case "math":
|
||||
background := captchaBackground(option.Background)
|
||||
driver = base64Captcha.NewDriverMath(
|
||||
option.Height, option.Width, 3,
|
||||
base64Captcha.OptionShowHollowLine, background,
|
||||
base64Captcha.DefaultEmbeddedFonts, []string{},
|
||||
)
|
||||
break
|
||||
err := captcha.WriteAudio(buff, id, option.Lang)
|
||||
if err != nil {
|
||||
exception.New("make audio captcha error: %s", 500, err).Throw()
|
||||
}
|
||||
content := "data:audio/mp3;base64," + base64.StdEncoding.EncodeToString(buff.Bytes())
|
||||
log.Debug("ID:%s Audio Captcha:%s", id, toString(store.Get(id, false)))
|
||||
return id, content
|
||||
|
||||
default:
|
||||
driver = base64Captcha.NewDriverDigit(
|
||||
option.Height, option.Width, 5,
|
||||
0.7, 80,
|
||||
)
|
||||
break
|
||||
err := captcha.WriteImage(buff, id, option.Width, option.Height)
|
||||
if err != nil {
|
||||
exception.New("make image captcha error: %s", 500, err).Throw()
|
||||
}
|
||||
|
||||
content := "data:image/png;base64," + base64.StdEncoding.EncodeToString(buff.Bytes())
|
||||
log.Debug("ID:%s Image Captcha:%s", id, toString(store.Get(id, false)))
|
||||
return id, content
|
||||
}
|
||||
|
||||
c := base64Captcha.NewCaptcha(driver, captchaStore)
|
||||
id, content, err := c.Generate()
|
||||
if err != nil {
|
||||
exception.New("生成验证码出错 %s", 500, err).Throw()
|
||||
}
|
||||
|
||||
// 打印日志
|
||||
log.Debug("图形/音频 ID:%s 验证码:%s", id, captchaStore.Get(id, false))
|
||||
|
||||
return id, content
|
||||
}
|
||||
|
||||
// CaptchaValidate 校验验证码
|
||||
func CaptchaValidate(id string, value string) bool {
|
||||
return captchaStore.Verify(id, value, true)
|
||||
}
|
||||
|
||||
func captchaBackground(s string) *color.RGBA {
|
||||
if s == "" {
|
||||
s = "#555555"
|
||||
}
|
||||
bg, err := captchaParseHexColorFast(s)
|
||||
if err != nil {
|
||||
exception.New("背景色格式错误 %s", 400, s).Throw()
|
||||
}
|
||||
return &bg
|
||||
}
|
||||
|
||||
func captchaParseHexColorFast(s string) (c color.RGBA, err error) {
|
||||
c.A = 0xff
|
||||
|
||||
if s[0] != '#' {
|
||||
return c, errors.New("invalid format")
|
||||
}
|
||||
|
||||
hexToByte := func(b byte) byte {
|
||||
switch {
|
||||
case b >= '0' && b <= '9':
|
||||
return b - '0'
|
||||
case b >= 'a' && b <= 'f':
|
||||
return b - 'a' + 10
|
||||
case b >= 'A' && b <= 'F':
|
||||
return b - 'A' + 10
|
||||
}
|
||||
err = errors.New("invalid format")
|
||||
return 0
|
||||
}
|
||||
|
||||
switch len(s) {
|
||||
case 7:
|
||||
c.R = hexToByte(s[1])<<4 + hexToByte(s[2])
|
||||
c.G = hexToByte(s[3])<<4 + hexToByte(s[4])
|
||||
c.B = hexToByte(s[5])<<4 + hexToByte(s[6])
|
||||
case 4:
|
||||
c.R = hexToByte(s[1]) * 17
|
||||
c.G = hexToByte(s[2]) * 17
|
||||
c.B = hexToByte(s[3]) * 17
|
||||
default:
|
||||
err = errors.New("invalid format")
|
||||
}
|
||||
return
|
||||
func CaptchaValidate(id string, code string) bool {
|
||||
return captcha.VerifyString(id, code)
|
||||
}
|
||||
|
||||
// ProcessCaptchaValidate xiang.helper.CaptchaValidate 校验图形/音频验证码
|
||||
|
|
@ -160,7 +113,7 @@ func ProcessCaptcha(process *process.Process) interface{} {
|
|||
option := CaptchaOption{
|
||||
Width: any.Of(process.ArgsURLValue(0, "width", "240")).CInt(),
|
||||
Height: any.Of(process.ArgsURLValue(0, "height", "80")).CInt(),
|
||||
Length: any.Of(process.ArgsURLValue(0, "height", "4")).CInt(),
|
||||
Length: any.Of(process.ArgsURLValue(0, "height", "6")).CInt(),
|
||||
Type: process.ArgsURLValue(0, "type", "math"),
|
||||
Background: process.ArgsURLValue(0, "background", "#FFFFFF"),
|
||||
Lang: process.ArgsURLValue(0, "lang", "zh"),
|
||||
|
|
@ -171,3 +124,11 @@ func ProcessCaptcha(process *process.Process) interface{} {
|
|||
"content": content,
|
||||
}
|
||||
}
|
||||
|
||||
func toString(digits []byte) string {
|
||||
var buf bytes.Buffer
|
||||
for _, d := range digits {
|
||||
buf.WriteByte(d + '0')
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ func TestCaptcha(t *testing.T) {
|
|||
})
|
||||
assert.IsType(t, "string", id)
|
||||
assert.IsType(t, "string", content)
|
||||
captchaStore.Get(id, false)
|
||||
assert.True(t, CaptchaValidate(id, captchaStore.Get(id, false)))
|
||||
assert.True(t, CaptchaValidate(id, toString(store.Get(id, false))))
|
||||
|
||||
id, content = CaptchaMake(CaptchaOption{
|
||||
Type: "math",
|
||||
|
|
@ -31,8 +30,7 @@ func TestCaptcha(t *testing.T) {
|
|||
})
|
||||
assert.IsType(t, "string", id)
|
||||
assert.IsType(t, "string", content)
|
||||
captchaStore.Get(id, false)
|
||||
assert.True(t, CaptchaValidate(id, captchaStore.Get(id, false)))
|
||||
assert.True(t, CaptchaValidate(id, toString(store.Get(id, false))))
|
||||
|
||||
id, content = CaptchaMake(CaptchaOption{
|
||||
Type: "digit",
|
||||
|
|
@ -43,8 +41,7 @@ func TestCaptcha(t *testing.T) {
|
|||
})
|
||||
assert.IsType(t, "string", id)
|
||||
assert.IsType(t, "string", content)
|
||||
captchaStore.Get(id, false)
|
||||
assert.True(t, CaptchaValidate(id, captchaStore.Get(id, false)))
|
||||
assert.True(t, CaptchaValidate(id, toString(store.Get(id, false))))
|
||||
}
|
||||
|
||||
func TestProcessCaptcha(t *testing.T) {
|
||||
|
|
@ -56,7 +53,7 @@ func TestProcessCaptcha(t *testing.T) {
|
|||
assert.IsType(t, "string", res.Get("id"))
|
||||
assert.IsType(t, "string", res.Get("content"))
|
||||
|
||||
value := captchaStore.Get(res.Get("id").(string), false)
|
||||
value := toString(store.Get(res.Get("id").(string), false))
|
||||
p = process.New("xiang.helper.CaptchaValidate", res.Get("id"), value)
|
||||
assert.True(t, p.Run().(bool))
|
||||
assert.Panics(t, func() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue