View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    * 
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   ******************************************************************************/
11  package com.jsql.view.swing.manager;
12  
13  import com.jsql.model.injection.method.AbstractMethodInjection;
14  import com.jsql.model.injection.engine.model.Engine;
15  import com.jsql.util.LogLevelUtil;
16  import com.jsql.util.StringUtil;
17  import com.jsql.view.subscriber.SubscriberScan;
18  import com.jsql.view.swing.list.*;
19  import com.jsql.view.swing.manager.util.StateButton;
20  import com.jsql.view.swing.util.I18nViewUtil;
21  import com.jsql.view.swing.util.MediatorHelper;
22  import com.jsql.view.swing.util.UiUtil;
23  import org.apache.logging.log4j.LogManager;
24  import org.apache.logging.log4j.Logger;
25  import org.json.JSONArray;
26  import org.json.JSONException;
27  
28  import javax.swing.*;
29  import java.awt.*;
30  import java.awt.event.ActionEvent;
31  import java.awt.event.ActionListener;
32  import java.io.BufferedReader;
33  import java.io.IOException;
34  import java.io.InputStreamReader;
35  import java.nio.charset.StandardCharsets;
36  import java.util.List;
37  import java.util.Objects;
38  import java.util.Optional;
39  
40  /**
41   * Manager to display webpages frequently used as backoffice administration.
42   */
43  public class ManagerScan extends AbstractManagerList {
44      
45      private static final Logger LOGGER = LogManager.getRootLogger();
46  
47      public static final String NAME = "listManagerScan";
48  
49      /**
50       * Create admin page finder.
51       */
52      public ManagerScan() {
53          super("swing/list/scan-page.json");
54  
55          this.listPaths.setTransferHandler(null);
56          this.listPaths.setTransferHandler(new ListTransfertHandlerScan());
57          this.listPaths.setCellRenderer(new DefaultListCellRenderer() {
58              @Override
59              public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
60                  JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
61                  ItemList itemList = (ItemList) value;
62                  if (itemList.isVulnerable()) {
63                      label.setIcon(UiUtil.TICK_GREEN.getIcon());
64                  }
65                  return label;
66              }
67          });
68          
69          this.listPaths.setName(ManagerScan.NAME);
70  
71          JPanel lastLine = this.getLastLinePanel();
72          this.add(lastLine, BorderLayout.SOUTH);
73          
74          this.listPaths.addListSelectionListener(e -> {
75              if (this.listPaths.getSelectedValue() == null) {
76                  return;
77              }
78              
79              var beanInjection = ((ItemListScan) this.listPaths.getSelectedValue()).getBeanInjection();
80              MediatorHelper.panelAddressBar().getTextFieldAddress().setText(beanInjection.getUrl());
81              MediatorHelper.panelAddressBar().getTextFieldHeader().setText(beanInjection.getHeader());
82              MediatorHelper.panelAddressBar().getTextFieldRequest().setText(beanInjection.getRequest());
83              
84              String requestType = beanInjection.getRequestType();
85              if (requestType != null && !requestType.isEmpty()) {
86                  MediatorHelper.panelAddressBar().getAtomicRadioMethod().setText(requestType);
87              } else {
88                  MediatorHelper.panelAddressBar().getAtomicRadioMethod().setText(StringUtil.GET);
89              }
90              
91              AbstractMethodInjection method = beanInjection.getMethodInstance();
92              if (method == MediatorHelper.model().getMediatorMethod().getHeader()) {
93                  MediatorHelper.panelAddressBar().getAtomicRadioHeader().setSelected(true);
94              } else if (method == MediatorHelper.model().getMediatorMethod().getRequest()) {
95                  MediatorHelper.panelAddressBar().getAtomicRadioMethod().setSelected(true);
96              } else {
97                  MediatorHelper.panelAddressBar().getAtomicRadioRequest().setSelected(true);
98              }
99          });
100     }
101 
102     @Override
103     public void buildList(String nameFile) {
104         var jsonScan = new StringBuilder();
105         try (
106             var inputStream = UiUtil.class.getClassLoader().getResourceAsStream(nameFile);
107             var inputStreamReader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
108             var reader = new BufferedReader(inputStreamReader)
109         ) {
110             String line;
111             while ((line = reader.readLine()) != null) {
112                 jsonScan.append(line);
113             }
114             var jsonArrayScan = new JSONArray(jsonScan.toString());
115             for (var i = 0 ; i < jsonArrayScan.length() ; i++) {
116                 this.itemsList.add(new ItemListScan(jsonArrayScan.getJSONObject(i)));
117             }
118             this.listPaths = new DnDListScan(this.itemsList);
119         } catch (JSONException | IOException e) {
120             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
121         }
122     }
123 
124     private JPanel getLastLinePanel() {
125         var lastLine = new JPanel();
126         lastLine.setOpaque(false);
127         lastLine.setLayout(new BoxLayout(lastLine, BoxLayout.X_AXIS));
128 
129         this.buildRunButton("SCAN_RUN_BUTTON_LABEL", "SCAN_RUN_BUTTON_TOOLTIP");
130         this.run.addActionListener(new ActionScan());
131 
132         lastLine.add(this.horizontalGlue);
133         lastLine.add(this.progressBar);
134         lastLine.add(this.run);
135         return lastLine;
136     }
137 
138     private class ActionScan implements ActionListener {
139         @Override
140         public void actionPerformed(ActionEvent e) {
141             if (ManagerScan.this.listPaths.getSelectedValuesList().isEmpty()) {
142                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Select URL(s) to scan");
143                 return;
144             }
145             new Thread(() -> {
146                 if (ManagerScan.this.run.getState() == StateButton.STARTABLE) {
147                     ManagerScan.this.run.setText(I18nViewUtil.valueByKey("SCAN_RUN_BUTTON_STOP"));
148                     ManagerScan.this.run.setState(StateButton.STOPPABLE);
149                     ManagerScan.this.progressBar.setVisible(true);
150                     ManagerScan.this.horizontalGlue.setVisible(false);
151                     DefaultListModel<ItemList> listModel = (DefaultListModel<ItemList>) ManagerScan.this.listPaths.getModel();
152                     for (var i = 0 ; i < listModel.getSize() ; i++) {
153                         listModel.get(i).reset();
154                     }
155                     ManagerScan.this.scan(ManagerScan.this.listPaths.getSelectedValuesList());
156                 } else {
157                     MediatorHelper.model().getResourceAccess().setScanStopped(true);
158                     MediatorHelper.model().setIsStoppedByUser(true);
159                     ManagerScan.this.run.setEnabled(false);
160                     ManagerScan.this.run.setState(StateButton.STOPPING);
161                 }
162             }, "ThreadScan").start();
163         }
164     }
165     
166     /**
167      * Start fast scan of URLs in sequence and display result.
168      * Unplug any existing view and plug a console-like view in order to
169      * respond appropriately to GUI message with simple text result instead of
170      * build complex graphical components during the multi website injections.
171      * At the end of the scan it plugs again the default view.
172      * @param urlsItemList contains a list of String URL
173      */
174     public void scan(List<ItemList> urlsItemList) {
175         MediatorHelper.frame().resetInterface();  // Erase everything in the view from a previous injection
176         
177         // wait for ending of ongoing interaction between two injections
178         try {
179             Thread.sleep(500);
180         } catch (InterruptedException e) {
181             LOGGER.log(LogLevelUtil.IGNORE, e, e);
182             Thread.currentThread().interrupt();
183         }
184 
185         // Display result only in console
186         MediatorHelper.frame().getSubscriberView().getSubscription().cancel();
187         var subscriberScan = new SubscriberScan();
188         MediatorHelper.model().subscribe(subscriberScan);
189 
190         MediatorHelper.model().setIsScanning(true);
191         MediatorHelper.model().getResourceAccess().setScanStopped(false);
192         
193         for (ItemList urlItemList: urlsItemList) {
194             if (  // detect interrupt by user to end intermediate scan
195                 MediatorHelper.model().isStoppedByUser()
196                 || MediatorHelper.model().getResourceAccess().isScanStopped()
197             ) {
198                 break;
199             }
200 
201             var urlItemListScan = (ItemListScan) urlItemList;
202             LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Scanning {}", urlItemListScan.getBeanInjection().getUrl());
203 
204             Optional<Engine> optionalEngine = MediatorHelper.model().getMediatorEngine().getEngines()
205                 .stream()
206                 .filter(engine -> engine.toString().equalsIgnoreCase(urlItemListScan.getBeanInjection().getEngine()))
207                 .findAny();
208 
209             MediatorHelper.model().getMediatorEngine().setEngineByUser(
210                 optionalEngine.orElse(MediatorHelper.model().getMediatorEngine().getAuto())
211             );
212             MediatorHelper.model().getMediatorUtils().parameterUtil().controlInput(
213                 urlItemListScan.getBeanInjection().getUrl(),
214                 urlItemListScan.getBeanInjection().getRequest(),
215                 urlItemListScan.getBeanInjection().getHeader(),
216                 urlItemListScan.getBeanInjection().getMethodInstance(),
217                 urlItemListScan.getBeanInjection().getRequestType(),
218                 true
219             );
220             
221             try {
222                 Thread.sleep(500);
223             } catch (InterruptedException e) {
224                 LOGGER.log(LogLevelUtil.IGNORE, e, e);
225                 Thread.currentThread().interrupt();
226             }
227         }
228         
229         // Get back the default view
230         subscriberScan.getSubscription().cancel();
231         MediatorHelper.model().subscribe(MediatorHelper.frame().getSubscriberView());
232 
233         MediatorHelper.model().setIsScanning(false);
234         MediatorHelper.model().setIsStoppedByUser(false);
235         MediatorHelper.model().getResourceAccess().setScanStopped(false);
236 
237         this.endProcess();
238     }
239 }