fix(gui): improve apk signature loading speed (PR #2481)
fix(gui): improve spk signature loading speed (fix #1827)
This commit is contained in:
@@ -1,250 +0,0 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.android.apksig.ApkVerifier;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.api.ResourceType;
|
||||
import jadx.api.impl.SimpleCodeInfo;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.panel.HtmlPanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.utils.CertificateManager;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.zip.IZipEntry;
|
||||
|
||||
public class ApkSignature extends JNode {
|
||||
private static final long serialVersionUID = -9121321926113143407L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ApkSignature.class);
|
||||
|
||||
private static final ImageIcon CERTIFICATE_ICON = UiUtils.openSvgIcon("nodes/styleKeyPack");
|
||||
|
||||
private final transient File openFile;
|
||||
private ICodeInfo content;
|
||||
|
||||
@Nullable
|
||||
public static ApkSignature getApkSignature(JadxWrapper wrapper) {
|
||||
// Only show the ApkSignature node if an AndroidManifest.xml is present.
|
||||
// Without a manifest the Google ApkVerifier refuses to work.
|
||||
File apkFile = null;
|
||||
for (ResourceFile resFile : wrapper.getResources()) {
|
||||
if (resFile.getType() == ResourceType.MANIFEST) {
|
||||
IZipEntry zipEntry = resFile.getZipEntry();
|
||||
if (zipEntry != null) {
|
||||
apkFile = zipEntry.getZipFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (apkFile == null) {
|
||||
return null;
|
||||
}
|
||||
return new ApkSignature(apkFile);
|
||||
}
|
||||
|
||||
public ApkSignature(File openFile) {
|
||||
this.openFile = openFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return CERTIFICATE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return "APK signature";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentPanel getContentPanel(TabbedPane tabbedPane) {
|
||||
return new HtmlPanel(tabbedPane, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeInfo getCodeInfo() {
|
||||
if (content != null) {
|
||||
return this.content;
|
||||
}
|
||||
ApkVerifier verifier = new ApkVerifier.Builder(openFile).build();
|
||||
try {
|
||||
ApkVerifier.Result result = verifier.verify();
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>APK signature verification result:</h1>");
|
||||
|
||||
builder.append("<p><b>");
|
||||
if (result.isVerified()) {
|
||||
builder.escape(NLS.str("apkSignature.verificationSuccess"));
|
||||
} else {
|
||||
builder.escape(NLS.str("apkSignature.verificationFailed"));
|
||||
}
|
||||
builder.append("</b></p>");
|
||||
|
||||
final String err = NLS.str("apkSignature.errors");
|
||||
final String warn = NLS.str("apkSignature.warnings");
|
||||
final String sigSuccKey = "apkSignature.signatureSuccess";
|
||||
final String sigFailKey = "apkSignature.signatureFailed";
|
||||
|
||||
writeIssues(builder, err, result.getErrors());
|
||||
|
||||
if (!result.getV1SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV1Scheme() ? sigSuccKey : sigFailKey, 1));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.escape(signer.getName());
|
||||
builder.append(" (");
|
||||
builder.escape(signer.getSignatureFileName());
|
||||
builder.append(")");
|
||||
builder.append("</h3>");
|
||||
writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV2SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV2Scheme() ? sigSuccKey : sigFailKey, 2));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V2SchemeSignerInfo signer : result.getV2SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV3SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV3Scheme() ? sigSuccKey : sigFailKey, 3));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV3SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV31SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV31Scheme() ? sigSuccKey : sigFailKey, 31));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV31SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
writeIssues(builder, warn, result.getWarnings());
|
||||
|
||||
this.content = new SimpleCodeInfo(builder.toString());
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>");
|
||||
builder.escape(NLS.str("apkSignature.exception"));
|
||||
builder.append("</h1><pre>");
|
||||
builder.escape(ExceptionUtils.getStackTrace(e));
|
||||
builder.append("</pre>");
|
||||
return new SimpleCodeInfo(builder.toString());
|
||||
}
|
||||
return this.content;
|
||||
}
|
||||
|
||||
private void writeCertificate(StringEscapeUtils.Builder builder, Certificate cert) {
|
||||
CertificateManager certMgr = new CertificateManager(cert);
|
||||
builder.append("<blockquote><pre>");
|
||||
builder.escape(certMgr.generateHeader());
|
||||
builder.append("</pre><pre>");
|
||||
builder.escape(certMgr.generatePublicKey());
|
||||
builder.append("</pre><pre>");
|
||||
builder.escape(certMgr.generateSignature());
|
||||
builder.append("</pre><pre>");
|
||||
builder.append(certMgr.generateFingerprint());
|
||||
builder.append("</pre></blockquote>");
|
||||
}
|
||||
|
||||
private void writeIssues(StringEscapeUtils.Builder builder, String issueType, List<ApkVerifier.IssueWithParams> issueList) {
|
||||
if (!issueList.isEmpty()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(issueType);
|
||||
builder.append("</h3>");
|
||||
builder.append("<blockquote>");
|
||||
// Unprotected Zip entry issues are very common, handle them separately
|
||||
List<ApkVerifier.IssueWithParams> unprotIssues = issueList.stream()
|
||||
.filter(i -> i.getIssue() == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY)
|
||||
.collect(Collectors.toList());
|
||||
if (!unprotIssues.isEmpty()) {
|
||||
builder.append("<h4>");
|
||||
builder.escape(NLS.str("apkSignature.unprotectedEntry"));
|
||||
builder.append("</h4><blockquote>");
|
||||
for (ApkVerifier.IssueWithParams issue : unprotIssues) {
|
||||
builder.escape((String) issue.getParams()[0]);
|
||||
builder.append("<br>");
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
List<ApkVerifier.IssueWithParams> remainingIssues = issueList.stream()
|
||||
.filter(i -> i.getIssue() != ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY)
|
||||
.collect(Collectors.toList());
|
||||
if (!remainingIssues.isEmpty()) {
|
||||
builder.append("<pre>\n");
|
||||
for (ApkVerifier.IssueWithParams issue : remainingIssues) {
|
||||
builder.escape(issue.toString());
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("</pre>\n");
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.android.apksig.ApkVerifier;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.api.ResourceType;
|
||||
import jadx.api.impl.SimpleCodeInfo;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.panel.HtmlPanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.utils.CertificateManager;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.zip.IZipEntry;
|
||||
|
||||
public class ApkSignatureNode extends JNode {
|
||||
private static final long serialVersionUID = -9121321926113143407L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ApkSignatureNode.class);
|
||||
|
||||
private static final ImageIcon CERTIFICATE_ICON = UiUtils.openSvgIcon("nodes/styleKeyPack");
|
||||
|
||||
private final transient File openFile;
|
||||
private ICodeInfo content;
|
||||
private volatile boolean loadingStarted = false;
|
||||
private static TabbedPane tabbedPane;
|
||||
|
||||
@Nullable
|
||||
public static ApkSignatureNode getApkSignature(JadxWrapper wrapper) {
|
||||
// Only show the ApkSignature node if an AndroidManifest.xml is present.
|
||||
// Without a manifest the Google ApkVerifier refuses to work.
|
||||
File apkFile = null;
|
||||
for (ResourceFile resFile : wrapper.getResources()) {
|
||||
if (resFile.getType() == ResourceType.MANIFEST) {
|
||||
IZipEntry zipEntry = resFile.getZipEntry();
|
||||
if (zipEntry != null) {
|
||||
apkFile = zipEntry.getZipFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (apkFile == null) {
|
||||
return null;
|
||||
}
|
||||
return new ApkSignatureNode(apkFile);
|
||||
}
|
||||
|
||||
public ApkSignatureNode(File openFile) {
|
||||
this.openFile = openFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return CERTIFICATE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return "APK signature";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentPanel getContentPanel(TabbedPane tabbedPane) {
|
||||
ApkSignatureNode.tabbedPane = tabbedPane;
|
||||
return new HtmlPanel(tabbedPane, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeInfo getCodeInfo() {
|
||||
if (content != null) {
|
||||
return content;
|
||||
}
|
||||
|
||||
// If loading hasn't started yet, start it.
|
||||
if (!loadingStarted) {
|
||||
loadingStarted = true;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
new ApkSignatureWorker(this).execute();
|
||||
});
|
||||
|
||||
return new SimpleCodeInfo(StringEscapeUtils.escapeHtml4(NLS.str("apkSignature.loading")));
|
||||
}
|
||||
|
||||
return new SimpleCodeInfo(StringEscapeUtils.escapeHtml4(NLS.str("apkSignature.loading")));
|
||||
}
|
||||
|
||||
private void writeCertificate(StringEscapeUtils.Builder builder, Certificate cert) {
|
||||
CertificateManager certMgr = new CertificateManager(cert);
|
||||
builder.append("<blockquote><pre>");
|
||||
builder.escape(certMgr.generateHeader());
|
||||
builder.append("</pre><pre>");
|
||||
builder.escape(certMgr.generatePublicKey());
|
||||
builder.append("</pre><pre>");
|
||||
builder.escape(certMgr.generateSignature());
|
||||
builder.append("</pre><pre>");
|
||||
builder.append(certMgr.generateFingerprint());
|
||||
builder.append("</pre></blockquote>");
|
||||
}
|
||||
|
||||
private static void writeIssues(StringEscapeUtils.Builder builder, String issueType, List<ApkVerifier.IssueWithParams> issueList) {
|
||||
if (!issueList.isEmpty()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(issueType);
|
||||
builder.append("</h3>");
|
||||
builder.append("<blockquote>");
|
||||
// Unprotected Zip entry issues are very common, handle them separately
|
||||
List<ApkVerifier.IssueWithParams> unprotIssues = issueList.stream()
|
||||
.filter(i -> i.getIssue() == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY)
|
||||
.collect(Collectors.toList());
|
||||
if (!unprotIssues.isEmpty()) {
|
||||
builder.append("<h4>");
|
||||
builder.escape(NLS.str("apkSignature.unprotectedEntry"));
|
||||
builder.append("</h4><blockquote>");
|
||||
for (ApkVerifier.IssueWithParams issue : unprotIssues) {
|
||||
builder.escape((String) issue.getParams()[0]);
|
||||
builder.append("<br>");
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
List<ApkVerifier.IssueWithParams> remainingIssues = issueList.stream()
|
||||
.filter(i -> i.getIssue() != ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY)
|
||||
.collect(Collectors.toList());
|
||||
if (!remainingIssues.isEmpty()) {
|
||||
builder.append("<pre>\n");
|
||||
for (ApkVerifier.IssueWithParams issue : remainingIssues) {
|
||||
builder.escape(issue.toString());
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("</pre>\n");
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ApkSignatureWorker extends SwingWorker<ICodeInfo, Void> {
|
||||
private final ApkSignatureNode node;
|
||||
|
||||
public ApkSignatureWorker(ApkSignatureNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ICodeInfo doInBackground() {
|
||||
LOG.debug("Starting APK signature verification for {}", node.openFile);
|
||||
ApkVerifier verifier = new ApkVerifier.Builder(node.openFile).build();
|
||||
try {
|
||||
ApkVerifier.Result result = verifier.verify();
|
||||
|
||||
// Build HTML content
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>APK signature verification result:</h1>");
|
||||
|
||||
builder.append("<p><b>");
|
||||
if (result.isVerified()) {
|
||||
builder.escape(NLS.str("apkSignature.verificationSuccess"));
|
||||
} else {
|
||||
builder.escape(NLS.str("apkSignature.verificationFailed"));
|
||||
}
|
||||
builder.append("</b></p>");
|
||||
|
||||
final String err = NLS.str("apkSignature.errors");
|
||||
final String warn = NLS.str("apkSignature.warnings");
|
||||
final String sigSuccKey = "apkSignature.signatureSuccess";
|
||||
final String sigFailKey = "apkSignature.signatureFailed";
|
||||
|
||||
ApkSignatureNode parentNode = node;
|
||||
|
||||
writeIssues(builder, err, result.getErrors());
|
||||
|
||||
if (!result.getV1SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV1Scheme() ? sigSuccKey : sigFailKey, 1));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.escape(signer.getName());
|
||||
builder.append(" (");
|
||||
builder.escape(signer.getSignatureFileName());
|
||||
builder.append(")");
|
||||
builder.append("</h3>");
|
||||
parentNode.writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV2SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV2Scheme() ? sigSuccKey : sigFailKey, 2));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V2SchemeSignerInfo signer : result.getV2SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
parentNode.writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV3SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV3Scheme() ? sigSuccKey : sigFailKey, 3));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV3SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
parentNode.writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
if (!result.getV31SchemeSigners().isEmpty()) {
|
||||
builder.append("<h2>");
|
||||
builder.escape(NLS.str(result.isVerifiedUsingV31Scheme() ? sigSuccKey : sigFailKey, 31));
|
||||
builder.append("</h2>\n");
|
||||
|
||||
builder.append("<blockquote>");
|
||||
for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV31SchemeSigners()) {
|
||||
builder.append("<h3>");
|
||||
builder.escape(NLS.str("apkSignature.signer"));
|
||||
builder.append(" ");
|
||||
builder.append(Integer.toString(signer.getIndex() + 1));
|
||||
builder.append("</h3>");
|
||||
parentNode.writeCertificate(builder, signer.getCertificate());
|
||||
writeIssues(builder, err, signer.getErrors());
|
||||
writeIssues(builder, warn, signer.getWarnings());
|
||||
}
|
||||
builder.append("</blockquote>");
|
||||
}
|
||||
writeIssues(builder, warn, result.getWarnings());
|
||||
|
||||
return new SimpleCodeInfo(builder.toString());
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to verify APK signature for {}", node.openFile, e);
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>");
|
||||
builder.escape(NLS.str("apkSignature.exception"));
|
||||
builder.append("</h1><pre>");
|
||||
builder.escape(ExceptionUtils.getStackTrace(e));
|
||||
builder.append("</pre>");
|
||||
return new SimpleCodeInfo(builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
node.content = get();
|
||||
if (tabbedPane != null) {
|
||||
ContentPanel panel = tabbedPane.getTabByNode(node);
|
||||
if (panel instanceof HtmlPanel) {
|
||||
((HtmlPanel) panel).loadContent(node);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Could not find TabbedPane to refresh ApkSignatureNode panel.");
|
||||
}
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
LOG.error("Error during APK signature verification SwingWorker", e);
|
||||
StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4);
|
||||
builder.append("<h1>");
|
||||
builder.escape(NLS.str("apkSignature.exception"));
|
||||
builder.append("</h1><pre>");
|
||||
Throwable cause = (e instanceof ExecutionException) ? e.getCause() : e;
|
||||
builder.escape(ExceptionUtils.getStackTrace(cause));
|
||||
builder.append("</pre>");
|
||||
node.content = new SimpleCodeInfo(builder.toString());
|
||||
|
||||
if (tabbedPane != null) {
|
||||
ContentPanel panel = tabbedPane.getTabByNode(node);
|
||||
if (panel instanceof HtmlPanel) {
|
||||
((HtmlPanel) panel).loadContent(node);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
node.loadingStarted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.ui.JadxSettingsWindow;
|
||||
import jadx.gui.settings.ui.plugins.PluginSettings;
|
||||
import jadx.gui.tree.TreeExpansionService;
|
||||
import jadx.gui.treemodel.ApkSignature;
|
||||
import jadx.gui.treemodel.ApkSignatureNode;
|
||||
import jadx.gui.treemodel.JInputFiles;
|
||||
import jadx.gui.treemodel.JInputScripts;
|
||||
import jadx.gui.treemodel.JInputs;
|
||||
@@ -682,7 +682,7 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
private void addTreeCustomNodes() {
|
||||
treeRoot.replaceCustomNode(ApkSignature.getApkSignature(wrapper));
|
||||
treeRoot.replaceCustomNode(ApkSignatureNode.getApkSignature(wrapper));
|
||||
treeRoot.replaceCustomNode(new SummaryNode(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ public final class HtmlPanel extends ContentPanel {
|
||||
setLayout(new BorderLayout());
|
||||
textArea = new JHtmlPane();
|
||||
loadSettings();
|
||||
textArea.setText(jnode.getCodeInfo().getCodeStr());
|
||||
textArea.setCaretPosition(0); // otherwise the start view will be the last line
|
||||
loadContent(jnode);
|
||||
textArea.setEditable(false);
|
||||
JScrollPane sp = new JScrollPane(textArea);
|
||||
add(sp);
|
||||
@@ -38,6 +37,11 @@ public final class HtmlPanel extends ContentPanel {
|
||||
textArea.setFont(settings.getFont());
|
||||
}
|
||||
|
||||
public void loadContent(JNode jnode) {
|
||||
textArea.setText(jnode.getCodeInfo().getCodeStr());
|
||||
textArea.setCaretPosition(0); // otherwise the start view will be the last line
|
||||
}
|
||||
|
||||
public JEditorPane getHtmlArea() {
|
||||
return textArea;
|
||||
}
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256-Fingerabdruck
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=Signierer
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=Signaturprüfung erfolgreich abgeschlossen
|
||||
apkSignature.verificationFailed=Signaturprüfung fehlgeschlagen
|
||||
apkSignature.signatureSuccess=Gültige APK-Signatur v%d gefunden
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 Fingerprint
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=Signer
|
||||
apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=Signature verification succeeded
|
||||
apkSignature.verificationFailed=Signature verification failed
|
||||
apkSignature.signatureSuccess=Valid APK signature v%d found
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=Huella SHA-256
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
#apkSignature.signer=Signer
|
||||
#apkSignature.loading=Loading signature...
|
||||
#apkSignature.verificationSuccess=Signature verification succeeded
|
||||
#apkSignature.verificationFailed=Signature verification failed
|
||||
#apkSignature.signatureSuccess=Valid APK signature v%d found
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=Sidik Jari SHA-256
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=Penandatangan
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=Verifikasi tanda tangan berhasil
|
||||
apkSignature.verificationFailed=Verifikasi tanda tangan gagal
|
||||
apkSignature.signatureSuccess=Tanda tangan APK yang valid v%d ditemukan
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 지문
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=서명자
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=서명 검증 성공
|
||||
apkSignature.verificationFailed=서명 검증 실패
|
||||
apkSignature.signatureSuccess=유효한 APK 서명 v%d을(를) 찾았습니다.
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=Assinatura digital SHA-256
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=Assinador
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=Verificação de assinatura bem-sucedida
|
||||
apkSignature.verificationFailed=Verificação de assinatura falhou
|
||||
apkSignature.signatureSuccess=Assinatura válida de apk v%d encontrada
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 Fingerprint
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=Signer
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=Signature verification succeeded
|
||||
apkSignature.verificationFailed=Signature verification failed
|
||||
apkSignature.signatureSuccess=Valid APK signature v%d found
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 签名
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=签名者
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=签名验证成功
|
||||
apkSignature.verificationFailed=签名验证失败
|
||||
apkSignature.signatureSuccess=找到有效的 APK 签名 v%d
|
||||
|
||||
@@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 指紋
|
||||
certificate.serialPubKeyY=Y
|
||||
|
||||
apkSignature.signer=簽署者
|
||||
#apkSignature.loading=Loading signature...
|
||||
apkSignature.verificationSuccess=簽名驗證成功
|
||||
apkSignature.verificationFailed=簽名驗證失敗
|
||||
apkSignature.signatureSuccess=找到可用的 APK 簽名 v%d
|
||||
|
||||
Reference in New Issue
Block a user