Files
Spark/server/handler/generate.go
2022-03-16 16:26:28 +08:00

185 lines
5.5 KiB
Go

package handler
import (
"Spark/modules"
"Spark/server/common"
"Spark/server/config"
"Spark/utils"
"bytes"
"encoding/hex"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"math/big"
"net/http"
"strconv"
"strings"
)
type clientCfg struct {
Secure bool `json:"secure"`
Host string `json:"host"`
Port int `json:"port"`
Path string `json:"path"`
UUID string `json:"uuid"`
Key string `json:"key"`
}
var (
errTooLargeEntity = errors.New(`length of data can not excess buffer size`)
)
//func init() {
// clientUUID := utils.GetUUID()
// clientKey, _ := common.EncAES(clientUUID, append([]byte("XZB_Spark"), bytes.Repeat([]byte{25}, 24-9)...))
// cfg, _ := genConfig(clientCfg{
// Secure: false,
// Host: "47.102.136.182",
// Port: 1025,
// Path: "/",
// UUID: hex.EncodeToString(clientUUID),
// Key: hex.EncodeToString(clientKey),
// })
// output := ``
// temp := hex.EncodeToString(cfg)
// for i := 0; i < len(temp); i += 2 {
// output += `\x` + temp[i:i+2]
// }
// ioutil.WriteFile(`./Client.cfg`, []byte(output), 0755)
//}
func checkClient(ctx *gin.Context) {
var form struct {
OS string `json:"os" yaml:"os" form:"os" binding:"required"`
Arch string `json:"arch" yaml:"arch" form:"arch" binding:"required"`
Host string `json:"host" yaml:"host" form:"host" binding:"required"`
Port uint16 `json:"port" yaml:"port" form:"port" binding:"required"`
Path string `json:"path" yaml:"path" form:"path" binding:"required"`
Secure string `json:"secure" yaml:"secure" form:"secure"`
}
if err := ctx.ShouldBind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `参数不完整`})
return
}
_, err := common.BuiltFS.Open(fmt.Sprintf(`/%v_%v`, form.OS, form.Arch))
if err != nil {
ctx.JSON(http.StatusNotFound, modules.Packet{Code: 1, Msg: `该系统或架构的客户端尚未编译`})
return
}
_, err = genConfig(clientCfg{
Secure: form.Secure == `true`,
Host: form.Host,
Port: int(form.Port),
Path: form.Path,
UUID: strings.Repeat(`FF`, 16),
Key: strings.Repeat(`FF`, 32),
})
if err != nil {
if err == errTooLargeEntity {
ctx.JSON(http.StatusRequestEntityTooLarge, modules.Packet{Code: 1, Msg: `配置信息过长`})
return
}
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `配置文件生成失败`})
return
}
ctx.JSON(http.StatusOK, modules.Packet{Code: 0})
}
func generateClient(ctx *gin.Context) {
var form struct {
OS string `json:"os" yaml:"os" form:"os" binding:"required"`
Arch string `json:"arch" yaml:"arch" form:"arch" binding:"required"`
Host string `json:"host" yaml:"host" form:"host" binding:"required"`
Port uint16 `json:"port" yaml:"port" form:"port" binding:"required"`
Path string `json:"path" yaml:"path" form:"path" binding:"required"`
Secure string `json:"secure" yaml:"secure" form:"secure"`
}
if err := ctx.ShouldBind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `参数不完整`})
return
}
tpl, err := common.BuiltFS.Open(fmt.Sprintf(`/%v_%v`, form.OS, form.Arch))
if err != nil {
ctx.JSON(http.StatusNotFound, modules.Packet{Code: 1, Msg: `该系统或架构的客户端尚未编译`})
return
}
clientUUID := utils.GetUUID()
clientKey, err := common.EncAES(clientUUID, config.Config.StdSalt)
if err != nil {
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `配置文件生成失败`})
return
}
cfgBytes, err := genConfig(clientCfg{
Secure: form.Secure == `true`,
Host: form.Host,
Port: int(form.Port),
Path: form.Path,
UUID: hex.EncodeToString(clientUUID),
Key: hex.EncodeToString(clientKey),
})
if err != nil {
if err == errTooLargeEntity {
ctx.JSON(http.StatusRequestEntityTooLarge, modules.Packet{Code: 1, Msg: `配置信息过长`})
return
}
ctx.JSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `配置文件生成失败`})
return
}
ctx.Header(`Accept-Ranges`, `none`)
ctx.Header(`Content-Transfer-Encoding`, `binary`)
ctx.Header(`Content-Type`, `application/octet-stream`)
if stat, err := tpl.Stat(); err == nil {
ctx.Header(`Content-Length`, strconv.FormatInt(stat.Size(), 10))
}
if form.OS == `windows` {
ctx.Header(`Content-Disposition`, `attachment; filename=client.exe;`)
} else {
ctx.Header(`Content-Disposition`, `attachment; filename=client;`)
}
cfgBuffer := bytes.Repeat([]byte{'\x19'}, 384)
prevBuffer := make([]byte, 0)
for {
thisBuffer := make([]byte, 1024)
n, err := tpl.Read(thisBuffer)
thisBuffer = thisBuffer[:n]
tempBuffer := append(prevBuffer, thisBuffer...)
bufIndex := bytes.Index(tempBuffer, cfgBuffer)
if bufIndex > -1 {
tempBuffer = bytes.Replace(tempBuffer, cfgBuffer, cfgBytes, -1)
}
ctx.Writer.Write(tempBuffer[:len(prevBuffer)])
prevBuffer = tempBuffer[len(prevBuffer):]
if err != nil {
break
}
}
if len(prevBuffer) > 0 {
ctx.Writer.Write(prevBuffer)
prevBuffer = []byte{}
}
}
func genConfig(cfg clientCfg) ([]byte, error) {
data, err := utils.JSON.Marshal(cfg)
if err != nil {
return nil, err
}
key := utils.GetUUID()
data, err = common.EncAES(data, key)
if err != nil {
return nil, err
}
final := append(key, data...)
if len(final) > 384-2 {
return nil, errTooLargeEntity
}
dataLen := big.NewInt(int64(len(final))).Bytes()
dataLen = append(bytes.Repeat([]byte{'\x00'}, 2-len(dataLen)), dataLen...)
final = append(dataLen, final...)
for len(final) < 384 {
final = append(final, utils.GetUUID()...)
}
return final[:384], nil
}