Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
184 lines
4.6 KiB
Go
184 lines
4.6 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestContainsPathTraversal(t *testing.T) {
|
|
cases := []struct {
|
|
path string
|
|
want bool
|
|
}{
|
|
{"", false},
|
|
{"/home/user/docs", false},
|
|
{"C:\\Users\\alice", false},
|
|
{"~/Downloads", false},
|
|
{"../etc/passwd", true},
|
|
{"/home/user/../../etc", true},
|
|
{"foo/../bar", true},
|
|
}
|
|
for _, tc := range cases {
|
|
if got := containsPathTraversal(tc.path); got != tc.want {
|
|
t.Errorf("containsPathTraversal(%q) = %v, want %v", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveListDirPathRejectsTraversal(t *testing.T) {
|
|
_, err := resolveListDirPath("../outside")
|
|
if err == nil {
|
|
t.Fatal("expected traversal error")
|
|
}
|
|
}
|
|
|
|
func TestResolveListDirPathEmptyUsesHome(t *testing.T) {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
t.Skip("no home dir")
|
|
}
|
|
for _, input := range []string{"", "~", "@home"} {
|
|
got, err := resolveListDirPath(input)
|
|
if err != nil {
|
|
t.Fatalf("resolveListDirPath(%q): %v", input, err)
|
|
}
|
|
if got != filepath.Clean(home) {
|
|
t.Fatalf("resolveListDirPath(%q) = %q, want %q", input, got, home)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsBlockedDeletePath(t *testing.T) {
|
|
if !isBlockedDeletePath(`C:\Windows\System32\kernel32.dll`) {
|
|
t.Fatal("expected Windows system path blocked")
|
|
}
|
|
if !isBlockedDeletePath(`/usr/bin/bash`) {
|
|
t.Fatal("expected /usr blocked")
|
|
}
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
t.Skip("no home")
|
|
}
|
|
if !isBlockedDeletePath(home) {
|
|
t.Fatal("expected home root blocked")
|
|
}
|
|
tmp := filepath.Join(home, "test_delete_guard.txt")
|
|
if isBlockedDeletePath(tmp) {
|
|
t.Fatalf("expected user file path allowed: %s", tmp)
|
|
}
|
|
}
|
|
|
|
func TestReadFileCommandRejectsOversize(t *testing.T) {
|
|
dir := t.TempDir()
|
|
big := filepath.Join(dir, "huge.bin")
|
|
if err := os.WriteFile(big, make([]byte, maxReadFileBytes+1), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c := newTestClient(t)
|
|
var gotOK bool
|
|
var gotMsg string
|
|
c.commandResultHook = func(_ string, success bool, message string) {
|
|
gotOK = success
|
|
gotMsg = message
|
|
}
|
|
c.handleCommand("read_file", 0, "", big, "", "")
|
|
if gotOK {
|
|
t.Fatal("oversize read_file should fail")
|
|
}
|
|
if !strings.Contains(gotMsg, "file too large") {
|
|
t.Fatalf("message=%q", gotMsg)
|
|
}
|
|
}
|
|
|
|
func TestReadFileCommandAcceptsWithinCap(t *testing.T) {
|
|
dir := t.TempDir()
|
|
small := filepath.Join(dir, "small.txt")
|
|
want := "config-value"
|
|
if err := os.WriteFile(small, []byte(want), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c := newTestClient(t)
|
|
var gotOK bool
|
|
var gotMsg string
|
|
c.commandResultHook = func(_ string, success bool, message string) {
|
|
gotOK = success
|
|
gotMsg = message
|
|
}
|
|
c.handleCommand("read_file", 0, "", small, "", "")
|
|
if !gotOK || gotMsg != want {
|
|
t.Fatalf("ok=%v msg=%q want %q", gotOK, gotMsg, want)
|
|
}
|
|
}
|
|
|
|
func TestAgentConfigFileUploadReadRoundTrip(t *testing.T) {
|
|
dir := t.TempDir()
|
|
cfgPath := filepath.Join(dir, "agent-config.json")
|
|
payload := `{"server_url":"http://127.0.0.1:8989","worker_name":"test-node"}`
|
|
encoded := base64.StdEncoding.EncodeToString([]byte(payload))
|
|
|
|
c := newTestClient(t)
|
|
uploadDone := make(chan struct{})
|
|
c.commandResultHook = func(action string, success bool, message string) {
|
|
if action == "upload" {
|
|
if !success {
|
|
t.Fatalf("upload failed: %s", message)
|
|
}
|
|
close(uploadDone)
|
|
}
|
|
}
|
|
c.handleCommand("upload", 0, "", cfgPath, encoded, "")
|
|
<-uploadDone
|
|
|
|
readDone := make(chan struct{})
|
|
var readBody string
|
|
c.commandResultHook = func(action string, success bool, message string) {
|
|
if action == "read_file" {
|
|
if !success {
|
|
t.Fatalf("read_file failed: %s", message)
|
|
}
|
|
readBody = message
|
|
close(readDone)
|
|
}
|
|
}
|
|
c.handleCommand("read_file", 0, "", cfgPath, "", "")
|
|
<-readDone
|
|
if readBody != payload {
|
|
t.Fatalf("round-trip mismatch:\nwant %q\ngot %q", payload, readBody)
|
|
}
|
|
}
|
|
|
|
func TestReadFileCommandRejectsTraversal(t *testing.T) {
|
|
c := newTestClient(t)
|
|
var gotMsg string
|
|
c.commandResultHook = func(_ string, success bool, message string) {
|
|
if !success {
|
|
gotMsg = message
|
|
}
|
|
}
|
|
c.handleCommand("read_file", 0, "", "../../etc/passwd", "", "")
|
|
if !strings.Contains(gotMsg, "path traversal") {
|
|
t.Fatalf("message=%q", gotMsg)
|
|
}
|
|
}
|
|
|
|
func TestReadDirectoryEntriesCapsCount(t *testing.T) {
|
|
dir := t.TempDir()
|
|
for i := 0; i < maxListDirEntries+10; i++ {
|
|
name := filepath.Join(dir, fmt.Sprintf("file_%d.txt", i))
|
|
if err := os.WriteFile(name, []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
entries, err := readDirectoryEntries(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(entries) != maxListDirEntries {
|
|
t.Fatalf("entries len = %d, want cap %d", len(entries), maxListDirEntries)
|
|
}
|
|
}
|