add checkPassword to reset password by sms code (#378)

* add logout v2 for sso

* support sms-code login

* use db instead of memory cache for login code

* feature: support reset password by sms code

* remove deprecated api/code

* feature: support image captcha

* use db instead of memory cache for sso.auth.state

* add authLogin for login, v1/login; support (*)[.local].tpl for tpl file

* add username to sms-code api
This commit is contained in:
yubo 2020-11-05 12:20:02 +08:00 committed by GitHub
parent 2bcb20d710
commit df55398100
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 33 deletions

View File

@ -29,6 +29,9 @@ var (
errUnsupportCaptcha = errors.New("unsupported captcha") errUnsupportCaptcha = errors.New("unsupported captcha")
errInvalidAnswer = errors.New("Invalid captcha answer") errInvalidAnswer = errors.New("Invalid captcha answer")
// TODO: set false
debug = true
// https://captcha.mojotv.cn // https://captcha.mojotv.cn
captchaDirver = base64Captcha.DriverString{ captchaDirver = base64Captcha.DriverString{
Height: 30, Height: 30,
@ -128,6 +131,7 @@ type authRedirect struct {
func authAuthorizeV2(c *gin.Context) { func authAuthorizeV2(c *gin.Context) {
redirect := queryStr(c, "redirect", "/") redirect := queryStr(c, "redirect", "/")
log.Printf("---> redirect %s", redirect)
ret := &authRedirect{Redirect: redirect} ret := &authRedirect{Redirect: redirect}
username := cookieUsername(c) username := cookieUsername(c)
@ -236,6 +240,8 @@ func v1Login(c *gin.Context) {
user, err := authLogin(f) user, err := authLogin(f)
renderData(c, *user, err) renderData(c, *user, err)
go models.LoginLogNew(user.Username, f.RemoteAddr, "in")
} }
// authLogin called by /v1/rdb/login, /api/rdb/auth/login // authLogin called by /v1/rdb/login, /api/rdb/auth/login
@ -298,10 +304,11 @@ func v1SendLoginCodeBySms(c *gin.Context) {
return "", err return "", err
} }
// log.Printf("[sms -> %s] %s", phone, buf.String()) if debug {
return fmt.Sprintf("[debug]: %s", buf.String()), nil
}
// TODO: remove code from msg return "successed", nil
return fmt.Sprintf("[debug] msg: %s", buf.String()), nil
}() }()
renderData(c, msg, err) renderData(c, msg, err)
@ -344,22 +351,24 @@ func v1SendLoginCodeByEmail(c *gin.Context) {
return "", err return "", err
} }
err := redisc.Write(&dataobj.Message{ if err := redisc.Write(&dataobj.Message{
Tos: []string{email}, Tos: []string{email},
Content: buf.String(), Content: buf.String(),
}, config.SMS_QUEUE_NAME) }, config.SMS_QUEUE_NAME); err != nil {
return "", err
// log.Printf("[email -> %s] %s", email, buf.String()) }
// TODO: remove code from msg
return fmt.Sprintf("[debug] msg: %s", buf.String()), err
if debug {
return fmt.Sprintf("[debug]: %s", buf.String()), nil
}
return "successed", nil
}() }()
renderData(c, msg, err) renderData(c, msg, err)
} }
type sendRstCodeBySmsInput struct { type sendRstCodeBySmsInput struct {
Phone string `json:"phone"` Username string `json:"username"`
Phone string `json:"phone"`
} }
func sendRstCodeBySms(c *gin.Context) { func sendRstCodeBySms(c *gin.Context) {
@ -371,9 +380,9 @@ func sendRstCodeBySms(c *gin.Context) {
return "", fmt.Errorf("sms sender is disabled") return "", fmt.Errorf("sms sender is disabled")
} }
phone := f.Phone phone := f.Phone
user, _ := models.UserGet("phone=?", phone) user, _ := models.UserGet("username=? and phone=?", f.Username, phone)
if user == nil { if user == nil {
return "", fmt.Errorf("phone %s dose not exist", phone) return "", fmt.Errorf("user %s phone %s dose not exist", f.Username, phone)
} }
// general a random code and add cache // general a random code and add cache
@ -402,51 +411,61 @@ func sendRstCodeBySms(c *gin.Context) {
return "", err return "", err
} }
// log.Printf("[sms -> %s] %s", phone, buf.String()) if debug {
return fmt.Sprintf("[debug] msg: %s", buf.String()), nil
}
// TODO: remove code from msg return "successed", nil
return fmt.Sprintf("[debug] msg: %s", buf.String()), nil
}() }()
renderData(c, msg, err) renderData(c, msg, err)
} }
type rstPasswordInput struct { type rstPasswordInput struct {
Username string `json:"username"`
Phone string `json:"phone"` Phone string `json:"phone"`
Code string `json:"code"` Code string `json:"code"`
Password string `json:"password"` Password string `json:"password"`
Type string `json:"type"`
} }
func rstPassword(c *gin.Context) { func rstPassword(c *gin.Context) {
var in loginInput var in rstPasswordInput
bind(c, &in) bind(c, &in)
err := func() error { err := func() error {
user, _ := models.UserGet("phone=?", in.Phone) user, _ := models.UserGet("username=? and phone=?", in.Username, in.Phone)
if user == nil { if user == nil {
return fmt.Errorf("phone %s dose not exist", in.Phone) return fmt.Errorf("user's phone not exist")
} }
lc, err := models.LoginCodeGet("username=? and code=? and login_type=?", lc, err := models.LoginCodeGet("username=? and code=? and login_type=?",
user.Username, in.Code, models.LOGIN_T_RST) user.Username, in.Code, models.LOGIN_T_RST)
if err != nil { if err != nil {
return fmt.Errorf("invalid code", in.Phone) return fmt.Errorf("invalid code")
} }
if time.Now().Unix()-lc.CreatedAt > models.LOGIN_EXPIRES_IN { if time.Now().Unix()-lc.CreatedAt > models.LOGIN_EXPIRES_IN {
return fmt.Errorf("the code has expired", in.Phone) return fmt.Errorf("the code has expired")
} }
if in.Type == "verify-code" {
return nil
}
defer lc.Del()
// update password // update password
if user.Password, err = models.CryptoPass(in.Password); err != nil { if user.Password, err = models.CryptoPass(in.Password); err != nil {
return err return err
} }
if err = user.Update("password"); err != nil { if err = checkPassword(in.Password); err != nil {
return err return err
} }
lc.Del() if err = user.Update("password"); err != nil {
return err
}
return nil return nil
}() }()

View File

@ -1,6 +1,7 @@
package http package http
import ( import (
"fmt"
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -137,12 +138,12 @@ type idsForm struct {
Ids []int64 `json:"ids"` Ids []int64 `json:"ids"`
} }
func checkPassword(passwd string) { func checkPassword(passwd string) error {
indNum := [4]int{0, 0, 0, 0} indNum := [4]int{0, 0, 0, 0}
spCode := []byte{'!', '@', '#', '$', '%', '^', '&', '*', '_', '-', '~', '.', ',', '<', '>', '/', ';', ':', '|', '?', '+', '='} spCode := []byte{'!', '@', '#', '$', '%', '^', '&', '*', '_', '-', '~', '.', ',', '<', '>', '/', ';', ':', '|', '?', '+', '='}
if len(passwd) < 6 { if len(passwd) < 6 {
bomb("password too short") return fmt.Errorf("password too short")
} }
passwdByte := []byte(passwd) passwdByte := []byte(passwd)
@ -174,7 +175,7 @@ func checkPassword(passwd string) {
} }
if !has { if !has {
bomb("character: %s not supported", string(i)) return fmt.Errorf("character: %s not supported", string(i))
} }
} }
@ -185,9 +186,11 @@ func checkPassword(passwd string) {
codeCount += i codeCount += i
} }
if codeCount < 3 { if codeCount < 4 {
bomb("password too simple") return fmt.Errorf("password too simple")
} }
return nil
} }
// ------------ // ------------

View File

@ -42,7 +42,7 @@ type selfPasswordForm struct {
func selfPasswordPut(c *gin.Context) { func selfPasswordPut(c *gin.Context) {
var f selfPasswordForm var f selfPasswordForm
bind(c, &f) bind(c, &f)
checkPassword(f.NewPass) dangerous(checkPassword(f.NewPass))
oldpass, err := models.CryptoPass(f.OldPass) oldpass, err := models.CryptoPass(f.OldPass)
dangerous(err) dangerous(err)

View File

@ -49,7 +49,7 @@ func userAddPost(c *gin.Context) {
var f userProfileForm var f userProfileForm
bind(c, &f) bind(c, &f)
checkPassword(f.Password) dangerous(checkPassword(f.Password))
pass, err := models.CryptoPass(f.Password) pass, err := models.CryptoPass(f.Password)
dangerous(err) dangerous(err)
@ -81,7 +81,7 @@ func userAddPost(c *gin.Context) {
func userProfileGet(c *gin.Context) { func userProfileGet(c *gin.Context) {
user := User(urlParamInt64(c, "id")) user := User(urlParamInt64(c, "id"))
user.UUID = "" user.UUID = ""
renderData(c, user,nil) renderData(c, user, nil)
} }
func userProfilePut(c *gin.Context) { func userProfilePut(c *gin.Context) {
@ -147,7 +147,7 @@ func userPasswordPut(c *gin.Context) {
var f userPasswordForm var f userPasswordForm
bind(c, &f) bind(c, &f)
checkPassword(f.Password) dangerous(checkPassword(f.Password))
target := User(urlParamInt64(c, "id")) target := User(urlParamInt64(c, "id"))
@ -267,7 +267,7 @@ type userInviteForm struct {
func userInvitePost(c *gin.Context) { func userInvitePost(c *gin.Context) {
var f userInviteForm var f userInviteForm
bind(c, &f) bind(c, &f)
checkPassword(f.Password) dangerous(checkPassword(f.Password))
inv, err := models.InviteGet("token=?", f.Token) inv, err := models.InviteGet("token=?", f.Token)
dangerous(err) dangerous(err)