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