diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java b/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java index 830d46e..0ba75eb 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/Mod.java @@ -8,12 +8,19 @@ import java.util.Set; public class Mod { + public static final String VERSION_NAME_MOD = "1.0.13"; + public static final String VERSION_NAME_BRANCH = "mc1.20.1"; + public static final String VERSION_NAME = VERSION_NAME_MOD + "-" + VERSION_NAME_BRANCH; + public static final long VERSION_BUILD = 14; + + // NOTE: for increase contact to mod developer. public static final long DYNAMIC_PACK_HTTPS_FILE_SIZE_LIMIT = megabyte(8); // kb -> mb -> 5MB (for files in resourcepack) public static final long MODRINTH_HTTPS_FILE_SIZE_LIMIT = megabyte(1024); // 1 GB (for .zip files from modrinth) public static final long MOD_MODTINTH_API_LIMIT = megabyte(8); // 8 MB of api public static final long GZIP_LIMIT = megabyte(50); // 50 MB of .gz file public static final long MOD_FILES_LIMIT = megabyte(8); + public static final String MODRINTH_URL = "https://modrinth.com/mod/dynamicpack"; private static final Set ALLOWED_HOSTS = new HashSet<>(); static { diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java b/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java index 90ada74..7d9740b 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/pack/Pack.java @@ -2,6 +2,7 @@ import com.adamcalculator.dynamicpack.DynamicPackModBase; import com.adamcalculator.dynamicpack.PackUtil; +import com.adamcalculator.dynamicpack.status.StatusChecker; import com.adamcalculator.dynamicpack.sync.PackSyncProgress; import com.adamcalculator.dynamicpack.util.AFiles; import com.adamcalculator.dynamicpack.util.Out; @@ -50,6 +51,12 @@ public boolean isSyncing() { return isSyncing; } + // See StatusChecker for this. + // Developer can block network for specify version in dynamicpack.status.v1.json by security questions + public boolean isNetworkBlocked() { + return StatusChecker.isBlockUpdating(remoteTypeStr); + } + public boolean isZip() { if (location.isDirectory()) { return false; @@ -84,6 +91,7 @@ public long getLatestUpdated() { } public boolean checkIsUpdateAvailable() throws IOException { + checkNetwork(); return cachedUpdateAvailable = remote.checkUpdateAvailable(); } @@ -108,6 +116,9 @@ private void sync0(PackSyncProgress progress, boolean manually) throws Exception progress.done(false); return; } + + checkNetwork(); + if (!checkIsUpdateAvailable() && !manually) { progress.textLog("update not available"); progress.done(false); @@ -124,6 +135,12 @@ private void sync0(PackSyncProgress progress, boolean manually) throws Exception progress.done(reloadRequired); } + private void checkNetwork() { + if (isNetworkBlocked()) { + throw new SecurityException("Network is blocked for remote_type: " + remoteTypeStr + " in dynamicpack.status.v1.json by security questions!"); + } + } + private void checkSafePackMinecraftMeta() throws IOException { PackUtil.openPackFileSystem(location, path -> { Path mcmeta = path.resolve(DynamicPackModBase.MINECRAFT_META); diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java b/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java new file mode 100644 index 0000000..87e7898 --- /dev/null +++ b/common/src/main/java/com/adamcalculator/dynamicpack/status/StatusChecker.java @@ -0,0 +1,53 @@ +package com.adamcalculator.dynamicpack.status; + +import com.adamcalculator.dynamicpack.Mod; +import com.adamcalculator.dynamicpack.util.Out; +import com.adamcalculator.dynamicpack.util.Urls; +import org.json.JSONObject; + +public class StatusChecker { + private static final String URL = "https://adamcalculator.github.io/DynamicPack/dynamicpack.status.v1.json"; + + + private static boolean isUpdateAvailable = false; + private static boolean isFormatActual = true; + private static boolean isSafe = true; + private static boolean isChecked = false; + + public static void check() throws Exception { + Out.println("Checking status..."); + String s = Urls.parseContent(URL, 1024 * 1024 * 128); + JSONObject j = new JSONObject(s); + JSONObject lat = j.getJSONObject("latest_version"); + isUpdateAvailable = lat.getLong("build") > Mod.VERSION_BUILD; + isSafe = lat.getLong("safe") <= Mod.VERSION_BUILD; + isFormatActual = lat.getLong("format") <= Mod.VERSION_BUILD; + + isChecked = true; + Out.println(String.format("Status checked! isSafe=%s, isFormatActual=%s, isUpdateAvailable=%s", isSafe, isFormatActual, isUpdateAvailable)); + } + + public static boolean isBlockUpdating(String remoteType) { + if (remoteType.equals("modrinth")) { + return false; + } + return !isSafe(); + } + + + public static boolean isModUpdateAvailable() { + return isUpdateAvailable; + } + + public static boolean isSafe() { + return isSafe; + } + + public static boolean isFormatActual() { + return isFormatActual; + } + + public static boolean isChecked() { + return isChecked; + } +} diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java index d8e2894..e01cf56 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/sync/SyncThread.java @@ -1,5 +1,8 @@ package com.adamcalculator.dynamicpack.sync; +import com.adamcalculator.dynamicpack.status.StatusChecker; +import com.adamcalculator.dynamicpack.util.Out; + import java.util.function.Supplier; public class SyncThread extends Thread { @@ -10,6 +13,9 @@ public class SyncThread extends Thread { public SyncThread(Supplier taskSupplier) { super("SyncThread" + (counter++)); + if (counter > 1) { + Out.warn("Multiple SyncThread's is bad behavior..."); + } this.taskSupplier = taskSupplier; } @@ -27,6 +33,11 @@ public void run() { private void startSync() { + try { + StatusChecker.check(); + } catch (Exception e) { + Out.error("Error while check status!", e); + } taskSupplier.get().run(); } } diff --git a/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java b/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java index cf627f6..cbf7e20 100644 --- a/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java +++ b/common/src/main/java/com/adamcalculator/dynamicpack/util/Out.java @@ -16,7 +16,7 @@ public static void println(Object o) { System.out.println(o); return; } - LOGGER.warn(o + ""); + LOGGER.info(o + ""); } public static void error(String s, Exception e) { diff --git a/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java b/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java index d253bd6..95c05c1 100644 --- a/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java +++ b/src/client/java/com/adamcalculator/dynamicpack/FabricDynamicMod.java @@ -1,23 +1,30 @@ package com.adamcalculator.dynamicpack; import com.adamcalculator.dynamicpack.pack.Pack; +import com.adamcalculator.dynamicpack.status.StatusChecker; import com.adamcalculator.dynamicpack.sync.SyncThread; import com.adamcalculator.dynamicpack.sync.SyncingTask; import com.adamcalculator.dynamicpack.sync.state.StateDownloading; import com.adamcalculator.dynamicpack.sync.state.StateFileDeleted; import com.adamcalculator.dynamicpack.sync.state.SyncProgressState; +import com.adamcalculator.dynamicpack.util.Out; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.SharedConstants; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.toast.SystemToast; import net.minecraft.client.toast.ToastManager; import net.minecraft.resource.metadata.PackResourceMetadataReader; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.JsonHelper; public class FabricDynamicMod extends DynamicPackModBase implements ClientModInitializer { - private static final boolean SHOW_STATE = false; private SystemToast toast = null; private long toastUpdated = 0; @@ -40,6 +47,37 @@ public void setToastContent(Text title, Text text) { public void onInitializeClient() { var gameDir = FabricLoader.getInstance().getGameDir().toFile(); init(gameDir); + + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + ClientPlayerEntity player = client.player; + Text download = Text.translatable("dynamicpack.status_checker.download") + .fillStyle(Style.EMPTY + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("dynamicpack.status_checker.download.hover", Text.literal(Mod.MODRINTH_URL).formatted(Formatting.UNDERLINE, Formatting.AQUA)))) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, Mod.MODRINTH_URL)) + ) + .formatted(Formatting.YELLOW, Formatting.UNDERLINE); + + + if (player == null) { + Out.warn("player == null on world join"); + + } else if (!StatusChecker.isSafe()) { + player.sendMessage(Text.translatable("dynamicpack.status_checker.not_safe", download)); + setToastContent(Text.translatable("dynamicpack.status_checker.not_safe.toast.title"), + Text.translatable("dynamicpack.status_checker.not_safe.toast.description")); + + } else if (!StatusChecker.isFormatActual()) { + player.sendMessage(Text.translatable("dynamicpack.status_checker.format_not_actual", download)); + + } else if (StatusChecker.isModUpdateAvailable()) { + Out.println("DynamicPack mod update available: " + Mod.MODRINTH_URL); + + } else if (!StatusChecker.isChecked()) { + Out.warn("StatusChecker isChecked = false :("); + } else { + Out.println("Mod in actual state in current date!"); + } + }); } @Override diff --git a/src/main/resources/assets/dynamicpack/lang/en_us.json b/src/main/resources/assets/dynamicpack/lang/en_us.json index 042f466..dda5f11 100644 --- a/src/main/resources/assets/dynamicpack/lang/en_us.json +++ b/src/main/resources/assets/dynamicpack/lang/en_us.json @@ -15,5 +15,11 @@ "dynamicpack.toast.pack.state.unknown.description": "Processing...", "dynamicpack.screen.pack.description": "This resource pack support DynamicPack features!", "dynamicpack.screen.pack.remote_type": "Remote type: %s", - "dynamicpack.screen.pack.latestUpdated": "Latest updated at: %s" + "dynamicpack.screen.pack.latestUpdated": "Latest updated at: %s", + "dynamicpack.status_checker.not_safe": "Security update available for DynamicPack mod! This message should not be ignored, since the update has fixed possible vulnerabilities: %s", + "dynamicpack.status_checker.not_safe.toast.title": "DynamicPack", + "dynamicpack.status_checker.not_safe.toast.description": "Security update available", + "dynamicpack.status_checker.format_not_actual": "Dynamic pack format update available! Perhaps resource pack developers will use it, and then without updating the mod they will stop working: %s", + "dynamicpack.status_checker.download": "Download!", + "dynamicpack.status_checker.download.hover": "Click for go to %s" } \ No newline at end of file diff --git a/src/main/resources/assets/dynamicpack/lang/ru_ru.json b/src/main/resources/assets/dynamicpack/lang/ru_ru.json index 0f4e7cd..686aaac 100644 --- a/src/main/resources/assets/dynamicpack/lang/ru_ru.json +++ b/src/main/resources/assets/dynamicpack/lang/ru_ru.json @@ -15,5 +15,11 @@ "dynamicpack.toast.pack.state.unknown.description": "Обработка...", "dynamicpack.screen.pack.description": "Этот ресурспак поддерживает возможности мода DynamicPack!", "dynamicpack.screen.pack.remote_type": "Тип: %s", - "dynamicpack.screen.pack.latestUpdated": "Обновлён: %s" + "dynamicpack.screen.pack.latestUpdated": "Обновлён: %s", + "dynamicpack.status_checker.not_safe": "Доступно обновление безопасности для мода DynamicPack! Это сообщение не стоит игнорировать, поскольку в обновлении были исправлены возможные уязвимости: %s", + "dynamicpack.status_checker.not_safe.toast.title": "DynamicPack", + "dynamicpack.status_checker.not_safe.toast.description": "Доступно обновление безопасности", + "dynamicpack.status_checker.format_not_actual": "Доступно обновление формата динамических паков! Возможно разработчики ресурспаков будут его использовать, и тогда без обновления мода они работать перестанут: %s", + "dynamicpack.status_checker.download": "Загрузить!", + "dynamicpack.status_checker.download.hover": "Нажмите чтобы перейти %s" } \ No newline at end of file