import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.util.*; import java.awt.image.BufferedImage; import java.math.BigInteger; /** * * Beschreibung * * @version 1.1 vom 30.01.2020 * @author Thomas Schaller * Version 1.1: Hash-Funkion ausgetauscht, damit Hashes unterschiedlicher. , Ö/P-Schlüssel in der gleichen Farbe */ public class ChatClient extends JFrame implements MySocketListener { // protected int HOEHE = 60; // Anfang Attribute protected JPanel jPanel1 = new JPanel(null, true); protected JLabel jLabel2 = new JLabel(); protected JTextField jTFName = new JTextField(); protected JTextField jTFAdress = new JTextField(); protected JLabel jLabel3 = new JLabel(); protected JButton jBVerbinden = new JButton(); protected JLabel jLabel1 = new JLabel(); protected JNumberField jNFPort = new JNumberField(); protected JTextField jTFNachricht = new JTextField(); protected MySocket client = null; protected JLabel jLabel5 = new JLabel(); protected JScrollPane jScrollPane1 = new JScrollPane(); protected JScrollPane jScrollPane2 = new JScrollPane(); protected JPanel jp; protected ArrayList nachrichten; protected ArrayList keys; protected ArrayList kontakte; protected Key dragKey = null; protected JLabel jLabel4 = new JLabel(); protected GridBagLayout gbl; protected int keyColor = 0; private JLabel jLabel6 = new JLabel(); // Ende Attribute public ChatClient(String title) { // Frame-Initialisierung super(title); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); addWindowListener(new WindowListener() { public void windowActivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} public void windowClosing(WindowEvent e) { if (client != null) { client.sendeNachricht("exit"); client.trenneVerbindung(); } // end of if } public void windowDeactivated(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowIconified(WindowEvent e){} public void windowOpened(WindowEvent e){} }); int frameWidth = 1081; int frameHeight = 683; setSize(frameWidth, frameHeight); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int x = (d.width - getSize().width) / 2; int y = (d.height - getSize().height) / 2; setLocation(x, y); setResizable(false); Container cp = getContentPane(); cp.setLayout(null); // Anfang Komponenten jPanel1.setBounds(8, 8, 1041, 41); jPanel1.setOpaque(false); jPanel1.setBorder(BorderFactory.createBevelBorder(1, Color.WHITE, Color.DARK_GRAY)); cp.add(jPanel1); jLabel2.setBounds(264, 11, 62, 20); jLabel2.setText("Server"); jPanel1.add(jLabel2); jTFName.setBounds(80, 11, 150, 20); jTFName.setText("anonymous"); jPanel1.add(jTFName); jTFAdress.setBounds(312, 11, 150, 20); jTFAdress.setText("localhost"); jPanel1.add(jTFAdress); jLabel3.setBounds(496, 11, 62, 20); jLabel3.setText("Port"); jPanel1.add(jLabel3); jBVerbinden.setBounds(936, 8, 99, 25); jBVerbinden.setText("Verbinden"); jBVerbinden.setMargin(new Insets(2, 2, 2, 2)); jBVerbinden.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jBVerbinden_ActionPerformed(evt); } }); jPanel1.add(jBVerbinden); jLabel1.setBounds(8, 12, 62, 18); jLabel1.setText("Name"); jPanel1.add(jLabel1); jNFPort.setBounds(528, 11, 75, 20); jNFPort.setText("44444"); jPanel1.add(jNFPort); jLabel5.setBounds(8, 64, 62, 20); jLabel5.setText("Schlüssel"); cp.add(jLabel5); keys = new ArrayList(); JPanel jp2 = new PicPanel(keys); jp2.setToolTipText(""); jScrollPane2 = new JScrollPane(jp2); jScrollPane2.setBounds(96, 64, 953, 57); jp2.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { keyCached(evt); } public void mouseReleased(MouseEvent evt) { keyDropped(evt); } }); cp.add(jScrollPane2); jLabel4.setBounds(8, 144, 86, 20); jLabel4.setText("Nachrichten"); cp.add(jLabel4); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { ChatClient_WindowClosing(evt); } }); jLabel6.setBounds(816, 624, 229, 20); jLabel6.setText("(cc) 2020, Thomas Schaller, Version 1.1"); jLabel6.setForeground(Color.GRAY); cp.add(jLabel6); // Ende Komponenten jTFNachricht.setBounds(10, 20, 358, 20); jTFNachricht.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jTFNachricht_ActionPerformed(evt); } }); Random ran = new Random(); nachrichten = new ArrayList(); kontakte = new ArrayList(); kontakte.add("alle"); jp = new JPanel(); jScrollPane1 = new JScrollPane(jp); jScrollPane1.setBounds(96, 136, 953, 481); jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); jp.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { keyMessageCached(evt); } public void mouseReleased(MouseEvent evt) { keyMessageDropped(evt); } }); cp.add(jScrollPane1); gbl = new GridBagLayout(); jp.setLayout(gbl); this.updateNachrichtenListe(); setVisible(true); } // end of public ChatClient // Anfang Methoden public void jBVerbinden_ActionPerformed(ActionEvent evt) { String a = jTFAdress.getText(); int p = jNFPort.getInt(); if (client != null && client.isAktiv()) { jTFName.setEnabled(true); jTFAdress.setEnabled(true); jNFPort.setEnabled(true); jBVerbinden.setText("Verbinden"); client.sendeNachricht("exit"); client.trenneVerbindung(); } else { client = new MySocket(a, p, this); if (client.isAktiv()) { jTFName.setEnabled(false); jTFAdress.setEnabled(false); jNFPort.setEnabled(false); jBVerbinden.setText("Trennen"); client.sendeNachricht(("user:"+jTFName.getText()+":alle")); } } // end of if-else } // end of jBVerbinden_ActionPerformed public byte[] appendOther(byte[] a1, byte[] a2){ byte[] a3 = new byte[a1.length + a2.length]; System.arraycopy(a1, 0, a3, 0, a1.length); System.arraycopy(a2, 0, a3, a1.length, a2.length); return a3; } public void jBSend_ActionPerformed(ActionEvent evt) { if (client != null && client.isAktiv()) { JMyButton button = (JMyButton) evt.getSource(); Nachricht n = button.getNachricht(); n.setEmpfaenger((String) button.getEmpfaenger().getSelectedItem()); String b = "mess:"+n.getAbsender()+":"+n.getEmpfaenger()+":"+Base64.encode(n.getInhalt())+":"+Base64.encode(n.getHashCode()); client.sendeNachricht(b); this.updateNachrichtenListe(); } else { jTFName.setEnabled(true); jTFAdress.setEnabled(true); jNFPort.setEnabled(true); jBVerbinden.setEnabled(true); } // end of if } // end of jBSend_ActionPerformed public void generateKeyPair(int bits) { RSA rsa = new RSA(bits); rsa.generateKey(); int c = keyColor; addKey(rsa.getPublicKey()); keyColor = c; addKey(rsa.getPrivateKey()); } public void addKey(Key k) { boolean schonda = false; for (Key kk : keys) { if (kk.getN().equals(k.getN()) && kk.getE().equals(k.getE())) { JOptionPane.showMessageDialog(this, "Dieser Schlüssel entspricht dem schon vorhandenen Schlüssel "+kk.getName(), "Achtung", JOptionPane.WARNING_MESSAGE); break; } // end of if } // end of for k.setImage("key"+keyColor); keyColor = (keyColor+1)%10; keys.add(k); jScrollPane2.repaint(); } public void showPublicZertKey() { Key k = RSA.getPublicKeyZert(); addKey(k); } public void signKey(Key k) { Key nk = new Key(k.getName()+"(z)",k.getE(),k.getN()); nk.sign(RSA.getPrivateKeyZert(),jTFName.getText()); nk.setImage(k.getFilename()+"s"); keys.add(keys.indexOf(k)+1,nk); jScrollPane2.repaint(); } public void deleteKey(Key k) { keys.remove(k); jScrollPane2.repaint(); } public void neuerClient(MySocket client) { } public void nachrichtEmpfangen(MySocket client) { String s = client.holeNachricht(); String[] ss = s.split(":"); if (ss[0].equals("user")) { kontakte.add(ss[1]); Nachricht n = new Nachricht("Server","alle","Neuer User: "+ss[1]); n.setSended(true); nachrichten.add(0,n); this.updateNachrichtenListe(); } if(ss[0].equals("mess")) { String hash; if (ss.length==5) { hash = ss[4]; } else { hash = ""; }// end of if Nachricht n = new Nachricht(ss[1],ss[2],Base64.decode(ss[3]),Base64.decode(hash)); nachrichten.add(0,n); this.updateNachrichtenListe(); } // end of if } public void verbindungBeendet(MySocket client) { jTFName.setEnabled(true); jTFAdress.setEnabled(true); jNFPort.setEnabled(true); jBVerbinden.setText("Verbinden"); client = null; } public void jTFNachricht_ActionPerformed(ActionEvent evt) { Nachricht n = new Nachricht(jTFName.getText(),"", jTFNachricht.getText()); jTFNachricht.setText(""); nachrichten.add(0,n); this.updateNachrichtenListe(); jTFNachricht.requestFocus(); } // end of jTFNachricht_ActionPerformed public void keyCached(MouseEvent evt) { Key k = null; if (evt.getX()>10 && evt.getX()< keys.size()*32+10) { int k_nr = (int) ((evt.getX()-10) /32); k = keys.get(k_nr); } if (evt.getButton() == evt.BUTTON1) { if (k != null) { Toolkit toolkit = Toolkit.getDefaultToolkit(); dragKey = k; Cursor c = toolkit.createCustomCursor(dragKey.getImage() , new Point(0, 0), "img"); setCursor (c); } } else { new KeyPopup(evt,this, k); } // end of if } public void keyDropped(MouseEvent evt) { GridBagConstraints c = new GridBagConstraints(); Point p = evt.getPoint(); Point pp = SwingUtilities.convertPoint(jScrollPane2, p, jScrollPane2.getParent()); Point pp2 = SwingUtilities.convertPoint(jScrollPane2, p, jScrollPane1); if (pp2.getY()>0 && pp2.getY() < jScrollPane1.getHeight() && pp2.getX()>=0 && pp2.getX() < jScrollPane1.getWidth() && dragKey!=null) { Point ppp = SwingUtilities.convertPoint(jScrollPane2, p, jp); Component cc = jp.getComponentAt(ppp.x,ppp.y); GridBagLayout gbl = (GridBagLayout) jp.getLayout(); c = gbl.getConstraints(cc); int n_nr = c.gridy-1; if (n_nr == -1) { Nachricht n; if (dragKey.isSigned()) { n = new Nachricht(jTFName.getText(),"",dragKey.toString(jTFName.getText()).getBytes(),dragKey.getHashCode()); } else { n = new Nachricht(jTFName.getText(),"",dragKey.toString(jTFName.getText())); } // end of if-else nachrichten.add(0,n); this.updateNachrichtenListe(); } if (n_nr >= 0 && n_nr < nachrichten.size() && c.gridx==1) { byte[] klar = nachrichten.get(n_nr).getInhalt(); if (dragKey.calcBlocksize()= 0 && n_nr < nachrichten.size() && c.gridx==2) { byte[] klar = nachrichten.get(n_nr).getHashCode(); if (dragKey.calcBlocksize()= 0) { int n_nr = gbc.gridy-1; String[] teile = nachrichten.get(n_nr).getInhaltString().split(",|="); if (teile[0].equals("Key:Name")) { BigInteger e = new BigInteger(teile[3]); BigInteger n = new BigInteger(teile[5]); dragKey = new Key(teile[1],e,n) ; dragKey.setImage("key"+keyColor); Toolkit toolkit = Toolkit.getDefaultToolkit(); Cursor c = toolkit.createCustomCursor(dragKey.getImage() , new Point(0, 0), "img"); setCursor (c); } // end of if } } // end of if if (evt.getButton() == evt.BUTTON3 && gbc.gridx == 1) { int n_nr = gbc.gridy-1; makeMessagePopup(evt,nachrichten.get(n_nr)); } // end of if } protected void makeMessagePopup(MouseEvent evt, Nachricht n) { new MessagePopup(evt, this, n); } public void keyMessageDropped(MouseEvent evt) { Point p = evt.getPoint(); Point pp = SwingUtilities.convertPoint(jp, p, jScrollPane2); if (pp.getY()>0 && pp.getY() < jScrollPane2.getHeight() && pp.getX()>=0 && pp.getX() < jScrollPane2.getWidth() && dragKey!=null) { this.addKey(dragKey); } dragKey = null; Cursor dc = new Cursor(Cursor.DEFAULT_CURSOR); setCursor (dc); } // end of jLabel5_MouseClicked public void updateNachrichtenListe() { //jp.setBounds(jScrollPane1.getViewport().getBounds()); GridBagConstraints c = new GridBagConstraints(); while (jp.getComponentCount()>1) { jp.remove(1); } // end of while //jp.removeAll(); if (jp.getComponentCount()==0) { JPanel eingabe = new JPanel(); eingabe.setBorder(BorderFactory.createBevelBorder(0)); eingabe.setLayout(null); eingabe.setBackground(new Color(250,255,200)); eingabe.setOpaque(true); eingabe.setPreferredSize(new Dimension(150,HOEHE)); c.gridx=0; c.gridy = 0; c.gridwidth=5; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; jTFNachricht.setBounds(100,20,800,20); JLabel nn = new JLabel(); nn.setText("Neue Nachricht"); nn.setBounds(2,20,90,20); eingabe.add(nn); eingabe.add(jTFNachricht); jp.add(eingabe,c); } // end of if c.weightx=0; c.gridwidth=1; int xx = 1; JLabel name = null; for (Nachricht n : nachrichten) { if (n.getKeys().size()>0 && name != null) { GridBagConstraints c2 = gbl.getConstraints(name); c2.gridheight++; gbl.setConstraints(name,c2); } else { name = new JLabel(); name.setText("Von "+n.getAbsender()+""); name.setBorder(BorderFactory.createBevelBorder(0)); name.setBackground(new Color(250,255,200)); name.setOpaque(true); c.gridx=0; c.gridy = xx; c.fill = GridBagConstraints.BOTH; jp.add(name,c); } // end of if-else JPanel nnn = new JPanel(); nnn.setLayout(new GridBagLayout()); nnn.setBorder(BorderFactory.createBevelBorder(0)); nnn.setBackground(new Color(250,255,200)); nnn.setOpaque(true); PicPanel pp = new PicPanel(n.getKeys()); pp.setPreferredSize(new Dimension(n.getKeys().size()*32,HOEHE)); pp.setBackground(new Color(250,255,200)); JMyLabel nachricht = new JMyLabel(n,""); if (n.getInhaltString().trim().length()>65) { nachricht.setText(""+n.getInhaltString().trim().substring(0,62)+"..."); } else { nachricht.setText(""+n.getInhaltString().trim()+""); } // end of if-else c.gridx=0; c.gridy = 0; c.weightx=1.0; c.weighty= 0; nnn.add(nachricht,c); c.gridx=1; c.gridy = 0; c.weightx=0.0; c.weighty= 0; nnn.add(pp,c); c.gridx=1; c.gridy = xx; c.weightx = 1.0; jp.add(nnn,c); nnn = new JPanel(); nnn.setLayout(new GridBagLayout()); nnn.setBorder(BorderFactory.createBevelBorder(0)); nnn.setBackground(new Color(250,255,200)); nnn.setOpaque(true); pp = new PicPanel(n.getHashKeys()); pp.setPreferredSize(new Dimension(n.getHashKeys().size()*32,HOEHE)); pp.setBackground(new Color(250,255,200)); String hc = new String(n.getHashCode()); if (hc.trim().length()>15) { hc = hc.substring(0,15)+"..."; } //end of if-else JMyLabel hash = new JMyLabel(n, hc); c.gridx=0; c.gridy = 0; c.weightx=1.0; c.weighty= 0; nnn.add(hash,c); c.gridx=1; c.gridy = 0; c.weightx=0.0; c.weighty= 0; nnn.add(pp,c); c.gridx=2; c.gridy = xx; c.weightx = 0.0; jp.add(nnn,c); JPanel abspanel = new JPanel(); abspanel.setPreferredSize(new Dimension(150,HOEHE)); abspanel.setBorder(BorderFactory.createBevelBorder(0)); abspanel.setBackground(new Color(250,255,200)); abspanel.setOpaque(true); abspanel.setLayout(new FlowLayout()); if (n.getEmpfaenger().equals("")) { String[] stringlist = new String[100]; JComboBox cb = new JComboBox(kontakte.toArray(stringlist)); abspanel.add(cb); ImageIcon water = new ImageIcon("arrow.png"); JMyButton button = new JMyButton(n, cb, water); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jBSend_ActionPerformed(evt); } }); abspanel.add(button); } else { abspanel.add(new JLabel("an "+n.getEmpfaenger())); } c.gridx=4; c.gridy = xx; c.weightx = 0.0; jp.add(abspanel,c); xx++; } JPanel dummy = new JPanel(); dummy.setBorder(BorderFactory.createBevelBorder(0)); dummy.setLayout(null); dummy.setBackground(new Color(250,255,200)); dummy.setOpaque(true); dummy.setPreferredSize(new Dimension(150,HOEHE)); c.gridx=0; c.gridy = xx; c.gridwidth=5; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; jp.add(dummy,c); jp.revalidate(); jp.repaint(); } public void ChatClient_WindowClosing(WindowEvent evt) { // TODO hier Quelltext einfügen } // end of ChatClient_WindowClosing // Ende Methoden public static void main(String[] args) { new ChatClient("ChatClient"); } // end of main } // end of class ChatClient