Java Integration
v1.0.6Panduan lengkap untuk mengintegrasikan NxGate ke plugin Minecraft Java Anda. Versi 1.0.6 membawa fitur hardening: offline grace period, heartbeat, retry otomatis, dan TLS pinning.
Instalasi
Maven
1<repositories>2 <repository>3 <id>github</id>4 <url>https://maven.pkg.github.com/NoxlyDev/NxGate-Library</url>5 </repository>6</repositories>78<dependencies>9 <dependency>10 <groupId>xyz.noxlydev.nxgate</groupId>11 <artifactId>nxgate</artifactId>12 <version>1.0.6</version>13 </dependency>14</dependencies>
Gradle (Kotlin DSL)
1repositories {2 maven {3 url = uri("https://maven.pkg.github.com/NoxlyDev/NxGate-Library")4 credentials {5 username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_USERNAME")6 password = project.findProperty("gpr.token") ?: System.getenv("GITHUB_TOKEN")7 }8 }9}1011dependencies {12 implementation("xyz.noxlydev.nxgate:nxgate:1.0.6")13}
Penting: GitHub Token Required
Library NxGate di-host di GitHub Packages. Anda HARUS menambahkan GitHub token dengan scope read:packages di file ~/.m2/settings.xml.
1<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.04 http://maven.apache.org/xsd/settings-1.0.0.xsd">5 <servers>6 <server>7 <id>github</id>8 <username>YOUR_GITHUB_USERNAME</username>9 <password>YOUR_GITHUB_TOKEN</password>10 </server>11 </servers>12</settings>
Penggunaan Dasar
Berikut contoh implementasi paling sederhana — cocok untuk MVP atau plugin internal:
1. Konfigurasi config.yml
1# NxGate License Configuration2license-key: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
2. Main.java
1import xyz.noxlydev.nxgate.NxGate;2import org.bukkit.plugin.java.JavaPlugin;34public class Main extends JavaPlugin {56 private static final String USER_ID = "YOUR_USER_ID";7 private static final String PUBLIC_KEY =8 "-----BEGIN PUBLIC KEY-----\n" +9 "<PUBLIC_KEY_RSA_BASE64>\n" +10 "-----END PUBLIC KEY-----";1112 @Override13 public void onEnable() {14 saveDefaultConfig();15 String licenseKey = getConfig().getString("license-key");1617 // 2-arg constructor mengaktifkan RSA challenge otomatis18 NxGate.ValidationType result = new NxGate(USER_ID, PUBLIC_KEY)19 .setValidationServer("https://api.nxgate.noxlydev.xyz")20 .verify(licenseKey, "MyPlugin");2122 if (result == NxGate.ValidationType.VALID) {23 getLogger().info("License verified successfully!");24 } else {25 getLogger().severe("License verification failed: " + result);26 getServer().getPluginManager().disablePlugin(this);27 }28 }29}
Catatan
- Constructor 2 argumen
new NxGate(userId, publicKey)otomatis mengaktifkan RSA challenge. - Default server URL:
https://api.nxgate.noxlydev.xyz— boleh tidak di-set. - Method
verify(key, scope)returnNxGate.ValidationType. - Untuk production, gunakan HardenedNxGate (lihat section bawah) — bukan
NxGatementah.
Penggunaan Advanced (Builder Methods)
Class NxGate di v1.0.6 menambah builder method baru untuk retry, timeout, metadata augmentation, dan TLS pinning:
Retry exponential backoff (factor 3) saat CONNECTION_ERROR / SERVER_ERROR.
HTTP timeout. Default 10s/10s. Lebih kecil = gagal lebih cepat.
Tambahkan machineFp + jarFp ke metadata untuk tamper detection.
Pin SHA-256 sertifikat server. Kebal MITM (Burp/mitmproxy).
1import xyz.noxlydev.nxgate.NxGate;2import org.bukkit.plugin.java.JavaPlugin;3import java.util.List;45public class Main extends JavaPlugin {67 @Override8 public void onEnable() {9 saveDefaultConfig();10 String licenseKey = getConfig().getString("license-key");1112 NxGate.ValidationType result = new NxGate(USER_ID, PUBLIC_KEY)13 .setValidationServer("https://api.nxgate.noxlydev.xyz")14 .withRetry(3, 1000) // retry 3x, backoff awal 1s (exponential)15 .withTimeout(8000, 8000) // connect 8s, read 8s16 .withMetadataAugmentation(true) // kirim machineFp + jarFp ke server17 // .withTlsPinning(List.of("a1b2c3...")) // optional: pin SHA-256 cert18 .debug() // print log request/response (dev only)19 .verify(licenseKey, "MyPlugin");2021 switch (result) {22 case VALID:23 getLogger().info("License OK");24 break;25 case NOT_FOUND:26 getLogger().severe("License key tidak ditemukan");27 disablePlugin();28 break;29 case NOT_ACTIVE:30 getLogger().severe("License belum diaktifkan");31 disablePlugin();32 break;33 case EXPIRED:34 getLogger().severe("License sudah expired");35 disablePlugin();36 break;37 case LICENSE_SCOPE_FAILED:38 getLogger().severe("Scope tidak cocok dengan dashboard");39 disablePlugin();40 break;41 case IP_LIMIT_EXCEEDED:42 getLogger().severe("Batas IP terlampaui");43 disablePlugin();44 break;45 case RATE_LIMIT_EXCEEDED:46 getLogger().warning("Rate limit, coba lagi nanti");47 disablePlugin();48 break;49 case FAILED_CHALLENGE:50 getLogger().severe("RSA challenge gagal — public key salah?");51 disablePlugin();52 break;53 case CONNECTION_ERROR:54 getLogger().severe("Tidak dapat terhubung ke server NxGate");55 disablePlugin();56 break;57 case SERVER_ERROR:58 getLogger().severe("Server NxGate mengembalikan response invalid");59 disablePlugin();60 break;61 }62 }6364 private void disablePlugin() {65 getServer().getPluginManager().disablePlugin(this);66 }67}
HardenedNxGate (Production-Ready) ⭐
Direkomendasikan untuk semua plugin production
HardenedNxGate.Builder menggabungkan retry, timeout, RSA challenge, offline grace cache (HMAC-signed, machine-bound), dan background heartbeat dalam satu API yang siap pakai.
Offline Grace Period
Plugin tetap jalan hingga 24 jam (configurable) saat API NxGate tidak bisa dihubungi.
Background Heartbeat
Re-verify license tiap N jam. License yang dicabut langsung trigger callback.
Tamper-Resistant Cache
Cache HMAC-SHA256 di-bind ke machine + JAR fingerprint. Tidak bisa dipindah/diedit.
1import xyz.noxlydev.nxgate.HardenedNxGate;2import xyz.noxlydev.nxgate.NxGate;3import org.bukkit.Bukkit;4import org.bukkit.plugin.java.JavaPlugin;5import java.util.concurrent.TimeUnit;67public class Main extends JavaPlugin {89 private HardenedNxGate gate;1011 @Override12 public void onEnable() {13 saveDefaultConfig();1415 gate = new HardenedNxGate.Builder()16 .userId("YOUR_USER_ID")17 .publicKey(PUBLIC_KEY)18 .scope("MyPlugin")19 .serverUrl("https://api.nxgate.noxlydev.xyz")20 .cacheDir(getDataFolder()) // file .nxgate-cache disimpan di sini21 .gracePeriod(24, TimeUnit.HOURS) // berapa lama plugin tetap jalan saat offline22 .heartbeat(6, TimeUnit.HOURS) // re-verify periodik23 .retry(3, 1000) // 3 attempt, backoff 1s24 .logger(getLogger())25 .onRevoked(reason -> {26 // Dipanggil saat heartbeat mendeteksi license dicabut/expired27 getLogger().severe("License revoked: " + reason);28 Bukkit.getScheduler().runTask(this,29 () -> Bukkit.getPluginManager().disablePlugin(this));30 })31 .build();3233 boolean ok = gate.verifyBlocking(getConfig().getString("license-key"));34 if (!ok) {35 getLogger().severe("License INVALID (" + gate.getLastResult() + ")");36 Bukkit.getPluginManager().disablePlugin(this);37 return;38 }3940 // Mulai background heartbeat — re-verify tiap 6 jam (configurable)41 gate.startHeartbeat(() -> getConfig().getString("license-key"));4243 // ... register commands, listeners, dll44 }4546 @Override47 public void onDisable() {48 if (gate != null) gate.shutdown(); // hentikan thread heartbeat49 }50}
Builder Options
| Method | Default | Deskripsi |
|---|---|---|
| .userId(String) | — | User ID dari dashboard NxGate. Wajib. |
| .publicKey(String) | — | Public RSA key (PEM) untuk verify challenge. |
| .scope(String) | null | Scope untuk membatasi license per produk. |
| .serverUrl(String) | api.nxgate.noxlydev.xyz | URL API NxGate. |
| .cacheDir(File) | . | Folder penyimpanan file .nxgate-cache. |
| .gracePeriod(n, unit) | 24 HOURS | Berapa lama cache valid saat offline. |
| .heartbeat(n, unit) | 6 HOURS | Interval re-verify periodik. |
| .retry(attempts, ms) | 3, 1000 | Retry + initial backoff (exponential). |
| .logger(Logger) | java.util.logging | Logger plugin (biasanya getLogger()). |
| .onRevoked(Consumer) | null | Callback saat heartbeat deteksi license dicabut. |
| .tlsPins(List) | null | SHA-256 pin sertifikat server (optional). |
Wajib panggil shutdown() di onDisable
Heartbeat berjalan di daemon thread. Tanpa gate.shutdown(), thread akan tetap hidup saat plugin di-reload dan menyebabkan thread leak.
Fingerprints Utility
Class Fingerprints baru di v1.0.6 menyediakan hash stabil untuk identifikasi mesin & integritas JAR. Otomatis dipakai oleh HardenedNxGate, tapi bisa juga dipakai langsung:
1import xyz.noxlydev.nxgate.Fingerprints;23// Hash 32-char dari OS + hostname + MAC address4String machineFp = Fingerprints.machine();56// Hash SHA-256 dari JAR yang me-load class ini (deteksi tampering)7String jarFp = Fingerprints.callerJar();89getLogger().info("Machine: " + machineFp);10getLogger().info("Plugin JAR: " + jarFp);1112// Hasil sudah di-cache setelah panggilan pertama, aman dipanggil dari thread mana pun.
Fingerprints.machine()
SHA-256 (32 hex char) dari kombinasi os.name + os.arch + hostname + first non-loopback MAC. Stabil per-mesin.
Fingerprints.callerJar()
SHA-256 (32 hex char) dari isi JAR yang me-load class. Berubah jika JAR dimodifikasi/re-packaged.
Shade & Relocate (Wajib)
Selalu shade + relocate
Library xyz.noxlydev.nxgate dan dependency org.json harus di-shade & relocate untuk menghindari konflik dengan plugin lain yang pakai library/versi berbeda.
Maven (maven-shade-plugin)
1<build>2 <plugins>3 <plugin>4 <groupId>org.apache.maven.plugins</groupId>5 <artifactId>maven-shade-plugin</artifactId>6 <version>3.5.1</version>7 <executions>8 <execution>9 <phase>package</phase>10 <goals><goal>shade</goal></goals>11 <configuration>12 <relocations>13 <relocation>14 <pattern>xyz.noxlydev.nxgate</pattern>15 <shadedPattern>your.plugin.package.libs.nxgate</shadedPattern>16 </relocation>17 <relocation>18 <pattern>org.json</pattern>19 <shadedPattern>your.plugin.package.libs.json</shadedPattern>20 </relocation>21 </relocations>22 </configuration>23 </execution>24 </executions>25 </plugin>26 </plugins>27</build>
Gradle (Shadow plugin)
1plugins {2 id("com.gradleup.shadow") version "8.3.5"3}45tasks.shadowJar {6 relocate("xyz.noxlydev.nxgate", "your.plugin.package.libs.nxgate")7 relocate("org.json", "your.plugin.package.libs.json")8}
Migrasi dari 1.0.4 ←' 1.0.6
100% backwards compatible — kode lama tetap jalan tanpa perubahan. Yang perlu dilakukan:
- Ganti versi di
pom.xml/build.gradle.ktsdari1.0.4ke1.0.6. - (Opsional) Tambahkan
.withRetry(3, 1000)dan.withTimeout(8000, 8000)untuk ketahanan. - (Direkomendasikan) Migrasi ke
HardenedNxGate.Builderuntuk dukungan offline + heartbeat. - Tambah relocate
org.jsondi shade config.