TabResults.java

/*******************************************************************************
 * Copyhacked (H) 2012-2025.
 * This program and the accompanying materials
 * are made available under no term at all, use it like
 * you want, but share and discuss it
 * every time possible with every body.
 *
 * Contributors:
 *      ron190 at ymail dot com - initial implementation
 *******************************************************************************/
package com.jsql.view.swing.tab;

import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.jsql.model.bean.database.AbstractElementDatabase;
import com.jsql.util.I18nUtil;
import com.jsql.util.LogLevelUtil;
import com.jsql.util.StringUtil;
import com.jsql.view.swing.action.ActionCloseTabResult;
import com.jsql.view.swing.action.HotkeyUtil;
import com.jsql.view.swing.popupmenu.JPopupMenuText;
import com.jsql.view.swing.terminal.*;
import com.jsql.view.swing.tab.dnd.DnDTabbedPane;
import com.jsql.view.swing.tab.dnd.TabTransferHandler;
import com.jsql.view.swing.table.PanelTable;
import com.jsql.view.swing.text.JPopupTextArea;
import com.jsql.view.swing.util.MediatorHelper;
import com.jsql.view.swing.util.UiStringUtil;
import com.jsql.view.swing.util.UiUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.UUID;
import java.util.function.IntConsumer;

/**
 * TabbedPane containing result injection panels.
 */
public class TabResults extends DnDTabbedPane {

    /**
     * Log4j logger sent to view.
     */
    private static final Logger LOGGER = LogManager.getRootLogger();

    public static final String TAB_EXPLOIT_FAILURE_INCORRECT_URL = "Tab exploit failure: incorrect URL";
    public static final String RCE_SHELL = "RCE shell";

    /**
     * Create the panel containing injection results.
     */
    public TabResults() {
        this.setName("tabResults");
        this.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        this.setTransferHandler(new TabTransferHandler());
        this.putClientProperty("JTabbedPane.tabClosable", true);
        this.putClientProperty("JTabbedPane.tabCloseCallback", (IntConsumer) ActionCloseTabResult::perform);
        UIManager.put("TabbedPane.closeHoverForeground", LogLevelUtil.COLOR_RED);
        HotkeyUtil.addShortcut(this);  // Add hotkeys to root-pane ctrl-tab, ctrl-shift-tab, ctrl-w
        this.addMouseWheelListener(new TabbedPaneMouseWheelListener());
        MediatorHelper.register(this);
    }

    public void addFileTab(String label, String content, String path) {
        JTextArea fileText = new JPopupTextArea().getProxy();
        fileText.setText(content);
        fileText.setFont(new Font(UiUtil.FONT_NAME_MONO_NON_ASIAN, Font.PLAIN, 14));
        fileText.setCaretPosition(0);
        this.addTextTab(label, path, fileText, UiUtil.DOWNLOAD.getIcon());
        MediatorHelper.tabManagersCards().addToLists(path, label);
    }

    public void addReportTab(String content) {
        JEditorPane editorPane = new JEditorPane();
        editorPane.setContentType("text/html");
        editorPane.setText("<html><span style=\"white-space: nowrap; font-family:'"+ UiUtil.FONT_NAME_MONO_NON_ASIAN +"'\">" + content + "</span></html>");
        editorPane.setFont(UIManager.getFont("TextArea.font"));  // required to increase text size
        editorPane.setDragEnabled(true);
        editorPane.setEditable(false);
        editorPane.setCaretPosition(0);
        editorPane.getCaret().setBlinkRate(0);
        editorPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
        editorPane.setComponentPopupMenu(new JPopupMenuText(editorPane));
        editorPane.addHyperlinkListener(linkEvent -> {
            if (HyperlinkEvent.EventType.ACTIVATED.equals(linkEvent.getEventType())) {
                try {
                    Desktop.getDesktop().browse(linkEvent.getURL().toURI());
                } catch (IOException | URISyntaxException | UnsupportedOperationException e) {
                    LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failing to browse Url", e);
                }
            }
        });
        editorPane.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent focusEvent) {
                editorPane.getCaret().setVisible(true);
                editorPane.getCaret().setSelectionVisible(true);
                editorPane.getCaret().setBlinkRate(0);
            }
        });
        UiUtil.init(editorPane);  // silent delete

        this.addTextTab("Vulnerability report", "Analysis report with all payloads detected", editorPane, UiUtil.APP_ICON.getIcon());
    }

    public void addTextTab(String label, String toolTipText, JComponent componentText, FlatSVGIcon icon) {
        var scroller = new JScrollPane(componentText);
        this.addTab(label + StringUtils.SPACE, scroller);
        this.setSelectedComponent(scroller);  // Focus on the new tab
        this.setToolTipTextAt(this.indexOfComponent(scroller), toolTipText);
        var header = new TabHeader(label, icon);
        this.setTabComponentAt(this.indexOfComponent(scroller), header);

        this.updateUI();  // required: light, open/close prefs, dark => light artifacts
    }

    public void addTabExploitWeb(String url) {
        try {
            var terminalID = UUID.randomUUID();
            var terminal = new ExploitWeb(terminalID, url);
            MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);

            JScrollPane scroller = new JScrollPane(terminal);
            this.addTab("Web shell", scroller);
            this.setSelectedComponent(scroller);  // Focus on the new tab

            var header = new TabHeader("Web shell", UiUtil.TERMINAL.getIcon());
            this.setTabComponentAt(this.indexOfComponent(scroller), header);
            terminal.requestFocusInWindow();

            this.updateUI();  // required: light, open/close prefs, dark => light artifacts
        } catch (MalformedURLException | URISyntaxException e) {
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
        }
    }

    public void addTabExploitUdfMysql() {
        try {
            var terminalID = UUID.randomUUID();
            var terminal = new ExploitUdfMysql(terminalID);
            MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);

            JScrollPane scroller = new JScrollPane(terminal);
            this.addTab("UDF shell", scroller);
            this.setSelectedComponent(scroller);  // Focus on the new tab

            var header = new TabHeader("UDF shell", UiUtil.TERMINAL.getIcon());
            this.setTabComponentAt(this.indexOfComponent(scroller), header);
            terminal.requestFocusInWindow();

            this.updateUI();  // required: light, open/close prefs, dark => light artifacts
        } catch (MalformedURLException | URISyntaxException e) {
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
        }
    }

    public void addTabExploitRceOracle() {
        try {
            var terminalID = UUID.randomUUID();
            var terminal = new ExploitRceOracle(terminalID);
            MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);

            JScrollPane scroller = new JScrollPane(terminal);
            this.addTab(TabResults.RCE_SHELL, scroller);
            this.setSelectedComponent(scroller);  // Focus on the new tab

            var header = new TabHeader(TabResults.RCE_SHELL, UiUtil.TERMINAL.getIcon());
            this.setTabComponentAt(this.indexOfComponent(scroller), header);
            terminal.requestFocusInWindow();

            this.updateUI();  // required: light, open/close prefs, dark => light artifacts
        } catch (MalformedURLException | URISyntaxException e) {
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
        }
    }

    public void addTabExploitRcePostgres() {
        try {
            var terminalID = UUID.randomUUID();
            var terminal = new ExploitRcePostgres(terminalID);
            MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);

            JScrollPane scroller = new JScrollPane(terminal);
            this.addTab(TabResults.RCE_SHELL, scroller);
            this.setSelectedComponent(scroller);  // Focus on the new tab

            var header = new TabHeader(TabResults.RCE_SHELL, UiUtil.TERMINAL.getIcon());
            this.setTabComponentAt(this.indexOfComponent(scroller), header);
            terminal.requestFocusInWindow();

            this.updateUI();  // required: light, open/close prefs, dark => light artifacts
        } catch (MalformedURLException | URISyntaxException e) {
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
        }
    }

    public void addTabExploitSql(String url, String user, String pass) {
        try {
            var terminalID = UUID.randomUUID();
            var terminal = new ExploitSql(terminalID, url, user, pass);
            MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);

            JScrollPane scroller = new JScrollPane(terminal);
            this.addTab("SQL shell", scroller);
            this.setSelectedComponent(scroller);  // Focus on the new tab

            var header = new TabHeader("SQL shell", UiUtil.TERMINAL.getIcon());
            this.setTabComponentAt(this.indexOfComponent(scroller), header);
            terminal.requestFocusInWindow();

            this.updateUI();  // required: light, open/close prefs, dark => light artifacts
        } catch (MalformedURLException | URISyntaxException e) {
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
        }
    }
    
    public void addTabValues(String[][] data, String[] columnNames, AbstractElementDatabase table) {
        var panelTable = new PanelTable(data, columnNames);
        
        this.addTab(StringUtil.detectUtf8(table.toString()), panelTable);
        panelTable.setComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
        
        this.setSelectedComponent(panelTable);  // Focus on the new tab

        var header = new TabHeader(UiStringUtil.detectUtf8Html(table.toString()), UiUtil.TABLE_BOLD.getIcon());
        this.setTabComponentAt(this.indexOfComponent(panelTable), header);

        this.updateUI();  // required: light, open/close prefs, dark => light artifacts
    }
}