186 lines
4.5 KiB
Go
186 lines
4.5 KiB
Go
package client
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"crypto/aes"
|
|
"crypto/md5"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
var pipeReqPrefix = []byte("houston_pipe_req")
|
|
var pipeReqHandle = map[string]func(hc *houstonClient, meta *procmeta, param string) error{
|
|
"upload": handleStdOutUploadRequest,
|
|
}
|
|
|
|
func HandleHoustonPipeReq(hc *houstonClient, meta *procmeta, buff []byte) (pipeRequest bool, retErr error) {
|
|
if !bytes.HasPrefix(buff, pipeReqPrefix) {
|
|
return false, nil // Not a pipe request
|
|
}
|
|
|
|
command, param, err := parsePipeReq(buff)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
if handler, ok := pipeReqHandle[command]; ok {
|
|
if err := handler(hc, meta, param); err != nil {
|
|
return true, err
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
var pipeReqDelimeter = []byte("|")
|
|
var pipeReqKey = []byte{
|
|
0x77, 0x77, 0x71, 0x3c, 0x75, 0x64, 0x22, 0x54,
|
|
0x3e, 0x41, 0x27, 0x68, 0x39, 0x6e, 0x23, 0x49,
|
|
0x5f, 0x66, 0x71, 0x50, 0x32, 0x68, 0x53, 0x43,
|
|
0x72, 0x2f, 0x62, 0x39, 0x6e, 0x22, 0x27, 0x2d,
|
|
}
|
|
var errInvalidRequestBuff = errors.New("parsePipeReq got invalid request format")
|
|
|
|
func parsePipeReq(buff []byte) (command, param string, err error) {
|
|
//buff == "houston_pipe_req|EncryptString\r\n"
|
|
parts := bytes.Split(buff, pipeReqDelimeter)
|
|
if len(parts) != 2 {
|
|
return "", "", errInvalidRequestBuff
|
|
}
|
|
|
|
//Decrypt
|
|
decryptBuff, err := decryptPipeReq(parts[1])
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
//buff == houston_pipe_req|command|example_paramstring|MD5
|
|
//decryptBuff == command|example_paramstring|MD5
|
|
parts = bytes.Split(decryptBuff, pipeReqDelimeter)
|
|
if len(parts) != 3 {
|
|
return "", "", errInvalidRequestBuff
|
|
}
|
|
|
|
command = string(parts[0])
|
|
param = string(parts[1])
|
|
receivedHash := string(parts[2])
|
|
if err := validatePipeReq(command, param, receivedHash); err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return command, param, nil
|
|
}
|
|
|
|
func decryptPipeReq(encordBuff []byte) ([]byte, error) {
|
|
decordBuff, err := base64.StdEncoding.DecodeString(string(encordBuff))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(decordBuff)%aes.BlockSize != 0 {
|
|
return nil, errors.New("parsePipeReq got encrypted data which is not a multiple of the block size")
|
|
}
|
|
|
|
aesBlock, err := aes.NewCipher(pipeReqKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
decryptBuff := make([]byte, len(decordBuff))
|
|
for start := 0; start < len(decordBuff); start += aes.BlockSize {
|
|
aesBlock.Decrypt(decryptBuff[start:start+aes.BlockSize], decordBuff[start:start+aes.BlockSize])
|
|
}
|
|
return decryptBuff, nil
|
|
}
|
|
|
|
var errValidatePipeFail = errors.New("validatePipeReq fail to check validation of buff")
|
|
|
|
func validatePipeReq(command, param, receivedHash string) error {
|
|
//Decord receivedHash
|
|
receiveHashLen := md5.Size * 2
|
|
if len(receivedHash) < receiveHashLen {
|
|
return errValidatePipeFail
|
|
}
|
|
decordHash, err := hex.DecodeString(receivedHash[0:receiveHashLen])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//Generate md5 from command and param
|
|
var reqBuilder strings.Builder
|
|
reqBuilder.WriteString(command)
|
|
reqBuilder.Write(pipeReqDelimeter)
|
|
reqBuilder.WriteString(param)
|
|
|
|
buffHashWriter := md5.New()
|
|
buffHashWriter.Write([]byte(reqBuilder.String()))
|
|
|
|
buffHash := buffHashWriter.Sum(nil)
|
|
if !bytes.Equal(decordHash, buffHash) {
|
|
return errValidatePipeFail
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func handleStdOutUploadRequest(hc *houstonClient, meta *procmeta, param string) error {
|
|
if uploadZipPath, err := compressFile(param); err != nil {
|
|
return err
|
|
} else {
|
|
hc.uploadToAppendFile(uploadZipPath, meta.name, meta.version, filepath.Base(uploadZipPath))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func compressFile(fullPath string) (string, error) {
|
|
ext := filepath.Ext(fullPath)
|
|
zipFullPath := fullPath[:len(fullPath)-len(ext)] + ".zip"
|
|
|
|
// Create
|
|
newZipFile, err := os.Create(zipFullPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer newZipFile.Close()
|
|
zipWriter := zip.NewWriter(newZipFile)
|
|
defer zipWriter.Close()
|
|
|
|
// Open
|
|
fileToZip, err := os.Open(fullPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer fileToZip.Close()
|
|
fileToZipInfo, err := fileToZip.Stat()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Zip
|
|
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
fileToZipHeader.Name = fileToZipInfo.Name()
|
|
fileToZipHeader.Method = zip.Deflate
|
|
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
_, err = io.Copy(fileToZipWriter, fileToZip)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Remove
|
|
err = os.Remove(fullPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return zipFullPath, nil
|
|
}
|