Package org.owasp.webscarab.ui.swing.editors

Source Code of org.owasp.webscarab.ui.swing.editors.AMFPanel$AMFTreeTableModel

package org.owasp.webscarab.ui.swing.editors;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

import org.owasp.webscarab.util.swing.JTreeTable;
import org.owasp.webscarab.util.swing.treetable.DefaultTreeTableModel;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.ActionContext;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;

/**
* Panel for parsing and manipulating AMF0 and AMF3 requests/responses. It is
* currently only possible to change String and long values.
*
* Currently this panels relies on code from Adobe's BlazeDS project.
*
* NB: This class was ported from Java 1.5 and from some of SwingLabs' swingx
* components and may therefore need more testing.
*
* @author Martin Clausen <mclausen@deloitte.dk>
*
*/
public class AMFPanel extends JPanel implements ByteArrayEditor, ActionListener {
  /** The parsed ActionMessage object. */
  private ActionMessage message;

  private ActionContext messageContext;

  private SerializationContext serialContext;

  /** The AMF encoded message. */
  private byte[] messageBytes;

  /** The views are organized in tabs. */
  private JTabbedPane tabs;

  private JTreeTable treeTable;

  private JTextPane stringsArea;

  private JTextPane hexArea;

  private JButton exportButton;

  private JFileChooser fc;

  public static boolean DEBUG = true;

  /** Default constructor. */
  public AMFPanel() {
    super(new GridLayout(1, 1));
    setName("AMF");

    // Organize the views in tabs
    tabs = new JTabbedPane();

    // The following line enables to use scrolling tabs.
    tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
  }

  // ByteArrayEditor METHODS

  public String[] getContentTypes() {
    return new String[] { "application/x-amf" };
  }

  public boolean isModified() {
    return true;
  }

  public void setEditable(boolean editable) {
    // Ignore
  }

  public void setBytes(String contentType, byte[] messageBytes) {
    this.messageBytes = (byte[]) messageBytes.clone();
    parseAMFMessage();
    addTreeTable();
    updateStringsArea();
    updateHexArea();
    add(tabs);
  }

  public byte[] getBytes() {
    encodeAMFMessage();
    return (byte[]) messageBytes.clone();
  }

  private void parseAMFMessage() {
    try {
      serialContext = SerializationContext.getSerializationContext();
      serialContext.instantiateTypes = false;

      AmfTrace trace = null;
      if (DEBUG)
        trace = new AmfTrace();

      AmfMessageDeserializer amfder = new AmfMessageDeserializer();
      amfder.initialize(serialContext, new ByteArrayInputStream(
          messageBytes), trace);

      message = new ActionMessage();
      messageContext = new ActionContext();
      amfder.readMessage(message, messageContext);

      if (DEBUG)
        System.err.println(trace);
    } catch (Exception x) {
      x.printStackTrace();
    }
  }

  private void encodeAMFMessage() {
    try {
      AmfTrace trace = null;
      if (DEBUG)
        trace = new AmfTrace();

      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      AmfMessageSerializer amfser = new AmfMessageSerializer();
      amfser.initialize(serialContext, baos, trace);
      amfser.writeMessage(message);
      messageBytes = baos.toByteArray();

      if (DEBUG) {
        System.out.println(dump("", messageBytes, 0,
            messageBytes.length));
        System.err.println(trace);
      }
    } catch (Exception x) {
      x.printStackTrace();
    }
  }

  private static byte[] encodeAMFMessage(ActionMessage message) {
    byte[] messageBytes = null;
    try {
      AmfTrace trace = null;
      if (DEBUG)
        trace = new AmfTrace();

      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      AmfMessageSerializer amfser = new AmfMessageSerializer();
      SerializationContext context = SerializationContext
          .getSerializationContext();
      context.instantiateTypes = false;
      amfser.initialize(context, baos, trace);
      amfser.writeMessage(message);
      messageBytes = baos.toByteArray();

      if (DEBUG) {
        System.out.println(dump("", messageBytes, 0,
            messageBytes.length));
        System.err.println(trace);
      }
    } catch (Exception x) {
      x.printStackTrace();
    }
    return messageBytes;
  }

  // /////////////////////////////////////////////////////////////////////////////////////
  // ///////// ///////////
  // ///////// GUI SETUP ///////////
  // ///////// ///////////
  // /////////////////////////////////////////////////////////////////////////////////////

  private void addTreeTable() {
    AMFTreeTableModel dataTreeTableModel = generateModel();
    treeTable = new JTreeTable(dataTreeTableModel);

    tabs.addTab("AMF", new JScrollPane(treeTable));
    tabs.setMnemonicAt(0, KeyEvent.VK_1);
  }

  private String strings(byte[] data) {
    StringBuffer sb = new StringBuffer();
    boolean foundString = false;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    for (int i = 0; i < data.length; i++) {
      int ch = (char) (data[i] & 0xff);
      if (ch >= ' ' && ch < 0x7f) {
        baos.write(ch);
        foundString = true;
      } else if (foundString) {
        byte[] tmp = baos.toByteArray();
        sb.append(new String(tmp)).append('\n');
        baos.reset();
        foundString = false;
      }
    }
    return sb.toString();
  }

  void updateStringsArea() {
    if (stringsArea == null) {
      stringsArea = new JTextPane();
      stringsArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
      stringsArea.setEditable(false);
      stringsArea.setText(strings(messageBytes));
      tabs.addTab("Strings", new JScrollPane(stringsArea));
      tabs.setMnemonicAt(1, KeyEvent.VK_2);
    } else {
      stringsArea.setText(strings(messageBytes));
    }
  }

  void updateHexArea() {
    if (hexArea == null) {
      fc = new JFileChooser();

      exportButton = new JButton("Export");
      exportButton.addActionListener(this);

      JPanel buttonPanel = new JPanel();
      buttonPanel.add(exportButton);

      hexArea = new JTextPane();
      hexArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
      hexArea.setEditable(false);
      hexArea.setText(dump("", messageBytes, 0, messageBytes.length));

      JPanel hexPanel = new JPanel(new BorderLayout());
      hexPanel.add(buttonPanel, BorderLayout.PAGE_END);
      hexPanel.add(new JScrollPane(hexArea), BorderLayout.CENTER);

      tabs.addTab("HEX", hexPanel);
      tabs.setMnemonicAt(2, KeyEvent.VK_3);
    } else {
      hexArea.setText(dump("", messageBytes, 0, messageBytes.length));
    }
  }

  public void actionPerformed(ActionEvent e) {
    try {
      if (e.getSource() == exportButton) {
        int returnVal = fc.showSaveDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
          File file = fc.getSelectedFile();
          if (DEBUG)
            System.out.print("Exporting data to file "
                + file.getCanonicalPath() + "...");
          FileOutputStream fos = new FileOutputStream(file);
          fos.write(messageBytes);
          fos.close();
          if (DEBUG)
            System.out.println("done");
        }
      }
    } catch (Exception x) {
      x.printStackTrace();
    }
  }

  // /////////////////////////////////////////////////////////////////////////////////////
  // ///////// ///////////
  // ///////// DATA MODEL ///////////
  // ///////// ///////////
  // /////////////////////////////////////////////////////////////////////////////////////

  private static class AMFData {
    private String field;

    private String type;

    private Class typeClass;

    private String value;

    private Object object;

    private boolean isEditable;

    private ActionMessage message;

    private static String OBJ_TYPE(Object o) {
      if (o == null)
        return "Null";
      String s = o.getClass().getName();
      StringTokenizer token = new StringTokenizer(s, ".");
      while (token.hasMoreElements())
        s = (String) token.nextElement();
      return s;
    }

    private static String OBJ_VALUE(Object o) {
      if (o == null)
        return "";
      return o.toString();
    }

    private static Class OBJ_CLASS(Object o) {
      if (o == null)
        return null;
      return o.getClass();
    }

    public AMFData(String field, String type, String value) {
      this.field = field;
      this.type = type;
      this.typeClass = null;
      this.value = value;
      this.object = null;
      this.isEditable = false;
    }

    public AMFData(String field, Object object, boolean isEditable,
        ActionMessage message) {
      try {
        this.field = field;

        // Call appropriate get method
        Object value;
        if (object instanceof HashMap) {
          value = ((HashMap) object).get(field);
        } else {
          Method m = object.getClass().getMethod("get" + field, (Class[]) null);
          value = m.invoke(object, (Object[]) null);
        }

        this.type = OBJ_TYPE(value);
        this.typeClass = OBJ_CLASS(value);
        this.value = OBJ_VALUE(value);
        this.object = object;
        this.isEditable = isEditable;
        this.message = message;
      } catch (Exception x) {
        x.printStackTrace();
      }
    }

    public String getField() {
      return field;
    }

    public String getType() {
      return type;
    }

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      if (!isEditable)
        return;
      if (DEBUG)
        System.out.println("Setting " + value);
      try {
        // Invoke appropriate set method
        if (object instanceof HashMap) {
          ((HashMap) object).put(field, value);
        } else {
          Method m;
          // XXX arhhggg, pls fix me...
          if (type.equals("Long")) {
            m = object.getClass().getMethod("set" + field,
                new Class[] { long.class });
            m.invoke(object, new Object[] { new Long(value) });

          } else {
            m = object.getClass().getMethod("set" + field,
                new Class[] { typeClass });
            m.invoke(object, new Object[] { value });
          }
        }

        // Update instance, this is needed for updating GUI
        this.value = value;

        encodeAMFMessage(message);
      } catch (Exception x) {
        x.printStackTrace();
      }
    }

    public String toString() {
      return field;
    }
  }

  private static class AMFTreeTableNode extends DefaultMutableTreeNode {
    public AMFTreeTableNode(AMFData data) {
      super(data);
    }

    public boolean isEditable(int column) {
      return (column == 2) ? true : false;
    }

    /**
     * Called when done editing a cell from {@link DefaultTreeTableModel}.
     */
    public void setValueAt(Object value, int column) {
      if (DEBUG) {
        System.out.println("Setting value at column " + column + " to "
            + value + " (an instance of " + value.getClass() + ")");
      }

      if (getUserObject() instanceof AMFData) {
        AMFData data = (AMFData) getUserObject();
        switch (column) {
        case 2:
          data.setValue(value.toString());
        }
      }
    }

    /**
     * must override this for setValue from {@link DefaultTreeTableModel} to
     * work properly!
     */
    public int getColumnCount() {
      return 3;
    }

    /**
     * Called when done editing a cell from {@link DefaultTreeTableModel}.
     */
    public Object getValueAt(int column) {
      if (getUserObject() instanceof AMFData) {
        AMFData data = (AMFData) getUserObject();
        switch (column) {
        case 0:
          return data.getField();
        case 1:
          return data.getType();
        case 2:
          return data.getValue();
        }
      }
      throw new RuntimeException("Unknown user object: "
          + getUserObject());
    }
  }

  private static class AMFTreeTableModel extends DefaultTreeTableModel {
    private static String[] columnNames = { "Field", "Type", "Value" };

    public AMFTreeTableModel(TreeNode node) {
      super(node);
    }

    public int getColumnCount() {
      return 3;
    }

    public String getColumnName(int column) {
      return columnNames[column];
    }

    public Class getColumnClass(int column) {
      // TODO Auto-generated method stub
      return super.getColumnClass(column);
    }

    public Object getValueAt(Object node, int column) {
      AMFTreeTableNode n = (AMFTreeTableNode) node;
      return n.getValueAt(column);
    }

    public boolean isCellEditable(Object node, int column) {
      if (column == 0)
        return true;
      AMFTreeTableNode n = (AMFTreeTableNode) node;
      return n.isEditable(column);
    }

    public void setValueAt(Object value, Object node, int column) {
      AMFTreeTableNode n = (AMFTreeTableNode) node;
      n.setValueAt(value, column);
    }
  }

  public AMFTreeTableModel generateModel() {
    DefaultMutableTreeNode rootNode = new AMFTreeTableNode(new AMFData(
        "Message", "", ""));

    AMFTreeTableNode headersNode = new AMFTreeTableNode(new AMFData(
        "Headers", "", ""));
    rootNode.add(headersNode);

    for (int i = 0; i < message.getHeaderCount(); i++) {
      if (DEBUG)
        System.out.println("Reading header: " + i);

      AMFTreeTableNode headerNode = new AMFTreeTableNode(new AMFData("["
          + i + "]", "Header Part", ""));
      headersNode.add(headerNode);

      addObject(headerNode, message.getHeader(i));
    }

    AMFTreeTableNode bodiesNode = new AMFTreeTableNode(new AMFData(
        "Bodies", "", ""));
    rootNode.add(bodiesNode);

    for (int i = 0; i < message.getBodyCount(); i++) {
      if (DEBUG)
        System.out.println("Reading body: " + i);

      AMFTreeTableNode bodyNode = new AMFTreeTableNode(new AMFData("["
          + i + "]", "Body Part", ""));
      bodiesNode.add(bodyNode);

      addObject(bodyNode, message.getBody(i));
    }

    return new AMFTreeTableModel(rootNode);
  }

  private boolean isComplex(Object object) {
    return (object instanceof Object[])
        || (object instanceof HashMap)
        || (object instanceof List)
        || (object != null && object.getClass().getPackage().toString()
            .indexOf("flex.messaging.messages") > -1);
  }

  private void addObject(AMFTreeTableNode node, Object object) {
    try {
      if (object instanceof Object[]) {
        AMFTreeTableNode objectsNode = new AMFTreeTableNode(
            new AMFData("", "Array", ""));
        node.add(objectsNode);

        Object[] array = (Object[]) object;
        for (int i = 0; i < array.length; i++)
          addObject(objectsNode, array[i]);
      } else if (object instanceof HashMap) {
        AMFTreeTableNode hashNode = new AMFTreeTableNode(new AMFData(
            "", "HashMap", ""));
        node.add(hashNode);

        HashMap map = (HashMap) object;
        for (Iterator it = map.keySet().iterator(); it.hasNext();) {
          String key = (String) it.next();

          AMFTreeTableNode dataNode = new AMFTreeTableNode(
              new AMFData(key, map, true, message));
          hashNode.add(dataNode);
        }
        // } else if (object instanceof List) {
        // AMFTreeTableNode listNode =
        // new AMFTreeTableNode(new AMFData("", "List", ""));
        // node.add(listNode);
        //
        // List<?> list = (List<?>)object;
        // for (Iterator<?> it = list.iterator(); it.hasNext(); ) {
        // Object listobj = it.next();
        // if (isComplex(listobj))
        // addObject(listNode, listobj);
        // else {
        // String val = (String)it.next();
        //           
        // AMFTreeTableNode dataNode =
        // new AMFTreeTableNode(new AMFData("", val, ""));
        // listNode.add(dataNode);
        // }
        // }
      } else {
        Method[] methods = object.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
          Method m = methods[i];
          String name = m.getName();
          Class[] paramTypes = m.getParameterTypes();
          if (name.startsWith("get") && !name.equals("getClass")
              && paramTypes.length == 0) {
            Object val = m.invoke(object, (Object[]) null);
            if (isComplex(val))
              addObject(node, val);
            else {
              String getter = name.substring(3);
              AMFData data = new AMFData(getter, object, true,
                  message);
              AMFTreeTableNode objectNode = new AMFTreeTableNode(
                  data);
              node.add(objectNode);
            }
          }
        }
      }
    } catch (Exception x) {
      x.printStackTrace();
    }
  }

  private static final String NL = System.getProperty("line.separator", "\n");

  private static boolean isprint(int c) {
    return ((c >= 0 && c <= 33) || (c > 126 && c <= 256)) ? false : true;
  }

  static String dump(String desc, byte[] data, int off, int len) {
    final String hex = "0123456789abcdef";
    StringBuffer sb = new StringBuffer();
    if (desc.length() != 0)
      sb.append(desc + NL);
    int n = len / 16, i, o;
    for (i = 0; i < n; i++) {
      o = i * 16;
      sb.append(hex.charAt((o >>> 12) & 0x0f)); // offset
      sb.append(hex.charAt((o >>> 8) & 0x0f)); // offset
      sb.append(hex.charAt((o >>> 4) & 0x0f)); // offset
      sb.append(hex.charAt((o) & 0x0f)); // offset
      sb.append(": ");

      for (int j = 0; j < 16; j++) {
        o = data[off + i * 16 + j] & 0xff;
        sb.append(hex.charAt((o >>> 4) & 0x0f));
        sb.append(hex.charAt((o) & 0x0f));
        sb.append(" ");
      }

      sb.append("  ");
      for (int j = 0; j < 16; j++) {
        char c = (char) (data[off + i * 16 + j] & 0xff);
        sb.append(isprint(c) ? c : '.');
      }
      sb.append(NL);
    }
    if ((n = len % 16) != 0) {
      o = i * 16;
      sb.append(hex.charAt((o >>> 12) & 0x0f)); // offset
      sb.append(hex.charAt((o >>> 8) & 0x0f)); // offset
      sb.append(hex.charAt((o >>> 4) & 0x0f)); // offset
      sb.append(hex.charAt((o) & 0x0f)); // offset
      sb.append(": ");

      for (int j = 0; j < n; j++) {
        o = data[off + i * 16 + j] & 0xff;
        sb.append(hex.charAt((o >>> 4) & 0x0f));
        sb.append(hex.charAt((o) & 0x0f));
        sb.append(" ");
      }
      for (int j = n; j < 16; j++)
        sb.append("   ");

      sb.append("  ");
      for (int j = 0; j < n; j++) {
        char c = (char) (data[off + i * 16 + j] & 0xff);
        sb.append(isprint(c) ? c : '.');
      }
      sb.append(NL);
    }
    return sb.toString();
  }

  private static byte[] readfile(String filename) {
    byte[] tmp = null;
    try {
      RandomAccessFile raf = new RandomAccessFile(filename, "r");
      tmp = new byte[(int) raf.length()];
      raf.readFully(tmp);
      raf.close();
    } catch (Exception x) {
      x.printStackTrace();
    }
    return tmp;
  }

  public static void main(String[] args) {
    try {
      byte[] messageBytes = readfile("c:\\temp\\temp\\amf-passwd-res.bin");
      JFrame mainFrame = new JFrame("AMF Panel");
      mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      AMFPanel amfPanel = new AMFPanel();
      amfPanel.setBytes("", messageBytes);
      mainFrame.getContentPane().add(amfPanel);
      Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
      mainFrame.setSize(screenSize.width * 2 / 3,
          screenSize.height * 2 / 3);
      mainFrame.setLocationRelativeTo(null);
      mainFrame.pack();
      mainFrame.setVisible(true);
    } catch (Exception x) {
      x.printStackTrace();
    }
  }
}
TOP

Related Classes of org.owasp.webscarab.ui.swing.editors.AMFPanel$AMFTreeTableModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.