169 lines
3.1 KiB
Go
169 lines
3.1 KiB
Go
package account
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha512"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"git.trj.tw/golang/go-gallery/modules/memstore"
|
|
|
|
"git.trj.tw/golang/go-gallery/models"
|
|
"git.trj.tw/golang/go-gallery/modules/context"
|
|
"git.trj.tw/golang/go-gallery/modules/utils"
|
|
"golang.org/x/crypto/pbkdf2"
|
|
)
|
|
|
|
var passIterator = 2048
|
|
var passLen = 64
|
|
var passSaltLen = 16
|
|
var passHash = sha512.New
|
|
|
|
// UserLogin route
|
|
func UserLogin(c *context.Context) {
|
|
loginArg := struct {
|
|
Account string `form:"account" json:"account" binding:"required"`
|
|
Password string `form:"password" json:"password" binding:"required"`
|
|
}{
|
|
Account: "",
|
|
Password: "",
|
|
}
|
|
err := c.BindData(&loginArg)
|
|
if err != nil {
|
|
c.DataFormat(nil)
|
|
return
|
|
}
|
|
|
|
acc, err := models.GetAccount(loginArg.Account)
|
|
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
if acc == nil {
|
|
c.NotFound("User not found")
|
|
return
|
|
}
|
|
|
|
strs := strings.Split(acc.Password, ".")
|
|
if len(strs) != 2 {
|
|
c.ServerError("store pass format error")
|
|
return
|
|
}
|
|
b, err := hex.DecodeString(strs[0])
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
hashPass, err := hex.DecodeString(strs[1])
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
|
|
enc := pbkdf2.Key([]byte(loginArg.Password), b, passIterator, passLen, passHash)
|
|
|
|
if enc == nil || !reflect.DeepEqual(enc, hashPass) {
|
|
c.DataFormat("password error")
|
|
return
|
|
}
|
|
|
|
res := utils.ToMap(acc)
|
|
|
|
m := make(map[string]interface{})
|
|
|
|
m["user"] = res
|
|
|
|
jsonStr, err := json.Marshal(m)
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
|
|
tByte := make([]byte, 20)
|
|
_, err = rand.Read(tByte)
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
|
|
err = memstore.RedisSet("golang", hex.EncodeToString(tByte), string(jsonStr), 3600)
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
}
|
|
|
|
m["token"] = hex.EncodeToString(tByte)
|
|
|
|
c.Success(m)
|
|
}
|
|
|
|
// UserLogout route
|
|
func UserLogout(c *context.Context) {
|
|
token := c.GetHeader("X-Auth-Token")
|
|
if len(token) == 0 {
|
|
c.DataFormat("token not found")
|
|
return
|
|
}
|
|
|
|
err := memstore.RedisDel("golang", token)
|
|
if err != nil {
|
|
c.ServerError("remvoe session fail")
|
|
return
|
|
}
|
|
|
|
c.Success(nil)
|
|
}
|
|
|
|
// UserSignup route
|
|
func UserSignup(c *context.Context) {
|
|
singupObj := struct {
|
|
Account string `json:"account" binding:"required"`
|
|
Password string `json:"password" binding:"required"`
|
|
Nick string `json:"nick"`
|
|
Email string `json:"email" binding:"required"`
|
|
}{}
|
|
|
|
err := c.BindData(&singupObj)
|
|
if err != nil {
|
|
c.DataFormat(nil)
|
|
return
|
|
}
|
|
|
|
salt := make([]byte, passSaltLen)
|
|
_, err = rand.Read(salt)
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
|
|
passBuf := pbkdf2.Key([]byte(singupObj.Password), salt, passIterator, passLen, passHash)
|
|
passStr := hex.EncodeToString(salt) + "." + hex.EncodeToString(passBuf)
|
|
|
|
dat, err := models.GetAccount(singupObj.Account)
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
if dat != nil {
|
|
c.DataFormat("account exists")
|
|
return
|
|
}
|
|
dat = nil
|
|
|
|
acc := &models.Account{}
|
|
acc.Account = singupObj.Account
|
|
acc.Nick = singupObj.Nick
|
|
acc.Password = passStr
|
|
acc.Email = singupObj.Email
|
|
|
|
err = acc.Create()
|
|
if err != nil {
|
|
c.ServerError(nil)
|
|
return
|
|
}
|
|
|
|
c.Success(nil)
|
|
}
|