From 6808016ab74a49ac8c4e1daf4948904beee6bdad Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Wed, 11 Jun 2014 01:45:31 -0400 Subject: [PATCH] Added support for the C CLI's ~/.mpw config file to speed up sign-in to the GUI. --- .../lhunath/masterpassword/AppleGUI.java | 32 +++ .../masterpassword/AuthenticationPanel.java | 40 ++++ .../ConfigAuthenticationPanel.java | 87 +++++++++ .../lyndir/lhunath/masterpassword/GUI.java | 50 ++--- .../lhunath/masterpassword/PasswordFrame.java | 11 +- .../TextAuthenticationPanel.java | 88 +++++++++ .../lhunath/masterpassword/UnlockFrame.java | 184 ++++++++---------- .../lyndir/lhunath/masterpassword/User.java | 35 +++- 8 files changed, 390 insertions(+), 137 deletions(-) create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AppleGUI.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AuthenticationPanel.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/ConfigAuthenticationPanel.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/TextAuthenticationPanel.java diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AppleGUI.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AppleGUI.java new file mode 100644 index 00000000..fb0a3992 --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AppleGUI.java @@ -0,0 +1,32 @@ +package com.lyndir.lhunath.masterpassword; + +import com.apple.eawt.*; + + +/** + * @author lhunath, 2014-06-10 + */ +public class AppleGUI extends GUI { + + public AppleGUI() { + + Application application = Application.getApplication(); + application.addAppEventListener( new AppForegroundListener() { + + @Override + public void appMovedToBackground(AppEvent.AppForegroundEvent arg0) { + } + + @Override + public void appRaisedToForeground(AppEvent.AppForegroundEvent arg0) { + open(); + } + } ); + application.addAppEventListener( new AppReOpenedListener() { + @Override + public void appReOpened(AppEvent.AppReOpenedEvent arg0) { + open(); + } + } ); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AuthenticationPanel.java new file mode 100644 index 00000000..053cd7bf --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/AuthenticationPanel.java @@ -0,0 +1,40 @@ +package com.lyndir.lhunath.masterpassword; + +import com.google.common.io.Resources; +import java.awt.*; +import javax.swing.*; + + +/** + * @author lhunath, 2014-06-11 + */ +public abstract class AuthenticationPanel extends JPanel { + + protected final UnlockFrame unlockFrame; + + public AuthenticationPanel(final UnlockFrame unlockFrame) { + this.unlockFrame = unlockFrame; + + setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) ); + + // Avatar + add( Box.createVerticalGlue() ); + add( new JLabel( new ImageIcon( Resources.getResource( "media/Avatars/avatar-0.png" ) ) ) { + @Override + public Dimension getMaximumSize() { + return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ); + } + } ); + add( Box.createVerticalGlue() ); + } + + protected void updateUser() { + unlockFrame.setUser( getUser() ); + } + + protected abstract User getUser(); + + public Component getFocusComponent() { + return null; + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/ConfigAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/ConfigAuthenticationPanel.java new file mode 100644 index 00000000..f39945b0 --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/ConfigAuthenticationPanel.java @@ -0,0 +1,87 @@ +package com.lyndir.lhunath.masterpassword; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.io.CharStreams; +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.util.Iterator; +import javax.swing.*; + + +/** + * @author lhunath, 2014-06-11 + */ +public class ConfigAuthenticationPanel extends AuthenticationPanel implements ItemListener, ActionListener { + + private final JComboBox userField; + + public ConfigAuthenticationPanel(final UnlockFrame unlockFrame) { + + // User + super( unlockFrame ); + JLabel userLabel = new JLabel( "User:" ); + userLabel.setAlignmentX( LEFT_ALIGNMENT ); + userLabel.setHorizontalAlignment( SwingConstants.CENTER ); + userLabel.setVerticalAlignment( SwingConstants.BOTTOM ); + add( userLabel ); + + userField = new JComboBox( new DefaultComboBoxModel<>( readConfigUsers() ) ) { + @Override + public Dimension getMaximumSize() { + return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); + } + }; + userField.setAlignmentX( LEFT_ALIGNMENT ); + userField.addItemListener( this ); + userField.addActionListener( this ); + add( userField ); + } + + @Override + protected User getUser() { + return (User) userField.getSelectedItem(); + } + + public static boolean hasConfigUsers() { + return new File( System.getProperty( "user.home" ), ".mpw" ).canRead(); + } + + private User[] readConfigUsers() { + ImmutableList.Builder users = ImmutableList.builder(); + File mpwConfig = new File( System.getProperty( "user.home" ), ".mpw" ); + try (FileReader mpwReader = new FileReader( mpwConfig )) { + for (String line : CharStreams.readLines( mpwReader )) { + if (line.startsWith( "#" ) || line.startsWith( "//" ) || line.isEmpty()) { + continue; + } + + Iterator fields = Splitter.on( ':' ).limit( 2 ).split( line ).iterator(); + String userName = fields.next(), masterPassword = fields.next(); + users.add( new User( userName, masterPassword ) ); + } + + return Iterables.toArray( users.build(), User.class ); + } + catch (FileNotFoundException e) { + return null; + } + catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public void itemStateChanged(final ItemEvent e) { + updateUser(); + } + + @Override + public void actionPerformed(final ActionEvent e) { + updateUser(); + unlockFrame.trySignIn( userField ); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/GUI.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/GUI.java index 42ac90cc..60e47de4 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/GUI.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/GUI.java @@ -15,7 +15,8 @@ */ package com.lyndir.lhunath.masterpassword; -import com.apple.eawt.*; +import com.google.common.base.Optional; +import com.lyndir.lhunath.opal.system.util.TypeUtils; import java.io.IOException; import javax.swing.*; @@ -33,37 +34,18 @@ public class GUI implements UnlockFrame.SignInCallback { public static void main(final String[] args) throws IOException { + // Apple + Optional appleGUI = TypeUtils.newInstance( AppleGUI.class ); + if (appleGUI.isPresent()) { + appleGUI.get().open(); + return; + } + + // All others new GUI().open(); } - public GUI() { - - try { - getClass().getClassLoader().loadClass( "com.apple.eawt.Application" ); - Application application = Application.getApplication(); - application.addAppEventListener( new AppForegroundListener() { - - @Override - public void appMovedToBackground(AppEvent.AppForegroundEvent arg0) { - } - - @Override - public void appRaisedToForeground(AppEvent.AppForegroundEvent arg0) { - open(); - } - } ); - application.addAppEventListener( new AppReOpenedListener() { - @Override - public void appReOpened(AppEvent.AppReOpenedEvent arg0) { - open(); - } - } ); - } - catch (ClassNotFoundException | NoClassDefFoundError ignored) { - } - } - - private void open() { + void open() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { @@ -77,9 +59,13 @@ public class GUI implements UnlockFrame.SignInCallback { } @Override - public boolean signedIn(final String userName, final String masterPassword) { - final byte[] key = MasterPassword.keyForPassword( masterPassword, userName ); - passwordFrame = new PasswordFrame( new User( userName, key ) ); + public boolean signedIn(final User user) { + if (!user.hasKey()) { + return false; + } + user.getKey(); + + passwordFrame = new PasswordFrame( user ); open(); return true; diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/PasswordFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/PasswordFrame.java index 0acb737b..ca170e11 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/PasswordFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/PasswordFrame.java @@ -40,7 +40,8 @@ public class PasswordFrame extends JFrame implements DocumentListener { root.setBorder( new EmptyBorder( 20, 20, 20, 20 ) ); // User - add( new JLabel( strf( "Generating passwords for: %s", user.getName() ) ), BorderLayout.NORTH ); + add( label = new JLabel( strf( "Generating passwords for: %s", user.getName() ) ), BorderLayout.NORTH ); + label.setAlignmentX( LEFT_ALIGNMENT ); // Site JPanel sitePanel = new JPanel(); @@ -49,13 +50,16 @@ public class PasswordFrame extends JFrame implements DocumentListener { add( sitePanel, BorderLayout.CENTER ); // Site Name - sitePanel.add( new JLabel( "Site Name:", JLabel.LEADING ) ); + sitePanel.add( label = new JLabel( "Site Name:", JLabel.LEADING ) ); + label.setAlignmentX( LEFT_ALIGNMENT ); + sitePanel.add( siteNameField = new JTextField() { @Override public Dimension getMaximumSize() { return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); } } ); + siteNameField.setAlignmentX( LEFT_ALIGNMENT ); siteNameField.getDocument().addDocumentListener( this ); siteNameField.addActionListener( new ActionListener() { @Override @@ -86,7 +90,9 @@ public class PasswordFrame extends JFrame implements DocumentListener { return new Dimension( 50, getPreferredSize().height ); } } ) ); + siteTypeField.setAlignmentX( LEFT_ALIGNMENT ); siteTypeField.setSelectedItem( MPElementType.GeneratedLong ); + siteCounterField.setAlignmentX( LEFT_ALIGNMENT ); siteCounterField.addChangeListener( new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { @@ -96,6 +102,7 @@ public class PasswordFrame extends JFrame implements DocumentListener { // Password add( passwordLabel = new JLabel( " ", JLabel.CENTER ), BorderLayout.SOUTH ); + passwordLabel.setAlignmentX( LEFT_ALIGNMENT ); passwordLabel.setFont( passwordLabel.getFont().deriveFont( 40f ) ); pack(); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/TextAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/TextAuthenticationPanel.java new file mode 100644 index 00000000..9a1e2edf --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/TextAuthenticationPanel.java @@ -0,0 +1,88 @@ +package com.lyndir.lhunath.masterpassword; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + + +/** + * @author lhunath, 2014-06-11 + */ +public class TextAuthenticationPanel extends AuthenticationPanel implements DocumentListener, ActionListener { + + private final JTextField userNameField; + private final JPasswordField masterPasswordField; + + public TextAuthenticationPanel(final UnlockFrame unlockFrame) { + + // User Name + super( unlockFrame ); + JLabel userNameLabel = new JLabel( "User Name:" ); + userNameLabel.setAlignmentX( Component.LEFT_ALIGNMENT ); + userNameLabel.setHorizontalAlignment( SwingConstants.CENTER ); + userNameLabel.setVerticalAlignment( SwingConstants.BOTTOM ); + add( userNameLabel ); + + userNameField = new JTextField() { + @Override + public Dimension getMaximumSize() { + return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); + } + }; + userNameField.setAlignmentX( Component.LEFT_ALIGNMENT ); + userNameField.getDocument().addDocumentListener( this ); + userNameField.addActionListener( this ); + add( userNameField ); + + // Master Password + JLabel masterPasswordLabel = new JLabel( "Master Password:" ); + masterPasswordLabel.setAlignmentX( Component.LEFT_ALIGNMENT ); + masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER ); + masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM ); + add( masterPasswordLabel ); + + masterPasswordField = new JPasswordField() { + @Override + public Dimension getMaximumSize() { + return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); + } + }; + masterPasswordField.setAlignmentX( Component.LEFT_ALIGNMENT ); + masterPasswordField.addActionListener( this ); + masterPasswordField.getDocument().addDocumentListener( this ); + add( masterPasswordField ); + } + + @Override + public Component getFocusComponent() { + return userNameField; + } + + @Override + protected User getUser() { + return new User( userNameField.getText(), new String( masterPasswordField.getPassword() ) ); + } + + @Override + public void insertUpdate(final DocumentEvent e) { + updateUser(); + } + + @Override + public void removeUpdate(final DocumentEvent e) { + updateUser(); + } + + @Override + public void changedUpdate(final DocumentEvent e) { + updateUser(); + } + + @Override + public void actionPerformed(final ActionEvent e) { + updateUser(); + unlockFrame.trySignIn(userNameField,masterPasswordField ); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/UnlockFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/UnlockFrame.java index bcaac7c0..e12f7c07 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/UnlockFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/UnlockFrame.java @@ -1,96 +1,48 @@ package com.lyndir.lhunath.masterpassword; -import com.google.common.io.Resources; +import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse; + import com.lyndir.lhunath.masterpassword.util.Components; import java.awt.*; -import java.awt.event.ActionEvent; +import java.awt.event.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.*; import javax.swing.border.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; /** * @author lhunath, 2014-06-08 */ -public class UnlockFrame extends JFrame implements DocumentListener { +public class UnlockFrame extends JFrame { private static final ExecutorService executor = Executors.newSingleThreadExecutor(); private final SignInCallback signInCallback; - private final JPanel root; - private final JLabel avatarView; - private final JTextField userNameField; - private final JTextField masterPasswordField; - private final JButton signInButton; + private final JPanel root; + private final JButton signInButton; + private final JPanel authenticationContainer; + private boolean useConfig; + public User user; public UnlockFrame(final SignInCallback signInCallback) throws HeadlessException { super( "Unlock Master Password" ); this.signInCallback = signInCallback; - JLabel label; - setDefaultCloseOperation( DISPOSE_ON_CLOSE ); setContentPane( root = new JPanel( new BorderLayout( 20, 20 ) ) ); root.setBorder( new EmptyBorder( 20, 20, 20, 20 ) ); - JPanel userAndPassword = new JPanel(); - userAndPassword.setLayout( new BoxLayout( userAndPassword, BoxLayout.PAGE_AXIS ) ); - userAndPassword.setBorder( new CompoundBorder( new EtchedBorder( EtchedBorder.RAISED ), new EmptyBorder( 8, 8, 8, 8 ) ) ); - add( userAndPassword, BorderLayout.CENTER ); - - // Avatar - userAndPassword.add( Box.createVerticalGlue() ); - userAndPassword.add( avatarView = new JLabel( new ImageIcon( Resources.getResource( "media/Avatars/avatar-0.png" ) ) ) { - @Override - public Dimension getMaximumSize() { - return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE ); - } - } ); - userAndPassword.add( Box.createVerticalGlue() ); - - // User Name - userAndPassword.add( label = new JLabel( "User Name:" ) ); - label.setHorizontalAlignment( SwingConstants.CENTER ); - label.setVerticalAlignment( SwingConstants.BOTTOM ); - userAndPassword.add( userNameField = new JTextField() { - @Override - public Dimension getMaximumSize() { - return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); - } - } ); - userNameField.getDocument().addDocumentListener( this ); - userNameField.addActionListener( new AbstractAction() { - @Override - public void actionPerformed(final ActionEvent e) { - trySignIn(); - } - } ); - - // Master Password - userAndPassword.add( label = new JLabel( "Master Password:" ) ); - label.setHorizontalAlignment( SwingConstants.CENTER ); - label.setVerticalAlignment( SwingConstants.BOTTOM ); - userAndPassword.add( masterPasswordField = new JPasswordField() { - @Override - public Dimension getMaximumSize() { - return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); - } - } ); - masterPasswordField.getDocument().addDocumentListener( this ); - masterPasswordField.addActionListener( new AbstractAction() { - @Override - public void actionPerformed(final ActionEvent e) { - trySignIn(); - } - } ); + authenticationContainer = new JPanel(); + authenticationContainer.setLayout( new BoxLayout( authenticationContainer, BoxLayout.PAGE_AXIS ) ); + authenticationContainer.setBorder( new CompoundBorder( new EtchedBorder( EtchedBorder.RAISED ), new EmptyBorder( 8, 8, 8, 8 ) ) ); + add( authenticationContainer ); // Sign In - add( Components.boxLayout( BoxLayout.LINE_AXIS, Box.createGlue(), signInButton = new JButton( "Sign In" ), Box.createGlue() ), - BorderLayout.SOUTH ); + root.add( Components.boxLayout( BoxLayout.LINE_AXIS, Box.createGlue(), signInButton = new JButton( "Sign In" ), Box.createGlue() ), + BorderLayout.SOUTH ); + signInButton.setAlignmentX( LEFT_ALIGNMENT ); signInButton.addActionListener( new AbstractAction() { @Override public void actionPerformed(final ActionEvent e) { @@ -98,43 +50,91 @@ public class UnlockFrame extends JFrame implements DocumentListener { } } ); - checkSignIn(); - - pack(); - setMinimumSize( getSize() ); - setPreferredSize( new Dimension( 300, 300 ) ); - pack(); + useConfig = ConfigAuthenticationPanel.hasConfigUsers(); + createAuthenticationPanel(); setLocationByPlatform( true ); setLocationRelativeTo( null ); } - private boolean checkSignIn() { - String userName = userNameField.getText(); - String masterPassword = masterPasswordField.getText(); + private void repack() { + setPreferredSize( null ); + pack(); + setMinimumSize( getSize() ); + setPreferredSize( new Dimension( 300, 300 ) ); + pack(); + } - boolean enabled = !userName.isEmpty() && !masterPassword.isEmpty(); + private void createAuthenticationPanel() { + authenticationContainer.removeAll(); + + final AuthenticationPanel authenticationPanel; + if (useConfig) { + authenticationPanel = new ConfigAuthenticationPanel( this ); + } else { + authenticationPanel = new TextAuthenticationPanel( this ); + } + authenticationPanel.updateUser(); + authenticationContainer.add( authenticationPanel, BorderLayout.CENTER ); + + final JCheckBox configCheckBox = new JCheckBox( "Use Config File" ); + configCheckBox.setAlignmentX( LEFT_ALIGNMENT ); + configCheckBox.setSelected( useConfig ); + configCheckBox.addItemListener( new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + useConfig = configCheckBox.isSelected(); + SwingUtilities.invokeLater( new Runnable() { + @Override + public void run() { + createAuthenticationPanel(); + } + } ); + } + } ); + authenticationContainer.add( configCheckBox ); + checkSignIn(); + validate(); + repack(); + + + SwingUtilities.invokeLater( new Runnable() { + @Override + public void run() { + ifNotNullElse( authenticationPanel.getFocusComponent(), signInButton ).requestFocusInWindow(); + } + } ); + } + + void setUser(User user) { + this.user = user; + checkSignIn(); + } + + boolean checkSignIn() { + boolean enabled = user != null && !user.getName().isEmpty() && user.hasKey(); signInButton.setEnabled( enabled ); return enabled; } - private void trySignIn() { - if (!checkSignIn()) + void trySignIn(final JComponent... signInComponents) { + if (!checkSignIn()) { return; + } - final String userName = userNameField.getText(); - final String masterPassword = masterPasswordField.getText(); + for (JComponent signInComponent : signInComponents) { + signInComponent.setEnabled( false ); + } - userNameField.setEnabled( false ); - masterPasswordField.setEnabled( false ); signInButton.setEnabled( false ); signInButton.setText( "Signing In..." ); executor.submit( new Runnable() { @Override public void run() { - final boolean success = signInCallback.signedIn( userName, masterPassword ); + final boolean success = signInCallback.signedIn( user ); + SwingUtilities.invokeLater( new Runnable() { @Override public void run() { @@ -143,9 +143,10 @@ public class UnlockFrame extends JFrame implements DocumentListener { return; } - userNameField.setEnabled( true ); - masterPasswordField.setEnabled( true ); signInButton.setText( "Sign In" ); + for (JComponent signInComponent : signInComponents) { + signInComponent.setEnabled( true ); + } checkSignIn(); } } ); @@ -153,23 +154,8 @@ public class UnlockFrame extends JFrame implements DocumentListener { } ); } - @Override - public void insertUpdate(final DocumentEvent e) { - checkSignIn(); - } - - @Override - public void removeUpdate(final DocumentEvent e) { - checkSignIn(); - } - - @Override - public void changedUpdate(final DocumentEvent e) { - checkSignIn(); - } - interface SignInCallback { - boolean signedIn(String userName, String masterPassword); + boolean signedIn(User user); } } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/User.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/User.java index 2c579796..fcb62768 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/User.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/lhunath/masterpassword/User.java @@ -1,22 +1,49 @@ package com.lyndir.lhunath.masterpassword; +import static com.lyndir.lhunath.opal.system.util.StringUtils.*; + + /** * @author lhunath, 2014-06-08 */ public class User { - private final String name; - private final byte[] key; - public User(final String name, final byte[] key) { + private final String name; + private final String masterPassword; + private byte[] key; + + public User(final String name, final String masterPassword) { this.name = name; - this.key = key; + this.masterPassword = masterPassword; } public String getName() { return name; } + public boolean hasKey() { + return key != null || (masterPassword != null && !masterPassword.isEmpty()); + } + public byte[] getKey() { + if (key == null) { + if (!hasKey()) { + throw new IllegalStateException( strf( "Master password unknown for user: %s", name ) ); + } else { + key = MasterPassword.keyForPassword( masterPassword, name ); + } + } + return key; } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } }