Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Dynu API #3

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ngrok-mc-impl
a efficient way of implementing NGROK into your minecraft server.
an efficient way of implementing NGROK into your minecraft server.

## Installation
1. Download the plugin jar from the latest Github Release.
Expand All @@ -15,4 +15,4 @@ a efficient way of implementing NGROK into your minecraft server.

![image](https://github.com/Ixf1nity/ngrok-mc-impl/assets/97213130/1c7b23c4-12b0-4bcd-ab91-5bf94141dfae)
![image](https://github.com/Ixf1nity/ngrok-mc-impl/assets/97213130/ab1440d9-c348-4617-a554-9e062795c10f)

![image](https://github.com/user-attachments/assets/df8a6043-eb48-4a2a-b239-69fdb660b302)
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>me.infinity</groupId>
<artifactId>ngrokcom</artifactId>
<version>1.3-SNAPSHOT</version>
<version>1.6-SNAPSHOT</version>
<packaging>jar</packaging>

<name>NgrokCommunication</name>
Expand Down Expand Up @@ -67,7 +67,7 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20.2-R0.1-SNAPSHOT</version>
<version>1.19.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down
173 changes: 168 additions & 5 deletions src/main/java/me/infinity/ngrokcom/NgrokCommunication.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.github.alexdlaird.ngrok.protocol.Proto;
import com.github.alexdlaird.ngrok.protocol.Region;
import com.github.alexdlaird.ngrok.protocol.Tunnel;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
Expand All @@ -21,31 +22,59 @@
import net.dv8tion.jda.api.utils.messages.MessageEditData;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;

public final class NgrokCommunication extends JavaPlugin implements EventListener {

private JDA client;
private NgrokClient ngrokClient;
private String publicIp;

private String dynuClientId;
private String dynuSecret;
private String dynuToken;
private String domain;
private String domainId;
private String dnsesPort;

private boolean discordModule;
private boolean discordModuleStatus = false;

private boolean dynu;
private int ngrokPort = 25565; // Default Minecraft server port

@Override
public void onEnable() {

Logger.getLogger(String.valueOf(com.github.alexdlaird.ngrok.process.NgrokProcess.class)).setLevel(Level.OFF);

this.saveDefaultConfig();
int ngrokPort = this.getServer().getPort();
this.discordModule = this.getConfig().getBoolean("DISCORD_UPDATES.ENABLED");
this.dynu = this.getConfig().getBoolean("DYNU_SETTINGS.ENABLED");
String ngrokAuthToken = this.getConfig().getString("NGROK_SETTINGS.AUTH_TOKEN");
int port = this.getConfig().getInt("NGROK_SETTINGS.PORT");

if (port == 0) {
ngrokPort = getServer().getPort();
} else {
ngrokPort = port;
}

if (ngrokAuthToken == null || ngrokAuthToken.isEmpty()) {
this.getLogger().warning("Ngrok authentication token is missing in the config. Shutting down...");
this.setEnabled(false);
return;
}

if (discordModule) {
String botToken = this.getConfig().getString("DISCORD_UPDATES.BOT_TOKEN");
Expand Down Expand Up @@ -112,13 +141,23 @@ public void onEnable() {
this.getLogger().warning("IP update message is missing in the config. Update message not sent.");
}
}


if (dynu) {
this.dynuClientId = this.getConfig().getString("DYNU_SETTINGS.CLIENT_ID");
this.dynuSecret = this.getConfig().getString("DYNU_SETTINGS.SECRET");
this.domain = this.getConfig().getString("DYNU_SETTINGS.DOMAIN");

this.getLogger().info("Dynu settings: " + dynuClientId + " " + dynuSecret + " " + domain);

update(publicIp);
}

this.getLogger().info("Listening server on port " + ngrokPort + ", IP: " + publicIp);
}

@Override
public void onDisable() {
System.setErr(null);
try {
if (ngrokClient != null && publicIp != null) {
this.ngrokClient.disconnect(publicIp);
Expand All @@ -138,4 +177,128 @@ public void onEvent(@NotNull GenericEvent genericEvent) {
this.discordModuleStatus = true;
}
}

public boolean update(String publicIp) {
String hostname = domain;
String password = this.getConfig().getString("DYNU_SETTINGS.PASSWORD");
try {
// Parse the public IP address
String[] parts = publicIp.split(":");
String host = parts[0];
int port = Integer.parseInt(parts[1]);

// Convert the hostname to IP address
InetAddress ipAddress = InetAddress.getByName(host);
String ip = ipAddress.getHostAddress();

URL url = new URL("https://api.dynu.com/nic/update?hostname=" + hostname + "&myip=" + ip + "&password=" + password);
URLConnection conn = url.openConnection();
conn.connect();

// Combine Client ID and Secret
String dynuFull = dynuClientId + ":" + dynuSecret;

// Retrieve Dynu Token
dynuToken = getToken(dynuFull);

// Get Domain Name + ID
getDomainInfo();

// Get DNS Records of Domain ID
getDNSRecords();

// Update DNS Record
updateDNS(port);

} catch (Exception e) {
this.getLogger().severe(e.getMessage());
}
return false;
}

private String getToken(String dynuFull) {
try {
this.getLogger().info("Getting token...");
URL url = new URL("https://api.dynu.com/v2/oauth2/token");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "Basic " + java.util.Base64.getEncoder().encodeToString(dynuFull.getBytes(StandardCharsets.UTF_8)));

BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String response = reader.readLine();
reader.close();

return response.split("\"")[3];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

private void getDomainInfo() {
try {
this.getLogger().info("Getting Domain Info...");
URL url = new URL("https://api.dynu.com/v2/dns");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "Bearer " + dynuToken);

BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String response = reader.readLine();
reader.close();

String[] parts = response.split("\"");
domainId = parts[6].replace(":", "").replace(",", ""); // Removing ":" and ","
domain = parts[9];
} catch (Exception e) {
e.printStackTrace();
}
}

private void getDNSRecords() {
try {
this.getLogger().info("Getting DNS Records... " + dynuToken + " " + domainId);
URL url = new URL("https://api.dynu.com/v2/dns/" + domainId + "/record");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "Bearer " + dynuToken);

BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String response = reader.readLine();
reader.close();

String[] records = response.split("\"");
for (int i = 0; i < records.length; i++) {
if (records[i].equals("recordType") && records[i + 2].equals("SRV")) {
dnsesPort = records[i - 15].replaceAll("[^0-9]", "");
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

private void updateDNS(int port) {
try {
this.getLogger().info("Updating DNS... " + dnsesPort);
URL url = new URL("https://api.dynu.com/v2/dns/" + domainId + "/record/" + dnsesPort);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "Bearer " + dynuToken);
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);

String data = "{\"nodeName\":\"_minecraft._tcp\",\"recordType\":\"SRV\",\"ttl\":120,\"state\":true,\"group\":\"\",\"host\":\"" + domain + "\",\"priority\":10,\"weight\":5,\"port\":" + port + "}";
conn.getOutputStream().write(data.getBytes());

conn.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
}
}
13 changes: 11 additions & 2 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
NGROK_SETTINGS:
AUTH_TOKEN: ""
REGION: "US" # IN, AP, AU, EU, JP, SA, US
#The region in which NGROK should host your tunnel. Use the closest to you for good ping.
# The region in which NGROK should host your tunnel. Use the closest to you for good ping.
PORT: 0 # Set to 0 to use the default port of the server.

# Discord IP update messages configuration.
DISCORD_UPDATES:
Expand All @@ -11,4 +12,12 @@ DISCORD_UPDATES:
UPDATE_CHANNEL_ID: ""
UPDATE_MESSAGE: "**Updated Server IP** : %server_ip%"
# DO NOT TOUCH, THIS IS MODIFIED BY THE PLUGIN.
UPDATE_MESSAGE_ID: 0
UPDATE_MESSAGE_ID: 0

# Dynu configuration & credentials
DYNU_SETTINGS:
ENABLED: false
DOMAIN: ""
PASSWORD: "" # The password may be supplied normally or as an MD5/SHA256 hash for security reasons.
CLIENT_ID: ""
SECRET: ""
5 changes: 3 additions & 2 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: NgrokCommunication
version: '${project.version}'
main: me.infinity.ngrokcom.NgrokCommunication
api-version: 1.20
api-version: 1.19
folia-supported: true
load: STARTUP
libraries:
- net.dv8tion:JDA:5.0.0-beta.18
- net.dv8tion:JDA:5.0.0-beta.18
Loading