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