From 8aad7c86bb4463dc17f808a25d2a75da7c8c0078 Mon Sep 17 00:00:00 2001 From: FongMi Date: Tue, 11 Oct 2022 19:28:58 +0800 Subject: [PATCH] Clean code --- .../com/fongmi/android/tv/api/ApiConfig.java | 106 ++---------------- .../com/fongmi/android/tv/api/Decoder.java | 72 ++++++++++++ .../com/fongmi/android/tv/utils/FileUtil.java | 3 +- .../com/fongmi/android/tv/utils/Json.java | 11 ++ .../com/fongmi/android/tv/utils/Utils.java | 6 +- 5 files changed, 96 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/com/fongmi/android/tv/api/Decoder.java diff --git a/app/src/main/java/com/fongmi/android/tv/api/ApiConfig.java b/app/src/main/java/com/fongmi/android/tv/api/ApiConfig.java index 7199ab556..b6a8c663e 100644 --- a/app/src/main/java/com/fongmi/android/tv/api/ApiConfig.java +++ b/app/src/main/java/com/fongmi/android/tv/api/ApiConfig.java @@ -3,7 +3,6 @@ package com.fongmi.android.tv.api; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; -import android.util.Base64; import com.fongmi.android.tv.R; import com.fongmi.android.tv.bean.Config; @@ -11,8 +10,6 @@ import com.fongmi.android.tv.bean.Live; import com.fongmi.android.tv.bean.Parse; import com.fongmi.android.tv.bean.Site; import com.fongmi.android.tv.net.Callback; -import com.fongmi.android.tv.net.OKHttp; -import com.fongmi.android.tv.utils.AES; import com.fongmi.android.tv.utils.FileUtil; import com.fongmi.android.tv.utils.Json; import com.fongmi.android.tv.utils.Prefers; @@ -22,12 +19,9 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; import org.json.JSONObject; -import java.io.BufferedReader; -import java.io.FileReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -89,108 +83,26 @@ public class ApiConfig { public void loadConfig(boolean cache, Callback callback) { new Thread(() -> { - String url = Prefers.getUrl(), pk = ";pk;"; - if (cache) getCacheConfig(url, callback); - else if (url.contains(pk)) { - String[] a = url.split(pk); - if (url.startsWith("http")) decryptWebConfig(a[0], callback, a[1]); - if (url.startsWith("file")) decryptFileConfig(a[0], callback, a[1]); - } else if (!url.contains(pk)) { - if (url.startsWith("http")) decryptWebConfig(url, callback, null); - if (url.startsWith("file")) decryptFileConfig(url, callback, null); - } else handler.post(() -> callback.error(0)); + if (cache) loadCache(Prefers.getUrl(), callback); + else loadJson(Prefers.getUrl(), callback); }).start(); } - private void decryptFileConfig(String url, Callback callback, String FinalKey) { - try { - String content = "", json = "", line = null, ls = System.getProperty("line.separator"); - BufferedReader read = new BufferedReader(new FileReader(FileUtil.getLocal(url))); - StringBuilder text = new StringBuilder(); - while ((line = read.readLine()) != null) { - text.append(line); - text.append(ls); - } - text.deleteCharAt(text.length() - 1); - read.close(); - String reader = text.toString(); - if (AES.isJson(reader)) { - getFileConfig(reader, callback); - return; - } else if (!reader.startsWith("2423")) { - content = new String(Base64.decode(reader.split("\\*\\*")[1], Base64.DEFAULT)); - } else { - content = reader; - } - if (content.startsWith("2423")) { - String data2 = content.substring(content.indexOf("2324") + 4, content.length() - 26); - content = new String(AES.toBytes(content)).toLowerCase(); - String key = AES.rightPading(content.substring(content.indexOf("$#") + 2, content.indexOf("#$")), "0", 16); - String iv = AES.rightPading(content.substring(content.length() - 13), "0", 16); - json = AES.CBC(data2, key, iv); - } else { - json = AES.ECB(content, FinalKey); - } - parseConfig(new Gson().fromJson(json, JsonObject.class), callback); - } catch (Exception e) { - e.printStackTrace(); - handler.post(() -> callback.error(R.string.error_config_get)); - } - } - - private void decryptWebConfig(String url, Callback callback, String FinalKey) { - try { - String content = "", json = ""; - String reader = OKHttp.newCall(url).execute().body().string(); - if (AES.isJson(reader)) { - getWebConfig(reader, callback); - return; - } else if (!reader.startsWith("2423")) { - content = new String(Base64.decode(reader.split("\\*\\*")[1], Base64.DEFAULT)); - } else { - content = reader; - } - if (content.startsWith("2423")) { - String data2 = content.substring(content.indexOf("2324") + 4, content.length() - 26); - content = new String(AES.toBytes(content)).toLowerCase(); - String key = AES.rightPading(content.substring(content.indexOf("$#") + 2, content.indexOf("#$")), "0", 16); - String iv = AES.rightPading(content.substring(content.length() - 13), "0", 16); - json = AES.CBC(data2, key, iv); - } else { - json = AES.ECB(content, FinalKey); - } - parseConfig(new Gson().fromJson(json, JsonObject.class), callback); - } catch (Exception e) { - e.printStackTrace(); - handler.post(() -> callback.error(R.string.error_config_get)); - } - } - - private void getFileConfig(String url, Callback callback) { - try { - parseConfig(new Gson().fromJson(new JsonReader(new FileReader(FileUtil.getLocal(url))), JsonObject.class), callback); - } catch (Exception e) { - e.printStackTrace(); - getCacheConfig(url, callback); - } + private void loadCache(String url, Callback callback) { + String json = Config.find(url).getJson(); + if (!TextUtils.isEmpty(json)) parseConfig(JsonParser.parseString(json).getAsJsonObject(), callback); + else handler.post(() -> callback.error(R.string.error_config_get)); } - private void getWebConfig(String url, Callback callback) { + private void loadJson(String url, Callback callback) { try { - parseConfig(new Gson().fromJson(OKHttp.newCall(url).execute().body().string(), JsonObject.class), callback); + parseConfig(new Gson().fromJson(Decoder.getJson(url), JsonObject.class), callback); } catch (Exception e) { e.printStackTrace(); - getCacheConfig(url, callback); + loadCache(url, callback); } } - private void getCacheConfig(String url, Callback callback) { - String json = Config.find(url).getJson(); - if (!TextUtils.isEmpty(json)) - parseConfig(JsonParser.parseString(json).getAsJsonObject(), callback); - else handler.post(() -> callback.error(R.string.error_config_get)); - } - private void parseConfig(JsonObject object, Callback callback) { try { parseJson(object); diff --git a/app/src/main/java/com/fongmi/android/tv/api/Decoder.java b/app/src/main/java/com/fongmi/android/tv/api/Decoder.java new file mode 100644 index 000000000..26f74a973 --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/api/Decoder.java @@ -0,0 +1,72 @@ +package com.fongmi.android.tv.api; + +import android.util.Base64; + +import com.fongmi.android.tv.net.OKHttp; +import com.fongmi.android.tv.utils.FileUtil; +import com.fongmi.android.tv.utils.Json; + +import java.nio.charset.StandardCharsets; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class Decoder { + + public static String getJson(String url) throws Exception { + String key = url.contains(";") ? url.split(";")[2] : ""; + url = url.contains(";") ? url.split(";")[0] : url; + String data = getData(url); + if (Json.valid(data)) return data; + if (key.length() > 0) return ecb(data, key); + if (data.contains("**")) data = base64(data); + if (data.startsWith("2423")) data = cbc(data); + return data.replace("###", ""); + } + + private static String getData(String url) throws Exception { + if (url.startsWith("http")) return OKHttp.newCall(url).execute().body().string(); + else if (url.startsWith("file")) return FileUtil.read(url); + throw new Exception(); + } + + private static String ecb(String data, String key) throws Exception { + SecretKeySpec spec = new SecretKeySpec(padEnd(key), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, spec); + return new String(cipher.doFinal(decodeHex(data)), StandardCharsets.UTF_8); + } + + private static String cbc(String data) throws Exception { + int indexKey = data.indexOf("2324") + 4; + String key = new String(decodeHex(data.substring(0, indexKey)), StandardCharsets.UTF_8); + key = key.replace("$#", "").replace("#$", ""); + int indexIv = data.length() - 26; + String iv = data.substring(indexIv).trim(); + iv = new String(decodeHex(iv), StandardCharsets.UTF_8); + SecretKeySpec keySpec = new SecretKeySpec(padEnd(key), "AES"); + IvParameterSpec ivSpec = new IvParameterSpec(padEnd(iv)); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + data = data.substring(indexKey, indexIv).trim(); + byte[] encryptDataBytes = decodeHex(data); + byte[] decryptData = cipher.doFinal(encryptDataBytes); + return new String(decryptData, StandardCharsets.UTF_8); + } + + private static String base64(String data) { + return new String(Base64.decode(data.substring(data.indexOf("**") + 2), Base64.DEFAULT)); + } + + private static byte[] padEnd(String key) { + return (key + "0000000000000000".substring(key.length())).getBytes(StandardCharsets.UTF_8); + } + + private static byte[] decodeHex(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); + return data; + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/utils/FileUtil.java b/app/src/main/java/com/fongmi/android/tv/utils/FileUtil.java index 2ff2e6428..22050b87b 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/FileUtil.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/FileUtil.java @@ -86,9 +86,8 @@ public class FileUtil { int count; while ((count = fis.read(byteArray)) != -1) digest.update(byteArray, 0, count); fis.close(); - byte[] bytes = digest.digest(); StringBuilder sb = new StringBuilder(); - for (byte b : bytes) sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); + for (byte b : digest.digest()) sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); return sb.toString(); } catch (Exception e) { return ""; diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Json.java b/app/src/main/java/com/fongmi/android/tv/utils/Json.java index 4b6766d8f..6cd811f7e 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Json.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Json.java @@ -4,12 +4,23 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class Json { + public static boolean valid(String text) { + try { + new JSONObject(text); + return true; + } catch (Exception e) { + return false; + } + } + public static String safeString(JsonObject obj, String key, String value) { if (obj.has(key)) return obj.getAsJsonPrimitive(key).getAsString().trim(); else return value; diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Utils.java b/app/src/main/java/com/fongmi/android/tv/utils/Utils.java index b25eaa955..4d5a5ed21 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Utils.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Utils.java @@ -86,9 +86,9 @@ public class Utils { public static String getMD5(String src) { try { if (TextUtils.isEmpty(src)) return ""; - MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] messageDigest = md.digest(src.getBytes()); - BigInteger no = new BigInteger(1, messageDigest); + MessageDigest digest = MessageDigest.getInstance("MD5"); + byte[] bytes = digest.digest(src.getBytes()); + BigInteger no = new BigInteger(1, bytes); StringBuilder sb = new StringBuilder(no.toString(16)); while (sb.length() < 32) sb.insert(0, "0"); return sb.toString().toLowerCase();