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              if (
55                  ExceptionUtil.this.injectionModel.getMediatorUtils().getPreferencesUtil().isReportingBugs()
56                  && ExceptionUtils.getStackTrace(throwable).contains("com.jsql")
57                  && !(throwable instanceof OutOfMemoryError)
58                  && !ExceptionUtils.getStackTrace(throwable).contains("OutOfMemoryError")  // when implicit
59              ) {
60                  if (ExceptionUtils.getStackTrace(throwable).contains("Could not initialize class java.awt.Toolkit")) {
61                      LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "System libraries are missing, please use a proper Java runtime instead of headless runtime");
62                      return;
63                  } else if (ExceptionUtils.getStackTrace(throwable).contains("Could not initialize class sun.awt.X11.XToolkit")) {
64                      LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "System libraries are missing or wrong DISPLAY variable, please verify your settings");
65                      return;
66                  }
67  
68                  try {
69                      var messageDigest = MessageDigest.getInstance(Coder.MD5.label);
70  
71                      String stackTrace = ExceptionUtils.getStackTrace(throwable).trim();
72                      var passwordString = String.valueOf(stackTrace.toCharArray());
73  
74                      byte[] passwordByte = passwordString.getBytes(StandardCharsets.UTF_8);
75                      messageDigest.update(passwordByte, 0, passwordByte.length);
76  
77                      byte[] encodedPassword = messageDigest.digest();
78                      var md5Exception = HashUtil.digestToHexString(encodedPassword);
79                      if (!ExceptionUtil.this.exceptionsMd5Cached.contains(md5Exception)) {
80                          ExceptionUtil.this.exceptionsMd5Cached.add(md5Exception);
81                          ExceptionUtil.this.injectionModel.getMediatorUtils().getGitUtil().sendUnhandledException(
82                              thread.getName(),
83                              throwable
84                          );
85                      }
86                  } catch (NoSuchAlgorithmException e) {
87                      LOGGER.log(LogLevelUtil.IGNORE, e);
88                  }
89              }
90          }
91      }
92      
93      /**
94       * Add the error reporting mechanism on top of the JVM in order to
95       * intercept and process the error to GitHub.
96       */
97      public void setUncaughtExceptionHandler() {
98          Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());  // Regular Exception
99          try {  // Event dispatching thread Exception
100             SwingUtilities.invokeAndWait(() ->
101                 Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler())  // We are in the event dispatching thread
102             );
103         } catch (InvocationTargetException | InterruptedException e) {
104             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
105             Thread.currentThread().interrupt();
106         }
107     }
108 }