mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-09-01 03:55:47 +02:00
Huawei: Improved error handling for bin file parsing.
This commit is contained in:
parent
2aafad46eb
commit
1c19283192
@ -7,15 +7,23 @@ import java.util.Arrays;
|
||||
|
||||
public class HuaweiBinAppParser {
|
||||
|
||||
public static class HuaweiBinAppParseError extends Exception {
|
||||
public HuaweiBinAppParseError(String str) {
|
||||
super(str);
|
||||
}
|
||||
}
|
||||
|
||||
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 static final byte BIN_APP_MAGIC = (byte) 0xbe;
|
||||
|
||||
private static final int SIGN_HEADER_LEN = 32;
|
||||
private static final byte[] SIGN_MAGIC = "hw signed app ".getBytes();
|
||||
private static final byte[] SIGN_VERSION = "1000".getBytes();
|
||||
|
||||
|
||||
private String packageName;
|
||||
@ -26,59 +34,76 @@ public class HuaweiBinAppParser {
|
||||
}
|
||||
|
||||
public byte[] getEntryContent(String filename) {
|
||||
for(AppFileEntry en: entries) {
|
||||
if(en.filename.equals(filename)) {
|
||||
for (AppFileEntry en : entries) {
|
||||
if (en.filename.equals(filename)) {
|
||||
return en.content;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] readData(ByteBuffer data) {
|
||||
private byte[] readData(ByteBuffer data) throws Exception {
|
||||
long len = data.getLong();
|
||||
byte[] newPayload = new byte[(int)len];
|
||||
data.get(newPayload, 0, (int)len);
|
||||
if (len > Integer.MAX_VALUE || len <= 0) {
|
||||
throw new HuaweiBinAppParseError("Invalid data length");
|
||||
}
|
||||
byte[] newPayload = new byte[(int) len];
|
||||
data.get(newPayload, 0, (int) len);
|
||||
return newPayload;
|
||||
}
|
||||
|
||||
private String readString(ByteBuffer data) {
|
||||
int len = data.getInt();
|
||||
private String readStringInternal(ByteBuffer data, int len) throws Exception {
|
||||
byte[] newPayload = new byte[len];
|
||||
data.get(newPayload, 0, len);
|
||||
return new String(newPayload, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
private String readString(ByteBuffer data) throws Exception {
|
||||
int len = data.getInt();
|
||||
if (len <= 0 || len > data.remaining()) {
|
||||
throw new HuaweiBinAppParseError("Invalid string length");
|
||||
}
|
||||
return readStringInternal(data, len);
|
||||
}
|
||||
|
||||
private String readEmptyString(ByteBuffer data) throws Exception {
|
||||
int len = data.getInt();
|
||||
if (len < 0 || len > data.remaining()) {
|
||||
throw new HuaweiBinAppParseError("Invalid string length");
|
||||
}
|
||||
return readStringInternal(data, len);
|
||||
}
|
||||
|
||||
private int getSignLen(byte[] in) {
|
||||
byte[] signatureHeader = Arrays.copyOfRange(in, in.length - signHeaderLen, in.length);
|
||||
byte[] signatureHeader = Arrays.copyOfRange(in, in.length - SIGN_HEADER_LEN, in.length);
|
||||
ByteBuffer signatureHeaderBuf = ByteBuffer.wrap(signatureHeader);
|
||||
byte[] magic = new byte[signMagic.length];
|
||||
signatureHeaderBuf.get(magic, 0, signMagic.length);
|
||||
if(!Arrays.equals(signMagic, magic))
|
||||
byte[] magic = new byte[SIGN_MAGIC.length];
|
||||
signatureHeaderBuf.get(magic, 0, SIGN_MAGIC.length);
|
||||
if (!Arrays.equals(SIGN_MAGIC, magic))
|
||||
return 0;
|
||||
byte[] version = new byte[signVersion.length];
|
||||
signatureHeaderBuf.get(version, 0, signVersion.length);
|
||||
if(!Arrays.equals(signVersion, version))
|
||||
byte[] version = new byte[SIGN_VERSION.length];
|
||||
signatureHeaderBuf.get(version, 0, SIGN_VERSION.length);
|
||||
if (!Arrays.equals(SIGN_VERSION, 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");
|
||||
if (magic != BIN_APP_MAGIC) {
|
||||
throw new HuaweiBinAppParseError("Invalid magic");
|
||||
}
|
||||
this.packageName = readString(data);
|
||||
while(data.remaining() > signLen) {
|
||||
while (data.remaining() > signLen) {
|
||||
AppFileEntry ent = new AppFileEntry();
|
||||
ent.filename = readString(data);
|
||||
ent.path = readString(data);
|
||||
ent.path = readEmptyString(data);
|
||||
ent.content = readData(data);
|
||||
entries.add(ent);
|
||||
}
|
||||
|
@ -72,8 +72,8 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
GenericItem installItem = new GenericItem();
|
||||
|
||||
|
||||
if (helper.getWatchfacePreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getWatchfacePreviewBitmap());
|
||||
if (helper.getPreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getPreviewBitmap());
|
||||
}
|
||||
|
||||
installItem.setName(description.title);
|
||||
@ -116,8 +116,8 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
|
||||
GenericItem installItem = new GenericItem();
|
||||
|
||||
if (helper.getWatchfacePreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getWatchfacePreviewBitmap());
|
||||
if (helper.getPreviewBitmap() != null) {
|
||||
installItem.setPreview(helper.getPreviewBitmap());
|
||||
}
|
||||
|
||||
installItem.setName(config.bundleName);
|
||||
|
@ -48,7 +48,7 @@ public class HuaweiFwHelper {
|
||||
private byte fileType = 0;
|
||||
String fileName = "";
|
||||
|
||||
Bitmap watchfacePreviewBitmap;
|
||||
Bitmap previewBitmap;
|
||||
HuaweiWatchfaceManager.WatchfaceDescription watchfaceDescription;
|
||||
HuaweiAppManager.AppConfig appConfig;
|
||||
Context mContext;
|
||||
@ -83,7 +83,6 @@ public class HuaweiFwHelper {
|
||||
|
||||
try {
|
||||
final UriHelper uriHelper = UriHelper.get(uri, this.mContext);
|
||||
|
||||
InputStream inputStream = uriHelper.openInputStream();
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
@ -96,10 +95,12 @@ public class HuaweiFwHelper {
|
||||
}
|
||||
|
||||
buffer.flush();
|
||||
byte[] hap_data = buffer.toByteArray();
|
||||
byte[] appData = buffer.toByteArray();
|
||||
|
||||
inputStream.close();
|
||||
|
||||
HuaweiBinAppParser app = new HuaweiBinAppParser();
|
||||
app.parseData(hap_data);
|
||||
app.parseData(appData);
|
||||
|
||||
byte[] config = app.getEntryContent("config.json");
|
||||
if(config == null)
|
||||
@ -107,20 +108,22 @@ public class HuaweiFwHelper {
|
||||
appConfig = new HuaweiAppManager.AppConfig(new String(config));
|
||||
fileName = app.getPackageName() + "_INSTALL"; //TODO: INSTALL or UPDATE suffix
|
||||
|
||||
fw = hap_data;
|
||||
fw = appData;
|
||||
fileSize = fw.length;
|
||||
|
||||
byte[] icon = app.getEntryContent("icon_small.png");
|
||||
if(icon != null) {
|
||||
watchfacePreviewBitmap = BitmapFactory.decodeByteArray(icon, 0, icon.length);
|
||||
previewBitmap = BitmapFactory.decodeByteArray(icon, 0, icon.length);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.error("The watchface file was not found.", e);
|
||||
LOG.error("The app file was not found.", e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("General IO error occurred.", e);
|
||||
} catch (HuaweiBinAppParser.HuaweiBinAppParseError e) {
|
||||
LOG.error("Error parsing app File", e);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unknown error occurred.", e);
|
||||
}
|
||||
@ -164,7 +167,7 @@ public class HuaweiFwHelper {
|
||||
watchfaceDescription = new HuaweiWatchfaceManager.WatchfaceDescription(xmlDescription);
|
||||
if (watchfacePackage.fileExists("preview/cover.jpg")) {
|
||||
final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg");
|
||||
watchfacePreviewBitmap = BitmapFactory.decodeByteArray(preview, 0, preview.length);
|
||||
previewBitmap = BitmapFactory.decodeByteArray(preview, 0, preview.length);
|
||||
}
|
||||
|
||||
byte[] watchfaceZip = watchfacePackage.getFileFromZip("com.huawei.watchface");
|
||||
@ -203,8 +206,8 @@ public class HuaweiFwHelper {
|
||||
return isWatchface() || isAPP();
|
||||
}
|
||||
|
||||
public Bitmap getWatchfacePreviewBitmap() {
|
||||
return watchfacePreviewBitmap;
|
||||
public Bitmap getPreviewBitmap() {
|
||||
return previewBitmap;
|
||||
}
|
||||
|
||||
public HuaweiWatchfaceManager.WatchfaceDescription getWatchfaceDescription() {
|
||||
|
Loading…
Reference in New Issue
Block a user