2
0

Moar UI work on the Java app + support for per-site algorithm versioning.

This commit is contained in:
Maarten Billemont 2015-02-04 19:51:38 -05:00
parent 78c593fc08
commit a6ab9b9194
19 changed files with 262 additions and 129 deletions

View File

@ -28,6 +28,7 @@ public abstract class MasterKey {
return create( Version.CURRENT, fullName, masterPassword );
}
@Nonnull
public static MasterKey create(Version version, final String fullName, final String masterPassword) {
switch (version) {
@ -75,6 +76,10 @@ public abstract class MasterKey {
public abstract String encode(final String siteName, final MPSiteType siteType, int siteCounter, final MPSiteVariant siteVariant,
@Nullable final String siteContext);
public boolean isValid() {
return masterKey != null;
}
public void invalidate() {
if (masterKey != null) {

View File

@ -100,13 +100,13 @@ public class MasterKeyV0 extends MasterKey {
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0];
int templateIndex = sitePasswordSeed[0] & 0xFFFF;
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1];
int characterIndex = sitePasswordSeed[i + 1] & 0xFFFF;
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,

View File

@ -13,7 +13,7 @@ import javax.annotation.Nullable;
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV2 extends MasterKeyV0 {
public class MasterKeyV2 extends MasterKeyV1 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV2.class );

View File

@ -14,7 +14,7 @@ import javax.annotation.Nullable;
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV3 extends MasterKeyV0 {
public class MasterKeyV3 extends MasterKeyV2 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV3.class );

View File

@ -1,6 +1,7 @@
package com.lyndir.masterpassword.gui;
import com.google.common.collect.ImmutableList;
import com.lyndir.masterpassword.util.Components;
import java.awt.*;
import javax.swing.*;
@ -8,12 +9,13 @@ import javax.swing.*;
/**
* @author lhunath, 2014-06-11
*/
public abstract class AuthenticationPanel extends JPanel {
public abstract class AuthenticationPanel extends Components.GradientPanel {
protected final UnlockFrame unlockFrame;
protected final JLabel avatarLabel;
public AuthenticationPanel(final UnlockFrame unlockFrame) {
super( null, null );
this.unlockFrame = unlockFrame;
setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) );

View File

@ -94,7 +94,7 @@ public class GUI implements UnlockFrame.SignInCallback {
@Override
public boolean signedIn(final User user) {
if (!user.hasKey())
if (!user.isKeyAvailable())
return false;
try {
user.getKey();

View File

@ -24,14 +24,10 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements
add( Components.stud() );
JLabel fullNameLabel = Components.label( "Full Name:" );
fullNameLabel.setAlignmentX( LEFT_ALIGNMENT );
fullNameLabel.setHorizontalAlignment( SwingConstants.CENTER );
fullNameLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( fullNameLabel );
fullNameField = Components.textField();
fullNameField.setFont( Res.valueFont().deriveFont( 12f ) );
fullNameField.setAlignmentX( LEFT_ALIGNMENT );
fullNameField.getDocument().addDocumentListener( this );
fullNameField.addActionListener( this );
add( fullNameField );
@ -39,13 +35,9 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements
// Master Password
JLabel masterPasswordLabel = Components.label( "Master Password:" );
masterPasswordLabel.setAlignmentX( LEFT_ALIGNMENT );
masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER );
masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( masterPasswordLabel );
masterPasswordField = Components.passwordField();
masterPasswordField.setAlignmentX( LEFT_ALIGNMENT );
masterPasswordField.addActionListener( this );
masterPasswordField.getDocument().addDocumentListener( this );
add( masterPasswordField );

View File

@ -1,6 +1,7 @@
package com.lyndir.masterpassword.gui;
import com.lyndir.masterpassword.MPSiteType;
import com.lyndir.masterpassword.MasterKey;
/**
@ -8,14 +9,17 @@ import com.lyndir.masterpassword.MPSiteType;
*/
public class IncognitoSite extends Site {
private String siteName;
private MPSiteType siteType;
private int siteCounter;
private String siteName;
private MPSiteType siteType;
private int siteCounter;
private MasterKey.Version algorithmVersion;
public IncognitoSite(final String siteName, final MPSiteType siteType, final int siteCounter) {
public IncognitoSite(final String siteName, final MPSiteType siteType, final int siteCounter,
final MasterKey.Version algorithmVersion) {
this.siteName = siteName;
this.siteType = siteType;
this.siteCounter = siteCounter;
this.algorithmVersion = algorithmVersion;
}
public String getSiteName() {
@ -34,6 +38,16 @@ public class IncognitoSite extends Site {
this.siteType = siteType;
}
@Override
public MasterKey.Version getAlgorithmVersion() {
return algorithmVersion;
}
@Override
public void setAlgorithmVersion(final MasterKey.Version algorithmVersion) {
this.algorithmVersion = algorithmVersion;
}
public int getSiteCounter() {
return siteCounter;
}

View File

@ -9,8 +9,9 @@ import com.lyndir.masterpassword.MasterKey;
*/
public class IncognitoUser extends User {
private final String fullName;
private final String masterPassword;
private final String fullName;
private final String masterPassword;
private MasterKey.Version algorithmVersion;
public IncognitoUser(final String fullName, final String masterPassword) {
this.fullName = fullName;
@ -28,7 +29,12 @@ public class IncognitoUser extends User {
@Override
public MasterKey.Version getAlgorithmVersion() {
return MasterKey.Version.CURRENT;
return algorithmVersion;
}
@Override
public void setAlgorithmVersion(final MasterKey.Version algorithmVersion) {
this.algorithmVersion = algorithmVersion;
}
@Override

View File

@ -44,19 +44,10 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite
// User
JLabel userLabel = Components.label( "User:" );
userLabel.setAlignmentX( LEFT_ALIGNMENT );
userLabel.setHorizontalAlignment( SwingConstants.CENTER );
userLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( userLabel );
userField = new JComboBox<ModelUser>( new DefaultComboBoxModel<>( readConfigUsers() ) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
userField = Components.comboBox( readConfigUsers() );
userField.setFont( Res.valueFont().deriveFont( 12f ) );
userField.setAlignmentX( LEFT_ALIGNMENT );
userField.addItemListener( this );
userField.addActionListener( this );
add( userField );
@ -64,13 +55,9 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite
// Master Password
masterPasswordLabel = Components.label( "Master Password:" );
masterPasswordLabel.setAlignmentX( LEFT_ALIGNMENT );
masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER );
masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( masterPasswordLabel );
masterPasswordField = Components.passwordField();
masterPasswordField.setAlignmentX( LEFT_ALIGNMENT );
masterPasswordField.addActionListener( this );
masterPasswordField.getDocument().addDocumentListener( this );
add( masterPasswordField );

View File

@ -1,6 +1,7 @@
package com.lyndir.masterpassword.gui;
import com.lyndir.masterpassword.MPSiteType;
import com.lyndir.masterpassword.MasterKey;
import com.lyndir.masterpassword.model.*;
@ -37,6 +38,19 @@ public class ModelSite extends Site {
}
}
@Override
public MasterKey.Version getAlgorithmVersion() {
return model.getAlgorithmVersion();
}
@Override
public void setAlgorithmVersion(final MasterKey.Version algorithmVersion) {
if (algorithmVersion != getAlgorithmVersion()) {
model.setAlgorithmVersion( algorithmVersion );
MPUserFileManager.get().save();
}
}
public int getSiteCounter() {
return model.getSiteCounter();
}

View File

@ -42,6 +42,12 @@ public class ModelUser extends User {
return model.getAlgorithmVersion();
}
@Override
public void setAlgorithmVersion(final MasterKey.Version algorithmVersion) {
model.setAlgorithmVersion( algorithmVersion );
MPUserFileManager.get().save();
}
@Override
public int getAvatar() {
return model.getAvatar();

View File

@ -20,52 +20,46 @@ import javax.swing.event.*;
*/
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 JPasswordField passwordField;
private final JLabel tipLabel;
private final JCheckBox maskPasswordField;
private final char passwordEchoChar;
private final Font passwordEchoFont;
private boolean updatingUI;
private Site currentSite;
private final User user;
private final Components.GradientPanel root;
private final JTextField siteNameField;
private final JButton siteAddButton;
private final JComboBox<MPSiteType> siteTypeField;
private final JComboBox<MasterKey.Version> siteVersionField;
private final JSpinner siteCounterField;
private final JPasswordField passwordField;
private final JLabel tipLabel;
private final JCheckBox maskPasswordField;
private final char passwordEchoChar;
private final Font passwordEchoFont;
private boolean updatingUI;
private Site currentSite;
public PasswordFrame(User user)
throws HeadlessException {
super( "Master Password" );
this.user = user;
JLabel label;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( new JPanel( new BorderLayout( 20, 20 ) ) {
{
setBackground( Res.colors().frameBg() );
setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
}
} );
// User
add( label = Components.label( strf( "Generating passwords for: %s", user.getFullName() ) ), BorderLayout.NORTH );
label.setAlignmentX( LEFT_ALIGNMENT );
setContentPane( root = Components.gradientPanel( new BorderLayout( 20, 20 ), Res.colors().frameBg() ) );
root.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
// Site
JPanel sitePanel = Components.boxLayout( BoxLayout.PAGE_AXIS );
sitePanel.setOpaque( true );
sitePanel.setBackground( Res.colors().controlBg() );
sitePanel.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
add( Components.bordered( sitePanel, BorderFactory.createRaisedBevelBorder(), Res.colors().frameBg() ), BorderLayout.CENTER );
// Site Name
sitePanel.add( label = Components.label( "Site Name:" ) );
label.setAlignmentX( LEFT_ALIGNMENT );
// User
sitePanel.add( Components.label( strf( "Generating passwords for: %s", user.getFullName() ), JLabel.CENTER ) );
sitePanel.add( Components.stud() );
// Site Name
sitePanel.add( Components.label( "Site Name:" ) );
JComponent siteControls = Components.boxLayout( BoxLayout.LINE_AXIS, //
siteNameField = Components.textField(), Components.stud(),
siteAddButton = Components.button( "Add Site" ) );
siteNameField.setAlignmentX( LEFT_ALIGNMENT );
siteNameField.getDocument().addDocumentListener( this );
siteNameField.addActionListener( new ActionListener() {
@Override
@ -94,8 +88,6 @@ public class PasswordFrame extends JFrame implements DocumentListener {
}
} );
siteAddButton.setVisible( false );
siteAddButton.setAlignmentX( RIGHT_ALIGNMENT );
siteAddButton.setAlignmentY( CENTER_ALIGNMENT );
siteAddButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
@ -103,23 +95,20 @@ public class PasswordFrame extends JFrame implements DocumentListener {
siteAddButton.setVisible( false );
}
} );
siteControls.setBackground( null );
siteControls.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteControls );
sitePanel.add( Components.stud() );
// Site Type & Counter
MPSiteType[] types = Iterables.toArray( MPSiteType.forClass( MPSiteTypeClass.Generated ), MPSiteType.class );
JComponent siteSettings = Components.boxLayout( BoxLayout.LINE_AXIS, //
siteTypeField = new JComboBox<>( types ), //
siteTypeField = Components.comboBox( types ), //
Components.stud(), //
siteVersionField = Components.comboBox( MasterKey.Version.values() ), //
Components.stud(), //
siteCounterField = Components.spinner(
new SpinnerNumberModel( 1, 1, Integer.MAX_VALUE, 1 ) ) );
siteSettings.setBackground( null );
siteSettings.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteSettings );
siteTypeField.setFont( Res.valueFont().deriveFont( 12f ) );
siteTypeField.setAlignmentX( LEFT_ALIGNMENT );
siteTypeField.setAlignmentY( CENTER_ALIGNMENT );
siteTypeField.setSelectedItem( MPSiteType.GeneratedLong );
siteTypeField.addItemListener( new ItemListener() {
@Override
@ -128,9 +117,18 @@ public class PasswordFrame extends JFrame implements DocumentListener {
}
} );
siteVersionField.setFont( Res.valueFont().deriveFont( 12f ) );
siteVersionField.setAlignmentX( RIGHT_ALIGNMENT );
siteVersionField.setSelectedItem( user.getAlgorithmVersion() );
siteVersionField.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
updatePassword();
}
} );
siteCounterField.setFont( Res.valueFont().deriveFont( 12f ) );
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
siteCounterField.setAlignmentY( CENTER_ALIGNMENT );
siteCounterField.addChangeListener( new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
@ -151,9 +149,11 @@ public class PasswordFrame extends JFrame implements DocumentListener {
// Password
passwordField = new JPasswordField();
passwordField.setAlignmentX( Component.CENTER_ALIGNMENT );
passwordField.setEditable( false );
passwordField.setHorizontalAlignment( JTextField.CENTER );
passwordField.putClientProperty( "JPasswordField.cutCopyAllowed", true );
passwordField.setBorder( null );
passwordEchoChar = passwordField.getEchoChar();
passwordEchoFont = passwordField.getFont().deriveFont( 40f );
updateMask();
@ -161,16 +161,15 @@ public class PasswordFrame extends JFrame implements DocumentListener {
// Tip
tipLabel = Components.label( " ", JLabel.CENTER );
tipLabel.setAlignmentX( Component.CENTER_ALIGNMENT );
JPanel passwordContainer = Components.boxLayout( BoxLayout.PAGE_AXIS, maskPasswordField,
Components.bordered( passwordField, BorderFactory.createLoweredSoftBevelBorder(),
Res.colors().frameBg() ), tipLabel );
passwordContainer.setBackground( null );
add( passwordContainer, BorderLayout.SOUTH );
JPanel passwordContainer = Components.boxLayout( BoxLayout.PAGE_AXIS, maskPasswordField, passwordField, tipLabel );
passwordContainer.setOpaque( true );
passwordContainer.setBackground( Color.white );
passwordContainer.setBorder( BorderFactory.createEmptyBorder( 8, 8, 8, 8 ) );
add( Components.bordered( passwordContainer, BorderFactory.createLoweredSoftBevelBorder(), Res.colors().frameBg() ),
BorderLayout.SOUTH );
pack();
setMinimumSize( getSize() );
setPreferredSize( new Dimension( 600, getSize().height ) );
setMinimumSize( new Dimension( Math.max( 600, getPreferredSize().width ), Math.max( 300, getPreferredSize().height ) ) );
pack();
setLocationByPlatform( true );
@ -188,19 +187,21 @@ public class PasswordFrame extends JFrame implements DocumentListener {
final String siteNameQuery = siteNameField.getText();
if (updatingUI)
return Futures.immediateCancelledFuture();
if (siteNameQuery == null || siteNameQuery.isEmpty() || !user.hasKey()) {
if (siteNameQuery == null || siteNameQuery.isEmpty() || !user.isKeyAvailable()) {
tipLabel.setText( null );
passwordField.setText( null );
return Futures.immediateCancelledFuture();
}
MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() );
final MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() );
final MasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.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 ) );
: Iterables.getFirst( user.findSitesByName( siteNameQuery ), new IncognitoSite( siteNameQuery, siteType, siteCounter, user.getAlgorithmVersion() ) );
assert site != null;
if (site == currentSite) {
site.setSiteType( siteType );
site.setAlgorithmVersion( siteVersion );
site.setSiteCounter( siteCounter );
}
@ -208,7 +209,8 @@ public class PasswordFrame extends JFrame implements DocumentListener {
@Override
public String call()
throws Exception {
return user.getKey().encode( site.getSiteName(), site.getSiteType(), site.getSiteCounter(), MPSiteVariant.Password, null );
return user.getKey( site.getAlgorithmVersion() )
.encode( site.getSiteName(), site.getSiteType(), site.getSiteCounter(), MPSiteVariant.Password, null );
}
} );
Futures.addCallback( passwordFuture, new FutureCallback<String>() {
@ -221,6 +223,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
currentSite = site;
siteAddButton.setVisible( user instanceof ModelUser && !(currentSite instanceof ModelSite) );
siteTypeField.setSelectedItem( currentSite.getSiteType() );
siteVersionField.setSelectedItem( currentSite.getAlgorithmVersion() );
siteCounterField.setValue( currentSite.getSiteCounter() );
siteNameField.setText( currentSite.getSiteName() );
if (siteNameField.getText().startsWith( siteNameQuery ))

View File

@ -3,6 +3,7 @@ package com.lyndir.masterpassword.gui;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.lyndir.masterpassword.MPSiteType;
import com.lyndir.masterpassword.MasterKey;
/**
@ -18,6 +19,10 @@ public abstract class Site {
public abstract void setSiteType(final MPSiteType siteType);
public abstract MasterKey.Version getAlgorithmVersion();
public abstract void setAlgorithmVersion(final MasterKey.Version algorithmVersion);
public abstract int getSiteCounter();
public abstract void setSiteCounter(final int siteCounter);

View File

@ -6,7 +6,6 @@ import com.lyndir.masterpassword.util.Components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/**
@ -14,13 +13,13 @@ import javax.swing.border.*;
*/
public class UnlockFrame extends JFrame {
private final SignInCallback signInCallback;
private final JPanel root;
private final JButton signInButton;
private final JPanel authenticationContainer;
private AuthenticationPanel authenticationPanel;
private boolean incognito;
public User user;
private final SignInCallback signInCallback;
private final Components.GradientPanel root;
private final JButton signInButton;
private final JPanel authenticationContainer;
private AuthenticationPanel authenticationPanel;
private boolean incognito;
public User user;
public UnlockFrame(final SignInCallback signInCallback)
throws HeadlessException {
@ -28,11 +27,11 @@ public class UnlockFrame extends JFrame {
this.signInCallback = signInCallback;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( root = new JPanel( new BorderLayout( 20, 20 ) ) );
root.setBackground( Res.colors().frameBg() );
root.setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
setContentPane( root = Components.gradientPanel( new BorderLayout( 20, 20 ), Res.colors().frameBg() ) );
root.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
authenticationContainer = Components.boxLayout( BoxLayout.PAGE_AXIS );
authenticationContainer.setOpaque( true );
authenticationContainer.setBackground( Res.colors().controlBg() );
authenticationContainer.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
add( Components.bordered( authenticationContainer, BorderFactory.createRaisedBevelBorder(), Res.colors().frameBg() ) );
@ -42,7 +41,6 @@ public class UnlockFrame extends JFrame {
Box.createGlue() );
signInBox.setBackground( null );
root.add( signInBox, BorderLayout.SOUTH );
signInButton.setAlignmentX( LEFT_ALIGNMENT );
signInButton.addActionListener( new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
@ -75,7 +73,6 @@ public class UnlockFrame extends JFrame {
authenticationContainer.add( Components.stud() );
final JCheckBox incognitoCheckBox = Components.checkBox( "Incognito" );
incognitoCheckBox.setAlignmentX( LEFT_ALIGNMENT );
incognitoCheckBox.setSelected( incognito );
incognitoCheckBox.addItemListener( new ItemListener() {
@Override
@ -91,7 +88,6 @@ public class UnlockFrame extends JFrame {
} );
JComponent toolsPanel = Components.boxLayout( BoxLayout.LINE_AXIS, incognitoCheckBox, Box.createGlue() );
toolsPanel.setAlignmentX( Component.LEFT_ALIGNMENT );
authenticationContainer.add( toolsPanel );
for (JButton button : authenticationPanel.getButtons()) {
button.setMargin( new Insets( 0, 0, 0, 0 ) );
@ -118,7 +114,7 @@ public class UnlockFrame extends JFrame {
}
boolean checkSignIn() {
boolean enabled = user != null && !user.getFullName().isEmpty() && user.hasKey();
boolean enabled = user != null && !user.getFullName().isEmpty() && user.isKeyAvailable();
signInButton.setEnabled( enabled );
return enabled;

View File

@ -2,9 +2,9 @@ package com.lyndir.masterpassword.gui;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.Maps;
import com.lyndir.masterpassword.MasterKey;
import com.lyndir.masterpassword.model.MPUser;
import java.security.KeyException;
import java.util.EnumMap;
import java.util.Objects;
import javax.annotation.Nonnull;
@ -14,7 +14,8 @@ import javax.annotation.Nonnull;
*/
public abstract class User {
private MasterKey key;
@Nonnull
private static final EnumMap<MasterKey.Version, MasterKey> keyByVersion = Maps.newEnumMap( MasterKey.Version.class );
public abstract String getFullName();
@ -22,32 +23,42 @@ public abstract class User {
public abstract MasterKey.Version getAlgorithmVersion();
public abstract void setAlgorithmVersion(final MasterKey.Version algorithmVersion);
public int getAvatar() {
return 0;
}
public boolean hasKey() {
public boolean isKeyAvailable() {
String masterPassword = getMasterPassword();
return key != null || (masterPassword != null && !masterPassword.isEmpty());
return masterPassword != null && !masterPassword.isEmpty();
}
@Nonnull
public MasterKey getKey() throws MasterKeyException {
if (key == null) {
String masterPassword = getMasterPassword();
if (masterPassword == null || masterPassword.isEmpty()) {
reset();
throw new MasterKeyException( strf( "Master password unknown for user: %s", getFullName() ) );
}
return getKey( getAlgorithmVersion() );
}
key = MasterKey.create( getAlgorithmVersion(), getFullName(), masterPassword );
@Nonnull
public MasterKey getKey(MasterKey.Version algorithmVersion) throws MasterKeyException {
String masterPassword = getMasterPassword();
if (masterPassword == null || masterPassword.isEmpty()) {
reset();
throw new MasterKeyException( strf( "Master password unknown for user: %s", getFullName() ) );
}
MasterKey key = keyByVersion.get( algorithmVersion );
if (key == null)
keyByVersion.put( algorithmVersion, key = MasterKey.create( algorithmVersion, getFullName(), masterPassword ) );
if (!key.isValid())
key.revalidate( masterPassword );
return key;
}
public void reset() {
key = null;
for (MasterKey key : keyByVersion.values())
key.invalidate();
}
public abstract Iterable<Site> findSitesByName(final String siteName);

View File

@ -1,5 +1,6 @@
package com.lyndir.masterpassword.util;
import com.lyndir.masterpassword.gui.ModelUser;
import com.lyndir.masterpassword.gui.Res;
import java.awt.*;
import javax.swing.*;
@ -12,8 +13,9 @@ import javax.swing.border.CompoundBorder;
*/
public abstract class Components {
public static JPanel boxLayout(int axis, Component... components) {
JPanel container = new JPanel();
public static GradientPanel boxLayout(int axis, Component... components) {
GradientPanel container = gradientPanel( null, null );
// container.setBackground( Color.red );
container.setLayout( new BoxLayout( container, axis ) );
for (Component component : components)
container.add( component );
@ -21,12 +23,12 @@ public abstract class Components {
return container;
}
public static JPanel bordered(final JComponent component, final Border border) {
public static GradientPanel bordered(final JComponent component, final Border border) {
return bordered( component, border, null );
}
public static JPanel bordered(final JComponent component, final Border border, Color background) {
JPanel box = boxLayout( BoxLayout.LINE_AXIS, component );
public static GradientPanel bordered(final JComponent component, final Border border, Color background) {
GradientPanel box = boxLayout( BoxLayout.LINE_AXIS, component );
if (border != null)
box.setBorder( border );
@ -37,12 +39,25 @@ public abstract class Components {
return box;
}
public static GradientPanel gradientPanel(final LayoutManager layout, final Color color) {
return new GradientPanel( layout, color ) {
{
setOpaque( color != null );
setBackground( null );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
};
}
public static JTextField textField() {
return new JTextField() {
{
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
setFont( Res.valueFont().deriveFont( 12f ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
@ -57,6 +72,8 @@ public abstract class Components {
{
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
@ -70,6 +87,8 @@ public abstract class Components {
return new JButton( label ) {
{
setFont( Res.controlFont().deriveFont( 12f ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
@ -80,7 +99,12 @@ public abstract class Components {
}
public static Component stud() {
return Box.createRigidArea( new Dimension( 8, 8 ) );
Dimension studDimension = new Dimension( 8, 8 );
Box.Filler rigidArea = new Box.Filler( studDimension, studDimension, studDimension );
rigidArea.setAlignmentX( Component.LEFT_ALIGNMENT );
rigidArea.setAlignmentY( Component.BOTTOM_ALIGNMENT );
rigidArea.setBackground( Color.red );
return rigidArea;
}
public static JSpinner spinner(final SpinnerModel model) {
@ -90,6 +114,8 @@ public abstract class Components {
BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) );
((DefaultEditor) getEditor()).getTextField().setBorder( editorBorder );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
@ -107,6 +133,13 @@ public abstract class Components {
return new JLabel( label, alignment ) {
{
setFont( Res.controlFont().deriveFont( 12f ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
}
@ -115,7 +148,67 @@ public abstract class Components {
return new JCheckBox( label ) {
{
setFont( Res.controlFont().deriveFont( 12f ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
};
}
@SafeVarargs
public static <V> JComboBox<V> comboBox(final V... values) {
return comboBox( new DefaultComboBoxModel<>( values ) );
}
public static <M> JComboBox<M> comboBox(final ComboBoxModel<M> model) {
return new JComboBox<M>( model ) {
{
setFont( Res.controlFont().deriveFont( 12f ) );
setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
}
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
}
public static class GradientPanel extends JPanel {
private Color gradientColor;
private GradientPaint paint;
protected GradientPanel(final LayoutManager layout, final Color gradientColor) {
super( layout );
this.gradientColor = gradientColor;
setBackground( null );
}
public Color getGradientColor() {
return gradientColor;
}
public void setGradientColor(final Color gradientColor) {
this.gradientColor = gradientColor;
}
@Override
public void doLayout() {
super.doLayout();
if (gradientColor != null)
paint = new GradientPaint( new Point( 0, 0 ), gradientColor, new Point( getWidth(), getHeight() ), gradientColor.darker() );
}
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent( g );
if (paint != null) {
((Graphics2D) g).setPaint( paint );
g.fillRect( 0, 0, getWidth(), getHeight() );
}
}
}
}

View File

@ -6,7 +6,6 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.lyndir.masterpassword.*;
import java.util.Objects;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.Instant;
@ -19,7 +18,7 @@ public class MPSite {
public static final int DEFAULT_COUNTER = 1;
private final MPUser user;
private MasterKey.Version mpVersion;
private MasterKey.Version algorithmVersion;
private Instant lastUsed;
private String siteName;
private MPSiteType siteType;
@ -33,17 +32,17 @@ public class MPSite {
public MPSite(final MPUser user, final String siteName, final MPSiteType siteType, final int siteCounter) {
this.user = user;
this.mpVersion = MasterKey.Version.CURRENT;
this.algorithmVersion = MasterKey.Version.CURRENT;
this.lastUsed = new Instant();
this.siteName = siteName;
this.siteType = siteType;
this.siteCounter = siteCounter;
}
protected MPSite(final MPUser user, final MasterKey.Version mpVersion, final Instant lastUsed, final String siteName, final MPSiteType siteType, final int siteCounter,
protected MPSite(final MPUser user, final MasterKey.Version algorithmVersion, final Instant lastUsed, final String siteName, final MPSiteType siteType, final int siteCounter,
final int uses, final String loginName, final String importContent) {
this.user = user;
this.mpVersion = mpVersion;
this.algorithmVersion = algorithmVersion;
this.lastUsed = lastUsed;
this.siteName = siteName;
this.siteType = siteType;
@ -69,12 +68,12 @@ public class MPSite {
return null;
}
public MasterKey.Version getMPVersion() {
return mpVersion;
public MasterKey.Version getAlgorithmVersion() {
return algorithmVersion;
}
public void setMPVersion(final MasterKey.Version mpVersion) {
this.mpVersion = mpVersion;
public void setAlgorithmVersion(final MasterKey.Version mpVersion) {
this.algorithmVersion = mpVersion;
}
public Instant getLastUsed() {

View File

@ -82,7 +82,7 @@ public class MPSiteMarshaller {
site.getUses(), // uses
strf( "%d:%d:%d", //
site.getSiteType().getType(), // type
site.getMPVersion(), // algorithm
site.getAlgorithmVersion(), // algorithm
site.getSiteCounter() ), // counter
ifNotNullElse( site.getLoginName(), "" ), // loginName
site.getSiteName(), // siteName