From c2a6a3d035e04aeb26972c3a49c6ea8943cbd204 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Tue, 16 Dec 2014 22:13:11 -0500 Subject: [PATCH] Full ability to load, add and autocomplete sites from history. --- .../gui/IncognitoAuthenticationPanel.java | 3 + .../masterpassword/gui/IncognitoSite.java | 44 +++++++ .../masterpassword/gui/IncognitoUser.java | 12 ++ .../gui/ModelAuthenticationPanel.java | 7 ++ .../lyndir/masterpassword/gui/ModelSite.java | 51 ++++++++ .../lyndir/masterpassword/gui/ModelUser.java | 47 +++++-- .../masterpassword/gui/PasswordFrame.java | 119 +++++++++++++----- .../com/lyndir/masterpassword/gui/Res.java | 65 ++++++---- .../com/lyndir/masterpassword/gui/Site.java | 29 +++++ .../masterpassword/gui/UnlockFrame.java | 2 + .../com/lyndir/masterpassword/gui/User.java | 6 + .../lyndir/masterpassword/model/MPSite.java | 16 ++- .../model/MPSiteMarshaller.java | 6 +- .../model/MPSiteUnmarshaller.java | 6 +- .../model/MPUserFileManager.java | 1 + .../masterpassword/model/MPUserManager.java | 5 + 16 files changed, 338 insertions(+), 81 deletions(-) create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoSite.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelSite.java create mode 100644 MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Site.java diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java index 5d94d5bb..3f6cfb5a 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoAuthenticationPanel.java @@ -21,6 +21,7 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements // Full Name super( unlockFrame ); JLabel fullNameLabel = new JLabel( "Full Name:" ); + fullNameLabel.setFont( Res.exoRegular().deriveFont( 12f ) ); fullNameLabel.setAlignmentX( LEFT_ALIGNMENT ); fullNameLabel.setHorizontalAlignment( SwingConstants.CENTER ); fullNameLabel.setVerticalAlignment( SwingConstants.BOTTOM ); @@ -32,6 +33,7 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); } }; + fullNameField.setFont( Res.sourceCodeProRegular().deriveFont( 12f ) ); fullNameField.setAlignmentX( LEFT_ALIGNMENT ); fullNameField.getDocument().addDocumentListener( this ); fullNameField.addActionListener( this ); @@ -39,6 +41,7 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements // Master Password JLabel masterPasswordLabel = new JLabel( "Master Password:" ); + masterPasswordLabel.setFont( Res.exoRegular().deriveFont( 12f ) ); masterPasswordLabel.setAlignmentX( LEFT_ALIGNMENT ); masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER ); masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM ); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoSite.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoSite.java new file mode 100644 index 00000000..c6671b70 --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/IncognitoSite.java @@ -0,0 +1,44 @@ +package com.lyndir.masterpassword.gui; + +import com.lyndir.masterpassword.MPSiteType; + + +/** + * @author lhunath, 14-12-16 + */ +public class IncognitoSite extends Site { + + private String siteName; + private MPSiteType siteType; + private int siteCounter; + + public IncognitoSite(final String siteName, final MPSiteType siteType, final int siteCounter) { + this.siteName = siteName; + this.siteType = siteType; + this.siteCounter = siteCounter; + } + + public String getSiteName() { + return siteName; + } + + public void setSiteName(final String siteName) { + this.siteName = siteName; + } + + public MPSiteType getSiteType() { + return siteType; + } + + public void setSiteType(final MPSiteType siteType) { + this.siteType = siteType; + } + + public int getSiteCounter() { + return siteCounter; + } + + public void setSiteCounter(final int siteCounter) { + this.siteCounter = siteCounter; + } +} 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 index ca4fddeb..6fd231d1 100644 --- 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 @@ -1,5 +1,8 @@ package com.lyndir.masterpassword.gui; +import com.google.common.collect.ImmutableList; + + /** * @author lhunath, 2014-06-08 */ @@ -21,4 +24,13 @@ public class IncognitoUser extends User { protected String getMasterPassword() { return masterPassword; } + + @Override + public Iterable findSitesByName(final String siteName) { + return ImmutableList.of(); + } + + @Override + public void addSite(final Site site) { + } } 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 index 6a49420b..6042527f 100644 --- 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 @@ -2,6 +2,7 @@ package com.lyndir.masterpassword.gui; import com.google.common.base.Function; import com.google.common.collect.*; +import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.masterpassword.model.MPUser; import com.lyndir.masterpassword.model.MPUserFileManager; import java.awt.*; @@ -17,6 +18,9 @@ import javax.swing.event.DocumentListener; */ public class ModelAuthenticationPanel extends AuthenticationPanel implements ItemListener, ActionListener, DocumentListener { + @SuppressWarnings("UnusedDeclaration") + private static final Logger logger = Logger.get( ModelAuthenticationPanel.class ); + private final JComboBox userField; private final JLabel masterPasswordLabel; private final JPasswordField masterPasswordField; @@ -38,6 +42,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite // User JLabel userLabel = new JLabel( "User:" ); + userLabel.setFont( Res.exoRegular().deriveFont( 12f ) ); userLabel.setAlignmentX( LEFT_ALIGNMENT ); userLabel.setHorizontalAlignment( SwingConstants.CENTER ); userLabel.setVerticalAlignment( SwingConstants.BOTTOM ); @@ -49,6 +54,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); } }; + userField.setFont( Res.sourceCodeProRegular().deriveFont( 12f ) ); userField.setAlignmentX( LEFT_ALIGNMENT ); userField.addItemListener( this ); userField.addActionListener( this ); @@ -56,6 +62,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite // Master Password masterPasswordLabel = new JLabel( "Master Password:" ); + masterPasswordLabel.setFont( Res.exoRegular().deriveFont( 12f ) ); masterPasswordLabel.setAlignmentX( LEFT_ALIGNMENT ); masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER ); masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM ); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelSite.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelSite.java new file mode 100644 index 00000000..1105cace --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/ModelSite.java @@ -0,0 +1,51 @@ +package com.lyndir.masterpassword.gui; + +import com.lyndir.masterpassword.MPSiteType; +import com.lyndir.masterpassword.model.*; + + +/** + * @author lhunath, 14-12-16 + */ +public class ModelSite extends Site { + + private final MPSite model; + + public ModelSite(final MPSiteResult result) { + this.model = result.getSite(); + } + + public String getSiteName() { + return model.getSiteName(); + } + + @Override + public void setSiteName(final String siteName) { + model.setSiteName( siteName ); + MPUserFileManager.get().save(); + } + + public MPSiteType getSiteType() { + return model.getSiteType(); + } + + @Override + public void setSiteType(final MPSiteType siteType) { + if (siteType != getSiteType()) { + model.setSiteType( siteType ); + MPUserFileManager.get().save(); + } + } + + public int getSiteCounter() { + return model.getSiteCounter(); + } + + @Override + public void setSiteCounter(final int siteCounter) { + if (siteCounter != getSiteCounter()) { + model.setSiteCounter( siteCounter ); + MPUserFileManager.get().save(); + } + } +} 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 index 4e56475b..d8e94f40 100644 --- 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 @@ -2,9 +2,12 @@ package com.lyndir.masterpassword.gui; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; import com.lyndir.masterpassword.MasterKey; -import com.lyndir.masterpassword.model.MPUser; -import com.lyndir.masterpassword.model.MPUserFileManager; +import com.lyndir.masterpassword.model.*; +import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; /** @@ -12,16 +15,20 @@ import com.lyndir.masterpassword.model.MPUserFileManager; */ public class ModelUser extends User { - private final MPUser user; + private final MPUser model; private String masterPassword; - public ModelUser(MPUser user) { - this.user = user; + public ModelUser(MPUser model) { + this.model = model; + } + + public MPUser getModel() { + return model; } @Override public String getFullName() { - return user.getFullName(); + return model.getFullName(); } @Override @@ -31,11 +38,11 @@ public class ModelUser extends User { @Override public int getAvatar() { - return user.getAvatar(); + return model.getAvatar(); } public void setAvatar(final int avatar) { - user.setAvatar( avatar % Res.avatars() ); + model.setAvatar( avatar % Res.avatars() ); MPUserFileManager.get().save(); } @@ -43,18 +50,36 @@ public class ModelUser extends User { this.masterPassword = masterPassword; } + @NotNull @Override public MasterKey getKey() { MasterKey key = super.getKey(); - if (!user.hasKeyID()) { - user.setKeyID( key.getKeyID() ); + if (!model.hasKeyID()) { + model.setKeyID( key.getKeyID() ); MPUserFileManager.get().save(); - } else if (!user.hasKeyID( key.getKeyID() )) + } else if (!model.hasKeyID( key.getKeyID() )) throw new IllegalStateException( strf( "Incorrect master password for user: %s", getFullName() ) ); return key; } + @Override + public Iterable findSitesByName(final String query) { + return FluentIterable.from( model.findSitesByName( query ) ).transform( new Function() { + @Nullable + @Override + public Site apply(final MPSiteResult result) { + return new ModelSite( result ); + } + } ); + } + + @Override + public void addSite(final Site site) { + model.addSite( new MPSite( site.getSiteName(), site.getSiteType(), site.getSiteCounter() ) ); + MPUserFileManager.get().save(); + } + public boolean keySaved() { return false; } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java index f1b6ff87..b52ac3e4 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/PasswordFrame.java @@ -3,11 +3,15 @@ package com.lyndir.masterpassword.gui; import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.*; +import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.util.Components; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.*; +import java.util.concurrent.Callable; +import javax.annotation.Nonnull; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; @@ -20,10 +24,13 @@ public class PasswordFrame extends JFrame implements DocumentListener { private final User user; private final JTextField siteNameField; + private final JButton siteAddButton; private final JComboBox siteTypeField; private final JSpinner siteCounterField; private final JTextField passwordField; private final JLabel tipLabel; + private boolean updatingUI; + private Site currentSite; public PasswordFrame(User user) throws HeadlessException { @@ -54,21 +61,40 @@ public class PasswordFrame extends JFrame implements DocumentListener { label.setFont( Res.exoRegular().deriveFont( 12f ) ); label.setAlignmentX( LEFT_ALIGNMENT ); - sitePanel.add( siteNameField = new JTextField() { + JComponent siteControls = Components.boxLayout( BoxLayout.LINE_AXIS, // + siteNameField = new JTextField() { + @Override + public Dimension getMaximumSize() { + return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); + } + }, siteAddButton = new JButton( "Add Site" ) { + @Override + public Dimension getMaximumSize() { + return new Dimension( 20, getPreferredSize().height ); + } + } ); + siteAddButton.setVisible( false ); + siteAddButton.setFont( Res.exoRegular().deriveFont( 12f ) ); + siteAddButton.setAlignmentX( RIGHT_ALIGNMENT ); + siteAddButton.setAlignmentY( CENTER_ALIGNMENT ); + siteAddButton.addActionListener( new ActionListener() { @Override - public Dimension getMaximumSize() { - return new Dimension( Integer.MAX_VALUE, getPreferredSize().height ); + public void actionPerformed(final ActionEvent e) { + PasswordFrame.this.user.addSite( currentSite ); + siteAddButton.setVisible( false ); } } ); - siteNameField.setFont( Res.exoRegular().deriveFont( 12f ) ); + siteControls.setAlignmentX( LEFT_ALIGNMENT ); + sitePanel.add( siteControls ); + siteNameField.setFont( Res.sourceCodeProRegular().deriveFont( 12f ) ); siteNameField.setAlignmentX( LEFT_ALIGNMENT ); siteNameField.getDocument().addDocumentListener( this ); siteNameField.addActionListener( new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { - updatePassword( new PasswordCallback() { + Futures.addCallback( updatePassword(), new FutureCallback() { @Override - public void passwordGenerated(final String siteName, final String sitePassword) { + public void onSuccess(final String sitePassword) { StringSelection clipboardContents = new StringSelection( sitePassword ); Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null ); @@ -85,6 +111,10 @@ public class PasswordFrame extends JFrame implements DocumentListener { } } ); } + + @Override + public void onFailure(final Throwable t) { + } } ); } } ); @@ -102,24 +132,24 @@ public class PasswordFrame extends JFrame implements DocumentListener { } ); siteSettings.setAlignmentX( LEFT_ALIGNMENT ); sitePanel.add( siteSettings ); - siteTypeField.setFont( Res.exoRegular().deriveFont( 12f ) ); + siteTypeField.setFont( Res.sourceCodeProRegular().deriveFont( 12f ) ); siteTypeField.setAlignmentX( LEFT_ALIGNMENT ); siteTypeField.setAlignmentY( CENTER_ALIGNMENT ); siteTypeField.setSelectedItem( MPSiteType.GeneratedLong ); siteTypeField.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { - updatePassword( null ); + updatePassword(); } } ); - siteCounterField.setFont( Res.exoRegular().deriveFont( 12f ) ); + siteCounterField.setFont( Res.sourceCodeProRegular().deriveFont( 12f ) ); siteCounterField.setAlignmentX( RIGHT_ALIGNMENT ); siteCounterField.setAlignmentY( CENTER_ALIGNMENT ); siteCounterField.addChangeListener( new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { - updatePassword( null ); + updatePassword(); } } ); @@ -132,7 +162,7 @@ public class PasswordFrame extends JFrame implements DocumentListener { // Tip tipLabel = new JLabel( " ", JLabel.CENTER ); - tipLabel.setFont( Res.exoThin().deriveFont( 9f ) ); + tipLabel.setFont( Res.exoRegular().deriveFont( 9f ) ); tipLabel.setAlignmentX( Component.CENTER_ALIGNMENT ); add( Components.boxLayout( BoxLayout.PAGE_AXIS, passwordField, tipLabel ), BorderLayout.SOUTH ); @@ -146,55 +176,76 @@ public class PasswordFrame extends JFrame implements DocumentListener { setLocationRelativeTo( null ); } - private void updatePassword(final PasswordCallback callback) { - final MPSiteType siteType = (MPSiteType) siteTypeField.getSelectedItem(); - final String siteName = siteNameField.getText(); - final int siteCounter = (Integer) siteCounterField.getValue(); + @Nonnull + private ListenableFuture updatePassword() { - if (siteType.getTypeClass() != MPSiteTypeClass.Generated || siteName == null || siteName.isEmpty() || !user.hasKey()) { + final String siteNameQuery = siteNameField.getText(); + if (updatingUI) + return Futures.immediateCancelledFuture(); + if (siteNameQuery == null || siteNameQuery.isEmpty() || !user.hasKey()) { passwordField.setText( null ); tipLabel.setText( null ); - return; + return Futures.immediateCancelledFuture(); } - Res.execute( new Runnable() { - @Override - public void run() { - final String sitePassword = user.getKey().encode( siteName, siteType, siteCounter, MPSiteVariant.Password, null ); - if (callback != null) - callback.passwordGenerated( siteName, sitePassword ); + MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() ); + final int siteCounter = (Integer) siteCounterField.getValue(); + final Site site = currentSite != null && currentSite.getSiteName().equals( siteNameQuery )? currentSite + : Iterables.getFirst( user.findSitesByName( siteNameQuery ), new IncognitoSite( siteNameQuery, siteType, siteCounter ) ); + assert site != null; + if (site == currentSite) { + site.setSiteType( siteType ); + site.setSiteCounter( siteCounter ); + } + ListenableFuture passwordFuture = Res.execute( new Callable() { + @Override + public String call() + throws Exception { + return user.getKey().encode( site.getSiteName(), site.getSiteType(), site.getSiteCounter(), MPSiteVariant.Password, null ); + } + } ); + Futures.addCallback( passwordFuture, new FutureCallback() { + @Override + public void onSuccess(final String sitePassword) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { - if (!siteName.equals( siteNameField.getText() )) - return; + updatingUI = true; + currentSite = site; + siteAddButton.setVisible( user instanceof ModelUser && !(currentSite instanceof ModelSite) ); + siteTypeField.setSelectedItem( currentSite.getSiteType() ); + siteCounterField.setValue( currentSite.getSiteCounter() ); + siteNameField.setText( currentSite.getSiteName() ); + if (siteNameField.getText().startsWith( siteNameQuery )) + siteNameField.select( siteNameQuery.length(), siteNameField.getText().length() ); passwordField.setText( sitePassword ); - tipLabel.setText( "Press [Enter] to copy the password." ); + tipLabel.setText( "Press [Enter] to copy the password. Then paste it into the password field." ); + updatingUI = false; } } ); } + + @Override + public void onFailure(final Throwable t) { + } } ); + + return passwordFuture; } @Override public void insertUpdate(final DocumentEvent e) { - updatePassword( null ); + updatePassword(); } @Override public void removeUpdate(final DocumentEvent e) { - updatePassword( null ); } @Override public void changedUpdate(final DocumentEvent e) { - updatePassword( null ); - } - - interface PasswordCallback { - - void passwordGenerated(String siteName, String sitePassword); + updatePassword(); } } diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java index 053edb61..2bbb471d 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Res.java @@ -5,13 +5,13 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.google.common.base.Throwables; import com.google.common.io.Resources; +import com.google.common.util.concurrent.*; import com.lyndir.lhunath.opal.system.logging.Logger; import java.awt.*; import java.awt.image.ImageObserver; import java.io.IOException; import java.net.URL; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.*; @@ -25,14 +25,15 @@ public abstract class Res { private static final ExecutorService executor = Executors.newSingleThreadExecutor(); private static final Logger logger = Logger.get( Res.class ); + private static Font sourceCodeProRegular; private static Font sourceCodeProBlack; private static Font exoBold; private static Font exoExtraBold; private static Font exoRegular; private static Font exoThin; - public static void execute(final Runnable job) { - executor.submit( new Runnable() { + public static Future execute(final Runnable job) { + return executor.submit( new Runnable() { @Override public void run() { try { @@ -45,6 +46,22 @@ public abstract class Res { } ); } + public static ListenableFuture execute(final Callable job) { + return JdkFutureAdapters.listenInPoolThread( executor.submit( new Callable() { + @Override + public V call() + throws Exception { + try { + return job.call(); + } + catch (Throwable t) { + logger.err( t, "Unexpected: %s", t.getLocalizedMessage() ); + throw t; + } + } + } ), executor ); + } + public static Icon iconAdd() { return new RetinaIcon( Resources.getResource( "media/icon_add@2x.png" ) ); } @@ -61,12 +78,20 @@ public abstract class Res { return 19; } + public static Font sourceCodeProRegular() { + try { + return sourceCodeProRegular != null? sourceCodeProRegular: (sourceCodeProRegular = + Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/SourceCodePro-Regular.otf" ).openStream() )); + } + catch (FontFormatException | IOException e) { + throw Throwables.propagate( e ); + } + } + public static Font sourceCodeProBlack() { try { - URL resource = Resources.getResource( "fonts/SourceCodePro-Bold.otf" ); - Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() ); - return sourceCodeProBlack != null? sourceCodeProBlack: // - (sourceCodeProBlack = font); + return sourceCodeProBlack != null? sourceCodeProBlack: (sourceCodeProBlack = + Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/SourceCodePro-Bold.otf" ).openStream() )); } catch (FontFormatException | IOException e) { throw Throwables.propagate( e ); @@ -75,10 +100,8 @@ public abstract class Res { public static Font exoBold() { try { - URL resource = Resources.getResource( "fonts/Exo2.0-Bold.otf" ); - Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() ); - return exoBold != null? exoBold: // - (exoBold = font); + return exoBold != null? exoBold: (exoBold = + Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/Exo2.0-Bold.otf" ).openStream() )); } catch (FontFormatException | IOException e) { throw Throwables.propagate( e ); @@ -87,10 +110,8 @@ public abstract class Res { public static Font exoExtraBold() { try { - URL resource = Resources.getResource( "fonts/Exo2.0-ExtraBold.otf" ); - Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() ); - return exoExtraBold != null? exoExtraBold: // - (exoExtraBold = font); + return exoExtraBold != null? exoExtraBold: (exoExtraBold + = Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/Exo2.0-ExtraBold.otf" ).openStream() )); } catch (FontFormatException | IOException e) { throw Throwables.propagate( e ); @@ -99,10 +120,8 @@ public abstract class Res { public static Font exoRegular() { try { - URL resource = Resources.getResource( "fonts/Exo2.0-Regular.otf" ); - Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() ); - return exoRegular != null? exoRegular: // - (exoRegular = font); + return exoRegular != null? exoRegular: (exoRegular = + Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/Exo2.0-Regular.otf" ).openStream() )); } catch (FontFormatException | IOException e) { throw Throwables.propagate( e ); @@ -111,10 +130,8 @@ public abstract class Res { public static Font exoThin() { try { - URL resource = Resources.getResource( "fonts/Exo2.0-Thin.otf" ); - Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() ); - return exoThin != null? exoThin: // - (exoThin = font); + return exoThin != null? exoThin: (exoThin = + Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( "fonts/Exo2.0-Thin.otf" ).openStream() )); } catch (FontFormatException | IOException e) { throw Throwables.propagate( e ); diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Site.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Site.java new file mode 100644 index 00000000..9e56788e --- /dev/null +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/Site.java @@ -0,0 +1,29 @@ +package com.lyndir.masterpassword.gui; + +import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; + +import com.lyndir.masterpassword.MPSiteType; + + +/** + * @author lhunath, 14-12-16 + */ +public abstract class Site { + + public abstract String getSiteName(); + + public abstract void setSiteName(final String siteName); + + public abstract MPSiteType getSiteType(); + + public abstract void setSiteType(final MPSiteType siteType); + + public abstract int getSiteCounter(); + + public abstract void setSiteCounter(final int siteCounter); + + @Override + public String toString() { + return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() ); + } +} diff --git a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java index 30aca015..7818187a 100644 --- a/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java +++ b/MasterPassword/Java/masterpassword-gui/src/main/java/com/lyndir/masterpassword/gui/UnlockFrame.java @@ -38,6 +38,7 @@ public class UnlockFrame extends JFrame { // Sign In root.add( Components.boxLayout( BoxLayout.LINE_AXIS, Box.createGlue(), signInButton = new JButton( "Sign In" ), Box.createGlue() ), BorderLayout.SOUTH ); + signInButton.setFont( Res.exoRegular().deriveFont( 12f ) ); signInButton.setAlignmentX( LEFT_ALIGNMENT ); signInButton.addActionListener( new AbstractAction() { @Override @@ -73,6 +74,7 @@ public class UnlockFrame extends JFrame { authenticationContainer.add( authenticationPanel, BorderLayout.CENTER ); final JCheckBox incognitoCheckBox = new JCheckBox( "Incognito" ); + incognitoCheckBox.setFont( Res.exoRegular().deriveFont( 12f ) ); incognitoCheckBox.setAlignmentX( LEFT_ALIGNMENT ); incognitoCheckBox.setSelected( incognito ); incognitoCheckBox.addItemListener( new ItemListener() { 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 index 9b56cba1..aacceafc 100644 --- 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 @@ -4,6 +4,7 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.lyndir.masterpassword.MasterKey; import javax.annotation.Nonnull; +import org.jetbrains.annotations.NotNull; /** @@ -26,6 +27,7 @@ public abstract class User { return key != null || (masterPassword != null && !masterPassword.isEmpty()); } + @NotNull @Nonnull public MasterKey getKey() { if (key == null) { @@ -46,4 +48,8 @@ public abstract class User { public String toString() { return getFullName(); } + + public abstract Iterable findSitesByName(final String siteName); + + public abstract void addSite(final Site site); } diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSite.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSite.java index 3820f219..7fd09f7e 100644 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSite.java +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSite.java @@ -6,17 +6,19 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import com.lyndir.masterpassword.*; import javax.annotation.Nullable; import org.joda.time.DateTime; +import org.joda.time.Instant; /** * @author lhunath, 14-12-05 */ public class MPSite { - public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong; - public static final int DEFAULT_COUNTER = 1; + + public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong; + public static final int DEFAULT_COUNTER = 1; private int mpVersion; - private DateTime lastUsed; + private Instant lastUsed; private String siteName; private MPSiteType siteType; private int siteCounter; @@ -28,12 +30,14 @@ public class MPSite { } public MPSite(final String siteName, final MPSiteType siteType, final int siteCounter) { + this.mpVersion = MasterKey.ALGORITHM; + this.lastUsed = new Instant(); this.siteName = siteName; this.siteType = siteType; this.siteCounter = siteCounter; } - protected MPSite(final int mpVersion, final DateTime lastUsed, final String siteName, final MPSiteType siteType, final int siteCounter, + protected MPSite(final int mpVersion, final Instant lastUsed, final String siteName, final MPSiteType siteType, final int siteCounter, final int uses, final String loginName, final String importContent) { this.mpVersion = mpVersion; this.lastUsed = lastUsed; @@ -65,11 +69,11 @@ public class MPSite { this.mpVersion = mpVersion; } - public DateTime getLastUsed() { + public Instant getLastUsed() { return lastUsed; } - public void setLastUsed(final DateTime lastUsed) { + public void setLastUsed(final Instant lastUsed) { this.lastUsed = lastUsed; } diff --git a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java index 048167b3..0673fd6f 100644 --- a/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java +++ b/MasterPassword/Java/masterpassword-model/src/main/java/com/lyndir/masterpassword/model/MPSiteMarshaller.java @@ -17,7 +17,7 @@ import org.joda.time.format.ISODateTimeFormat; */ public class MPSiteMarshaller { - private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTime(); + private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis(); private final StringBuilder export = new StringBuilder(); private ContentMode contentMode = ContentMode.PROTECTED; @@ -77,10 +77,10 @@ public class MPSiteMarshaller { } public String marshallSite(MPSite site) { - String exportLine = strf( "%s %8ld %8s %25s\t%25s\t%s", // + String exportLine = strf( "%s %8d %8s %25s\t%25s\t%s", // rfc3339.print( site.getLastUsed() ), // lastUsed site.getUses(), // uses - strf( "%lu:%lu:%lu", // + strf( "%d:%d:%d", // site.getSiteType().getMask(), // type site.getMPVersion(), // algorithm site.getSiteCounter() ), // counter 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 49870acd..14d5527a 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 @@ -29,7 +29,7 @@ public class MPSiteUnmarshaller { @SuppressWarnings("UnusedDeclaration") private static final Logger logger = Logger.get( MPSite.class ); - private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTime(); + private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis(); private static final Pattern[] unmarshallFormats = new Pattern[]{ Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ), Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) }; @@ -124,7 +124,7 @@ public class MPSiteUnmarshaller { switch (importFormat) { case 0: site = new MPSite( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ), // - rfc3339.parseDateTime( siteMatcher.group( 1 ) ), // + rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), // siteMatcher.group( 5 ), // Iterables.getOnlyElement( MPSiteType.forMask( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ) ), MPSite.DEFAULT_COUNTER, // @@ -135,7 +135,7 @@ public class MPSiteUnmarshaller { case 1: site = new MPSite( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ), // - rfc3339.parseDateTime( siteMatcher.group( 1 ) ), // + rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), // siteMatcher.group( 7 ), // Iterables.getOnlyElement( MPSiteType.forMask( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ) ), ConversionUtils.toIntegerNN( siteMatcher.group( 5 ).replace( ":", "" ) ), // 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 index 9ac95730..0771dd58 100644 --- 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 @@ -20,6 +20,7 @@ public class MPUserFileManager extends MPUserManager { private final File userFilesDirectory; public static MPUserFileManager get() { + MPUserManager.instance = instance; return instance; } 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 index 73c62697..ae6cd01d 100644 --- 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 @@ -11,6 +11,11 @@ import java.util.*; public abstract class MPUserManager { private final Map usersByName = Maps.newHashMap(); + static MPUserManager instance; + + public static MPUserManager get() { + return instance; + } public MPUserManager(final Iterable users) { for (MPUser user : users)