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

View File

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

View File

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

View File

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