View Javadoc
1   package com.jsql.util;
2   
3   import com.jsql.model.InjectionModel;
4   import com.jsql.util.bruter.Coder;
5   import com.jsql.util.bruter.HashUtil;
6   import org.apache.commons.lang3.exception.ExceptionUtils;
7   import org.apache.logging.log4j.Level;
8   import org.apache.logging.log4j.LogManager;
9   import org.apache.logging.log4j.Logger;
10  
11  import javax.swing.*;
12  import java.lang.reflect.InvocationTargetException;
13  import java.nio.charset.StandardCharsets;
14  import java.security.MessageDigest;
15  import java.security.NoSuchAlgorithmException;
16  import java.util.Set;
17  import java.util.concurrent.CopyOnWriteArraySet;
18  
19  /**
20   * Utility class managing exception reporting to GitHub.
21   */
22  public class ExceptionUtil {
23      
24      private static final Logger LOGGER = LogManager.getRootLogger();
25      
26      private final InjectionModel injectionModel;
27      
28      private final Set<String> exceptionsMd5Cached = new CopyOnWriteArraySet<>();
29      
30      public ExceptionUtil(InjectionModel injectionModel) {
31          this.injectionModel = injectionModel;
32      }
33      
34      /**
35       * Handler class processing errors on top of the JVM in order to send
36       * a report to GitHub automatically.
37       */
38      public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
39  
40          @Override
41          public void uncaughtException(Thread thread, Throwable throwable) {
42              LOGGER.log(
43                  LogLevelUtil.CONSOLE_JAVA,
44                  () -> String.format("Unhandled Exception on %s", thread.getName()),
45                  throwable
46              );
47              LOGGER.log(  // Display to stdout
48                  Level.ERROR,
49                  () -> String.format("Unhandled Exception on %s", thread.getName()),
50                  throwable
51              );
52  
53              // Report #214: ignore if OutOfMemoryError: Java heap space
54              String stackTrace = ExceptionUtils.getStackTrace(throwable);
55              if (
56                  ExceptionUtil.this.injectionModel.getMediatorUtils().preferencesUtil().isReportingBugs()
57                  && stackTrace.contains("com.jsql")
58                  && !(throwable instanceof OutOfMemoryError)
59                  && !stackTrace.contains("OutOfMemoryError")  // when implicit
60              ) {
61                  if (stackTrace.contains("Could not initialize class java.awt.Toolkit")) {
62                      LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "System libraries are missing, use a proper Java runtime instead of headless runtime", throwable);
63                      return;
64                  } else if (stackTrace.contains("Could not initialize class sun.awt.X11.XToolkit")) {
65                      LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "System libraries are missing or wrong DISPLAY variable, verify your settings", throwable);
66                      return;
67                  } else if (stackTrace.contains("ClassFormatError: Unknown constant tag")) {
68                      LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "Damaged class or JVM, verify your settings", throwable);
69                      return;
70                  }
71  
72                  try {
73                      var messageDigest = MessageDigest.getInstance(Coder.MD5.label);
74  
75                      String stackTraceTrim = stackTrace.trim();
76                      var passwordString = String.valueOf(stackTraceTrim.toCharArray());
77  
78                      byte[] passwordByte = passwordString.getBytes(StandardCharsets.UTF_8);
79                      messageDigest.update(passwordByte, 0, passwordByte.length);
80  
81                      byte[] encodedPassword = messageDigest.digest();
82                      var md5Exception = HashUtil.digestToHexString(encodedPassword);
83                      if (!ExceptionUtil.this.exceptionsMd5Cached.contains(md5Exception)) {
84                          ExceptionUtil.this.exceptionsMd5Cached.add(md5Exception);
85                          ExceptionUtil.this.injectionModel.getMediatorUtils().gitUtil().sendUnhandledException(
86                              thread.getName(),
87                              throwable
88                          );
89                      }
90                  } catch (NoSuchAlgorithmException e) {
91                      LOGGER.log(LogLevelUtil.IGNORE, e);
92                  }
93              }
94          }
95      }
96      
97      /**
98       * Add the error reporting mechanism on top of the JVM in order to
99       * intercept and process the error to GitHub.
100      */
101     public void setUncaughtExceptionHandler() {
102         Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());  // Regular Exception
103         try {  // Event dispatching thread Exception
104             SwingUtilities.invokeAndWait(() ->
105                 Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler())  // We are in the event dispatching thread
106             );
107         } catch (InvocationTargetException | InterruptedException e) {
108             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
109             Thread.currentThread().interrupt();
110         }
111     }
112 }