import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HexFormat;
import java.util.Random;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class PraktikAman {

    static String escapeHtml(String teks) {
        return teks.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#39;");
    }

    static String hashKataSandi(String sandi, byte[] garam) throws Exception {
        PBEKeySpec spec = new PBEKeySpec(sandi.toCharArray(), garam, 100_000, 256);
        SecretKeyFactory pabrik = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] kunci = pabrik.generateSecret(spec).getEncoded();
        spec.clearPassword();
        return HexFormat.of().formatHex(kunci);
    }

    static boolean verifikasi(String sandi, byte[] garam, String hashTersimpan)
            throws Exception {
        byte[] hitungUlang = HexFormat.of().parseHex(hashKataSandi(sandi, garam));
        // perbandingan waktu-konstan, bukan equals biasa
        return MessageDigest.isEqual(hitungUlang, HexFormat.of().parseHex(hashTersimpan));
    }

    public static void main(String[] args) throws Exception {
        System.out.println("== 1. Injection SQL ==");
        String masukan = "Buku' OR '1'='1";
        String queryRentan = "SELECT * FROM produk WHERE nama = '" + masukan + "'";
        String queryAman = "SELECT * FROM produk WHERE nama = ?";
        System.out.println("Masukan pengguna : " + masukan);
        System.out.println("Query rentan      : " + queryRentan);
        System.out.println("                   -> kondisi OR selalu bernilai benar");
        System.out.println("Query aman        : " + queryAman);
        System.out.println("                   -> parameter diikat sebagai data: " + masukan);

        System.out.println();
        System.out.println("== 2. Penyimpanan kata sandi (PBKDF2) ==");
        // garam tetap HANYA untuk demo; produksi memakai garam acak per pengguna
        byte[] garam = "garam-tetap-demo".getBytes(StandardCharsets.UTF_8);
        String hash = hashKataSandi("rahasia123", garam);
        System.out.println("hash PBKDF2WithHmacSHA256 (100000 iterasi):");
        System.out.println("  " + hash);
        System.out.println("verifikasi 'rahasia123' : " + verifikasi("rahasia123", garam, hash));
        System.out.println("verifikasi 'tebakan123' : " + verifikasi("tebakan123", garam, hash));

        System.out.println();
        System.out.println("== 3. Escape keluaran (XSS) ==");
        String komentar = "<script>alert('xss')</script>";
        System.out.println("Masukan : " + komentar);
        System.out.println("Aman    : " + escapeHtml(komentar));

        System.out.println();
        System.out.println("== 4. Token CSRF ==");
        String tokenSesi = String.format("%08x", new Random(42).nextInt());
        String tokenForm = tokenSesi;
        String tokenAsing = String.format("%08x", new Random(7).nextInt());
        System.out.println("token sesi : " + tokenSesi);
        System.out.println("form cocok : " + tokenForm + " -> "
                + MessageDigest.isEqual(tokenSesi.getBytes(StandardCharsets.UTF_8),
                        tokenForm.getBytes(StandardCharsets.UTF_8)));
        System.out.println("form lain  : " + tokenAsing + " -> "
                + MessageDigest.isEqual(tokenSesi.getBytes(StandardCharsets.UTF_8),
                        tokenAsing.getBytes(StandardCharsets.UTF_8)));
    }
}
