Full ability to load, add and autocomplete sites from history.
This commit is contained in:
parent
97dcc65eac
commit
c2a6a3d035
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
} );
|
||||
siteNameField.setFont( Res.exoRegular().deriveFont( 12f ) );
|
||||
siteAddButton.setVisible( false );
|
||||
siteAddButton.setFont( Res.exoRegular().deriveFont( 12f ) );
|
||||
siteAddButton.setAlignmentX( RIGHT_ALIGNMENT );
|
||||
siteAddButton.setAlignmentY( CENTER_ALIGNMENT );
|
||||
siteAddButton.addActionListener( new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
PasswordFrame.this.user.addSite( currentSite );
|
||||
siteAddButton.setVisible( false );
|
||||
}
|
||||
} );
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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() );
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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( ":", "" ) ), //
|
||||
|
@ -20,6 +20,7 @@ public class MPUserFileManager extends MPUserManager {
|
||||
private final File userFilesDirectory;
|
||||
|
||||
public static MPUserFileManager get() {
|
||||
MPUserManager.instance = instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user