From 4989334ff4b0792a00a403a36d7b092f52c93bf6 Mon Sep 17 00:00:00 2001 From: Me7c7 Date: Thu, 29 Aug 2024 23:43:27 +0300 Subject: [PATCH] Huawei: Instalattion of apps fixed. Correct bin files support --- .../devices/huawei/HuaweiAppParser.java | 65 -------------- .../devices/huawei/HuaweiBinAppParser.java | 86 +++++++++++++++++++ .../devices/huawei/HuaweiInstallHandler.java | 11 +-- .../devices/huawei/HuaweiAppManager.java | 44 ---------- .../devices/huawei/HuaweiFwHelper.java | 7 +- 5 files changed, 91 insertions(+), 122 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiAppParser.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBinAppParser.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiAppParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiAppParser.java deleted file mode 100644 index 56536be44..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiAppParser.java +++ /dev/null @@ -1,65 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.devices.huawei; - -import java.nio.ByteBuffer; -import java.util.ArrayList; - -public class HuaweiAppParser { - - public static class AppFileEntry { - public String filename; - public String folder; - public String unknown; - public byte[] content; - } - - private String packageName; - private final ArrayList entries = new ArrayList<>(); - - public String getPackageName() { - return packageName; - } - - public byte[] getEntryContent(String filename) { - for(AppFileEntry en: entries) { - if(en.filename.equals(filename)) { - return en.content; - } - } - return null; - } - - private byte[] readData(ByteBuffer data) { - int len = data.getInt(); - byte[] newPayload = new byte[len]; - data.get(newPayload, 0, len); - return newPayload; - } - - private String readString(ByteBuffer data) { - return new String(readData(data)); - } - - public void parseData(byte[] in) throws Exception { - - ByteBuffer data = ByteBuffer.wrap(in); - - byte magic = data.get(); - if(magic != (byte)0xbe){ - throw new Exception("Invalid magic"); - } - this.packageName = readString(data); - while(data.remaining() > 0) { - int pos = data.position(); - byte a = data.get(); - if(a != 0x00) - break; - data.position(pos); - AppFileEntry ent = new AppFileEntry(); - ent.filename = readString(data); - ent.folder = readString(data); - ent.unknown = readString(data); - ent.content = readData(data); - entries.add(ent); - } - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBinAppParser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBinAppParser.java new file mode 100644 index 000000000..1a31773f1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBinAppParser.java @@ -0,0 +1,86 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.huawei; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; + +public class HuaweiBinAppParser { + + public static class AppFileEntry { + public String filename; + public String path; + public byte[] content; + } + + private static final int signHeaderLen = 32; + private static final byte[] signMagic = "hw signed app ".getBytes(); + private static final byte[] signVersion = "1000".getBytes(); + + + private String packageName; + private final ArrayList entries = new ArrayList<>(); + + public String getPackageName() { + return packageName; + } + + public byte[] getEntryContent(String filename) { + for(AppFileEntry en: entries) { + if(en.filename.equals(filename)) { + return en.content; + } + } + return null; + } + + private byte[] readData(ByteBuffer data) { + long len = data.getLong(); + byte[] newPayload = new byte[(int)len]; + data.get(newPayload, 0, (int)len); + return newPayload; + } + + private String readString(ByteBuffer data) { + int len = data.getInt(); + byte[] newPayload = new byte[len]; + data.get(newPayload, 0, len); + return new String(newPayload, StandardCharsets.UTF_8); + } + + private int getSignLen(byte[] in) { + byte[] signatureHeader = Arrays.copyOfRange(in, in.length - signHeaderLen, in.length); + ByteBuffer signatureHeaderBuf = ByteBuffer.wrap(signatureHeader); + byte[] magic = new byte[signMagic.length]; + signatureHeaderBuf.get(magic, 0, signMagic.length); + if(!Arrays.equals(signMagic, magic)) + return 0; + byte[] version = new byte[signVersion.length]; + signatureHeaderBuf.get(version, 0, signVersion.length); + if(!Arrays.equals(signVersion, version)) + return 0; + //NOTE: we need only signature size. + return signatureHeaderBuf.getInt(); + } + + + + public void parseData(byte[] in) throws Exception { + //NOTE: Binary app file signed. We should avoid to read this signature. + int signLen = getSignLen(in); + ByteBuffer data = ByteBuffer.wrap(in); + + byte magic = data.get(); + if(magic != (byte)0xbe){ + throw new Exception("Invalid magic"); + } + this.packageName = readString(data); + while(data.remaining() > signLen) { + AppFileEntry ent = new AppFileEntry(); + ent.filename = readString(data); + ent.path = readString(data); + ent.content = readData(data); + entries.add(ent); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiInstallHandler.java index 2e9fa28b2..46fe0bde5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiInstallHandler.java @@ -108,16 +108,9 @@ public class HuaweiInstallHandler implements InstallHandler { LOG.debug("Initialized HuaweiInstallHandler"); } else if (helper.isAPP()) { - final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator; + final HuaweiAppManager.AppConfig config = helper.getAppConfig(); - String screenWindow = String.format("%d*%d", huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().height, - huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().width); - - String screenShape = huaweiCoordinatorSupplier.getHuaweiCoordinator().getAppDeviceParams().screenShape; - - HuaweiAppManager.AppConfig config = helper.getAppconfig(); - - this.valid = config.checkDistroFilters(screenShape, screenWindow); + this.valid = true; //NOTE: nothing to verify for now installActivity.setInstallEnabled(true); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiAppManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiAppManager.java index 75e392942..5d143974d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiAppManager.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiAppManager.java @@ -1,7 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; -import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,7 +24,6 @@ public class HuaweiAppManager { public String vendor; public String version; - JSONObject distroFilters = null; public AppConfig(String jsonStr) { @@ -36,52 +33,11 @@ public class HuaweiAppManager { this.vendor = config.getJSONObject("app").getString("vendor"); this.version = config.getJSONObject("app").getJSONObject("version").getString("name"); - parseDistroFilters(config); - } catch (Exception e) { LOG.error("Error decode app config", e); } } - private void parseDistroFilters(JSONObject config) { - try { - distroFilters = config.getJSONObject("module").getJSONObject("distroFilter"); - } catch (Exception e) { - LOG.error("Error decode app config distroFilter", e); - } - } - - private boolean isValInArray(JSONArray arr, String value) throws JSONException { - for (int i = 0; i < arr.length(); i++) { - if (arr.getString(i).equals(value)) - return true; - } - return false; - } - - public boolean checkDistroFilters(String screenShape, String screenWindow) { - if (distroFilters == null) - return false; - try { - boolean screenShapeSupported = false; - boolean screenWindowSupported = false; - if (distroFilters.has("screenShape")) { - JSONArray values = distroFilters.getJSONObject("screenShape").getJSONArray("value"); - String policy = distroFilters.getJSONObject("screenShape").getString("policy"); - screenShapeSupported = isValInArray(values, screenShape) && policy.equals("include"); - } - if (distroFilters.has("screenWindow")) { - JSONArray values = distroFilters.getJSONObject("screenWindow").getJSONArray("value"); - String policy = distroFilters.getJSONObject("screenWindow").getString("policy"); - screenWindowSupported = isValInArray(values, screenWindow) && policy.equals("include"); - } - return screenShapeSupported && screenWindowSupported; - } catch (Exception e) { - LOG.error("Error decode app config distroFilter", e); - return false; - } - } - } private final HuaweiSupportProvider support; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java index 71867e453..646d643eb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java @@ -31,7 +31,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiAppParser; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiBinAppParser; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile; @@ -71,7 +71,6 @@ public class HuaweiFwHelper { private void parseFile() { if(parseAsApp()) { assert appConfig.bundleName != null; - assert appConfig.distroFilters != null; fileType = FileUpload.Filetype.app; } else if (parseAsWatchFace()) { assert watchfaceDescription.screen != null; @@ -99,7 +98,7 @@ public class HuaweiFwHelper { buffer.flush(); byte[] hap_data = buffer.toByteArray(); - HuaweiAppParser app = new HuaweiAppParser(); + HuaweiBinAppParser app = new HuaweiBinAppParser(); app.parseData(hap_data); byte[] config = app.getEntryContent("config.json"); @@ -212,7 +211,7 @@ public class HuaweiFwHelper { return watchfaceDescription; } - public HuaweiAppManager.AppConfig getAppconfig() { + public HuaweiAppManager.AppConfig getAppConfig() { return appConfig; }