168 lines
3.5 KiB
Go
168 lines
3.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"log/slog"
|
|
"proxy-server/server/models"
|
|
"proxy-server/server/pkg/orm"
|
|
"proxy-server/server/pkg/resp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// region frp 接口
|
|
|
|
type FrpData struct {
|
|
Reject bool
|
|
RejectReason string
|
|
Unchange bool
|
|
}
|
|
|
|
func ChanRequest(c *gin.Context) {
|
|
type Body struct {
|
|
Content struct {
|
|
ProxyName string `json:"proxy_name"`
|
|
ProxyType string `json:"proxy_type"`
|
|
RemoteAddr string `json:"remote_addr"`
|
|
User interface{}
|
|
}
|
|
}
|
|
|
|
op := c.Query("op")
|
|
if op != "NewUserConn" {
|
|
_ = c.Error(errors.New("不支持的操作"))
|
|
return
|
|
}
|
|
|
|
id := c.GetHeader("X-Frp-Reqid")
|
|
if id == "" {
|
|
_ = c.Error(errors.New("请求头中缺少 X-Frp-Reqid"))
|
|
return
|
|
}
|
|
|
|
var body Body
|
|
err := c.ShouldBindJSON(&body)
|
|
if err != nil {
|
|
_ = c.Error(errors.Wrap(err, "解析请求正文失败"))
|
|
return
|
|
}
|
|
content := body.Content
|
|
|
|
// 检查此 ip 是否有权限访问目标 node
|
|
clientIp := strings.Split(content.RemoteAddr, ":")[0]
|
|
targetNode := content.ProxyName
|
|
slog.Debug(id + " 用户 " + clientIp + " 请求连接到 " + targetNode)
|
|
|
|
var channels []models.Channel
|
|
err = orm.DB.
|
|
Joins("INNER JOIN public.nodes n ON channels.node_id = n.id AND n.name = ?", targetNode).
|
|
Joins("INNER JOIN public.users u ON channels.user_id = u.id").
|
|
Joins("INNER JOIN public.user_ips ip ON u.id = ip.user_id AND ip.ip_address = ?", clientIp).
|
|
Find(&channels).Error
|
|
if err != nil {
|
|
_ = c.Error(errors.Wrap(err, "查询用户权限失败"))
|
|
return
|
|
}
|
|
|
|
// 返回响应
|
|
rsCount := len(channels)
|
|
if rsCount > 1 {
|
|
slog.Warn(clientIp + " + " + targetNode + "的组合有多个权限结果,这是不应当存在的")
|
|
}
|
|
|
|
if rsCount == 0 {
|
|
slog.Debug(id + " 没有权限")
|
|
reject(c)
|
|
return
|
|
}
|
|
channel := channels[0]
|
|
if channel.Expiration.Before(time.Now()) {
|
|
slog.Debug(id + " 权限已过期")
|
|
reject(c)
|
|
return
|
|
}
|
|
|
|
slog.Debug(id + " 通过验证")
|
|
confirm(c)
|
|
}
|
|
|
|
func ChanTest(c *gin.Context) {
|
|
var body map[string]interface{}
|
|
err := c.ShouldBindJSON(&body)
|
|
if err != nil {
|
|
slog.Error("解析请求正文失败", err)
|
|
}
|
|
for k, v := range body {
|
|
slog.Debug("map", "key: ", k, " value: ", v)
|
|
}
|
|
confirm(c)
|
|
}
|
|
|
|
func confirm(c *gin.Context) {
|
|
c.JSON(200, FrpData{
|
|
Reject: false,
|
|
Unchange: true,
|
|
})
|
|
}
|
|
|
|
func reject(c *gin.Context) {
|
|
c.JSON(401, FrpData{
|
|
Reject: true,
|
|
RejectReason: "客户端没有权限访问该节点",
|
|
})
|
|
}
|
|
|
|
// endregion
|
|
|
|
func ChanAuth(c *gin.Context) {
|
|
type Body struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
type Data struct {
|
|
Timeout uint64 `json:"timeout"`
|
|
}
|
|
|
|
var body Body
|
|
err := c.ShouldBindJSON(&body)
|
|
if err != nil {
|
|
_ = c.Error(err)
|
|
c.JSON(400, resp.Fail("请求参数错误"))
|
|
return
|
|
}
|
|
|
|
// 查找通道
|
|
var result *models.Channel
|
|
orm.DB.
|
|
Model(&models.Channel{}).
|
|
Where(&models.Channel{
|
|
Username: body.Username,
|
|
Password: body.Password,
|
|
}).
|
|
First(&result)
|
|
if result == nil {
|
|
_ = c.Error(errors.New("用户信息不存在"))
|
|
c.JSON(401, resp.Fail("账号密码错误"))
|
|
return
|
|
}
|
|
|
|
// 验证账号密码 todo 哈希密码验证
|
|
if result.Username != body.Username || result.Password != body.Password {
|
|
_ = c.Error(errors.New("账号密码错误"))
|
|
c.JSON(401, resp.Fail("账号密码错误"))
|
|
return
|
|
}
|
|
|
|
// 计算到期时间
|
|
timeout := result.Expiration.Sub(time.Now())
|
|
|
|
// todo 保存会话 对于大量短连接的情况,考虑如何保存连接会话信息
|
|
|
|
// 返回结果
|
|
c.JSON(200, resp.Done(Data{
|
|
Timeout: uint64(timeout.Seconds()),
|
|
}))
|
|
}
|