Skip to content

Commit

Permalink
Merge pull request #339 from wsczx/dev
Browse files Browse the repository at this point in the history
增加弹窗输入OTP动态码的功能
  • Loading branch information
bjdgyc authored Oct 8, 2024
2 parents 57b9e1d + 4c219a3 commit fe3a10a
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 71 deletions.
16 changes: 8 additions & 8 deletions server/dbdata/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ func checkLocalUser(name, pwd, group string) error {
}
// 判断otp信息
pinCode := pwd
if !v.DisableOtp {
pinCode = pwd[:pl-6]
otp := pwd[pl-6:]
if !checkOtp(name, otp, v.OtpSecret) {
return fmt.Errorf("%s %s", name, "动态码错误")
}
}
// if !v.DisableOtp {
// pinCode = pwd[:pl-6]
// otp := pwd[pl-6:]
// if !CheckOtp(name, otp, v.OtpSecret) {
// return fmt.Errorf("%s %s", name, "动态码错误")
// }
// }

// 判断用户密码
if pinCode != v.PinCode {
Expand Down Expand Up @@ -171,7 +171,7 @@ func init() {
}

// 判断令牌信息
func checkOtp(name, otp, secret string) bool {
func CheckOtp(name, otp, secret string) bool {
key := fmt.Sprintf("%s:%s", name, otp)

userOtpMux.Lock()
Expand Down
9 changes: 4 additions & 5 deletions server/dbdata/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/xlzd/gotp"
)

func TestCheckUser(t *testing.T) {
Expand All @@ -30,10 +29,10 @@ func TestCheckUser(t *testing.T) {
ast.Nil(err)

// 验证 PinCode + OtpSecret
totp := gotp.NewDefaultTOTP(u.OtpSecret)
secret := totp.Now()
err = CheckUser("aaa", u.PinCode+secret, group)
ast.Nil(err)
// totp := gotp.NewDefaultTOTP(u.OtpSecret)
// secret := totp.Now()
// err = CheckUser("aaa", u.PinCode+secret, group)
// ast.Nil(err)

// 单独验证密码
u.DisableOtp = true
Expand Down
7 changes: 3 additions & 4 deletions server/handler/antiBruteForce.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package handler
import (
"encoding/xml"
"io"
"log"
"net"
"net/http"
"strings"
Expand Down Expand Up @@ -85,21 +84,21 @@ func antiBruteForce(next http.Handler) http.Handler {

// 检查全局 IP 锁定
if base.Cfg.MaxGlobalIPBanCount > 0 && lockManager.checkGlobalIPLock(ip, now) {
log.Printf("IP %s is globally locked. Try again later.", ip)
base.Warn("IP", ip, "is globally locked. Try again later.")
http.Error(w, "Account globally locked due to too many failed attempts. Try again later.", http.StatusTooManyRequests)
return
}

// 检查全局用户锁定
if base.Cfg.MaxGlobalUserBanCount > 0 && lockManager.checkGlobalUserLock(username, now) {
log.Printf("User %s is globally locked. Try again later.", username)
base.Warn("User", username, "is globally locked. Try again later.")
http.Error(w, "Account globally locked due to too many failed attempts. Try again later.", http.StatusTooManyRequests)
return
}

// 检查单个用户的 IP 锁定
if base.Cfg.MaxBanCount > 0 && lockManager.checkUserIPLock(username, ip, now) {
log.Printf("IP %s is locked for user %s. Try again later.", ip, username)
base.Warn("IP", ip, "is locked for user", username, "Try again later.")
http.Error(w, "Account locked due to too many failed attempts. Try again later.", http.StatusTooManyRequests)
return
}
Expand Down
104 changes: 50 additions & 54 deletions server/handler/link_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package handler
import (
"bytes"
"context"
"crypto/md5"
"encoding/xml"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"strings"
Expand Down Expand Up @@ -47,7 +45,10 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
}
defer r.Body.Close()

cr := ClientRequest{}
cr := &ClientRequest{
RemoteAddr: r.RemoteAddr,
UserAgent: userAgent,
}
err = xml.Unmarshal(body, &cr)
if err != nil {
base.Error(err)
Expand Down Expand Up @@ -78,22 +79,27 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
return
}
// 用户活动日志
ua := dbdata.UserActLog{
ua := &dbdata.UserActLog{
Username: cr.Auth.Username,
GroupName: cr.GroupSelect,
RemoteAddr: r.RemoteAddr,
Status: dbdata.UserAuthSuccess,
DeviceType: cr.DeviceId.DeviceType,
PlatformVersion: cr.DeviceId.PlatformVersion,
}

sessionData := &AuthSession{
ClientRequest: cr,
UserActLog: ua,
}
// TODO 用户密码校验
err = dbdata.CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect)
if err != nil {
r = r.WithContext(context.WithValue(r.Context(), loginStatusKey, false)) // 传递登录失败状态
base.Warn(err, r.RemoteAddr)
ua.Info = err.Error()
ua.Status = dbdata.UserAuthFail
dbdata.UserActLogIns.Add(ua, userAgent)
dbdata.UserActLogIns.Add(*ua, userAgent)

w.WriteHeader(http.StatusOK)
data := RequestData{Group: cr.GroupSelect, Groups: dbdata.GetGroupNamesNormal(), Error: "用户名或密码错误"}
Expand All @@ -104,72 +110,62 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) {
return
}
r = r.WithContext(context.WithValue(r.Context(), loginStatusKey, true)) // 传递登录成功状态
dbdata.UserActLogIns.Add(ua, userAgent)
// if !ok {
// w.WriteHeader(http.StatusOK)
// data := RequestData{Group: cr.GroupSelect, Groups: base.Cfg.UserGroups, Error: "请先激活用户"}
// tplRequest(tpl_request, w, data)
// return
// }
dbdata.UserActLogIns.Add(*ua, userAgent)

// 创建新的session信息
sess := sessdata.NewSession("")
sess.Username = cr.Auth.Username
sess.Group = cr.GroupSelect
oriMac := cr.MacAddressList.MacAddress
sess.UniqueIdGlobal = cr.DeviceId.UniqueIdGlobal
sess.UserAgent = userAgent
sess.DeviceType = ua.DeviceType
sess.PlatformVersion = ua.PlatformVersion
sess.RemoteAddr = r.RemoteAddr
// 获取客户端mac地址
sess.UniqueMac = true
macHw, err := net.ParseMAC(oriMac)
v := &dbdata.User{}
err = dbdata.One("Username", cr.Auth.Username, v)
if err != nil {
var sum [16]byte
if sess.UniqueIdGlobal != "" {
sum = md5.Sum([]byte(sess.UniqueIdGlobal))
} else {
sum = md5.Sum([]byte(sess.Token))
sess.UniqueMac = false
base.Info("正在使用第三方认证方式登录")
CreateSession(w, r, sessionData)
return
}
// 用户otp验证
if !v.DisableOtp {
sessionID, err := GenerateSessionID()
if err != nil {
base.Error("Failed to generate session ID: ", err)
http.Error(w, "Failed to generate session ID", http.StatusInternalServerError)
return
}
macHw = sum[0:5] // 5个byte
macHw = append([]byte{0x02}, macHw...)
sess.MacAddr = macHw.String()

sessionData.ClientRequest.Auth.OtpSecret = v.OtpSecret
SessStore.SaveAuthSession(sessionID, sessionData)

SetCookie(w, "auth-session-id", sessionID, 0)

data := RequestData{}
w.WriteHeader(http.StatusOK)
tplRequest(tpl_otp, w, data)
return
}
sess.MacHw = macHw
// 统一macAddr的格式
sess.MacAddr = macHw.String()

other := &dbdata.SettingOther{}
_ = dbdata.SettingGet(other)
rd := RequestData{SessionId: sess.Sid, SessionToken: sess.Sid + "@" + sess.Token,
Banner: other.Banner, ProfileName: base.Cfg.ProfileName, ProfileHash: profileHash, CertHash: certHash}
w.WriteHeader(http.StatusOK)
tplRequest(tpl_complete, w, rd)
base.Info("login", cr.Auth.Username, userAgent)
CreateSession(w, r, sessionData)
}

const (
tpl_request = iota
tpl_complete
tpl_otp
)

func tplRequest(typ int, w io.Writer, data RequestData) {
if typ == tpl_request {
switch typ {
case tpl_request:
t, _ := template.New("auth_request").Parse(auth_request)
_ = t.Execute(w, data)
return
}
case tpl_complete:
if data.Banner != "" {
buf := new(bytes.Buffer)
_ = xml.EscapeText(buf, []byte(data.Banner))
data.Banner = buf.String()
}

if data.Banner != "" {
buf := new(bytes.Buffer)
_ = xml.EscapeText(buf, []byte(data.Banner))
data.Banner = buf.String()
t, _ := template.New("auth_complete").Parse(auth_complete)
_ = t.Execute(w, data)
case tpl_otp:
t, _ := template.New("auth_otp").Parse(auth_otp)
_ = t.Execute(w, data)
}

t, _ := template.New("auth_complete").Parse(auth_complete)
_ = t.Execute(w, data)
}

// 设置输出信息
Expand Down
Loading

0 comments on commit fe3a10a

Please sign in to comment.