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