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:
parent
2bcb20d710
commit
df55398100
|
@ -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
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue