Files
Spark/client/core/core.go
2022-03-16 16:26:28 +08:00

330 lines
7.8 KiB
Go

package core
import (
"Spark/client/common"
"Spark/client/config"
"Spark/client/service/basic"
"Spark/client/service/file"
"Spark/client/service/process"
"Spark/client/service/screenshot"
"Spark/client/service/terminal"
"Spark/modules"
"Spark/utils"
"encoding/hex"
"errors"
ws "github.com/gorilla/websocket"
"github.com/kataras/golog"
"net/http"
"os"
"strconv"
"time"
)
var stop bool
var (
errNoSecretHeader = errors.New(`can not find secret header`)
)
func Start() {
for !stop {
var err error
common.WSConn, err = connectWS()
if err != nil && !stop {
golog.Error(err)
<-time.After(5 * time.Second)
continue
}
err = reportWS(common.WSConn)
if err != nil && !stop {
golog.Error(err)
<-time.After(5 * time.Second)
continue
}
go heartbeat(common.WSConn)
err = handleWS(common.WSConn)
if err != nil && !stop {
golog.Error(err)
<-time.After(5 * time.Second)
continue
}
}
}
func connectWS() (*common.Conn, error) {
wsConn, wsResp, err := ws.DefaultDialer.Dial(config.GetBaseURL(true)+`/ws`, http.Header{
`UUID`: []string{config.Config.UUID},
`Key`: []string{config.Config.Key},
})
if err != nil {
return nil, err
}
header, find := wsResp.Header[`Secret`]
if !find || len(header) == 0 {
return nil, errNoSecretHeader
}
secret, err := hex.DecodeString(header[0])
return &common.Conn{Conn: wsConn, Secret: secret}, nil
}
func reportWS(wsConn *common.Conn) error {
device, err := GetDevice()
if err != nil {
return err
}
pack := modules.CommonPack{Act: `report`, Data: device}
err = common.SendPack(pack, wsConn)
common.WSConn.SetWriteDeadline(time.Time{})
if err != nil {
return err
}
common.WSConn.SetReadDeadline(time.Now().Add(5 * time.Second))
_, data, err := common.WSConn.ReadMessage()
common.WSConn.SetReadDeadline(time.Time{})
if err != nil {
return err
}
data, err = utils.Decrypt(data, common.WSConn.Secret)
if err != nil {
return err
}
err = utils.JSON.Unmarshal(data, &pack)
if err != nil {
return err
}
if pack.Code != 0 {
return errors.New(`unknown error occurred`)
}
return nil
}
func handleWS(wsConn *common.Conn) error {
errCount := 0
for {
_, data, err := wsConn.ReadMessage()
if err != nil {
golog.Error(err)
wsConn.Close()
return nil
}
data, err = utils.Decrypt(data, wsConn.Secret)
if err != nil {
golog.Error(err)
errCount++
if errCount > 3 {
break
}
continue
}
pack := modules.Packet{}
utils.JSON.Unmarshal(data, &pack)
if err != nil {
golog.Error(err)
errCount++
if errCount > 3 {
break
}
continue
}
errCount = 0
if pack.Data == nil {
pack.Data = map[string]interface{}{}
}
go handleAct(pack, wsConn)
}
wsConn.Close()
return nil
}
func handleAct(pack modules.Packet, wsConn *common.Conn) {
switch pack.Act {
case `offline`:
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
stop = true
wsConn.Close()
os.Exit(0)
return
case `lock`:
err := basic.Lock()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `logoff`:
err := basic.Logoff()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `hibernate`:
err := basic.Hibernate()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `suspend`:
err := basic.Suspend()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `restart`:
err := basic.Restart()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `shutdown`:
err := basic.Shutdown()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `screenshot`:
if pack.Data != nil {
if trigger, ok := pack.Data[`event`]; ok {
screenshot.GetScreenshot(trigger.(string))
}
}
case `initTerminal`:
err := terminal.InitTerminal(pack)
if err != nil {
common.SendCb(modules.Packet{Act: `initTerminal`, Code: 1, Msg: err.Error()}, pack, wsConn)
}
break
case `inputTerminal`:
terminal.InputTerminal(pack)
break
case `killTerminal`:
terminal.KillTerminal(pack)
break
case `listFiles`:
path := `/`
if val, ok := pack.Data[`path`]; ok {
if path, ok = val.(string); !ok {
path = `/`
}
}
files, err := file.ListFiles(path)
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0, Data: map[string]interface{}{`files`: files}}, pack, wsConn)
}
case `removeFile`:
path, ok := pack.Data[`path`]
if !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `can not find such a file or directory`}, pack, wsConn)
return
}
if path == `\` || path == `/` || len(path.(string)) == 0 {
common.SendCb(modules.Packet{Code: 1, Msg: `can not find such a file or directory`}, pack, wsConn)
return
}
err := os.RemoveAll(path.(string))
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `uploadFile`:
var path, trigger string
var start, end int64
{
tempVal, ok := pack.Data[`file`]
if !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
if path, ok = tempVal.(string); !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
tempVal, ok = pack.Data[`event`]
if !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
if trigger, ok = tempVal.(string); !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
tempVal, ok = pack.Data[`start`]
if ok {
if v, ok := tempVal.(float64); ok {
start = int64(v)
}
}
tempVal, ok = pack.Data[`end`]
if ok {
if v, ok := tempVal.(float64); ok {
end = int64(v)
if end > 0 {
end++
}
}
}
if end > 0 && end < start {
common.SendCb(modules.Packet{Code: 1, Msg: `文件范围错误`}, pack, wsConn)
return
}
}
err := file.UploadFile(path, trigger, start, end)
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
}
case `listProcesses`:
processes, err := process.ListProcesses()
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0, Data: map[string]interface{}{`processes`: processes}}, pack, wsConn)
}
case `killProcess`:
pidStr, ok := pack.Data[`pid`]
if !ok {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
pid, err := strconv.ParseInt(pidStr.(string), 10, 32)
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: `未知错误`}, pack, wsConn)
return
}
err = process.KillProcess(int32(pid))
if err != nil {
common.SendCb(modules.Packet{Code: 1, Msg: err.Error()}, pack, wsConn)
} else {
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
case `heartbeat`:
break
default:
common.SendCb(modules.Packet{Code: 0}, pack, wsConn)
}
return
}
func heartbeat(wsConn *common.Conn) error {
for range time.NewTicker(60 * time.Second).C {
device, err := GetDevice()
if err != nil {
golog.Error(err)
continue
}
err = common.SendPack(modules.CommonPack{Act: `setDevice`, Data: device}, wsConn)
if err != nil {
return err
}
}
return nil
}