2
0

Full ability to load, add and autocomplete sites from history.

This commit is contained in:
Maarten Billemont 2014-12-16 22:13:11 -05:00
parent 97dcc65eac
commit c2a6a3d035
16 changed files with 338 additions and 81 deletions

View File

@ -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 );

View File

@ -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;
}
}

View File

@ -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<Site> findSitesByName(final String siteName) {
return ImmutableList.of();
}
@Override
public void addSite(final Site site) {
}
}

View File

@ -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<ModelUser> 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 );

View File

@ -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();
}
}
}

View File

@ -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<Site> findSitesByName(final String query) {
return FluentIterable.from( model.findSitesByName( query ) ).transform( new Function<MPSiteResult, Site>() {
@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;
}

View File

@ -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<MPSiteType> 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<String>() {
@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<String> 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<String> passwordFuture = Res.execute( new Callable<String>() {
@Override
public String call()
throws Exception {
return user.getKey().encode( site.getSiteName(), site.getSiteType(), site.getSiteCounter(), MPSiteVariant.Password, null );
}
} );
Futures.addCallback( passwordFuture, new FutureCallback<String>() {
@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();
}
}

View File

@ -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 <V> ListenableFuture<V> execute(final Callable<V> job) {
return JdkFutureAdapters.listenInPoolThread( executor.submit( new Callable<V>() {
@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 );

View File

@ -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() );
}
}

View File

@ -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() {

View File

@ -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<Site> findSitesByName(final String siteName);
public abstract void addSite(final Site site);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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( ":", "" ) ), //

View File

@ -20,6 +20,7 @@ public class MPUserFileManager extends MPUserManager {
private final File userFilesDirectory;
public static MPUserFileManager get() {
MPUserManager.instance = instance;
return instance;
}

View File

@ -11,6 +11,11 @@ import java.util.*;
public abstract class MPUserManager {
private final Map<String, MPUser> usersByName = Maps.newHashMap();
static MPUserManager instance;
public static MPUserManager get() {
return instance;
}
public MPUserManager(final Iterable<MPUser> users) {
for (MPUser user : users)