/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * 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 net.java.sip.communicator.plugin.desktoputil.wizard; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.border.*; import javax.swing.table.*; import javax.swing.event.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.plugin.desktoputil.*; import org.jitsi.service.neomedia.*; /** * Contains the security settings for SIP media encryption. * * @author Ingo Bauersachs * @author Vincent Lucas */ public class SecurityPanel extends TransparentPanel implements ActionListener, TableModelListener { /** * Serial version UID. */ private static final long serialVersionUID = 0L; private final SecurityAccountRegistration regform; private JPanel pnlAdvancedSettings; private JCheckBox enableDefaultEncryption; private JCheckBox enableSipZrtpAttribute; private JComboBox<SavpOption> cboSavpOption; private JTable tabCiphers; private CipherTableModel cipherModel; private JLabel cmdExpandAdvancedSettings; /** * The TableModel used to configure the encryption protocols preferences. */ private EncryptionConfigurationTableModel encryptionConfigurationTableModel; /** * JTable with 2 buttons (up and down) which able to enable encryption * protocols and to choose their priority order. */ private PriorityTable encryptionProtocolPreferences; /** * Boolean used to display or not the SAVP options (only useful for SIP, not * for XMPP). */ private boolean displaySavpOtions; private static class SavpOption { int option; SavpOption(int option) { this.option = option; } @Override public String toString() { return UtilActivator.getResources().getI18NString( "plugin.sipaccregwizz.SAVP_OPTION_" + option); } } private static class Entry { String cipher; Boolean enabled; public Entry(String cipher, boolean enabled) { this.cipher = cipher; this.enabled = enabled; } } private static class CipherTableModel extends AbstractTableModel { /** * Serial version UID. */ private static final long serialVersionUID = 0L; private List<Entry> data = new ArrayList<Entry>(); private final String defaultCiphers = UtilActivator.getConfigurationService() .getString(SDesControl.SDES_CIPHER_SUITES); CipherTableModel(String ciphers) { loadData(ciphers); } public void loadData(String ciphers) { data.clear(); if(defaultCiphers == null) return; if(ciphers == null) ciphers = defaultCiphers; MediaService ms = DesktopUtilActivator.getMediaService(); SDesControl srtp = (SDesControl) ms.createSrtpControl(SrtpControlType.SDES); for (String cipher : srtp.getSupportedCryptoSuites()) { data.add(new Entry(cipher, ciphers.contains(cipher))); } fireTableDataChanged(); } @Override public Class<?> getColumnClass(int columnIndex) { switch(columnIndex) { case 0: return Boolean.class; case 1: return String.class; } return null; } public int getRowCount() { return data.size(); } public int getColumnCount() { return 2; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return (columnIndex == 0); } public Object getValueAt(int rowIndex, int columnIndex) { Entry e = data.get(rowIndex); switch(columnIndex) { case 0: return e.enabled; case 1: return e.cipher; } return null; } @Override public void setValueAt(Object value, int rowIndex, int columnIndex) { if ((columnIndex == 0) && (value instanceof Boolean)) { Entry e = data.get(rowIndex); e.enabled = (Boolean)value; fireTableCellUpdated(rowIndex, columnIndex); } } String getEnabledCiphers() { StringBuilder sb = new StringBuilder(); for (Entry e : data) { if(e.enabled) { sb.append(e.cipher); sb.append(','); } } if(sb.length() == 0) { return sb.toString(); } else { return sb.substring(0, sb.length()-1); } } } /** * Initiates a panel to configure the security (ZRTP and SDES) for SIP or * XMPP protocols. * * @param regform The registration form of the account to configure. * @param displaySavpOptions Boolean used to display or not the SAVP options * (only useful for SIP, not for XMPP). */ public SecurityPanel( SecurityAccountRegistration regform, boolean displaySavpOptions) { super(new BorderLayout(10, 10)); this.regform = regform; this.displaySavpOtions = displaySavpOptions; initComponents(); } private void initComponents() { setLayout(new BorderLayout()); final JPanel mainPanel = new TransparentPanel(); add(mainPanel, BorderLayout.NORTH); mainPanel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.anchor = GridBagConstraints.LINE_START; c.fill = GridBagConstraints.HORIZONTAL; //general encryption option enableDefaultEncryption = new SIPCommCheckBox(UtilActivator .getResources() .getI18NString("plugin.sipaccregwizz.ENABLE_DEFAULT_ENCRYPTION"), regform.isDefaultEncryption()); enableDefaultEncryption.addActionListener(this); mainPanel.add(enableDefaultEncryption, c); //warning message and button to show advanced options JLabel lblWarning = new JLabel(); lblWarning.setBorder(new EmptyBorder(10, 5, 10, 0)); lblWarning.setText(UtilActivator.getResources().getI18NString( "plugin.sipaccregwizz.SECURITY_WARNING", new String[]{ UtilActivator.getResources().getSettingsString( "service.gui.APPLICATION_NAME") } )); c.gridy++; mainPanel.add(lblWarning, c); cmdExpandAdvancedSettings = new JLabel(); cmdExpandAdvancedSettings.setBorder(new EmptyBorder(0, 5, 0, 0)); cmdExpandAdvancedSettings.setIcon(UtilActivator.getResources() .getImage("service.gui.icons.RIGHT_ARROW_ICON")); cmdExpandAdvancedSettings.setText(UtilActivator.getResources() .getI18NString("plugin.sipaccregwizz.SHOW_ADVANCED")); cmdExpandAdvancedSettings.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { cmdExpandAdvancedSettings.setIcon( UtilActivator.getResources().getImage( pnlAdvancedSettings.isVisible() ? "service.gui.icons.RIGHT_ARROW_ICON" : "service.gui.icons.DOWN_ARROW_ICON")); pnlAdvancedSettings.setVisible( !pnlAdvancedSettings.isVisible()); pnlAdvancedSettings.revalidate(); } }); c.gridy++; mainPanel.add(cmdExpandAdvancedSettings, c); pnlAdvancedSettings = new TransparentPanel(); pnlAdvancedSettings.setLayout(new GridBagLayout()); pnlAdvancedSettings.setVisible(false); c.gridy++; mainPanel.add(pnlAdvancedSettings, c); c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.gridwidth = 2; c.gridheight = 1; c.anchor = GridBagConstraints.LINE_START; c.fill = GridBagConstraints.HORIZONTAL; pnlAdvancedSettings.add(new JSeparator(), c); // Encryption protcol preferences. JLabel lblEncryptionProtocolPreferences = new JLabel(); lblEncryptionProtocolPreferences.setText(UtilActivator.getResources() .getI18NString( "plugin.sipaccregwizz.ENCRYPTION_PROTOCOL_PREFERENCES")); c.gridy++; pnlAdvancedSettings.add(lblEncryptionProtocolPreferences, c); int nbEncryptionProtocols = SecurityAccountRegistration.ENCRYPTION_PROTOCOLS.size(); String[] encryptions = new String[nbEncryptionProtocols]; boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols]; this.encryptionConfigurationTableModel = new EncryptionConfigurationTableModel( encryptions, selectedEncryptions); loadEncryptionProtocols(new HashMap<String, Integer>(), new HashMap<String, Boolean>()); this.encryptionProtocolPreferences = new PriorityTable( this.encryptionConfigurationTableModel, 60); this.encryptionConfigurationTableModel.addTableModelListener(this); c.gridy++; pnlAdvancedSettings.add(this.encryptionProtocolPreferences, c); //ZRTP JLabel lblZrtpOption = new JLabel(); lblZrtpOption.setBorder(new EmptyBorder(5, 5, 5, 0)); lblZrtpOption.setText(UtilActivator.getResources() .getI18NString("plugin.sipaccregwizz.ZRTP_OPTION")); c.gridx = 0; c.gridy++; c.gridwidth = 1; pnlAdvancedSettings.add(lblZrtpOption, c); c.gridx = 1; pnlAdvancedSettings.add(new JSeparator(), c); enableSipZrtpAttribute = new SIPCommCheckBox( UtilActivator.getResources() .getI18NString("plugin.sipaccregwizz.ENABLE_SIPZRTP_ATTRIBUTE"), regform.isSipZrtpAttribute()); c.gridx = 0; c.gridy++; c.gridwidth = 2; pnlAdvancedSettings.add(enableSipZrtpAttribute, c); //SDES JLabel lblSDesOption = new JLabel(); lblSDesOption.setBorder(new EmptyBorder(5, 5, 5, 0)); lblSDesOption.setText( UtilActivator.getResources().getI18NString( "plugin.sipaccregwizz.SDES_OPTION")); c.gridx = 0; c.gridy++; c.gridwidth = 1; pnlAdvancedSettings.add(lblSDesOption, c); c.gridx = 1; pnlAdvancedSettings.add(new JSeparator(), c); JLabel lblCipherInfo = new JLabel(); lblCipherInfo.setText(UtilActivator.getResources() .getI18NString("plugin.sipaccregwizz.CIPHER_SUITES")); c.gridx = 0; c.gridy++; c.gridwidth = 2; pnlAdvancedSettings.add(lblCipherInfo, c); cipherModel = new CipherTableModel(regform.getSDesCipherSuites()); tabCiphers = new JTable(cipherModel); tabCiphers.setShowGrid(false); tabCiphers.setTableHeader(null); TableColumnModel tableColumnModel = tabCiphers.getColumnModel(); TableColumn tableColumn = tableColumnModel.getColumn(0); tableColumn.setMaxWidth(tableColumn.getMinWidth()); JScrollPane scrollPane = new JScrollPane(tabCiphers); scrollPane.setPreferredSize(new Dimension(tabCiphers.getWidth(), 100)); c.gridy++; pnlAdvancedSettings.add(scrollPane, c); //SAVP selection c.gridx = 0; c.gridwidth = 1; JLabel lblSavpOption = new JLabel(); lblSavpOption.setBorder(new EmptyBorder(5, 5, 5, 0)); lblSavpOption.setText( UtilActivator.getResources().getI18NString( "plugin.sipaccregwizz.SAVP_OPTION")); if(this.displaySavpOtions) { c.gridy++; pnlAdvancedSettings.add(lblSavpOption, c); } c.gridx = 1; if(this.displaySavpOtions) { pnlAdvancedSettings.add(new JSeparator(), c); } cboSavpOption = new JComboBox<SavpOption>(new SavpOption[]{ new SavpOption(0), new SavpOption(1), new SavpOption(2) }); c.gridx = 0; c.gridwidth = 2; c.insets = new Insets(0, 20, 0, 0); if(this.displaySavpOtions) { c.gridy++; pnlAdvancedSettings.add(cboSavpOption, c); } } /** * Saves the user input when the "Next" wizard buttons is clicked. * * @param registration the SIPAccountRegistration * @return */ public boolean commitPanel(SecurityAccountRegistration registration) { registration.setDefaultEncryption(enableDefaultEncryption.isSelected()); registration.setEncryptionProtocols( encryptionConfigurationTableModel.getEncryptionProtocols()); registration.setEncryptionProtocolStatus( encryptionConfigurationTableModel .getEncryptionProtocolStatus()); registration.setSipZrtpAttribute(enableSipZrtpAttribute.isSelected()); registration.setSavpOption(((SavpOption) cboSavpOption .getSelectedItem()).option); registration.setSDesCipherSuites(cipherModel.getEnabledCiphers()); return true; } /** * Loads the account with the given identifier. * @param securityAccReg the account identifier */ public void loadAccount(SecurityAccountRegistration securityAccReg) { enableDefaultEncryption.setSelected( securityAccReg.isDefaultEncryption()); Map<String, Integer> encryptionProtocols = securityAccReg.getEncryptionProtocols(); Map<String, Boolean> encryptionProtocolStatus = securityAccReg.getEncryptionProtocolStatus(); this.loadEncryptionProtocols( encryptionProtocols, encryptionProtocolStatus); enableSipZrtpAttribute.setSelected(securityAccReg.isSipZrtpAttribute()); cboSavpOption.setSelectedIndex(securityAccReg.getSavpOption()); cipherModel.loadData(securityAccReg.getSDesCipherSuites()); loadStates(); } public void actionPerformed(ActionEvent e) { if(e.getSource() == enableDefaultEncryption) { loadStates(); } else if(e.getSource() == cmdExpandAdvancedSettings) { pnlAdvancedSettings.setVisible(!pnlAdvancedSettings.isVisible()); } } public void tableChanged(TableModelEvent e) { if(e.getSource() == this.encryptionConfigurationTableModel) { loadStates(); } } private void loadStates() { boolean b = enableDefaultEncryption.isSelected(); cboSavpOption.setEnabled(b); this.encryptionProtocolPreferences.setEnabled(b); enableSipZrtpAttribute.setEnabled( b && this.encryptionConfigurationTableModel .isEnabledLabel("ZRTP")); tabCiphers.setEnabled( b && this.encryptionConfigurationTableModel .isEnabledLabel("SDES")); } /** * Loads the list of enabled and disabled encryption protocols with their * priority. * * @param enabledEncryptionProtocols The list of enabled encryption protocol * available for this account. * @param disabledEncryptionProtocols The list of disabled encryption protocol * available for this account. */ private void loadEncryptionProtocols( Map<String, Integer> encryptionProtocols, Map<String, Boolean> encryptionProtocolStatus) { Object[] result = SecurityAccountRegistration .loadEncryptionProtocols( encryptionProtocols, encryptionProtocolStatus); String[] encryptions = (String[]) result[0]; boolean[] selectedEncryptions = (boolean[]) result[1]; this.encryptionConfigurationTableModel.init( encryptions, selectedEncryptions); } }