mirror of
https://github.com/nicksherron/bashhub-server.git
synced 2024-11-10 09:02:54 +08:00
Merge branch 'tests'
This commit is contained in:
commit
bc7aebe6a6
14 changed files with 1113 additions and 272 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,5 +2,4 @@ bin
|
|||
vendor
|
||||
dist
|
||||
dist.bk
|
||||
internal/test_data
|
||||
scripts/local
|
|
@ -2,9 +2,12 @@ language: go
|
|||
go:
|
||||
- "1.13.x"
|
||||
|
||||
services:
|
||||
- postgresql
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
install: true
|
||||
|
||||
script: go run *.go version
|
||||
script: go test ./... && go test github.com/nicksherron/bashhub-server/internal -postgres-uri "postgres://postgres:@localhost:5432?sslmode=disable"
|
56
Makefile
56
Makefile
|
@ -5,61 +5,41 @@ VERSION=$(shell git tag | sort --version-sort -r | head -1)
|
|||
GIT_COMMIT=$(shell git rev-parse HEAD)
|
||||
GIT_DIRTY=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true)
|
||||
BUILD_DATE=$(shell date '+%Y-%m-%d-%H:%M:%S')
|
||||
IMAGE_NAME := "nicksherron/bashhub-server"
|
||||
IMAGE_NAME="nicksherron/bashhub-server"
|
||||
|
||||
default: test
|
||||
|
||||
default: help
|
||||
|
||||
help:
|
||||
@echo 'Management commands for bashhub-server:'
|
||||
@echo
|
||||
@echo 'Usage:'
|
||||
@echo ' make build Compile the project.'
|
||||
@echo ' make get-deps runs dep ensure, mostly used for ci.'
|
||||
@echo ' make build-alpine Compile optimized for alpine linux.'
|
||||
@echo ' make package Build final docker image with just the go binary inside'
|
||||
@echo ' make tag Tag image created by package with latest, git commit and version'
|
||||
@echo ' make docker-build Build docker image'
|
||||
@echo ' make clean Clean the directory tree'
|
||||
@echo ' make test Run tests on a compiled project.'
|
||||
@echo ' make push Push tagged images to registry'
|
||||
@echo ' make clean Clean the directory tree.'
|
||||
@echo ' make test-postgres Start postgres in ephemeral docker container and run backend tests.'
|
||||
@echo ' make test-all Run test and test-postgres.'
|
||||
@echo
|
||||
|
||||
build:
|
||||
@echo "building ${BIN_NAME} ${VERSION}"
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
go build -ldflags "-X github.com/nicksherron/bashhub-server/cmd.Version=${VERSION} -X github.com/nicksherron/bashhub-server/cmd.GitCommit=${GIT_COMMIT} -X github.com/nicksherron/bashhub-server/cmd.BuildDate=${BUILD_DATE}" -o bin/${BIN_NAME}
|
||||
|
||||
get-deps:
|
||||
dep ensure
|
||||
|
||||
@echo "building $(BIN_NAME) $(VERSION)"
|
||||
@echo "GOPATH=$(GOPATH)"
|
||||
go build -ldflags "-X github.com/nicksherron/bashhub-server/cmd.Version=$(VERSION) -X github.com/nicksherron/bashhub-server/cmd.GitCommit=$(GIT_COMMIT) -X github.com/nicksherron/bashhub-server/cmd.BuildDate=$(BUILD_DATE)" -o bin/${BIN_NAME}
|
||||
|
||||
docker-build:
|
||||
docker build --no-cache=true --build-arg VERSION=${VERSION} --build-arg BUILD_DATE=${BUILD_DATE} --build-arg GIT_COMMIT=${GIT_COMMIT} -t $(IMAGE_NAME) .
|
||||
|
||||
|
||||
build-alpine:
|
||||
@echo "building ${BIN_NAME} ${VERSION}"
|
||||
@echo "GOPATH=${GOPATH}"
|
||||
go build -ldflags '-w -linkmode external -extldflags "-static" -X github.com/nicksherron/bashhub-server/cmd.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X github.com/nicksherron/bashhub-server/cmd.BuildDate=${BUILD_DATE}' -o bin/${BIN_NAME}
|
||||
|
||||
package:
|
||||
@echo "building image ${BIN_NAME} ${VERSION} $(GIT_COMMIT)"
|
||||
docker build --build-arg VERSION=${VERSION} --build-arg GIT_COMMIT=$(GIT_COMMIT) -t $(IMAGE_NAME):local .
|
||||
|
||||
tag:
|
||||
@echo "Tagging: latest ${VERSION} $(GIT_COMMIT)"
|
||||
docker tag $(IMAGE_NAME) $(IMAGE_NAME):$(GIT_COMMIT)
|
||||
docker tag $(IMAGE_NAME) $(IMAGE_NAME):${VERSION}
|
||||
docker tag $(IMAGE_NAME) $(IMAGE_NAME):latest
|
||||
|
||||
push: docker-build tag
|
||||
@echo "Pushing docker image to registry: latest ${VERSION} $(GIT_COMMIT)"
|
||||
docker push $(IMAGE_NAME):$(GIT_COMMIT)
|
||||
docker push $(IMAGE_NAME):${VERSION}
|
||||
docker push $(IMAGE_NAME):latest
|
||||
|
||||
clean:
|
||||
@test ! -e bin/${BIN_NAME} || rm bin/${BIN_NAME}
|
||||
@test ! -e bin/$(BIN_NAME) || rm bin/$(BIN_NAME)
|
||||
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
test-postgres:
|
||||
scripts/test_postgres.sh
|
||||
|
||||
test-all: test test-postgres
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ Available Commands:
|
|||
|
||||
Flags:
|
||||
-a, --addr string Ip and port to listen and serve on. (default "http://0.0.0.0:8080")
|
||||
--db string DB location (sqlite or postgres)
|
||||
--db string db location (sqlite or postgres)
|
||||
-h, --help help for this command
|
||||
--log string Set filepath for HTTP log. "" logs to stderr.
|
||||
|
||||
|
|
23
cmd/root.go
23
cmd/root.go
|
@ -30,16 +30,17 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var (
|
||||
logFile string
|
||||
dbPath string
|
||||
addr string
|
||||
rootCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Flags().Parse(args)
|
||||
checkBhEnv()
|
||||
startupMessage()
|
||||
internal.Run()
|
||||
internal.Run(dbPath, logFile, addr)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -54,9 +55,9 @@ func Execute() {
|
|||
|
||||
func init() {
|
||||
cobra.OnInitialize()
|
||||
rootCmd.PersistentFlags().StringVar(&internal.LogFile, "log", "", `Set filepath for HTTP log. "" logs to stderr`)
|
||||
rootCmd.PersistentFlags().StringVar(&internal.DbPath, "db", dbPath(), "DB location (sqlite or postgres)")
|
||||
rootCmd.PersistentFlags().StringVarP(&internal.Addr, "addr", "a", listenAddr(), "Ip and port to listen and serve on")
|
||||
rootCmd.PersistentFlags().StringVar(&logFile, "log", "", `Set filepath for HTTP log. "" logs to stderr`)
|
||||
rootCmd.PersistentFlags().StringVar(&dbPath, "db", sqlitePath(), "db location (sqlite or postgres)")
|
||||
rootCmd.PersistentFlags().StringVarP(&addr, "addr", "a", listenAddr(), "Ip and port to listen and serve on")
|
||||
|
||||
}
|
||||
|
||||
|
@ -74,10 +75,10 @@ func startupMessage() {
|
|||
\__ \ __/ | \ V / __/ |
|
||||
|___/\___|_| \_/ \___|_|
|
||||
|
||||
`, Version, internal.Addr)
|
||||
`, Version, addr)
|
||||
color.HiGreen(banner)
|
||||
fmt.Print("\n")
|
||||
log.Printf("Listening and serving HTTP on %v", internal.Addr)
|
||||
log.Printf("Listening and serving HTTP on %v", addr)
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
|
@ -92,7 +93,7 @@ func listenAddr() string {
|
|||
|
||||
}
|
||||
|
||||
func dbPath() string {
|
||||
func sqlitePath() string {
|
||||
dbFile := "data.db"
|
||||
f := filepath.Join(appDir(), dbFile)
|
||||
return f
|
||||
|
@ -118,7 +119,7 @@ func checkBhEnv() {
|
|||
msg := fmt.Sprintf(`
|
||||
WARNING: BH_URL is set to https://bashhub.com on this machine
|
||||
If you will be running bashhub-client locally be sure to add
|
||||
export BH_URL=%v to your .bashrc or .zshrc`, internal.Addr)
|
||||
fmt.Println(msg, "\n")
|
||||
export BH_URL=%v to your .bashrc or .zshrc`, addr)
|
||||
fmt.Println(msg)
|
||||
}
|
||||
}
|
||||
|
|
138
cmd/transfer.go
138
cmd/transfer.go
|
@ -31,6 +31,7 @@ import (
|
|||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
type cList struct {
|
||||
|
@ -55,31 +56,33 @@ var (
|
|||
dstToken string
|
||||
sysRegistered bool
|
||||
workers int
|
||||
unique bool
|
||||
limit int
|
||||
wg sync.WaitGroup
|
||||
wgSrc sync.WaitGroup
|
||||
cmdList commandsList
|
||||
transferCmd = &cobra.Command{
|
||||
Use: "transfer",
|
||||
Short: "Transfer bashhub history from one server to another",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Flags().Parse(args)
|
||||
|
||||
switch {
|
||||
case srcUser == "":
|
||||
_ = cmd.Usage()
|
||||
fmt.Print("\n\n")
|
||||
log.Fatal("--src-user can't be blank")
|
||||
case srcPass == "":
|
||||
_ = cmd.Usage()
|
||||
fmt.Print("\n\n")
|
||||
log.Fatal("--src-pass can't be blank")
|
||||
log.Fatal("src-user can't be blank")
|
||||
case dstUser == "":
|
||||
_ = cmd.Usage()
|
||||
fmt.Print("\n\n")
|
||||
log.Fatal("--dst-user can't be blank")
|
||||
case dstPass == "":
|
||||
_ = cmd.Usage()
|
||||
fmt.Print("\n\n")
|
||||
log.Fatal("--dst-pass can't be blank")
|
||||
case srcPass == "" || dstPass == "":
|
||||
if srcPass == "" {
|
||||
srcPass = credentials("source")
|
||||
}
|
||||
if dstPass == "" {
|
||||
dstPass = credentials("destination")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if workers > 10 && srcURL == "https://bashhub.com" {
|
||||
|
@ -88,30 +91,7 @@ var (
|
|||
than 10 when transferring from https://bashhub.com`)
|
||||
fmt.Print(msg, "\n\n")
|
||||
}
|
||||
|
||||
sysRegistered = false
|
||||
srcToken = getToken(srcURL, srcUser, srcPass)
|
||||
sysRegistered = false
|
||||
dstToken = getToken(dstURL, dstUser, dstPass)
|
||||
cmdList = getCommandList()
|
||||
counter := 0
|
||||
if !progress {
|
||||
bar = pb.ProgressBarTemplate(barTemplate).Start(len(cmdList)).SetMaxWidth(70)
|
||||
bar.Set("message", "transferring ")
|
||||
}
|
||||
client := &http.Client{}
|
||||
// ignore http errors. We try and recover them
|
||||
log.SetOutput(nil)
|
||||
for _, v := range cmdList {
|
||||
wg.Add(1)
|
||||
counter++
|
||||
go commandLookup(v.UUID, client, 0)
|
||||
if counter > workers {
|
||||
wg.Wait()
|
||||
counter = 0
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
run()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -120,14 +100,69 @@ func init() {
|
|||
rootCmd.AddCommand(transferCmd)
|
||||
transferCmd.PersistentFlags().StringVar(&srcURL, "src-url", "https://bashhub.com", "source url ")
|
||||
transferCmd.PersistentFlags().StringVar(&srcUser, "src-user", "", "source username")
|
||||
transferCmd.PersistentFlags().StringVar(&srcPass, "src-pass", "", "source password")
|
||||
transferCmd.PersistentFlags().StringVar(&srcPass, "src-pass", "", "source password (default is password prompt)")
|
||||
transferCmd.PersistentFlags().StringVar(&dstURL, "dst-url", "http://localhost:8080", "destination url")
|
||||
transferCmd.PersistentFlags().StringVar(&dstUser, "dst-user", "", "destination username")
|
||||
transferCmd.PersistentFlags().StringVar(&dstPass, "dst-pass", "", "destination password")
|
||||
transferCmd.PersistentFlags().StringVar(&dstPass, "dst-pass", "", "destination password (default is password prompt)")
|
||||
transferCmd.PersistentFlags().BoolVarP(&progress, "quiet", "q", false, "don't show progress bar")
|
||||
transferCmd.PersistentFlags().IntVarP(&workers, "workers", "w", 10, "max number of concurrent requests")
|
||||
}
|
||||
transferCmd.PersistentFlags().BoolVarP(&unique, "unique", "u", true, "don't include duplicate commands")
|
||||
transferCmd.PersistentFlags().IntVarP(&limit, "number", "n", 10000, "limit number of commands to transfer")
|
||||
|
||||
}
|
||||
func credentials(s string) string {
|
||||
|
||||
fmt.Printf("\nEnter %s password: ", s)
|
||||
bytePassword, err := terminal.ReadPassword(0)
|
||||
if err != nil {
|
||||
check(err)
|
||||
}
|
||||
password := string(bytePassword)
|
||||
|
||||
return strings.TrimSpace(password)
|
||||
}
|
||||
func run() {
|
||||
sysRegistered = false
|
||||
srcToken = getToken(srcURL, srcUser, srcPass)
|
||||
sysRegistered = false
|
||||
dstToken = getToken(dstURL, dstUser, dstPass)
|
||||
cmdList = getCommandList()
|
||||
counter := 0
|
||||
|
||||
if !progress {
|
||||
bar = pb.ProgressBarTemplate(barTemplate).Start(len(cmdList)).SetMaxWidth(70)
|
||||
bar.Set("message", "transferring ")
|
||||
}
|
||||
fmt.Print("\nstarting transfer...\n\n")
|
||||
client := &http.Client{}
|
||||
pipe := make(chan []byte)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case data := <-pipe:
|
||||
wgSrc.Add(1)
|
||||
go srcSend(data, client)
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
// ignore http errors. We try and recover them
|
||||
log.SetOutput(nil)
|
||||
for _, v := range cmdList {
|
||||
wg.Add(1)
|
||||
counter++
|
||||
go commandLookup(v.UUID, client, 0, pipe)
|
||||
if counter > workers {
|
||||
wg.Wait()
|
||||
counter = 0
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
if !progress {
|
||||
bar.Finish()
|
||||
}
|
||||
wgSrc.Wait()
|
||||
}
|
||||
func sysRegister(mac string, site string, user string, pass string) string {
|
||||
|
||||
var token string
|
||||
|
@ -166,7 +201,8 @@ func sysRegister(mac string, site string, user string, pass string) string {
|
|||
}
|
||||
j := make(map[string]interface{})
|
||||
|
||||
json.Unmarshal(buf, &j)
|
||||
err = json.Unmarshal(buf, &j)
|
||||
check(err)
|
||||
|
||||
if len(j) == 0 {
|
||||
log.Fatal("login failed for ", site)
|
||||
|
@ -186,6 +222,7 @@ func sysRegister(mac string, site string, user string, pass string) string {
|
|||
"hostname": host,
|
||||
"mac": mac,
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(sys)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -250,9 +287,10 @@ func getToken(site string, user string, pass string) string {
|
|||
}
|
||||
j := make(map[string]interface{})
|
||||
|
||||
json.Unmarshal(buf, &j)
|
||||
err = json.Unmarshal(buf, &j)
|
||||
check(err)
|
||||
|
||||
if len(j) == 0 {
|
||||
if len(j) == 0 || resp.StatusCode == 401 {
|
||||
log.Fatal("login failed for ", site)
|
||||
|
||||
}
|
||||
|
@ -260,7 +298,7 @@ func getToken(site string, user string, pass string) string {
|
|||
}
|
||||
|
||||
func getCommandList() commandsList {
|
||||
u := strings.TrimSpace(srcURL) + "/api/v1/command/search?unique=true&limit=1000000"
|
||||
u := strings.TrimSpace(srcURL) + fmt.Sprintf("/api/v1/command/search?unique=%v&limit=%v", unique, limit)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -291,16 +329,18 @@ func getCommandList() commandsList {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
func commandLookup(uuid string, client *http.Client, retries int) {
|
||||
func commandLookup(uuid string, client *http.Client, retries int, pipe chan []byte) {
|
||||
defer func() {
|
||||
wg.Done()
|
||||
if r := recover(); r != nil {
|
||||
mem := strings.Contains(fmt.Sprintf("%v", r), "runtime error: invalid memory address")
|
||||
eof := strings.Contains(fmt.Sprintf("%v", r), "EOF")
|
||||
if mem || eof {
|
||||
if retries < 10 {
|
||||
retries++
|
||||
commandLookup(uuid, client, retries)
|
||||
wg.Add(1)
|
||||
go commandLookup(uuid, client, retries, pipe)
|
||||
|
||||
} else {
|
||||
log.SetOutput(os.Stderr)
|
||||
log.Println("ERROR: failed over 10 times looking up command from source with uuid: ", uuid)
|
||||
|
@ -334,7 +374,7 @@ func commandLookup(uuid string, client *http.Client, retries int) {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
srcSend(body, client)
|
||||
pipe <- body
|
||||
}
|
||||
|
||||
func srcSend(data []byte, client *http.Client) {
|
||||
|
@ -342,7 +382,7 @@ func srcSend(data []byte, client *http.Client) {
|
|||
if !progress {
|
||||
bar.Add(1)
|
||||
}
|
||||
wg.Done()
|
||||
wgSrc.Done()
|
||||
}()
|
||||
body := bytes.NewReader(data)
|
||||
|
||||
|
@ -364,3 +404,9 @@ func srcSend(data []byte, client *http.Client) {
|
|||
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
322
cmd/transfer_test.go
Normal file
322
cmd/transfer_test.go
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2020 nicksherron <nsherron90@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/icrowley/fake"
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/nicksherron/bashhub-server/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
testWork bool
|
||||
testDir string
|
||||
src *exec.Cmd
|
||||
dst *exec.Cmd
|
||||
sessionStartTime int64
|
||||
commandsN int
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&srcURL, "src-url", "http://localhost:55555", "source url ")
|
||||
flag.StringVar(&srcUser, "src-user", "tester", "source username")
|
||||
flag.StringVar(&srcPass, "src-pass", "tester", "source password")
|
||||
flag.StringVar(&dstURL, "dst-url", "http://localhost:55556", "destination url")
|
||||
flag.StringVar(&dstUser, "dst-user", "tester", "destination username")
|
||||
flag.StringVar(&dstPass, "dst-pass", "tester", "destination password")
|
||||
flag.IntVar(&workers, "workers", 10, "max number of concurrent requests")
|
||||
flag.IntVar(&commandsN, "number", 200, "number of commmands to use for test")
|
||||
flag.BoolVar(&testWork, "testwork", false, "don't remove sqlite db and server log when done and print location")
|
||||
}
|
||||
|
||||
func startServer(cmd string, args []string, writer io.Writer) (p *exec.Cmd, err error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
check(err)
|
||||
}
|
||||
parent := filepath.Dir(cwd)
|
||||
|
||||
if cmd, err = exec.LookPath(cmd); err == nil {
|
||||
var procAttr os.ProcAttr
|
||||
procAttr.Dir = parent
|
||||
procAttr.Files = []*os.File{os.Stdin,
|
||||
os.Stdout, os.Stderr}
|
||||
p := exec.Command(cmd, args...)
|
||||
p.Dir = parent
|
||||
p.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
p.Stderr = writer
|
||||
return p, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func startSrc() (*exec.Cmd, error) {
|
||||
srcDB := filepath.Join(testDir, "src.db")
|
||||
srcLog := filepath.Join(testDir, "src-server.log")
|
||||
srcErr := filepath.Join(testDir, "src-stderr.log")
|
||||
srcArgs := []string{"run", ".", "-a", srcURL, "--db", srcDB, "--log", srcLog}
|
||||
f, err := os.Create(srcErr)
|
||||
check(err)
|
||||
return startServer("go", srcArgs, f)
|
||||
}
|
||||
|
||||
func startDst() (*exec.Cmd, error) {
|
||||
dstDB := filepath.Join(testDir, "dst.db")
|
||||
dstLog := filepath.Join(testDir, "dst-server.log")
|
||||
srcErr := filepath.Join(testDir, "dst-stderr.log")
|
||||
dstArgs := []string{"run", ".", "-a", dstURL, "--db", dstDB, "--log", dstLog}
|
||||
f, err := os.Create(srcErr)
|
||||
check(err)
|
||||
return startServer("go", dstArgs, f)
|
||||
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.Parse()
|
||||
|
||||
defer cleanup()
|
||||
|
||||
var err error
|
||||
testDir, err = ioutil.TempDir("", "bashhub-server-test-")
|
||||
check(err)
|
||||
|
||||
src, err = startSrc()
|
||||
check(err)
|
||||
err = src.Start()
|
||||
check(err)
|
||||
|
||||
dst, err = startDst()
|
||||
check(err)
|
||||
err = dst.Start()
|
||||
check(err)
|
||||
|
||||
tries := 0
|
||||
|
||||
for {
|
||||
if ping(srcURL) == nil && ping(dstURL) == nil {
|
||||
break
|
||||
}
|
||||
tries++
|
||||
if tries > 10 {
|
||||
log.Fatal("failed connecting to servers after 10 attempts")
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
createUser(srcURL, srcUser, srcPass)
|
||||
createUser(dstURL, dstUser, dstPass)
|
||||
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func ping(u string) error {
|
||||
_, err := http.Get(fmt.Sprintf("%v/ping", u))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createUser(u string, user string, pass string) {
|
||||
auth := map[string]interface{}{
|
||||
"email": "foo@gmail.com",
|
||||
"Username": user,
|
||||
"password": pass,
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(auth)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
u = fmt.Sprintf("%v/api/v1/user", u)
|
||||
req, err := http.NewRequest("POST", u, body)
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
defer resp.Body.Close()
|
||||
|
||||
}
|
||||
|
||||
func TestCreateToken(t *testing.T) {
|
||||
sysRegistered = false
|
||||
srcToken = getToken(srcURL, srcUser, srcPass)
|
||||
if srcToken == "" {
|
||||
t.Fatal("srcToken token is blank")
|
||||
}
|
||||
sysRegistered = false
|
||||
dstToken = getToken(dstURL, dstUser, dstPass)
|
||||
if dstToken == "" {
|
||||
t.Fatal("dstToken token is blank")
|
||||
}
|
||||
}
|
||||
|
||||
func commandInsert() {
|
||||
counter := 0
|
||||
sessionStartTime = time.Now().Unix() * 1000
|
||||
var w sync.WaitGroup
|
||||
for i := 0; i < commandsN; i++ {
|
||||
w.Add(1)
|
||||
counter++
|
||||
go func() {
|
||||
defer w.Done()
|
||||
var tc internal.Command
|
||||
uid, err := uuid.NewRandom()
|
||||
check(err)
|
||||
|
||||
tc.Command = fake.Words()
|
||||
tc.Path = "/dev/null"
|
||||
tc.Created = time.Now().Unix() * 1000
|
||||
tc.Uuid = uid.String()
|
||||
tc.ExitStatus = 0
|
||||
tc.SystemName = "system"
|
||||
tc.SessionID = "1000"
|
||||
tc.User.Username = srcUser
|
||||
tc.ProcessStartTime = sessionStartTime
|
||||
|
||||
payloadBytes, err := json.Marshal(&tc)
|
||||
check(err)
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%v/api/v1/command", srcURL), body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Add("Authorization", srcToken)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
defer resp.Body.Close()
|
||||
}()
|
||||
if counter > workers {
|
||||
w.Wait()
|
||||
counter = 0
|
||||
}
|
||||
|
||||
}
|
||||
w.Wait()
|
||||
}
|
||||
|
||||
func TestCommandList(t *testing.T) {
|
||||
commandInsert()
|
||||
cmdList = getCommandList()
|
||||
if len(cmdList) == 0 {
|
||||
t.Fatal("command list is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransfer(t *testing.T) {
|
||||
progress = true
|
||||
unique = false
|
||||
run()
|
||||
srcStatus := getStatus(t, srcURL, srcToken)
|
||||
dstStatus := getStatus(t, dstURL, dstToken)
|
||||
assert.Equal(t, srcStatus.TotalCommands, commandsN)
|
||||
assert.Equal(t, dstStatus.TotalCommands, srcStatus.TotalCommands)
|
||||
}
|
||||
|
||||
func BenchmarkGoInserts(b *testing.B) {
|
||||
client := &http.Client{}
|
||||
counter := 0
|
||||
pipe := make(chan []byte)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case data := <-pipe:
|
||||
wgSrc.Add(1)
|
||||
go srcSend(data, client)
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
for i := 0; i < b.N; i++ {
|
||||
wg.Add(1)
|
||||
counter++
|
||||
n := rand.Intn(commandsN)
|
||||
go commandLookup(cmdList[n].UUID, client, 0, pipe)
|
||||
if counter > workers {
|
||||
wg.Wait()
|
||||
counter = 0
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
if !progress {
|
||||
bar.Finish()
|
||||
}
|
||||
wgSrc.Wait()
|
||||
}
|
||||
|
||||
func getStatus(t *testing.T, u string, token string) internal.Status {
|
||||
u = fmt.Sprintf("%v/api/v1/client-view/status?processId=1000&startTime=%v", u, sessionStartTime)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
check(err)
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Add("Authorization", token)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var status internal.Status
|
||||
err = json.Unmarshal(body, &status)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
defer func() {
|
||||
if err := syscall.Kill(-dst.Process.Pid, syscall.SIGKILL); err != nil {
|
||||
log.Println("failed to kill: ", err)
|
||||
}
|
||||
if err := syscall.Kill(-src.Process.Pid, syscall.SIGKILL); err != nil {
|
||||
log.Println("failed to kill: ", err)
|
||||
}
|
||||
}()
|
||||
if !testWork {
|
||||
err := os.Chmod(testDir, 0777)
|
||||
check(err)
|
||||
err = os.RemoveAll(testDir)
|
||||
check(err)
|
||||
return
|
||||
}
|
||||
log.SetOutput(os.Stderr)
|
||||
log.Println("TESTWORK=", testDir)
|
||||
}
|
18
go.mod
18
go.mod
|
@ -1,17 +1,21 @@
|
|||
module github.com/nicksherron/bashhub-server
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.3
|
||||
github.com/cheggaaa/pb/v3 v3.0.4
|
||||
github.com/corpix/uarand v0.1.1 // indirect
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/gin-gonic/gin v1.5.0
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible
|
||||
github.com/spf13/cobra v0.0.3
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd
|
||||
github.com/magiconair/properties v1.8.0
|
||||
github.com/manifoldco/promptui v0.7.0
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
|
76
go.sum
76
go.sum
|
@ -1,11 +1,29 @@
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.3 h1:aK4E3DjihWEBUTjEeRnGkA5nUkmwJPL1CPonMa2usRs=
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.3/go.mod h1:MfPYA4ogzvOcVkRwAxT7quHOtQmVKDpTwxyUrC2DNw0=
|
||||
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
|
||||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/cheggaaa/pb/v3 v3.0.4 h1:QZEPYOj2ix6d5oEg63fbHmpolrnNiwjUsk+h74Yt4bM=
|
||||
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U=
|
||||
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -18,6 +36,7 @@ github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a
|
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
|
@ -37,6 +56,11 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428 h1:Mo9W14pwbO9VfRe+ygqZ8dFbPpoIK1HFrG/zjTuQ+nc=
|
||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
|
||||
|
@ -48,40 +72,63 @@ github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
|
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
|
||||
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/manifoldco/promptui v0.7.0 h1:3l11YT8tm9MnwGFQ4kETwkzpAwY2Jt9lCrumCUW4+z4=
|
||||
github.com/manifoldco/promptui v0.7.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -94,22 +141,26 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
|
|||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6 h1:Sy5bstxEqwwbYs6n0/pBuxKENqOeZUgD45Gp3Q3pqLg=
|
||||
golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -118,12 +169,13 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50
|
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
230
internal/db.go
230
internal/db.go
|
@ -39,31 +39,28 @@ import (
|
|||
|
||||
var (
|
||||
db *sql.DB
|
||||
// DbPath is the postgres connection uri or the sqlite db file location to use for backend.
|
||||
DbPath string
|
||||
connectionLimit int
|
||||
)
|
||||
|
||||
// DbInit initializes our db.
|
||||
func dbInit() {
|
||||
func dbInit(dbPath string) {
|
||||
var gormdb *gorm.DB
|
||||
var err error
|
||||
if strings.HasPrefix(DbPath, "postgres://") {
|
||||
if strings.HasPrefix(dbPath, "postgres://") {
|
||||
// postgres
|
||||
|
||||
db, err = sql.Open("postgres", DbPath)
|
||||
db, err = sql.Open("postgres", dbPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
gormdb, err = gorm.Open("postgres", DbPath)
|
||||
gormdb, err = gorm.Open("postgres", dbPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
connectionLimit = 50
|
||||
} else {
|
||||
// sqlite
|
||||
gormdb, err = gorm.Open("sqlite3", DbPath)
|
||||
gormdb, err = gorm.Open("sqlite3", dbPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -80,13 +77,16 @@ func dbInit() {
|
|||
},
|
||||
})
|
||||
|
||||
DbPath = fmt.Sprintf("file:%v?cache=shared&mode=rwc&_loc=auto", DbPath)
|
||||
db, err = sql.Open("sqlite3_with_regex", DbPath)
|
||||
dbPath = fmt.Sprintf("file:%v?cache=shared&mode=rwc&_loc=auto", dbPath)
|
||||
db, err = sql.Open("sqlite3_with_regex", dbPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
db.Exec("PRAGMA journal_mode=WAL;")
|
||||
_, err = db.Exec("PRAGMA journal_mode=WAL;")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
connectionLimit = 1
|
||||
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ func (cmd Command) commandInsert() int64 {
|
|||
|
||||
res, err := db.Exec(`
|
||||
INSERT INTO commands("process_id","process_start_time","exit_status","uuid","command", "created", "path", "user_id", "system_name")
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) ON CONFLICT do nothing`,
|
||||
cmd.ProcessId, cmd.ProcessStartTime, cmd.ExitStatus, cmd.Uuid, cmd.Command, cmd.Created, cmd.Path, cmd.User.ID, cmd.SystemName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -235,106 +235,107 @@ func (cmd Command) commandInsert() int64 {
|
|||
}
|
||||
|
||||
func (cmd Command) commandGet() ([]Query, error) {
|
||||
var results []Query
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
var (
|
||||
results []Query
|
||||
query string
|
||||
)
|
||||
if cmd.Unique || cmd.Query != "" {
|
||||
//postgres
|
||||
if connectionLimit != 1 {
|
||||
if cmd.SystemName != "" && cmd.Path != "" && cmd.Query != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $3
|
||||
AND "system_name" = $4
|
||||
AND "command" ~ $5
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path, cmd.SystemName, cmd.Query)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Path, cmd.SystemName, cmd.Query, cmd.Limit)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Query != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $3
|
||||
AND "command" ~ $4
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path, cmd.Query)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Path, cmd.Query, cmd.Limit)
|
||||
|
||||
} else if cmd.SystemName != "" && cmd.Query != "" {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "system_name" = $3
|
||||
AND "command" ~ $4
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.SystemName, cmd.Query)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.SystemName, cmd.Query, cmd.Limit)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Query != "" {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $3
|
||||
AND "command" ~ $4
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path, cmd.Query)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Path, cmd.Query, cmd.Limit)
|
||||
|
||||
} else if cmd.SystemName != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "system_name" = $3
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.SystemName)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.SystemName, cmd.Limit)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $3
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Path, cmd.Limit)
|
||||
|
||||
} else if cmd.Query != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "command" ~ $3
|
||||
WHERE "user_id" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Query)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Query, cmd.Limit)
|
||||
|
||||
} else if cmd.Query != "" {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "command" ~ $3
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Query)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "command" ~ '%v'
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Query, cmd.Limit)
|
||||
|
||||
} else {
|
||||
// unique
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON ("command") command, "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
WHERE "user_id" = '%v'
|
||||
) c
|
||||
ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit)
|
||||
ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Limit)
|
||||
}
|
||||
} else {
|
||||
// sqlite
|
||||
if cmd.SystemName != "" && cmd.Path != "" && cmd.Query != "" && cmd.Unique {
|
||||
// Have to use fmt.Sprintf to build queries where sqlite regexp function is used because of single quotes. Haven't found any other work around.
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
|
@ -342,120 +343,108 @@ func (cmd Command) commandGet() ([]Query, error) {
|
|||
AND "command" regexp '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Path, cmd.SystemName, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.SystemName != "" && cmd.Query != "" && cmd.Unique {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
AND "command" regexp '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.SystemName, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Query != "" && cmd.Unique {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
AND "command" regexp '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Path, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.SystemName != "" && cmd.Query != "" {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = %v'
|
||||
AND "command" regexp %v'
|
||||
AND "system_name" = '%v'
|
||||
AND "command" regexp '%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.SystemName, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Query != "" {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = %v'
|
||||
AND "command" regexp %v'
|
||||
AND "path" = '%v'
|
||||
AND "command" regexp '%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Path, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.SystemName != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "system_name" = $2
|
||||
GROUP BY "command" ORDER BY "created" DESC limit $3`, cmd.User.ID, cmd.SystemName, cmd.Limit)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.SystemName, cmd.Limit)
|
||||
|
||||
} else if cmd.Path != "" && cmd.Unique {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $2
|
||||
GROUP BY "command" ORDER BY "created" DESC limit $3`, cmd.User.ID, cmd.Path, cmd.Limit)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Path, cmd.Limit)
|
||||
|
||||
} else if cmd.Query != "" && cmd.Unique {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "command" regexp '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else if cmd.Query != "" {
|
||||
query := fmt.Sprintf(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "command" regexp'%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Query, cmd.Limit)
|
||||
|
||||
rows, err = db.Query(query)
|
||||
|
||||
} else {
|
||||
// unique
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created"
|
||||
FROM commands
|
||||
WHERE "user_id" = $1
|
||||
GROUP BY "command" ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit)
|
||||
WHERE "user_id" = '%v'
|
||||
GROUP BY "command" ORDER BY "created" DESC limit '%v';`, cmd.User.ID, cmd.Limit)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if cmd.Path != "" {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "path" = $3
|
||||
ORDER BY "created" DESC limit $2`, cmd.User.ID, cmd.Limit, cmd.Path)
|
||||
WHERE "user_id" = '%v'
|
||||
AND "path" = '%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Path, cmd.Limit)
|
||||
} else if cmd.SystemName != "" {
|
||||
rows, err = db.Query(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = $1
|
||||
AND "system_name" = $3
|
||||
ORDER BY "created" DESC limit $2`, cmd.User.ID, cmd.Limit, cmd.SystemName)
|
||||
query = fmt.Sprintf(`SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = '%v'
|
||||
AND "system_name" = '%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.SystemName, cmd.Limit)
|
||||
|
||||
} else {
|
||||
rows, err = db.Query(`
|
||||
query = fmt.Sprintf(`
|
||||
SELECT "command", "uuid", "created" FROM commands
|
||||
WHERE "user_id" = $1
|
||||
ORDER BY "created" DESC limit $2`, cmd.User.ID, cmd.Limit)
|
||||
WHERE "user_id" = '%v'
|
||||
ORDER BY "created" DESC limit '%v'`, cmd.User.ID, cmd.Limit)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rows, err := db.Query(query)
|
||||
|
||||
if err != nil {
|
||||
return []Query{}, nil
|
||||
return []Query{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var result Query
|
||||
err = rows.Scan(&result.Command, &result.Uuid, &result.Created)
|
||||
if err != nil {
|
||||
return []Query{}, nil
|
||||
return []Query{}, err
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
|
@ -466,11 +455,11 @@ func (cmd Command) commandGet() ([]Query, error) {
|
|||
func (cmd Command) commandGetUUID() (Query, error) {
|
||||
var result Query
|
||||
err := db.QueryRow(`
|
||||
SELECT "command","path", "created" , "uuid", "exit_status", "system_name"
|
||||
SELECT "command","path", "created" , "uuid", "exit_status", "system_name", "process_id"
|
||||
FROM commands
|
||||
WHERE "uuid" = $1
|
||||
AND "user_id" = $2`, cmd.Uuid, cmd.User.ID).Scan(&result.Command, &result.Path, &result.Created, &result.Uuid,
|
||||
&result.ExitStatus, &result.SystemName)
|
||||
&result.ExitStatus, &result.SystemName, &result.SessionID)
|
||||
if err != nil {
|
||||
return Query{}, err
|
||||
}
|
||||
|
@ -544,20 +533,22 @@ func (sys System) systemGet() (System, error) {
|
|||
func (status Status) statusGet() (Status, error) {
|
||||
var err error
|
||||
if connectionLimit != 1 {
|
||||
err = db.QueryRow(`select
|
||||
err = db.QueryRow(`
|
||||
select
|
||||
( select count(*) from commands where user_id = $1) as totalCommands,
|
||||
( select count(distinct process_id) from commands where user_id = $1) as totalSessions,
|
||||
( select count(distinct system_name) from commands where user_id = $1) as totalSystems,
|
||||
( select count (*) from commands where to_timestamp(cast(created/1000 as bigint))::date = now()::date and user_id = $1) as totalCommandsToday,
|
||||
( select count(*) from systems where user_id = $1) as totalSystems,
|
||||
( select count(*) from commands where to_timestamp(cast(created/1000 as bigint))::date = now()::date and user_id = $1) as totalCommandsToday,
|
||||
( select count(*) from commands where process_id = $2) as sessionTotalCommands`,
|
||||
status.User.ID, status.ProcessID).Scan(
|
||||
&status.TotalCommands, &status.TotalSessions, &status.TotalSystems,
|
||||
&status.TotalCommandsToday, &status.SessionTotalCommands)
|
||||
} else {
|
||||
err = db.QueryRow(`select
|
||||
err = db.QueryRow(`
|
||||
select
|
||||
( select count(*) from commands where user_id = $1) as totalCommands,
|
||||
( select count(distinct process_id) from commands where user_id = $1) as totalSessions,
|
||||
( select count(distinct system_name) from commands where user_id = $1) as totalSystems,
|
||||
( select count(*) from systems where user_id = $1) as totalSystems,
|
||||
( select count(*) from commands where date(created/1000, 'unixepoch') = date('now') and user_id = $1) as totalCommandsToday,
|
||||
( select count(*) from commands where process_id = $2) as sessionTotalCommands`,
|
||||
status.User.ID, status.ProcessID).Scan(
|
||||
|
@ -570,14 +561,13 @@ func (status Status) statusGet() (Status, error) {
|
|||
return status, err
|
||||
}
|
||||
|
||||
func importCommands(imp Import) {
|
||||
_, err := db.Exec(`INSERT INTO commands
|
||||
("command", "path", "created", "uuid", "exit_status",
|
||||
"system_name", "session_id", "user_id" )
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,(select "id" from users where "username" = $8)) ON CONFLICT do nothing`,
|
||||
imp.Command, imp.Path, imp.Created, imp.Uuid, imp.ExitStatus,
|
||||
imp.SystemName, imp.SessionID, imp.Username)
|
||||
func importCommands(imp Import) error {
|
||||
_, err := db.Exec(`
|
||||
INSERT INTO commands ("command", "path", "created", "uuid", "exit_status","system_name", "session_id", "user_id" )
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7 ,(select "id" from users where "username" = $8)) ON CONFLICT do nothing`,
|
||||
imp.Command, imp.Path, imp.Created, imp.Uuid, imp.ExitStatus, imp.SystemName, imp.SessionID, imp.Username)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package internal
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -103,42 +105,43 @@ type Import Query
|
|||
|
||||
var (
|
||||
// Addr is the listen and server address for our server (gin)
|
||||
Addr string
|
||||
//Addr string
|
||||
// LogFile is the log file location for http logging. Default is stderr.
|
||||
LogFile string
|
||||
//logFile string
|
||||
config Config
|
||||
)
|
||||
|
||||
func getLog() *os.File {
|
||||
|
||||
if LogFile != "" {
|
||||
f, err := os.Create(LogFile)
|
||||
func getLog(logFile string) io.Writer {
|
||||
switch {
|
||||
case logFile == "/dev/null":
|
||||
return ioutil.Discard
|
||||
case logFile != "":
|
||||
f, err := os.Create(logFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
default:
|
||||
return os.Stderr
|
||||
}
|
||||
}
|
||||
|
||||
// LoggerWithFormatter instance a Logger middleware with the specified log format function.
|
||||
func loggerWithFormatterWriter(f gin.LogFormatter) gin.HandlerFunc {
|
||||
func loggerWithFormatterWriter(logFile string, f gin.LogFormatter) gin.HandlerFunc {
|
||||
return gin.LoggerWithConfig(gin.LoggerConfig{
|
||||
Formatter: f,
|
||||
Output: getLog(),
|
||||
Output: getLog(logFile),
|
||||
})
|
||||
}
|
||||
|
||||
// Run starts server
|
||||
func Run() {
|
||||
// Initialize backend
|
||||
dbInit()
|
||||
|
||||
// configure routes and middleware
|
||||
func setupRouter(dbPath string, logFile string) *gin.Engine {
|
||||
dbInit(dbPath)
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
r.Use(loggerWithFormatterWriter(func(param gin.LogFormatterParams) string {
|
||||
r.Use(loggerWithFormatterWriter(logFile, func(param gin.LogFormatterParams) string {
|
||||
return fmt.Sprintf("[BASHHUB-SERVER] %v | %3d | %13v | %15s | %-7s %s\n",
|
||||
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
||||
param.StatusCode,
|
||||
|
@ -278,10 +281,9 @@ func Run() {
|
|||
command.Limit = num
|
||||
}
|
||||
}
|
||||
command.Unique = false
|
||||
if c.Query("unique") == "true" {
|
||||
command.Unique = true
|
||||
} else {
|
||||
command.Unique = false
|
||||
}
|
||||
command.Path = c.Query("path")
|
||||
command.Query = c.Query("query")
|
||||
|
@ -452,13 +454,26 @@ func Run() {
|
|||
return
|
||||
}
|
||||
claims := jwt.ExtractClaims(c)
|
||||
imp.Username = claims["username"].(string)
|
||||
importCommands(imp)
|
||||
user := claims["username"].(string)
|
||||
imp.Username = user
|
||||
err = importCommands(imp)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
})
|
||||
|
||||
Addr = strings.ReplaceAll(Addr, "http://", "")
|
||||
err = r.Run(Addr)
|
||||
return r
|
||||
}
|
||||
|
||||
// Run starts server
|
||||
func Run(dbFile string, logFile string, addr string) {
|
||||
r := setupRouter(dbFile, logFile)
|
||||
|
||||
addr = strings.ReplaceAll(addr, "http://", "")
|
||||
err := r.Run(addr)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error: \t", err)
|
||||
|
|
387
internal/server_test.go
Normal file
387
internal/server_test.go
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 2020 nicksherron <nsherron90@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
testWork = flag.Bool("testwork", false, "don't remove sqlite db and server log when done and print location")
|
||||
postgres = flag.String("postgres-uri", "", "postgres uri to use for postgres tests")
|
||||
sessionStartTime int64
|
||||
pid string
|
||||
dir string
|
||||
router *gin.Engine
|
||||
sysRegistered bool
|
||||
jwtToken string
|
||||
testDir string
|
||||
system sysStruct
|
||||
)
|
||||
|
||||
type sysStruct struct {
|
||||
user string
|
||||
pass string
|
||||
mac int
|
||||
email string
|
||||
systemName string
|
||||
host string
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
flag.Parse()
|
||||
defer dirCleanup()
|
||||
|
||||
var err error
|
||||
testDir, err = ioutil.TempDir("", "bashhub-server-test-")
|
||||
check(err)
|
||||
dir = "/tmp/foo"
|
||||
|
||||
dbPath := filepath.Join(testDir, "test.db")
|
||||
logFile := filepath.Join(testDir, "server.log")
|
||||
log.Print("sqlite tests")
|
||||
router = setupRouter(dbPath, logFile)
|
||||
|
||||
system = sysStruct{
|
||||
user: "tester",
|
||||
pass: "tester",
|
||||
mac: 888888888888888,
|
||||
email: "test@email.com",
|
||||
host: "some-host",
|
||||
}
|
||||
m.Run()
|
||||
|
||||
if *postgres != "" {
|
||||
log.Print("postgres tests")
|
||||
dbPath := *postgres
|
||||
logFile := filepath.Join(testDir, "postgres-server.log")
|
||||
router = setupRouter(dbPath, logFile)
|
||||
m.Run()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testRequest(method string, u string, body io.Reader) *httptest.ResponseRecorder {
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest(method, u, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Add("Authorization", jwtToken)
|
||||
router.ServeHTTP(w, req)
|
||||
return w
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createUser(t *testing.T) {
|
||||
auth := map[string]interface{}{
|
||||
"email": system.email,
|
||||
"Username": system.user,
|
||||
"password": system.pass,
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(auth)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
w := testRequest("POST", "/api/v1/user", body)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
}
|
||||
|
||||
func getToken(t *testing.T) string {
|
||||
|
||||
auth := map[string]interface{}{
|
||||
"username": system.user,
|
||||
"password": system.pass,
|
||||
"mac": strconv.Itoa(system.mac),
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(auth)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
w := testRequest("POST", "/api/v1/login", body)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
|
||||
buf, err := ioutil.ReadAll(w.Body)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
j := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(buf, &j)
|
||||
check(err)
|
||||
|
||||
if len(j) == 0 {
|
||||
t.Fatal("login failed for getToken")
|
||||
|
||||
}
|
||||
token := fmt.Sprintf("Bearer %v", j["accessToken"])
|
||||
|
||||
if !sysRegistered {
|
||||
// register system
|
||||
return sysRegister(t, token)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
func sysRegister(t *testing.T, token string) string {
|
||||
|
||||
jwtToken = token
|
||||
sysPayload := map[string]interface{}{
|
||||
"clientVersion": "1.2.0",
|
||||
"name": system.systemName,
|
||||
"hostname": system.host,
|
||||
"mac": strconv.Itoa(system.mac),
|
||||
}
|
||||
payloadBytes, err := json.Marshal(sysPayload)
|
||||
check(err)
|
||||
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
|
||||
w := testRequest("POST", "/api/v1/system", body)
|
||||
assert.Equal(t, 201, w.Code)
|
||||
|
||||
sysRegistered = true
|
||||
|
||||
return getToken(t)
|
||||
|
||||
}
|
||||
|
||||
func TestToken(t *testing.T) {
|
||||
createUser(t)
|
||||
systems := []string{
|
||||
"system-1",
|
||||
"system-2",
|
||||
"system-3",
|
||||
}
|
||||
for _, sys := range systems {
|
||||
system.systemName = sys
|
||||
system.mac++
|
||||
sysRegistered = false
|
||||
jwtToken = getToken(t)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCommandInsert(t *testing.T) {
|
||||
var commandTests = []Command{
|
||||
{ExitStatus: 0, Command: "cat foo.txt"},
|
||||
{ExitStatus: 0, Command: "ls"},
|
||||
{ExitStatus: 0, Command: "pwd"},
|
||||
{ExitStatus: 0, Command: "whoami"},
|
||||
{ExitStatus: 0, Command: "which cat"},
|
||||
{ExitStatus: 0, Command: "head foo.txt"},
|
||||
{ExitStatus: 0, Command: "sed 's/fooobaar/foobar/g' somefile.txt"},
|
||||
{ExitStatus: 0, Command: "curl google.com"},
|
||||
{ExitStatus: 0, Command: "file /dev/null"},
|
||||
{ExitStatus: 0, Command: "df -h"},
|
||||
{ExitStatus: 127, Command: "catt"},
|
||||
{ExitStatus: 127, Command: "cay"},
|
||||
}
|
||||
|
||||
sessionStartTime = time.Now().Unix() * 1000
|
||||
for i := 0; i < 5; i++ {
|
||||
for _, tc := range commandTests {
|
||||
uid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tc.ProcessId = i
|
||||
tc.Path = dir
|
||||
tc.Created = time.Now().Unix() * 1000
|
||||
tc.ProcessStartTime = sessionStartTime
|
||||
tc.Uuid = uid.String()
|
||||
payloadBytes, err := json.Marshal(&tc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := bytes.NewReader(payloadBytes)
|
||||
w := testRequest("POST", "/api/v1/command", body)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandQuery(t *testing.T) {
|
||||
type queryTest struct {
|
||||
query string
|
||||
expect int
|
||||
}
|
||||
var queryTests = []queryTest{
|
||||
{query: fmt.Sprintf("path=%v&unique=true&systemName=%v&query=^curl", url.QueryEscape(dir), system.systemName), expect: 1},
|
||||
{query: fmt.Sprintf("path=%v&query=^curl&unique=true", url.QueryEscape(dir)), expect: 1},
|
||||
{query: fmt.Sprintf("systemName=%v&query=^curl", system.systemName), expect: 5},
|
||||
{query: fmt.Sprintf("path=%v&query=^curl", url.QueryEscape(dir)), expect: 5},
|
||||
{query: fmt.Sprintf("systemName=%v&unique=true", system.systemName), expect: 10},
|
||||
{query: fmt.Sprintf("path=%v&unique=true", url.QueryEscape(dir)), expect: 10},
|
||||
{query: fmt.Sprintf("path=%v", url.QueryEscape(dir)), expect: 50},
|
||||
{query: fmt.Sprintf("systemName=%v", system.systemName), expect: 50},
|
||||
{query: "query=^curl&unique=true", expect: 1},
|
||||
{query: "query=^curl", expect: 5},
|
||||
{query: "unique=true", expect: 10},
|
||||
{query: "limit=1", expect: 1},
|
||||
}
|
||||
|
||||
for _, v := range queryTests {
|
||||
func() {
|
||||
u := fmt.Sprintf("/api/v1/command/search?%v", v.query)
|
||||
w := testRequest("GET", u, nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var data []Query
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v.expect != len(data) {
|
||||
t.Fatalf("expected: %v, got: %v -- query: %v ", v.expect, len(data), v.query)
|
||||
}
|
||||
assert.Contains(t, system.systemName, data[0].SystemName)
|
||||
assert.Contains(t, dir, data[0].Path)
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCommandFindDelete(t *testing.T) {
|
||||
|
||||
var record Command
|
||||
|
||||
func() {
|
||||
v := url.Values{}
|
||||
v.Add("limit", "1")
|
||||
v.Add("unique", "true")
|
||||
u := fmt.Sprintf("/api/v1/command/search?%v", v.Encode())
|
||||
w := testRequest("GET", u, nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var data []Command
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 1, len(data))
|
||||
record = data[0]
|
||||
}()
|
||||
func() {
|
||||
u := fmt.Sprintf("/api/v1/command/%v", record.Uuid)
|
||||
w := testRequest("GET", u, nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var data Command
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, record.Uuid, data.Uuid)
|
||||
pid = data.SessionID
|
||||
}()
|
||||
|
||||
func() {
|
||||
u := fmt.Sprintf("/api/v1/command/%v", record.Uuid)
|
||||
w := testRequest("DELETE", u, nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
}()
|
||||
func() {
|
||||
w := testRequest("GET", "/api/v1/command/search?", nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var data []Command
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 49, len(data))
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
u := fmt.Sprintf("/api/v1/client-view/status?processId=%v&startTime=%v", pid, sessionStartTime)
|
||||
w := testRequest("GET", u, nil)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var status Status
|
||||
err = json.Unmarshal(b, &status)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, status.TotalCommands, 49)
|
||||
assert.Equal(t, status.TotalSessions, 5)
|
||||
assert.Equal(t, status.TotalSystems, 3)
|
||||
assert.Equal(t, status.TotalCommandsToday, 49)
|
||||
assert.Equal(t, status.SessionTotalCommands, 9)
|
||||
|
||||
}
|
||||
|
||||
func dirCleanup() {
|
||||
if !*testWork {
|
||||
err := os.Chmod(testDir, 0777)
|
||||
check(err)
|
||||
err = os.RemoveAll(testDir)
|
||||
check(err)
|
||||
return
|
||||
}
|
||||
log.Println("TESTWORK=", testDir)
|
||||
|
||||
}
|
|
@ -41,7 +41,7 @@ export GO111MODULE=on
|
|||
|
||||
xgo \
|
||||
-out="bashhub-server-${version}" \
|
||||
--targets="windows/*,darwin/amd64,linux/386,linux/amd64" \
|
||||
--targets="linux/arm64,linux/arm-7,linux/amd64,linux/386,darwin/amd64,windows/*" \
|
||||
--dest=dist \
|
||||
-ldflags "-X github.com/nicksherron/bashhub-server/cmd.Version=${version}
|
||||
-X github.com/nicksherron/bashhub-server/cmd.GitCommit=${commit}
|
||||
|
@ -56,10 +56,12 @@ sudo chown -R $USER: dist/
|
|||
darwin_amd64=bashhub-server_${version}_darwin_amd64
|
||||
linux_386=bashhub-server_${version}_linux_386
|
||||
linux_amd64=bashhub-server_${version}_linux_amd64
|
||||
linux_arm64=bashhub-server_${version}_linux_arm64
|
||||
linux_arm_7=bashhub-server_${version}_linux_arm-7
|
||||
windows_386=bashhub-server_${version}_windows_386
|
||||
windows_amd64=bashhub-server_${version}_windows_amd64
|
||||
|
||||
mkdir dist/{$darwin_amd64,$linux_386,$linux_amd64,$windows_386,$windows_amd64}
|
||||
mkdir dist/{$darwin_amd64,$linux_386,$linux_amd64,$linux_arm64,$linux_arm_7,$windows_386,$windows_amd64}
|
||||
|
||||
pushd dist
|
||||
|
||||
|
@ -72,13 +74,19 @@ mv bashhub-server-${version}-linux-386 ${linux_386}/bashhub-server \
|
|||
mv bashhub-server-${version}-linux-amd64 ${linux_amd64}/bashhub-server \
|
||||
&& tar czvf ${linux_amd64}.tar.gz ${linux_amd64}
|
||||
|
||||
mv bashhub-server-${version}-linux-arm64 ${linux_arm64}/bashhub-server \
|
||||
&& tar czvf ${linux_arm64}.tar.gz ${linux_arm64}
|
||||
|
||||
mv bashhub-server-${version}-linux-arm-7 ${linux_arm_7}/bashhub-server \
|
||||
&& tar czvf ${linux_arm_7}.tar.gz ${linux_arm_7}
|
||||
|
||||
mv bashhub-server-${version}-windows-4.0-386.exe ${windows_386}/bashhub-server \
|
||||
&& zip -r ${windows_386}.zip ${windows_386}
|
||||
|
||||
mv bashhub-server-${version}-windows-4.0-amd64.exe ${windows_amd64}/bashhub-server \
|
||||
&& zip -r ${windows_amd64}.zip ${windows_amd64}
|
||||
|
||||
rm -rf {$darwin_amd64,$linux_386,$linux_amd64,$windows_386,$windows_amd64}
|
||||
rm -rf {$darwin_amd64,$linux_386,$linux_amd64,$linux_arm64,$linux_arm_7,$windows_386,$windows_amd64}
|
||||
|
||||
shasum -a 256 * > bashhub-server_${version}_checksums.txt
|
||||
|
||||
|
|
34
scripts/test_postgres.sh
Executable file
34
scripts/test_postgres.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright © 2020 nicksherron <nsherron90@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
CONTAINER="bashhub-postgres-test"
|
||||
|
||||
docker run -d --rm --name ${CONTAINER} -p 5444:5432 postgres
|
||||
|
||||
|
||||
until [ "$(docker exec bashhub-postgres-test pg_isready \
|
||||
-p 5432 -h localhost -U postgres -d postgres)" == "localhost:5432 - accepting connections" ]; do
|
||||
sleep 0.1;
|
||||
done;
|
||||
|
||||
go test github.com/nicksherron/bashhub-server/internal \
|
||||
-postgres-uri "postgres://postgres:@localhost:5444?sslmode=disable"
|
||||
|
||||
docker stop -t 0 ${CONTAINER} & docker wait ${CONTAINER}
|
Loading…
Reference in a new issue