Выбор строки пароля и вставка в блокноте показывает пароль - PullRequest
0 голосов
/ 08 января 2012

Я столкнулся с вышеупомянутой проблемой в своем недавно созданном Java-приложении. Несмотря на то, что я четко установил поле как JPasswordField и попытался замаскировать пароль звездочками, я продолжаю сталкиваться с этой проблемой. У меня проблема не возникает, когда мы редактируем поле пароля, она возникает только при выборе строки. Например, у меня есть 2 столбца в строке, и если я выделю всю строку и попытаюсь скопировать и вставить строку в блокноте, появится пароль. Я новичок в мире Java-программирования, и если кто-то может помочь, он мне очень поможет.

Ответы [ 4 ]

3 голосов
/ 08 января 2012

То, что вы хотите, довольно логично.При копировании и вставке данных из вашей таблицы следует учитывать рендеринг.

Стандартное действие копирования будет использовать данные, доступные в вашей модели, где пароль доступен в виде простого текста.Мы могли бы начать обсуждение того, хотите ли вы, чтобы ваша модель содержала пароль в виде обычного текста, без хэширования к нему ... но это не отвечает на ваш вопрос.

Для вашего вопроса вы должны изменить поведениедействия вырезания / копирования JTable.Ознакомьтесь с руководством по перетаскиванию Swing и, в частности, с разделом Добавление выреза, копирования и вставки .К сожалению, я не сразу нахожу пример для ссылки.

Редактировать

Ниже приведен пример JXTable, который использует визуализированные значения для действия копирования (я не копировал и вставлял импорт).Небольшое замечание по поводу кода:

  1. Он использует SwingX, чтобы проиллюстрировать что-то и для клеопатры
  2. Пример TableModel и его элементы довольно глупы.Чтобы избежать слишком большой работы, мне нужно было что-то похожее на наш реальный продукт, чтобы иметь возможность скопировать часть кода
  3. . Классы SpeedStringValue и AltitudeStringValue нарушают интерфейс StringValue, возвращая null.Мне было лень определять новый интерфейс, и экземпляр StringValue, который я установил на SwingX DefaultTableRenderer, ведет себя в соответствии с документацией.Однако я думаю, что наличие отдельных StringValue экземпляров, каждый из которых обладает знаниями для преобразования определенного класса в String, является реальным вариантом использования, в котором отсутствует SwingX
  4. . TransferHandler повторно используетStringValue логика для создания Table, содержащая только String экземпляров, а затем возвращается к поведению JTable по умолчанию.Это позволяет повторно использовать логику, реализованную в рендерере, и позволяет копировать визуальные значения вместо значений модели.Я не уверен, что это самое хорошее решение, но оно работает.Было бы хорошо, однако, если бы подобное поведение было стандартным в SwingX, поскольку у них уже есть инфраструктура
  5. В коде отсутствуют комментарии, так как он был уже достаточно длинным.Если что-то неясно, оставьте комментарий, и я постараюсь уточнить

    public class TableTransferHandlerDemo {
    
      public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
        EventQueue.invokeAndWait( new Runnable() {
          public void run() {
            JFrame frame = new JFrame( "TestFrame" );
    
            JPanel contentPane = new JPanel( new BorderLayout(  ) );
            contentPane.add( createTable(), BorderLayout.CENTER );
            frame.getContentPane().add( contentPane );
    
            frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
            frame.pack();
            frame.setVisible( true );
          }
        } );
      }
    
      private static CompositeStringValue createStringValue() {
        CompositeStringValue stringValue = new CompositeStringValue();
        stringValue.delegates.add( new AltitudeStringValue() );
        stringValue.delegates.add( new SpeedStringValue() );
        return stringValue;
      }
    
      public static JXTable createTable(){
        final JXTable table = new JXTable(  );
        table.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
        table.setModel( createTableModel() );
        CompositeStringValue stringValue = createStringValue();
        table.setDefaultRenderer( Object.class, new DefaultTableRenderer( stringValue ) );
        table.setTransferHandler( new TableTransferHandler( table, stringValue ) );
        //make sure ctrl-c triggers a copy
        InputMap inputMap = table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
        inputMap.put( KeyStroke.getKeyStroke( KeyEvent.VK_C, InputEvent.CTRL_MASK ), "copyAction" );
        table.getActionMap().put( "copyAction", new AbstractAction() {
          public void actionPerformed( ActionEvent e ) {
            ActionEvent event = new ActionEvent( table, e.getID(), e.getActionCommand(), e.getWhen(), e.getModifiers() );
            TransferHandler.getCopyAction().actionPerformed( event );
          }
        } );
        return table;
      }
    
      public static class Speed{
        public double speed;
        public String unit = "km/h";
        public Speed( double speed ){ this.speed = speed;}
      }
      public static class Altitude{
        public double altitude;
        public String unit = "m";
        public Altitude( double altitude ){ this.altitude = altitude; }
      }
      public static class SpeedStringValue implements StringValue{
        public String getString( Object o ) {
          if ( o instanceof Speed ){
            return ( ( Speed ) o ).speed + ( ( Speed ) o ).unit;
          }
          return null;
        }
      }
      public static class AltitudeStringValue implements StringValue{
        public String getString( Object o ) {
          if ( o instanceof Altitude ){
            return ( ( Altitude ) o ).altitude + ( ( Altitude ) o ).unit;
          }
          return null;
        }
      }
      public static class CompositeStringValue implements StringValue{
        public List<StringValue> delegates = new ArrayList<StringValue>(  );
        public String getString( Object o ) {
          for ( StringValue stringValue : delegates ) {
            String string = stringValue.getString( o );
            if ( string != null ) return string;
          }
          return o != null ? o.toString() : "null";
        }
      }
      public static TableModel createTableModel(){
        return new DefaultTableModel(
            new Object[][]{ new Object[]{ new Speed( 10 ), new Altitude( 100 )},
                new Object[]{ new Speed( 20 ), new Altitude( 200 ) }},
            new Object[]{"Speed", "Altitude"} );
      }
      public static class TableTransferHandler extends TransferHandler{
        private JXTable table;
        private StringValue stringValue;
    
        public TableTransferHandler( JXTable aTable, StringValue aStringValue ) {
          table = aTable;
          stringValue = aStringValue;
        }
        @Override
        public void exportToClipboard( JComponent aComponent, Clipboard aClipboard, int aAction ) throws IllegalStateException {
          JTable table = createTable();
          table.getTransferHandler().exportToClipboard( table, aClipboard, aAction );
        }
        @Override
        public void exportAsDrag( JComponent aComponent, InputEvent aEvent, int aAction ) {
          JTable table = createTable();
          table.getTransferHandler().exportAsDrag( table, aEvent, aAction );
        }
        @Override
        protected Transferable createTransferable( JComponent c ) {
          //this transfer handler should not create any transferables
          return null;
        }
        /**
         * Create a table, representing the JXTable containing only Strings
         */
        private JTable createTable() {
          JTable table = new JTable( new StringTableModel( this.table, stringValue ) );
          table.setSelectionModel( this.table.getSelectionModel() );//make sure the selection is synced
          return table;
        }
      }
    
      private static class StringTableModel extends AbstractTableModel {
        private JXTable delegateTable;
        private StringValue stringValue;
    
        private StringTableModel( JXTable aTable, StringValue aStringValue ) {
          delegateTable = aTable;
          stringValue = aStringValue;
        }
    
        public int getRowCount() {
          return delegateTable.getModel().getRowCount();
        }
    
        public int getColumnCount() {
          return delegateTable.getModel().getColumnCount();
        }
    
        public Object getValueAt( int aRowIndex, int aColumnIndex ) {
          return stringValue.getString( delegateTable.getValueAt( aRowIndex, aColumnIndex ) );
        }
      }
    }
    
2 голосов
/ 08 января 2012

Игра в игры в угадайку, как и все остальные (описание ... отсутствует; -)

Таким образом, предположим, что TableModel из двух столбцов, содержащий имя пользователя и пароль, соответственно, отображается в JTable с включенным перетаскиванием в trueи по умолчанию TransferHandler.Предполагая, что рендеринг пароля в JTable каким-то образом «замаскирован», но в c & p выглядит как открытый текст.

@ Робин уже обнаружил основную причину: по умолчанию TransferHandler просто использует getValueAt (...). ToString () для создания передаваемого.Это приводит к раскрытию строки пароля, то есть к тому, что хранится в модели.

Простой выход (в отличие от лучшего Transferhandler, о котором снова упоминал @Robin: используется render значение вместо toString. Примечание для себя: файловая задача для SwingX ) для * должна не хранить простой пароль, но объект-обертку:

public class Password {
    private final String password;

    public Password(String password) {
       this.password = password;
    }

    // api as needed to make it worthwile ...

    public boolean isValid(String password) {
        ...
    }

    // for the sake of c&p, override the toString
    // for the lazy, this is the string rep used by the default renderer
    @Override
    public String toString() {
        return "******************";
    }
}

Приложение (это специфично для SwingX, расширяя мой комментарий к примеру @ Robin)

На самом деле мне нравится такой подход, как быстрое решение для копирования.Просто «исправьте» модель обертки, чтобы в полной мере использовать текущий API, то есть использовать table.getStringAt (...) для представления String.При этом нет необходимости передавать StringValue в нескольких местах, внутренние устройства будут обрабатывать его соответствующим образом.

private static class StringTableModel extends AbstractTableModel {
    private JXTable delegateTable;

    private StringTableModel(JXTable aTable) {
        delegateTable = aTable;
    }

    @Override
    public int getRowCount() {
        return delegateTable.getRowCount();
    }

    @Override
    public int getColumnCount() {
        return delegateTable.getColumnCount();
    }

    @Override
    public Object getValueAt(int aRowIndex, int aColumnIndex) {
        return delegateTable.getStringAt(aRowIndex, aColumnIndex);
    }
}

На уровне платформы SwingX должен поддерживать WYSIWYE (что вы видите, что вы экспортируете) сразу после установки, так же как и другие WYSIWYX: X = M для совпадения,X = S для сортировки, X = F для фильтра.Поднята проблема 1477 в системе отслеживания проблем SwingX

1 голос
/ 08 января 2012

Используя приведенный пример здесь , я могу вставить, но не скопировать или вырезать пароль.Это происходит независимо от видимости настройки echoChar.Вы видите другой результат?

1 голос
/ 08 января 2012

Вы пытались отключить редактирование ячейки в столбце пароля?

Это можно сделать, расширив класс JTable и заменив функцию isCellEditable своей собственной реализацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...