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