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