mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-10-02 18:17:27 +13:00
Deobfuscate received server error messages
This commit is contained in:
parent
5056b248a9
commit
778485b4a9
4 changed files with 115 additions and 22 deletions
|
@ -12,6 +12,7 @@ import io.xpipe.beacon.exchange.MessageExchanges;
|
||||||
import io.xpipe.beacon.exchange.data.ClientErrorMessage;
|
import io.xpipe.beacon.exchange.data.ClientErrorMessage;
|
||||||
import io.xpipe.beacon.exchange.data.ServerErrorMessage;
|
import io.xpipe.beacon.exchange.data.ServerErrorMessage;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.core.store.ShellStore;
|
||||||
|
import io.xpipe.core.util.Deobfuscator;
|
||||||
import io.xpipe.core.util.JacksonMapper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
@ -276,8 +277,8 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var reader = JacksonMapper.newMapper().readerFor(ClientErrorMessage.class);
|
var message = JacksonMapper.getDefault().treeToValue(content, ClientErrorMessage.class);
|
||||||
return Optional.of(reader.readValue(content));
|
return Optional.of(message);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't parse client error message", ex);
|
throw new ConnectorException("Couldn't parse client error message", ex);
|
||||||
}
|
}
|
||||||
|
@ -290,8 +291,9 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var reader = JacksonMapper.newMapper().readerFor(ServerErrorMessage.class);
|
var message = JacksonMapper.getDefault().treeToValue(content, ServerErrorMessage.class);
|
||||||
return Optional.of(reader.readValue(content));
|
Deobfuscator.deobfuscate(message.getError());
|
||||||
|
return Optional.of(message);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't parse server error message", ex);
|
throw new ConnectorException("Couldn't parse server error message", ex);
|
||||||
}
|
}
|
||||||
|
|
94
core/src/main/java/io/xpipe/core/util/Deobfuscator.java
Normal file
94
core/src/main/java/io/xpipe/core/util/Deobfuscator.java
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
package io.xpipe.core.util;
|
||||||
|
|
||||||
|
import io.xpipe.core.charsetter.NewLine;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Deobfuscator {
|
||||||
|
|
||||||
|
public static void deobfuscate(Throwable throwable) {
|
||||||
|
if (!System.getenv().containsKey("XPIPE_MAPPING")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String deobf = deobfuscateToString(throwable);
|
||||||
|
if (deobf == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// "at package.class.method(source.java:123)"
|
||||||
|
Pattern tracePattern = Pattern.compile("\\s*at\\s+([\\w.$_]+)\\.([\\w$_]+)\\((.*):(\\d+)\\)(\\n|\\r\\n)");
|
||||||
|
Matcher traceMatcher = tracePattern.matcher(deobf);
|
||||||
|
List<StackTraceElement> stackTrace = new ArrayList<>();
|
||||||
|
while (traceMatcher.find()) {
|
||||||
|
String className = traceMatcher.group(1);
|
||||||
|
String methodName = traceMatcher.group(2);
|
||||||
|
String sourceFile = traceMatcher.group(3);
|
||||||
|
int lineNum = Integer.parseInt(traceMatcher.group(4));
|
||||||
|
stackTrace.add(new StackTraceElement(className, methodName, sourceFile, lineNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
throwable.setStackTrace(stackTrace.toArray(StackTraceElement[]::new));
|
||||||
|
|
||||||
|
// Also deobfuscate any other exceptions
|
||||||
|
if (throwable.getCause() != null && throwable.getCause() != throwable) {
|
||||||
|
deobfuscate(throwable.getCause());
|
||||||
|
}
|
||||||
|
for (Throwable suppressed : throwable.getSuppressed()) {
|
||||||
|
if (suppressed != throwable) deobfuscate(suppressed);
|
||||||
|
}
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
System.err.println("Deobfuscation failed");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String deobfuscateToString(Throwable t) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
t.printStackTrace(pw);
|
||||||
|
String stackTrace = sw.toString();
|
||||||
|
stackTrace = stackTrace.replaceAll("at .+/(.+)", "at $1");
|
||||||
|
|
||||||
|
if (!System.getenv().containsKey("XPIPE_MAPPING")) {
|
||||||
|
return stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var file = Files.createTempFile("xpipe_stracktrace", null);
|
||||||
|
Files.writeString(file, stackTrace);
|
||||||
|
var proc = new ProcessBuilder(
|
||||||
|
"retrace." + (OsType.getLocal().equals(OsType.WINDOWS) ? "bat" : "sh"),
|
||||||
|
System.getenv("XPIPE_MAPPING"),
|
||||||
|
file.toString())
|
||||||
|
.redirectErrorStream(true);
|
||||||
|
var active = proc.start();
|
||||||
|
var out = new String(active.getInputStream().readAllBytes()).replaceAll("\\r\\n", NewLine.LF.getNewLineString());
|
||||||
|
var code = active.waitFor();
|
||||||
|
if (code == 0) {
|
||||||
|
return out;
|
||||||
|
} else {
|
||||||
|
System.err.println("Deobfuscation failed: " + out);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.err.println("Deobfuscation failed");
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printStackTrace(Throwable t) {
|
||||||
|
var s = deobfuscateToString(t);
|
||||||
|
System.err.println(s);
|
||||||
|
}
|
||||||
|
}
|
13
core/src/main/java/io/xpipe/core/util/ModuleHelper.java
Normal file
13
core/src/main/java/io/xpipe/core/util/ModuleHelper.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package io.xpipe.core.util;
|
||||||
|
|
||||||
|
public class ModuleHelper {
|
||||||
|
|
||||||
|
public static boolean isImage() {
|
||||||
|
return ModuleHelper.class
|
||||||
|
.getProtectionDomain()
|
||||||
|
.getCodeSource()
|
||||||
|
.getLocation()
|
||||||
|
.getProtocol()
|
||||||
|
.equals("jrt");
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,6 @@ import io.xpipe.core.process.CommandProcessControl;
|
||||||
import io.xpipe.core.process.OsType;
|
import io.xpipe.core.process.OsType;
|
||||||
import io.xpipe.core.process.ShellProcessControl;
|
import io.xpipe.core.process.ShellProcessControl;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class XPipeInstallation {
|
public class XPipeInstallation {
|
||||||
|
|
||||||
public static String getInstallationBasePathForCLI(ShellProcessControl p, String cliExecutable) throws Exception {
|
public static String getInstallationBasePathForCLI(ShellProcessControl p, String cliExecutable) throws Exception {
|
||||||
|
@ -32,7 +30,7 @@ public class XPipeInstallation {
|
||||||
public static boolean containsCompatibleDefaultInstallation(ShellProcessControl p, String version) throws Exception {
|
public static boolean containsCompatibleDefaultInstallation(ShellProcessControl p, String version) throws Exception {
|
||||||
var defaultBase = getDefaultInstallationBasePath(p);
|
var defaultBase = getDefaultInstallationBasePath(p);
|
||||||
var executable = getInstallationExecutable(p, defaultBase);
|
var executable = getInstallationExecutable(p, defaultBase);
|
||||||
if (executable.isEmpty()) {
|
if (!p.executeBooleanSimpleCommand(p.getShellType().createFileExistsCommand(executable))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,14 +42,7 @@ public class XPipeInstallation {
|
||||||
public static String getInstallationExecutable(ShellProcessControl p, String installation) throws Exception {
|
public static String getInstallationExecutable(ShellProcessControl p, String installation) throws Exception {
|
||||||
var executable = getDaemonExecutablePath(p.getOsType());
|
var executable = getDaemonExecutablePath(p.getOsType());
|
||||||
var file = FileNames.join(installation, executable);
|
var file = FileNames.join(installation, executable);
|
||||||
try (CommandProcessControl c =
|
return file;
|
||||||
p.command(p.getShellType().createFileExistsCommand(file)).start()) {
|
|
||||||
if (!c.startAndCheckExit()) {
|
|
||||||
throw new IOException("File not found: " + file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDataBasePath(ShellProcessControl p) throws Exception {
|
public static String getDataBasePath(ShellProcessControl p) throws Exception {
|
||||||
|
@ -83,13 +74,6 @@ public class XPipeInstallation {
|
||||||
path = "/opt/xpipe";
|
path = "/opt/xpipe";
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CommandProcessControl c =
|
|
||||||
p.command(p.getShellType().createFileExistsCommand(path)).start()) {
|
|
||||||
if (!c.discardAndCheckExit()) {
|
|
||||||
throw new IOException("Installation not found in " + path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue