diff --git a/README.md b/README.md index 643896e1b..1aaaaeae7 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,7 @@ SiYuan is made possible by the following open source projects. * [https://github.com/siyuan-note/encryption](https://github.com/siyuan-note/encryption) `Mulan PSL v2` * [https://github.com/siyuan-note/filelock](https://github.com/siyuan-note/filelock) `Mulan PSL v2` * [https://github.com/siyuan-note/httpclient](https://github.com/siyuan-note/httpclient) `Mulan PSL v2` +* [https://github.com/steambap/captcha](https://github.com/steambap/captcha) `MIT License` * [https://github.com/vmihailenco/msgpack](https://github.com/vmihailenco/msgpack) `BSD-2-Clause License` * [https://github.com/xrash/smetrics](https://github.com/xrash/smetrics) `MIT License` * [https://github.com/microsoft/TypeScript](https://github.com/microsoft/TypeScript) `Apache-2.0 License` diff --git a/README_zh_CN.md b/README_zh_CN.md index 34b8c5949..e61203969 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -305,6 +305,7 @@ * [https://github.com/siyuan-note/encryption](https://github.com/siyuan-note/encryption) `Mulan PSL v2` * [https://github.com/siyuan-note/filelock](https://github.com/siyuan-note/filelock) `Mulan PSL v2` * [https://github.com/siyuan-note/httpclient](https://github.com/siyuan-note/httpclient) `Mulan PSL v2` +* [https://github.com/steambap/captcha](https://github.com/steambap/captcha) `MIT License` * [https://github.com/vmihailenco/msgpack](https://github.com/vmihailenco/msgpack) `BSD-2-Clause License` * [https://github.com/xrash/smetrics](https://github.com/xrash/smetrics) `MIT License` * [https://github.com/microsoft/TypeScript](https://github.com/microsoft/TypeScript) `Apache-2.0 License` diff --git a/app/guide/20210808180117-6v0mkxr/20201121224345-rc27qvo.sy b/app/guide/20210808180117-6v0mkxr/20201121224345-rc27qvo.sy index 567995548..09be989f3 100644 --- a/app/guide/20210808180117-6v0mkxr/20201121224345-rc27qvo.sy +++ b/app/guide/20210808180117-6v0mkxr/20201121224345-rc27qvo.sy @@ -6,7 +6,7 @@ "id": "20201121224345-rc27qvo", "title": "Acknowledgements", "type": "doc", - "updated": "20220714213452" + "updated": "20220716105832" }, "Children": [ { @@ -29,7 +29,7 @@ "ListData": {}, "Properties": { "id": "20220522101213-z3hokh2", - "updated": "20220714213452" + "updated": "20220716105832" }, "Children": [ { @@ -2831,6 +2831,76 @@ } ] }, + { + "ID": "20220716105829-vbod5lq", + "Type": "NodeListItem", + "ListData": { + "BulletChar": 42, + "Marker": "Kg==" + }, + "Properties": { + "id": "20220716105829-vbod5lq", + "updated": "20220716105832" + }, + "Children": [ + { + "ID": "20220716105829-ogsmwn0", + "Type": "NodeParagraph", + "Properties": { + "id": "20220716105829-ogsmwn0", + "updated": "20220716105832" + }, + "Children": [ + { + "Type": "NodeLink", + "Data": "span", + "Children": [ + { + "Type": "NodeOpenBracket" + }, + { + "Type": "NodeLinkText", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseBracket" + }, + { + "Type": "NodeOpenParen" + }, + { + "Type": "NodeLinkDest", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseParen" + } + ] + }, + { + "Type": "NodeText", + "Data": " " + }, + { + "Type": "NodeCodeSpan", + "Data": "code", + "Children": [ + { + "Type": "NodeCodeSpanOpenMarker" + }, + { + "Type": "NodeCodeSpanContent", + "Data": "MIT License" + }, + { + "Type": "NodeCodeSpanCloseMarker" + } + ] + } + ] + } + ] + }, { "ID": "20220522101213-wxfscvi", "Type": "NodeListItem", diff --git a/app/guide/20210808180117-czj9bvb/20201121212605-9td1a62.sy b/app/guide/20210808180117-czj9bvb/20201121212605-9td1a62.sy index d95e6653f..416cc69db 100644 --- a/app/guide/20210808180117-czj9bvb/20201121212605-9td1a62.sy +++ b/app/guide/20210808180117-czj9bvb/20201121212605-9td1a62.sy @@ -6,7 +6,7 @@ "id": "20201121212605-9td1a62", "title": "致谢", "type": "doc", - "updated": "20220714214930" + "updated": "20220716105842" }, "Children": [ { @@ -29,7 +29,7 @@ "ListData": {}, "Properties": { "id": "20220522101224-ctmcj3d", - "updated": "20220714214930" + "updated": "20220716105842" }, "Children": [ { @@ -2901,6 +2901,76 @@ } ] }, + { + "ID": "20220716105842-riuwgbq", + "Type": "NodeListItem", + "ListData": { + "BulletChar": 42, + "Marker": "Kg==" + }, + "Properties": { + "id": "20220716105842-riuwgbq", + "updated": "20220716105842" + }, + "Children": [ + { + "ID": "20220716105842-c8od9nd", + "Type": "NodeParagraph", + "Properties": { + "id": "20220716105842-c8od9nd", + "updated": "20220716105842" + }, + "Children": [ + { + "Type": "NodeLink", + "Data": "span", + "Children": [ + { + "Type": "NodeOpenBracket" + }, + { + "Type": "NodeLinkText", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseBracket" + }, + { + "Type": "NodeOpenParen" + }, + { + "Type": "NodeLinkDest", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseParen" + } + ] + }, + { + "Type": "NodeText", + "Data": " " + }, + { + "Type": "NodeCodeSpan", + "Data": "code", + "Children": [ + { + "Type": "NodeCodeSpanOpenMarker" + }, + { + "Type": "NodeCodeSpanContent", + "Data": "MIT License" + }, + { + "Type": "NodeCodeSpanCloseMarker" + } + ] + } + ] + } + ] + }, { "ID": "20220522101224-4u2mzml", "Type": "NodeListItem", diff --git a/app/guide/20211226090932-5lcq56f/20211226114929-08ap1r0.sy b/app/guide/20211226090932-5lcq56f/20211226114929-08ap1r0.sy index 3f81c76e4..0811393cb 100644 --- a/app/guide/20211226090932-5lcq56f/20211226114929-08ap1r0.sy +++ b/app/guide/20211226090932-5lcq56f/20211226114929-08ap1r0.sy @@ -5,7 +5,7 @@ "icon": "1f64f", "id": "20211226114929-08ap1r0", "title": "致謝", - "updated": "20220714214924" + "updated": "20220716105852" }, "Children": [ { @@ -28,7 +28,7 @@ "ListData": {}, "Properties": { "id": "20220326092650-r61gazd", - "updated": "20220714214924" + "updated": "20220716105852" }, "Children": [ { @@ -2900,6 +2900,76 @@ } ] }, + { + "ID": "20220716105851-g73ysy4", + "Type": "NodeListItem", + "ListData": { + "BulletChar": 42, + "Marker": "Kg==" + }, + "Properties": { + "id": "20220716105851-g73ysy4", + "updated": "20220716105852" + }, + "Children": [ + { + "ID": "20220716105851-yzv7qyo", + "Type": "NodeParagraph", + "Properties": { + "id": "20220716105851-yzv7qyo", + "updated": "20220716105852" + }, + "Children": [ + { + "Type": "NodeLink", + "Data": "span", + "Children": [ + { + "Type": "NodeOpenBracket" + }, + { + "Type": "NodeLinkText", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseBracket" + }, + { + "Type": "NodeOpenParen" + }, + { + "Type": "NodeLinkDest", + "Data": "https://github.com/steambap/captcha" + }, + { + "Type": "NodeCloseParen" + } + ] + }, + { + "Type": "NodeText", + "Data": " " + }, + { + "Type": "NodeCodeSpan", + "Data": "code", + "Children": [ + { + "Type": "NodeCodeSpanOpenMarker" + }, + { + "Type": "NodeCodeSpanContent", + "Data": "MIT License" + }, + { + "Type": "NodeCodeSpanCloseMarker" + } + ] + } + ] + } + ] + }, { "ID": "20220522101113-k9lx1nj", "Type": "NodeListItem", diff --git a/app/stage/auth.html b/app/stage/auth.html index 8cedecaa2..fba03eaad 100644 --- a/app/stage/auth.html +++ b/app/stage/auth.html @@ -437,7 +437,7 @@ } else { exitApp() } - }).catch(() =>{ + }).catch(() => { exitApp() }) } catch (e) { @@ -462,15 +462,16 @@ }).then((response) => { if (0 === response.code) { window.location.href = '/' - } else { - document.querySelector('#message').classList.add('b3-snackbar--show') - document.querySelector('#message').firstElementChild.textContent = response.msg - inputElement.value = '' - setTimeout(() => { - document.querySelector('#message').classList.remove('b3-snackbar--show') - document.querySelector('#message').firstElementChild.textContent = '' - }, 6000) + return } + + document.querySelector('#message').classList.add('b3-snackbar--show') + document.querySelector('#message').firstElementChild.textContent = response.msg + inputElement.value = '' + setTimeout(() => { + document.querySelector('#message').classList.remove('b3-snackbar--show') + document.querySelector('#message').firstElementChild.textContent = '' + }, 6000) }) } diff --git a/kernel/api/router.go b/kernel/api/router.go index 370dcf34c..c2d845914 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -32,6 +32,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/system/uiproc", addUIProcess) ginServer.Handle("POST", "/api/system/loginAuth", model.LoginAuth) ginServer.Handle("POST", "/api/system/logoutAuth", model.LogoutAuth) + ginServer.Handle("GET", "/api/system/getCaptcha", model.GetCaptcha) // 需要鉴权 diff --git a/kernel/cache/asset.go b/kernel/cache/asset.go index 13d5ebc55..ed1c87742 100644 --- a/kernel/cache/asset.go +++ b/kernel/cache/asset.go @@ -45,7 +45,7 @@ func LoadAssets() { } return nil } - if strings.HasSuffix(info.Name(), ".sya") { + if strings.HasSuffix(info.Name(), ".sya") || strings.HasPrefix(info.Name(), ".") { return nil } diff --git a/kernel/go.mod b/kernel/go.mod index 6ec979f0c..b4dc07f48 100644 --- a/kernel/go.mod +++ b/kernel/go.mod @@ -44,6 +44,7 @@ require ( github.com/siyuan-note/eventbus v0.0.0-20220624162334-ca7c06dc771f github.com/siyuan-note/filelock v0.0.0-20220704090116-54dfb035283f github.com/siyuan-note/httpclient v0.0.0-20220709030145-2bfb50f28e73 + github.com/steambap/captcha v1.4.1 github.com/vmihailenco/msgpack/v5 v5.3.5 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 golang.org/x/image v0.0.0-20220617043117-41969df76e82 @@ -68,6 +69,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/goccy/go-json v0.9.8 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/glog v1.0.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect diff --git a/kernel/go.sum b/kernel/go.sum index b60494d95..2e1f1619a 100644 --- a/kernel/go.sum +++ b/kernel/go.sum @@ -199,6 +199,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +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/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -537,6 +539,8 @@ github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t6 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/steambap/captcha v1.4.1 h1:OmMdxLCWCqJvsFaFYwRpvMckIuvI6s8s1LsBrBw97P0= +github.com/steambap/captcha v1.4.1/go.mod h1:oC9T7IfEgnrhzjDz5Djf1H7GPffCzRMbsQfFkJmhlnk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -621,6 +625,7 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/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-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw= golang.org/x/image v0.0.0-20220617043117-41969df76e82/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/kernel/model/session.go b/kernel/model/session.go index 11089b034..0a634fdaf 100644 --- a/kernel/model/session.go +++ b/kernel/model/session.go @@ -24,6 +24,7 @@ import ( ginSessions "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" "github.com/siyuan-note/siyuan/kernel/util" + "github.com/steambap/captcha" ) func LogoutAuth(c *gin.Context) { @@ -53,27 +54,85 @@ func LogoutAuth(c *gin.Context) { func LoginAuth(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) + arg, ok := util.JsonArg(c, ret) if !ok { return } + var inputCaptcha string + session := util.GetSession(c) + if session.NeedCaptcha() { + _ = inputCaptcha + //captchaArg := arg["captcha"] + //if nil == captchaArg { + // c.Status(400) + // ret.Code = -1 + // ret.Msg = "need input captcha" + // return + //} + //inputCaptcha = captchaArg.(string) + // + //if session.Captcha != inputCaptcha { + // ret.Code = -1 + // ret.Msg = "invalid captcha" + // return + //} + } + authCode := arg["authCode"].(string) if Conf.AccessAuthCode != authCode { ret.Code = -1 ret.Msg = Conf.Language(83) + + session.WrongAuthCount++ + session.Captcha = gulu.Rand.String(7) + if session.NeedCaptcha() { + ret.Code = 1 // 需要渲染验证码 + } + + if err := session.Save(c); nil != err { + util.LogErrorf("save session failed: " + err.Error()) + c.Status(500) + return + } return } - session := &util.SessionData{ID: gulu.Rand.Int(0, 1024), AccessAuthCode: authCode} + session.AccessAuthCode = authCode + session.WrongAuthCount = 0 + session.Captcha = gulu.Rand.String(7) if err := session.Save(c); nil != err { - util.LogErrorf("saves session failed: " + err.Error()) - ret.Code = -1 - ret.Msg = "save session failed" + util.LogErrorf("save session failed: " + err.Error()) + c.Status(500) return } } +func GetCaptcha(c *gin.Context) { + img, err := captcha.NewMathExpr(150, 30) + if nil != err { + util.LogErrorf("generates captcha failed: " + err.Error()) + c.Status(500) + return + } + + session := util.GetSession(c) + session.Captcha = img.Text + if err = session.Save(c); nil != err { + util.LogErrorf("save session failed: " + err.Error()) + c.Status(500) + return + } + + if err = img.WriteImage(c.Writer); nil != err { + util.LogErrorf("writes captcha image failed: " + err.Error()) + c.Status(500) + return + } + c.Status(200) +} + func CheckReadonly(c *gin.Context) { if util.ReadOnly { result := util.NewResult() diff --git a/kernel/util/session.go b/kernel/util/session.go index fa663f4f5..1dfb66ae8 100644 --- a/kernel/util/session.go +++ b/kernel/util/session.go @@ -26,6 +26,12 @@ import ( type SessionData struct { ID int AccessAuthCode string + WrongAuthCount int + Captcha string +} + +func (sd *SessionData) NeedCaptcha() bool { + return 3 < sd.WrongAuthCount } // Save saves the current session of the specified context.