299 lines
7.8 KiB
Go
299 lines
7.8 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"gitee.ltd/lxh/logger/log"
|
|
"github.com/gin-gonic/gin"
|
|
"os"
|
|
"strings"
|
|
"wireguard-dashboard/client"
|
|
"wireguard-dashboard/http/param"
|
|
"wireguard-dashboard/model/entity"
|
|
"wireguard-dashboard/model/template_data"
|
|
"wireguard-dashboard/model/vo"
|
|
"wireguard-dashboard/queues"
|
|
"wireguard-dashboard/repository"
|
|
"wireguard-dashboard/utils"
|
|
)
|
|
|
|
type clients struct{}
|
|
|
|
func Client() clients {
|
|
return clients{}
|
|
}
|
|
|
|
// List
|
|
// @description: 客户端列表
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) List(c *gin.Context) {
|
|
var p param.ClientList
|
|
if err := c.ShouldBind(&p); err != nil {
|
|
utils.GinResponse(c).FailedWithErr("参数错误", err)
|
|
return
|
|
}
|
|
|
|
data, total, err := repository.Client().List(p)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("获取失败")
|
|
return
|
|
}
|
|
|
|
utils.GinResponse(c).OkWithPage(data, total, p.Current, p.Size)
|
|
}
|
|
|
|
// Save
|
|
// @description: 新增/更新客户端
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) Save(c *gin.Context) {
|
|
var p param.SaveClient
|
|
if err := c.ShouldBind(&p); err != nil {
|
|
utils.GinResponse(c).FailedWithErr("参数错误", err)
|
|
return
|
|
}
|
|
|
|
info, ok := c.Get("user")
|
|
if !ok {
|
|
utils.GinResponse(c).FailedWithMsg("获取信息失败")
|
|
return
|
|
}
|
|
|
|
_, err := repository.Client().Save(p, info.(*entity.User).Id)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithErr("操作失败", err)
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
if err = queues.PutAsyncWireguardConfigFile(p.ServerId); err != nil {
|
|
log.Errorf("[新增/编辑客户端]同步配置文件失败: %v", err.Error())
|
|
}
|
|
}()
|
|
|
|
utils.GinResponse(c).OK()
|
|
}
|
|
|
|
// Delete
|
|
// @description: 删除客户端
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) Delete(c *gin.Context) {
|
|
var id = c.Param("id")
|
|
if id == "" || id == "undefined" {
|
|
utils.GinResponse(c).FailedWithMsg("参数错误")
|
|
return
|
|
}
|
|
|
|
if err := repository.Client().Delete(id); err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("操作失败")
|
|
return
|
|
}
|
|
|
|
utils.GinResponse(c).OK()
|
|
}
|
|
|
|
// Download
|
|
// @description: 下载配置文件
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) Download(c *gin.Context) {
|
|
var id = c.Param("id")
|
|
if id == "" || id == "undefined" {
|
|
utils.GinResponse(c).FailedWithMsg("参数错误")
|
|
return
|
|
}
|
|
|
|
data, err := repository.Client().GetById(id)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("获取失败")
|
|
return
|
|
}
|
|
|
|
var keys template_data.Keys
|
|
_ = json.Unmarshal([]byte(data.Keys), &keys)
|
|
|
|
setting, err := repository.System().GetServerSetting()
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("获取设置失败")
|
|
return
|
|
}
|
|
|
|
// 处理一下数据
|
|
execData := template_data.ClientConfig{
|
|
PrivateKey: keys.PrivateKey,
|
|
IpAllocation: data.IpAllocation,
|
|
MTU: setting.MTU,
|
|
DNS: strings.Join(setting.DnsServer, ","),
|
|
PublicKey: keys.PublicKey,
|
|
PresharedKey: keys.PresharedKey,
|
|
AllowedIPS: data.AllowedIps,
|
|
Endpoint: setting.EndpointAddress,
|
|
ListenPort: data.Server.ListenPort,
|
|
PersistentKeepalive: setting.PersistentKeepalive,
|
|
}
|
|
|
|
// 不同环境下处理文件路径
|
|
var outPath = "/tmp/" + fmt.Sprintf("%s.conf", data.Name)
|
|
var templatePath = "./template/wg.client.conf"
|
|
if os.Getenv("GIN_MODE") != "release" {
|
|
outPath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\" + fmt.Sprintf("%s.conf", data.Name)
|
|
templatePath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\wg.client.conf"
|
|
}
|
|
|
|
// 渲染数据
|
|
parseTemplate, err := utils.Template().Parse(templatePath)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("读取模板文件失败")
|
|
return
|
|
}
|
|
|
|
err = utils.Template().Execute(parseTemplate, execData, outPath)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("文件渲染失败")
|
|
return
|
|
}
|
|
|
|
// 输出文件流
|
|
c.Header("Content-Type", "application/octet-stream")
|
|
c.Header("Content-Disposition", "attachment; filename="+outPath)
|
|
c.Header("Content-Transfer-Encoding", "binary")
|
|
c.Header("Connection", "keep-alive")
|
|
c.File(outPath)
|
|
if err = os.Remove(outPath); err != nil {
|
|
log.Errorf("删除临时文件失败: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
// GenerateQrCode
|
|
// @description: 生成客户端信息二维码
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) GenerateQrCode(c *gin.Context) {
|
|
var id = c.Param("id")
|
|
if id == "" || id == "undefined" {
|
|
utils.GinResponse(c).FailedWithMsg("参数错误")
|
|
return
|
|
}
|
|
|
|
data, err := repository.Client().GetById(id)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("获取失败")
|
|
return
|
|
}
|
|
|
|
var keys template_data.Keys
|
|
_ = json.Unmarshal([]byte(data.Keys), &keys)
|
|
|
|
setting, err := repository.System().GetServerSetting()
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("获取设置失败")
|
|
return
|
|
}
|
|
|
|
// 处理一下数据
|
|
execData := template_data.ClientConfig{
|
|
PrivateKey: keys.PrivateKey,
|
|
IpAllocation: data.IpAllocation,
|
|
MTU: setting.MTU,
|
|
PublicKey: keys.PublicKey,
|
|
PresharedKey: keys.PresharedKey,
|
|
AllowedIPS: data.AllowedIps,
|
|
Endpoint: setting.EndpointAddress,
|
|
ListenPort: data.Server.ListenPort,
|
|
PersistentKeepalive: setting.PersistentKeepalive,
|
|
}
|
|
|
|
// 不同环境下处理文件路径
|
|
var outPath = "/tmp/" + fmt.Sprintf("%s.conf", data.Name)
|
|
var templatePath = "./template/wg.client.conf"
|
|
if os.Getenv("GIN_MODE") != "release" {
|
|
outPath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\" + fmt.Sprintf("%s.conf", data.Name)
|
|
templatePath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\wg.client.conf"
|
|
}
|
|
|
|
// 渲染数据
|
|
parseTemplate, err := utils.Template().Parse(templatePath)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("读取模板文件失败")
|
|
return
|
|
}
|
|
|
|
err = utils.Template().Execute(parseTemplate, execData, outPath)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("文件渲染失败")
|
|
return
|
|
}
|
|
|
|
// 读取文件内容
|
|
fileContent, err := os.ReadFile(outPath)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithMsg("读取文件失败")
|
|
return
|
|
}
|
|
|
|
png, err := utils.QRCode().GenerateQrCodeBase64(fileContent, 256)
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithErr("生成二维码失败", err)
|
|
return
|
|
}
|
|
|
|
if err = os.Remove(outPath); err != nil {
|
|
log.Errorf("删除临时文件失败: %s", err.Error())
|
|
}
|
|
|
|
utils.GinResponse(c).OKWithData(map[string]interface{}{
|
|
"qrCode": png,
|
|
})
|
|
}
|
|
|
|
// Status
|
|
// @description: 获取客户端状态信息,链接状态等
|
|
// @receiver clients
|
|
// @param c
|
|
func (clients) Status(c *gin.Context) {
|
|
var p param.ClientStatusList
|
|
if err := c.ShouldBind(&p); err != nil {
|
|
utils.GinResponse(c).FailedWithErr("参数错误", err)
|
|
return
|
|
}
|
|
|
|
// 使用sdk拉取一下客户端信息
|
|
devices, err := client.WireguardClient.Devices()
|
|
if err != nil {
|
|
utils.GinResponse(c).FailedWithErr("获取客户端信息失败", err)
|
|
return
|
|
}
|
|
|
|
var data []vo.ClientStatus
|
|
// 遍历客户端数据,并渲染数据信息
|
|
for _, d := range devices {
|
|
for _, p := range d.Peers {
|
|
clientInfo, err := repository.Client().GetByPublicKey(p.PublicKey.String())
|
|
if err != nil {
|
|
log.Errorf("没有找到公钥匹配的客户端: %s", p.PublicKey.String())
|
|
continue
|
|
}
|
|
var ipAllocation string
|
|
for _, iaip := range p.AllowedIPs {
|
|
ipAllocation += iaip.String() + ","
|
|
}
|
|
ipAllocation = strings.TrimRight(ipAllocation, ",")
|
|
isOnline := p.LastHandshakeTime.Minute() < 1
|
|
data = append(data, vo.ClientStatus{
|
|
Name: clientInfo.Name,
|
|
Email: clientInfo.Email,
|
|
IpAllocation: ipAllocation,
|
|
Endpoint: p.Endpoint.String(),
|
|
Received: utils.FlowCalculation().Parse(p.ReceiveBytes),
|
|
Transmitted: utils.FlowCalculation().Parse(p.TransmitBytes),
|
|
IsOnline: isOnline,
|
|
LastHandShake: p.LastHandshakeTime.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
}
|
|
|
|
utils.GinResponse(c).OKWithData(data)
|
|
}
|