From 84b624aea2bcf973d90e6a3e3d23ea4ab64192af Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Thu, 11 Dec 2014 20:35:19 -0500 Subject: [PATCH] WIP - integrate user and site storage through export files into Java Swing GUI. --- .../com/lyndir/masterpassword/MPSiteType.java | 8 +- .../com/lyndir/masterpassword/MasterKey.java | 15 +- .../Java/masterpassword-gui/pom.xml | 2 +- .../ConfigAuthenticationPanel.java | 164 ------------------ .../java/com/lyndir/masterpassword/User.java | 49 ------ .../masterpassword/{ => gui}/AppleGUI.java | 2 +- .../{ => gui}/AuthenticationPanel.java | 7 +- .../masterpassword/{ => gui}/Config.java | 2 +- .../lyndir/masterpassword/{ => gui}/GUI.java | 13 +- .../IncognitoAuthenticationPanel.java} | 40 ++--- .../masterpassword/gui/IncognitoUser.java | 24 +++ .../gui/ModelAuthenticationPanel.java | 163 +++++++++++++++++ .../lyndir/masterpassword/gui/ModelUser.java | 52 ++++++ .../{ => gui}/PasswordFrame.java | 5 +- .../lyndir/masterpassword/{ => gui}/Res.java | 6 +- .../masterpassword/{ => gui}/UnlockFrame.java | 48 ++--- .../com/lyndir/masterpassword/gui/User.java | 45 +++++ .../src/main/resources/media/icon_add.png | Bin 0 -> 1440 bytes .../src/main/resources/media/icon_add@2x.png | Bin 0 -> 3498 bytes .../model/MPSiteFileManager.java | 52 ------ .../masterpassword/model/MPSiteManager.java | 30 ---- .../model/MPSiteUnmarshaller.java | 6 +- .../lyndir/masterpassword/model/MPUser.java | 52 +++++- .../model/MPUserFileManager.java | 77 ++++++++ .../masterpassword/model/MPUserManager.java | 32 ++++ 25 files changed, 512 insertions(+), 382 deletions(-) delete mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/ConfigAuthenticationPanel.java delete mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/User.java rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/AppleGUI.java (96%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/AuthenticationPanel.java (84%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/Config.java (90%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/GUI.java (93%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{TextAuthenticationPanel.java => gui/IncognitoAuthenticationPanel.java} (60%) create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoUser.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelAuthenticationPanel.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelUser.java rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/PasswordFrame.java (98%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/Res.java (97%) rename MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/{ => gui}/UnlockFrame.java (73%) create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/User.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/resources/media/icon_add.png create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/resources/media/icon_add@2x.png delete mode 100644 MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteFileManager.java delete mode 100644 MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteManager.java create mode 100644 MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserFileManager.java create mode 100644 MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserManager.java diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java index 1ea12ae6..da5e8509 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MPSiteType.java @@ -181,10 +181,14 @@ public enum MPSiteType { */ public static ImmutableList forMask(final int mask) { + int typeIndex = mask & 0xF, typeMask = mask & ~0xF; + ImmutableList.Builder types = ImmutableList.builder(); - for (MPSiteType siteType : values()) - if ((siteType.getMask() & mask) != 0) + for (MPSiteType siteType : values()) { + int siteMask = siteType.getMask(), siteTypeIndex = siteMask & 0xF, siteTypeMask = siteMask & ~0xF; + if ((siteTypeMask & typeMask) != 0 && (typeIndex == 0 || siteTypeIndex == typeIndex)) types.add( siteType ); + } return types.build(); } diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java index 8c12d500..a13ed702 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/masterpassword/MasterKey.java @@ -52,13 +52,14 @@ public class MasterKey { String mpKeyScope = MPSiteVariant.Password.getScope(); byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MP_charset ), userNameLengthBytes, userNameBytes ); logger.trc( "key scope: %s", mpKeyScope ); - logger.trc( "masterKeySalt ID: %s", idForBytes( masterKeySalt ) ); + logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) ); try { masterKey = SCrypt.scrypt( masterPassword.getBytes( MP_charset ), masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen ); valid = true; - logger.trc( "masterKey ID: %s (derived in %.2fs)", idForBytes( masterKey ), (System.currentTimeMillis() - start) / 1000D ); + logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ), + (System.currentTimeMillis() - start) / 1000D ); } catch (GeneralSecurityException e) { throw logger.bug( e ); @@ -70,7 +71,7 @@ public class MasterKey { return fullName; } - public String getKeyID() { + public byte[] getKeyID() { Preconditions.checkState( valid ); return idForBytes( masterKey ); @@ -111,10 +112,10 @@ public class MasterKey { siteContext == null? "(null)": siteContext ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); - logger.trc( "sitePasswordInfo ID: %s", idForBytes( sitePasswordInfo ) ); + logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) ); byte[] sitePasswordSeed = MP_mac.of( masterKey, sitePasswordInfo ); - logger.trc( "sitePasswordSeed ID: %s", idForBytes( sitePasswordSeed ) ); + logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) ); Preconditions.checkState( sitePasswordSeed.length > 0 ); int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign. @@ -145,7 +146,7 @@ public class MasterKey { return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MP_byteOrder ).putInt( integer ).array(); } - private static String idForBytes(final byte[] bytes) { - return CodeUtils.encodeHex( MP_hash.of( bytes ) ); + private static byte[] idForBytes(final byte[] bytes) { + return MP_hash.of( bytes ); } } diff --git a/MasterPassword/Java/masterpassword-gui/pom.xml b/MasterPassword/Java/masterpassword-gui/pom.xml index 2870ecc4..63aab06a 100644 --- a/MasterPassword/Java/masterpassword-gui/pom.xml +++ b/MasterPassword/Java/masterpassword-gui/pom.xml @@ -47,7 +47,7 @@ - com.lyndir.masterpassword.GUI + com.lyndir.masterpassword.gui.GUI diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/ConfigAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/ConfigAuthenticationPanel.java deleted file mode 100644 index 688a6b52..00000000 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/ConfigAuthenticationPanel.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.lyndir.masterpassword; - -import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; - -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 java.util.NoSuchElementException; -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - - -/** - * @author lhunath, 2014-06-11 - */ -public class ConfigAuthenticationPanel extends AuthenticationPanel implements ItemListener, ActionListener, DocumentListener { - - private final JComboBox userField; - private final JLabel masterPasswordLabel; - private final JPasswordField masterPasswordField; - - 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 ); - - // Master Password - 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 masterPasswordField.isVisible()? masterPasswordField: null; - } - - @Override - protected void updateUser(boolean repack) { - boolean masterPasswordMissing = userField.getSelectedItem() == null || !((User) userField.getSelectedItem()).hasKey(); - if (masterPasswordField.isVisible() != masterPasswordMissing) { - masterPasswordLabel.setVisible( masterPasswordMissing ); - masterPasswordField.setVisible( masterPasswordMissing ); - repack = true; - } - - super.updateUser( repack ); - } - - @Override - protected User getUser() { - User selectedUser = (User) userField.getSelectedItem(); - if (selectedUser.hasKey()) { - return selectedUser; - } - - return new User( selectedUser.getUserName(), new String( masterPasswordField.getPassword() ) ); - } - - public String getHelpText() { - return "Reads users from ~/.mpw, the following syntax applies:\nUser Name:masterpassword" - + "\n\nEnsure the file's permissions make it only readable by you!"; - } - - 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) { - JOptionPane.showMessageDialog( this, "First create the config file at:\n" + mpwConfig.getAbsolutePath() + - "\n\nIt should contain a line for each user of the following format:" + - "\nUser Name:masterpassword" + - "\n\nEnsure the file's permissions make it only readable by you!", // - "Config File Not Found", JOptionPane.WARNING_MESSAGE ); - return new User[0]; - } - catch (IOException | NoSuchElementException e) { - e.printStackTrace(); - String error = ifNotNullElse( e.getLocalizedMessage(), ifNotNullElse( e.getMessage(), e.toString() ) ); - JOptionPane.showMessageDialog( this, // - "Problem reading config file:\n" + mpwConfig.getAbsolutePath() // - + "\n\n" + error, // - "Config File Not Readable", JOptionPane.WARNING_MESSAGE ); - return new User[0]; - } - } - - @Override - public void itemStateChanged(final ItemEvent e) { - updateUser( false ); - } - - @Override - public void actionPerformed(final ActionEvent e) { - updateUser( false ); - unlockFrame.trySignIn( userField ); - } - - @Override - public void insertUpdate(final DocumentEvent e) { - updateUser( false ); - } - - @Override - public void removeUpdate(final DocumentEvent e) { - updateUser( false ); - } - - @Override - public void changedUpdate(final DocumentEvent e) { - updateUser( false ); - } -} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/User.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/User.java deleted file mode 100644 index 52a7e1ec..00000000 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/User.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.lyndir.masterpassword; - -import static com.lyndir.lhunath.opal.system.util.StringUtils.*; - - -/** - * @author lhunath, 2014-06-08 - */ -public class User { - - private final String userName; - private final String masterPassword; - private MasterKey key; - - public User(final String userName, final String masterPassword) { - this.userName = userName; - this.masterPassword = masterPassword; - } - - public String getUserName() { - return userName; - } - - public boolean hasKey() { - return key != null || (masterPassword != null && !masterPassword.isEmpty()); - } - - public MasterKey getKey() { - if (key == null) { - if (!hasKey()) { - throw new IllegalStateException( strf( "Master password unknown for user: %s", userName ) ); - } else { - key = new MasterKey( userName, masterPassword ); - } - } - - return key; - } - - @Override - public int hashCode() { - return userName.hashCode(); - } - - @Override - public String toString() { - return userName; - } -} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AppleGUI.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AppleGUI.java similarity index 96% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AppleGUI.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AppleGUI.java index b9e52213..82f010a4 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AppleGUI.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AppleGUI.java @@ -1,4 +1,4 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import com.apple.eawt.*; import javax.swing.*; diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AuthenticationPanel.java similarity index 84% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AuthenticationPanel.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AuthenticationPanel.java index d8ec8df6..13ea880c 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/AuthenticationPanel.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/AuthenticationPanel.java @@ -1,5 +1,6 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; +import com.google.common.collect.ImmutableList; import java.awt.*; import javax.swing.*; @@ -41,7 +42,7 @@ public abstract class AuthenticationPanel extends JPanel { return null; } - public String getHelpText() { - return null; + public Iterable getButtons() { + return ImmutableList.of(); } } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Config.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Config.java similarity index 90% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Config.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Config.java index d50005fa..f3f7cc85 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Config.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Config.java @@ -1,4 +1,4 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import com.lyndir.lhunath.opal.system.util.ConversionUtils; diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/GUI.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/GUI.java similarity index 93% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/GUI.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/GUI.java index 856ddc99..0d6adf8b 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/GUI.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/GUI.java @@ -15,19 +15,16 @@ */ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import com.google.common.base.Charsets; import com.google.common.io.*; -import com.lyndir.lhunath.opal.system.CodeUtils; -import com.lyndir.lhunath.opal.system.MessageDigests; import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.util.TypeUtils; import java.io.*; import java.net.URI; import java.net.URL; import java.util.Enumeration; -import java.util.List; import java.util.jar.*; import javax.swing.*; @@ -94,20 +91,18 @@ public class GUI implements UnlockFrame.SignInCallback { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { - if (passwordFrame == null) { + if (passwordFrame == null) unlockFrame.setVisible( true ); - } else { + else passwordFrame.setVisible( true ); - } } } ); } @Override public boolean signedIn(final User user) { - if (!user.hasKey()) { + if (!user.hasKey()) return false; - } user.getKey(); passwordFrame = newPasswordFrame( user ); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/TextAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java similarity index 60% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/TextAuthenticationPanel.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java index 9526a743..c1056205 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/TextAuthenticationPanel.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java @@ -1,4 +1,4 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import java.awt.*; import java.awt.event.ActionEvent; @@ -11,35 +11,35 @@ import javax.swing.event.DocumentListener; /** * @author lhunath, 2014-06-11 */ -public class TextAuthenticationPanel extends AuthenticationPanel implements DocumentListener, ActionListener { +public class IncognitoAuthenticationPanel extends AuthenticationPanel implements DocumentListener, ActionListener { - private final JTextField userNameField; + private final JTextField fullNameField; private final JPasswordField masterPasswordField; - public TextAuthenticationPanel(final UnlockFrame unlockFrame) { + public IncognitoAuthenticationPanel(final UnlockFrame unlockFrame) { - // User Name + // Full Name super( unlockFrame ); - JLabel userNameLabel = new JLabel( "User Name:" ); - userNameLabel.setAlignmentX( Component.LEFT_ALIGNMENT ); - userNameLabel.setHorizontalAlignment( SwingConstants.CENTER ); - userNameLabel.setVerticalAlignment( SwingConstants.BOTTOM ); - add( userNameLabel ); + JLabel fullNameLabel = new JLabel( "Full Name:" ); + fullNameLabel.setAlignmentX( LEFT_ALIGNMENT ); + fullNameLabel.setHorizontalAlignment( SwingConstants.CENTER ); + fullNameLabel.setVerticalAlignment( SwingConstants.BOTTOM ); + add( fullNameLabel ); - userNameField = new JTextField() { + fullNameField = 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 ); + fullNameField.setAlignmentX( LEFT_ALIGNMENT ); + fullNameField.getDocument().addDocumentListener( this ); + fullNameField.addActionListener( this ); + add( fullNameField ); // Master Password JLabel masterPasswordLabel = new JLabel( "Master Password:" ); - masterPasswordLabel.setAlignmentX( Component.LEFT_ALIGNMENT ); + masterPasswordLabel.setAlignmentX( LEFT_ALIGNMENT ); masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER ); masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM ); add( masterPasswordLabel ); @@ -50,7 +50,7 @@ public class TextAuthenticationPanel extends AuthenticationPanel implements Docu return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); } }; - masterPasswordField.setAlignmentX( Component.LEFT_ALIGNMENT ); + masterPasswordField.setAlignmentX( LEFT_ALIGNMENT ); masterPasswordField.addActionListener( this ); masterPasswordField.getDocument().addDocumentListener( this ); add( masterPasswordField ); @@ -58,12 +58,12 @@ public class TextAuthenticationPanel extends AuthenticationPanel implements Docu @Override public Component getFocusComponent() { - return userNameField; + return fullNameField; } @Override protected User getUser() { - return new User( userNameField.getText(), new String( masterPasswordField.getPassword() ) ); + return new IncognitoUser( fullNameField.getText(), new String( masterPasswordField.getPassword() ) ); } @Override @@ -84,6 +84,6 @@ public class TextAuthenticationPanel extends AuthenticationPanel implements Docu @Override public void actionPerformed(final ActionEvent e) { updateUser( false ); - unlockFrame.trySignIn( userNameField, masterPasswordField ); + unlockFrame.trySignIn( fullNameField, masterPasswordField ); } } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoUser.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoUser.java new file mode 100644 index 00000000..ca4fddeb --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoUser.java @@ -0,0 +1,24 @@ +package com.lyndir.masterpassword.gui; + +/** + * @author lhunath, 2014-06-08 + */ +public class IncognitoUser extends User { + + private final String fullName; + private final String masterPassword; + + public IncognitoUser(final String fullName, final String masterPassword) { + this.fullName = fullName; + this.masterPassword = masterPassword; + } + + public String getFullName() { + return fullName; + } + + @Override + protected String getMasterPassword() { + return masterPassword; + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelAuthenticationPanel.java new file mode 100644 index 00000000..a0bbc48f --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelAuthenticationPanel.java @@ -0,0 +1,163 @@ +package com.lyndir.masterpassword.gui; + +import com.google.common.base.Function; +import com.google.common.collect.*; +import com.lyndir.masterpassword.model.MPUser; +import com.lyndir.masterpassword.model.MPUserFileManager; +import java.awt.*; +import java.awt.event.*; +import javax.annotation.Nullable; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + + +/** + * @author lhunath, 2014-06-11 + */ +public class ModelAuthenticationPanel extends AuthenticationPanel implements ItemListener, ActionListener, DocumentListener { + + private final JComboBox userField; + private final JLabel masterPasswordLabel; + private final JPasswordField masterPasswordField; + + public ModelAuthenticationPanel(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 ); + + // Master Password + masterPasswordLabel = new JLabel( "Master Password:" ); + masterPasswordLabel.setAlignmentX( 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( LEFT_ALIGNMENT ); + masterPasswordField.addActionListener( this ); + masterPasswordField.getDocument().addDocumentListener( this ); + add( masterPasswordField ); + } + + @Override + public Component getFocusComponent() { + return masterPasswordField.isVisible()? masterPasswordField: null; + } + + @Override + protected void updateUser(boolean repack) { + int selectedIndex = userField.getSelectedIndex(); + if (selectedIndex >= 0) { + ModelUser selectedUser = userField.getModel().getElementAt( selectedIndex ); + boolean showPasswordField = !selectedUser.keySaved(); + if (masterPasswordField.isVisible() != showPasswordField) { + masterPasswordLabel.setVisible( showPasswordField ); + masterPasswordField.setVisible( showPasswordField ); + repack = true; + } + } + + super.updateUser( repack ); + } + + @Override + protected User getUser() { + int selectedIndex = userField.getSelectedIndex(); + if (selectedIndex < 0) + return null; + + ModelUser selectedUser = userField.getModel().getElementAt( selectedIndex ); + if (selectedUser != null) + selectedUser.setMasterPassword( new String( masterPasswordField.getPassword() ) ); + + return selectedUser; + } + + @Override + public Iterable getButtons() { + return ImmutableList.of( new JButton( Res.iconAdd() ) { + { + addActionListener( new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + String fullName = JOptionPane.showInputDialog( ModelAuthenticationPanel.this, // + "Enter your full name, ensuring it is correctly spelled and capitalized:", + "New User", JOptionPane.QUESTION_MESSAGE ); + MPUserFileManager.get().addUser( new MPUser( fullName ) ); + userField.setModel( new DefaultComboBoxModel<>( readConfigUsers() ) ); + updateUser( true ); + } + } ); + } + }, new JButton( Res.iconQuestion() ) { + { + addActionListener( new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + JOptionPane.showMessageDialog( ModelAuthenticationPanel.this, // + "Reads users and sites from the directory at ~/.mpw.", // + "Help", JOptionPane.INFORMATION_MESSAGE ); + } + } ); + } + } ); + } + + private ModelUser[] readConfigUsers() { + return FluentIterable.from( MPUserFileManager.get().getUsers() ).transform( new Function() { + @Nullable + @Override + public ModelUser apply(final MPUser model) { + return new ModelUser( model ); + } + } ).toArray( ModelUser.class ); + } + + @Override + public void itemStateChanged(final ItemEvent e) { + updateUser( false ); + } + + @Override + public void actionPerformed(final ActionEvent e) { + updateUser( false ); + unlockFrame.trySignIn( userField ); + } + + @Override + public void insertUpdate(final DocumentEvent e) { + updateUser( false ); + } + + @Override + public void removeUpdate(final DocumentEvent e) { + updateUser( false ); + } + + @Override + public void changedUpdate(final DocumentEvent e) { + updateUser( false ); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelUser.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelUser.java new file mode 100644 index 00000000..113ed1a7 --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelUser.java @@ -0,0 +1,52 @@ +package com.lyndir.masterpassword.gui; + +import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; + +import com.lyndir.masterpassword.MasterKey; +import com.lyndir.masterpassword.model.MPUser; +import com.lyndir.masterpassword.model.MPUserFileManager; + + +/** + * @author lhunath, 14-12-08 + */ +public class ModelUser extends User { + + private final MPUser user; + private String masterPassword; + + public ModelUser(MPUser user) { + this.user = user; + } + + @Override + public String getFullName() { + return user.getFullName(); + } + + @Override + protected String getMasterPassword() { + return masterPassword; + } + + public void setMasterPassword(final String masterPassword) { + this.masterPassword = masterPassword; + } + + @Override + public MasterKey getKey() { + MasterKey key = super.getKey(); + if (!user.hasKeyID()) { + user.setKeyID( key.getKeyID() ); + MPUserFileManager.get().save(); + } + else if (!user.hasKeyID( key.getKeyID() )) + throw new IllegalStateException( strf( "Incorrect master password for user: %s", getFullName() ) ); + + return key; + } + + public boolean keySaved() { + return false; + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/PasswordFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java similarity index 98% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/PasswordFrame.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java index 80641ab7..f1b6ff87 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/PasswordFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java @@ -1,8 +1,9 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.google.common.collect.Iterables; +import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.util.Components; import java.awt.*; import java.awt.datatransfer.StringSelection; @@ -38,7 +39,7 @@ public class PasswordFrame extends JFrame implements DocumentListener { } ); // User - add( label = new JLabel( strf( "Generating passwords for: %s", user.getUserName() ) ), BorderLayout.NORTH ); + add( label = new JLabel( strf( "Generating passwords for: %s", user.getFullName() ) ), BorderLayout.NORTH ); label.setFont( Res.exoRegular().deriveFont( 12f ) ); label.setAlignmentX( LEFT_ALIGNMENT ); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Res.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java similarity index 97% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Res.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java index ef85a14f..5cccafa8 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/Res.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java @@ -1,4 +1,4 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse; import static com.lyndir.lhunath.opal.system.util.StringUtils.*; @@ -45,6 +45,10 @@ public abstract class Res { } ); } + public static Icon iconAdd() { + return new RetinaIcon( Resources.getResource( "media/icon_add@2x.png" ) ); + } + public static Icon iconQuestion() { return new RetinaIcon( Resources.getResource( "media/icon_question@2x.png" ) ); } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/UnlockFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java similarity index 73% rename from MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/UnlockFrame.java rename to MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java index 4c3d796b..30aca015 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/UnlockFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java @@ -1,4 +1,4 @@ -package com.lyndir.masterpassword; +package com.lyndir.masterpassword.gui; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; @@ -18,7 +18,7 @@ public class UnlockFrame extends JFrame { private final JPanel root; private final JButton signInButton; private final JPanel authenticationContainer; - private boolean useConfig; + private boolean incognito; public User user; public UnlockFrame(final SignInCallback signInCallback) @@ -46,7 +46,6 @@ public class UnlockFrame extends JFrame { } } ); - useConfig = ConfigAuthenticationPanel.hasConfigUsers(); createAuthenticationPanel(); setLocationByPlatform( true ); @@ -65,21 +64,21 @@ public class UnlockFrame extends JFrame { authenticationContainer.removeAll(); final AuthenticationPanel authenticationPanel; - if (useConfig) { - authenticationPanel = new ConfigAuthenticationPanel( this ); + if (incognito) { + authenticationPanel = new IncognitoAuthenticationPanel( this ); } else { - authenticationPanel = new TextAuthenticationPanel( this ); + authenticationPanel = new ModelAuthenticationPanel( this ); } authenticationPanel.updateUser( false ); authenticationContainer.add( authenticationPanel, BorderLayout.CENTER ); - final JCheckBox typeCheckBox = new JCheckBox( "Use Config File" ); - typeCheckBox.setAlignmentX( LEFT_ALIGNMENT ); - typeCheckBox.setSelected( useConfig ); - typeCheckBox.addItemListener( new ItemListener() { + final JCheckBox incognitoCheckBox = new JCheckBox( "Incognito" ); + incognitoCheckBox.setAlignmentX( LEFT_ALIGNMENT ); + incognitoCheckBox.setSelected( incognito ); + incognitoCheckBox.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { - useConfig = typeCheckBox.isSelected(); + incognito = incognitoCheckBox.isSelected(); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { @@ -89,24 +88,15 @@ public class UnlockFrame extends JFrame { } } ); - JButton typeHelp = new JButton( Res.iconQuestion() ); - typeHelp.setMargin( new Insets( 0, 0, 0, 0 ) ); - typeHelp.setBackground( Color.red ); - typeHelp.setAlignmentX( RIGHT_ALIGNMENT ); - typeHelp.setBorder( null ); - typeHelp.addActionListener( new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - JOptionPane.showMessageDialog( UnlockFrame.this, authenticationPanel.getHelpText(), "Help", - JOptionPane.INFORMATION_MESSAGE ); - } - } ); - if (authenticationPanel.getHelpText() == null) { - typeHelp.setVisible( false ); + JComponent toolsPanel = Components.boxLayout( BoxLayout.LINE_AXIS, incognitoCheckBox, Box.createGlue() ); + toolsPanel.setAlignmentX( Component.LEFT_ALIGNMENT ); + authenticationContainer.add( toolsPanel ); + for (JButton button : authenticationPanel.getButtons()) { + button.setMargin( new Insets( 0, 0, 0, 0 ) ); + button.setAlignmentX( RIGHT_ALIGNMENT ); + button.setBorder( null ); + toolsPanel.add( button ); } - JComponent typePanel = Components.boxLayout( BoxLayout.LINE_AXIS, typeCheckBox, Box.createGlue(), typeHelp ); - typePanel.setAlignmentX( Component.LEFT_ALIGNMENT ); - authenticationContainer.add( typePanel ); checkSignIn(); validate(); @@ -126,7 +116,7 @@ public class UnlockFrame extends JFrame { } boolean checkSignIn() { - boolean enabled = user != null && !user.getUserName().isEmpty() && user.hasKey(); + boolean enabled = user != null && !user.getFullName().isEmpty() && user.hasKey(); signInButton.setEnabled( enabled ); return enabled; diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/User.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/User.java new file mode 100644 index 00000000..5dd9336e --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/User.java @@ -0,0 +1,45 @@ +package com.lyndir.masterpassword.gui; + +import static com.lyndir.lhunath.opal.system.util.StringUtils.*; + +import com.lyndir.masterpassword.MasterKey; +import javax.annotation.Nonnull; + + +/** + * @author lhunath, 2014-06-08 + */ +public abstract class User { + + private MasterKey key; + + public abstract String getFullName(); + + protected abstract String getMasterPassword(); + + public boolean hasKey() { + String masterPassword = getMasterPassword(); + return key != null || (masterPassword != null && !masterPassword.isEmpty()); + } + + @Nonnull + public MasterKey getKey() { + if (key == null) { + if (!hasKey()) + throw new IllegalStateException( strf( "Master password unknown for user: %s", getFullName() ) ); + key = new MasterKey( getFullName(), getMasterPassword() ); + } + + return key; + } + + @Override + public int hashCode() { + return getFullName().hashCode(); + } + + @Override + public String toString() { + return getFullName(); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/resources/media/icon_add.png b/MasterPassword/Java/masterpassword-gui/src/main/resources/media/icon_add.png new file mode 100644 index 0000000000000000000000000000000000000000..401494a52be3f12eae5d76955f20e1514714c683 GIT binary patch literal 1440 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 Y50Kg;S?HB&bpQYW07*qoM6N<$f;8E>=Kufz literal 0 HcmV?d00001 diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteFileManager.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteFileManager.java deleted file mode 100644 index 611b304a..00000000 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteFileManager.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.lyndir.masterpassword.model; - -import com.google.common.io.CharSink; -import com.lyndir.lhunath.opal.system.logging.Logger; -import java.io.*; - - -/** - * @author lhunath, 14-12-07 - */ -public class MPSiteFileManager extends MPSiteManager { - - @SuppressWarnings("UnusedDeclaration") - private static final Logger logger = Logger.get( MPSiteFileManager.class ); - - private final File file; - - public static MPSiteFileManager create(final File file) { - try { - return new MPSiteFileManager( file ); - } - catch (IOException e) { - throw logger.bug( e, "Unable to open sites from file: %s", file ); - } - } - - protected MPSiteFileManager(final File file) - throws IOException { - - super( MPSiteUnmarshaller.unmarshall( file ).getUser() ); - this.file = file; - } - - public void save() { - try { - new CharSink() { - @Override - public Writer openStream() - throws IOException { - return new FileWriter( file ); - } - }.write( MPSiteMarshaller.marshallSafe( getUser() ).getExport() ); - } - catch (IOException e) { - logger.err( e, "Unable to save sites to file: %s", file ); - } - } - - public File getFile() { - return file; - } -} diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteManager.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteManager.java deleted file mode 100644 index 5b4e1d60..00000000 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteManager.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.lyndir.masterpassword.model; - -import com.google.common.collect.ImmutableList; -import java.util.Collection; - - -/** - * @author lhunath, 14-12-05 - */ -public abstract class MPSiteManager { - - private final MPUser user; - - public MPSiteManager(final MPUser user) { - this.user = user; - } - - public MPUser getUser() { - return user; - } - - public Collection findSitesByName(String query) { - ImmutableList.Builder results = ImmutableList.builder(); - for (MPSite site : user.getSites()) - if (site.getSiteName().startsWith( query )) - results.add( new MPSiteResult( site ) ); - - return results.build(); - } -} diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java index 98939446..49870acd 100644 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteUnmarshaller.java @@ -31,9 +31,9 @@ public class MPSiteUnmarshaller { private static final Logger logger = Logger.get( MPSite.class ); private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTime(); private static final Pattern[] unmarshallFormats = new Pattern[]{ - Pattern.compile( "^([^ ]+) +([[:digit:]]+) +([[:digit:]]+)(:[[:digit:]]+)? +([^\t]+)\t(.*)" ), - Pattern.compile( "^([^ ]+) +([[:digit:]]+) +([[:digit:]]+)(:[[:digit:]]+)?(:[[:digit:]]+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) }; - private static final Pattern headerFormat = Pattern.compile( "^#[[:space:]]*([^:]+): (.*)" ); + Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ), + Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) }; + private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" ); private final int importFormat; private final int mpVersion; diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUser.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUser.java index 3f436f00..a6bd2abb 100644 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUser.java +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUser.java @@ -1,10 +1,11 @@ package com.lyndir.masterpassword.model; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.masterpassword.MPSiteType; import java.util.*; -import org.joda.time.DateTime; +import org.joda.time.*; /** @@ -12,18 +13,24 @@ import org.joda.time.DateTime; */ public class MPUser { - private final String fullName; - private final byte[] keyID; - private final int avatar; - private final MPSiteType defaultType; - private final DateTime lastUsed; + private final String fullName; private final Collection sites = Sets.newHashSet(); + private byte[] keyID; + private int avatar; + private MPSiteType defaultType; + private ReadableInstant lastUsed; + + public MPUser(final String fullName) { + this( fullName, null ); + } + public MPUser(final String fullName, final byte[] keyID) { this( fullName, keyID, 0, MPSiteType.GeneratedLong, new DateTime() ); } - public MPUser(final String fullName, final byte[] keyID, final int avatar, final MPSiteType defaultType, final DateTime lastUsed) { + public MPUser(final String fullName, final byte[] keyID, final int avatar, final MPSiteType defaultType, + final ReadableInstant lastUsed) { this.fullName = fullName; this.keyID = keyID; this.avatar = avatar; @@ -31,6 +38,15 @@ public class MPUser { this.lastUsed = lastUsed; } + public Collection findSitesByName(String query) { + ImmutableList.Builder results = ImmutableList.builder(); + for (MPSite site : getSites()) + if (site.getSiteName().startsWith( query )) + results.add( new MPSiteResult( site ) ); + + return results.build(); + } + public void addSite(final MPSite site) { sites.add( site ); } @@ -39,6 +55,10 @@ public class MPUser { return fullName; } + public boolean hasKeyID() { + return keyID != null; + } + public boolean hasKeyID(final byte[] keyID) { return Arrays.equals( this.keyID, keyID ); } @@ -47,18 +67,34 @@ public class MPUser { return CodeUtils.encodeHex( keyID ); } + public void setKeyID(final byte[] keyID) { + this.keyID = keyID; + } + public int getAvatar() { return avatar; } + public void setAvatar(final int avatar) { + this.avatar = avatar; + } + public MPSiteType getDefaultType() { return defaultType; } - public DateTime getLastUsed() { + public void setDefaultType(final MPSiteType defaultType) { + this.defaultType = defaultType; + } + + public ReadableInstant getLastUsed() { return lastUsed; } + public void updateLastUsed() { + this.lastUsed = new Instant(); + } + public Iterable getSites() { return sites; } diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserFileManager.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserFileManager.java new file mode 100644 index 00000000..9ac95730 --- /dev/null +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserFileManager.java @@ -0,0 +1,77 @@ +package com.lyndir.masterpassword.model; + +import com.google.common.base.*; +import com.google.common.collect.*; +import com.google.common.io.CharSink; +import com.lyndir.lhunath.opal.system.logging.Logger; +import java.io.*; +import javax.annotation.Nullable; + + +/** + * @author lhunath, 14-12-07 + */ +public class MPUserFileManager extends MPUserManager { + + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( MPUserFileManager.class ); + private static final MPUserFileManager instance = create( new File( System.getProperty( "user.home" ), ".mpw" ) ); + + private final File userFilesDirectory; + + public static MPUserFileManager get() { + return instance; + } + + public static MPUserFileManager create(final File userFilesDirectory) { + return new MPUserFileManager( userFilesDirectory ); + } + + protected MPUserFileManager(final File userFilesDirectory) { + + super( unmarshallUsers( userFilesDirectory ) ); + this.userFilesDirectory = userFilesDirectory; + } + + private static Iterable unmarshallUsers(final File userFilesDirectory) { + if (!userFilesDirectory.mkdirs() && !userFilesDirectory.isDirectory()) { + logger.err( "Couldn't create directory for user files: %s", userFilesDirectory ); + return ImmutableList.of(); + } + + return FluentIterable.from( ImmutableList.copyOf( userFilesDirectory.listFiles( new FilenameFilter() { + @Override + public boolean accept(final File dir, final String name) { + return name.endsWith( ".mpsites" ); + } + } ) ) ).transform( new Function() { + @Nullable + @Override + public MPUser apply(final File file) { + try { + return MPSiteUnmarshaller.unmarshall( file ).getUser(); + } + catch (IOException e) { + logger.err( e, "Couldn't read user from: %s", file ); + return null; + } + } + } ).filter( Predicates.notNull() ); + } + + public void save() { + for (final MPUser user : getUsers()) + try { + new CharSink() { + @Override + public Writer openStream() + throws IOException { + return new FileWriter( new File(userFilesDirectory, user.getFullName() + ".mpsites" ) ); + } + }.write( MPSiteMarshaller.marshallSafe( user ).getExport() ); + } + catch (IOException e) { + logger.err( e, "Unable to save sites for user: %s", user ); + } + } +} diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserManager.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserManager.java new file mode 100644 index 00000000..73c62697 --- /dev/null +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPUserManager.java @@ -0,0 +1,32 @@ +package com.lyndir.masterpassword.model; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Maps; +import java.util.*; + + +/** + * @author lhunath, 14-12-05 + */ +public abstract class MPUserManager { + + private final Map usersByName = Maps.newHashMap(); + + public MPUserManager(final Iterable users) { + for (MPUser user : users) + addUser( user ); + } + + public SortedSet getUsers() { + return FluentIterable.from( usersByName.values() ).toSortedSet( new Comparator() { + @Override + public int compare(final MPUser user1, final MPUser user2) { + return user1.getLastUsed().compareTo( user2.getLastUsed() ); + } + } ); + } + + public void addUser(final MPUser user) { + usersByName.put( user.getFullName(), user ); + } +}