Saving custom passwords and logins.
This commit is contained in:
		@@ -66,6 +66,7 @@ public class MPMasterKey {
 | 
			
		||||
     *
 | 
			
		||||
     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
			
		||||
     */
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public byte[] getKeyID(final MPAlgorithm algorithm)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
 | 
			
		||||
@@ -87,6 +88,7 @@ public class MPMasterKey {
 | 
			
		||||
        return !invalidated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private byte[] masterKey(final MPAlgorithm algorithm)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
        Preconditions.checkArgument( masterPassword.length > 0 );
 | 
			
		||||
@@ -109,6 +111,7 @@ public class MPMasterKey {
 | 
			
		||||
        return masterKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private byte[] siteKey(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
 | 
			
		||||
                           final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
@@ -141,13 +144,19 @@ public class MPMasterKey {
 | 
			
		||||
     *                    In the case of {@link MPResultTypeClass#Stateful} types, the result of
 | 
			
		||||
     *                    {@link #siteState(String, MPAlgorithm, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code null} if the result type is missing a required parameter.
 | 
			
		||||
     *
 | 
			
		||||
     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public String siteResult(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
 | 
			
		||||
                             final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
			
		||||
                             final MPResultType resultType, @Nullable final String resultParam)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
 | 
			
		||||
        if ((resultType.getTypeClass() == MPResultTypeClass.Stateful) && (resultParam == null))
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        byte[] masterKey = masterKey( algorithm );
 | 
			
		||||
        byte[] siteKey   = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
 | 
			
		||||
 | 
			
		||||
@@ -176,6 +185,7 @@ public class MPMasterKey {
 | 
			
		||||
     *
 | 
			
		||||
     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
			
		||||
     */
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public String siteState(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
 | 
			
		||||
                            final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
			
		||||
                            final MPResultType resultType, final String resultParam)
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ public enum MPResultType {
 | 
			
		||||
    /**
 | 
			
		||||
     * 16: pg^VMAUBk5x3p%HP%i4=
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedMaximum( "maximum", "Maximum Security", "pg^VMAUBk5x3p%HP%i4=", "20 characters, contains symbols.", //
 | 
			
		||||
    GeneratedMaximum( "maximum", "Maximum Security", "pg^VMAUBk5x3p%HP%i4=", "20 characters, contains symbols", //
 | 
			
		||||
                      ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ),
 | 
			
		||||
                                        new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
 | 
			
		||||
                      MPResultTypeClass.Template, 0x0 ),
 | 
			
		||||
@@ -49,7 +49,7 @@ public enum MPResultType {
 | 
			
		||||
    /**
 | 
			
		||||
     * 17: BiroYena8:Kixa
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedLong( "long", "Long Password", "BiroYena8:Kixa", "Copy-friendly, 14 characters, contains symbols.", //
 | 
			
		||||
    GeneratedLong( "long", "Long Password", "BiroYena8:Kixa", "Copy-friendly, 14 characters, contains symbols", //
 | 
			
		||||
                   ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
 | 
			
		||||
                                     new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
 | 
			
		||||
                                     new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
 | 
			
		||||
@@ -66,7 +66,7 @@ public enum MPResultType {
 | 
			
		||||
    /**
 | 
			
		||||
     * 18: BirSuj0-
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedMedium( "medium", "Medium Password", "BirSuj0-", "Copy-friendly, 8 characters, contains symbols.", //
 | 
			
		||||
    GeneratedMedium( "medium", "Medium Password", "BirSuj0-", "Copy-friendly, 8 characters, contains symbols", //
 | 
			
		||||
                     ImmutableList.of( new MPTemplate( "CvcnoCvc" ),
 | 
			
		||||
                                       new MPTemplate( "CvcCvcno" ) ), //
 | 
			
		||||
                     MPResultTypeClass.Template, 0x2 ),
 | 
			
		||||
@@ -74,14 +74,14 @@ public enum MPResultType {
 | 
			
		||||
    /**
 | 
			
		||||
     * 19: Bir8
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedShort( "short", "Short Password", "Bir8", "Copy-friendly, 4 characters, no symbols.", //
 | 
			
		||||
    GeneratedShort( "short", "Short Password", "Bir8", "Copy-friendly, 4 characters, no symbols", //
 | 
			
		||||
                    ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
 | 
			
		||||
                    MPResultTypeClass.Template, 0x3 ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 20: pO98MoD0
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedBasic( "basic", "Basic Password", "pO98MoD0", "8 characters, no symbols.", //
 | 
			
		||||
    GeneratedBasic( "basic", "Basic Password", "pO98MoD0", "8 characters, no symbols", //
 | 
			
		||||
                    ImmutableList.of( new MPTemplate( "aaanaaan" ),
 | 
			
		||||
                                      new MPTemplate( "aannaaan" ),
 | 
			
		||||
                                      new MPTemplate( "aaannaaa" ) ), //
 | 
			
		||||
@@ -90,44 +90,44 @@ public enum MPResultType {
 | 
			
		||||
    /**
 | 
			
		||||
     * 21: 2798
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedPIN( "pin", "PIN Code", "2798", "4 numbers.", //
 | 
			
		||||
    GeneratedPIN( "pin", "PIN Code", "2798", "4 numbers", //
 | 
			
		||||
                  ImmutableList.of( new MPTemplate( "nnnn" ) ), //
 | 
			
		||||
                  MPResultTypeClass.Template, 0x5 ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 30: birsujano
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedName( "name", "Name", "birsujano", "9 letter name.", //
 | 
			
		||||
    GeneratedName( "name", "Name", "birsujano", "9 letter name", //
 | 
			
		||||
                   ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
 | 
			
		||||
                   MPResultTypeClass.Template, 0xE ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 31: bir yennoquce fefi
 | 
			
		||||
     */
 | 
			
		||||
    GeneratedPhrase( "phrase", "Phrase", "bir yennoquce fefi", "20 character sentence.", //
 | 
			
		||||
    GeneratedPhrase( "phrase", "Phrase", "bir yennoquce fefi", "20 character sentence", //
 | 
			
		||||
                     ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
 | 
			
		||||
                                       new MPTemplate( "cvc cvccvcvcv cvcv" ),
 | 
			
		||||
                                       new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
 | 
			
		||||
                     MPResultTypeClass.Template, 0xF ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 1056: Custom saved password.
 | 
			
		||||
     * 1056: Custom saved value.
 | 
			
		||||
     */
 | 
			
		||||
    StoredPersonal( "personal", "Saved Password", null, "AES-encrypted, exportable.", //
 | 
			
		||||
    StoredPersonal( "personal", "Saved", null, "AES-encrypted, exportable", //
 | 
			
		||||
                    ImmutableList.<MPTemplate>of(), //
 | 
			
		||||
                    MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 2081: Custom saved password that should not be exported from the device.
 | 
			
		||||
     * 2081: Custom saved value that should not be exported from the device.
 | 
			
		||||
     */
 | 
			
		||||
    StoredDevicePrivate( "device", "Private Password", null, "AES-encrypted, not exported.", //
 | 
			
		||||
    StoredDevicePrivate( "device", "Private", null, "AES-encrypted, not exported", //
 | 
			
		||||
                         ImmutableList.<MPTemplate>of(), //
 | 
			
		||||
                         MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 4160: Derive a unique binary key.
 | 
			
		||||
     */
 | 
			
		||||
    DeriveKey( "key", "Binary Key", null, "Encryption key.", //
 | 
			
		||||
    DeriveKey( "key", "Binary Key", null, "Encryption key", //
 | 
			
		||||
               ImmutableList.<MPTemplate>of(), //
 | 
			
		||||
               MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -160,6 +160,10 @@ public abstract class Res {
 | 
			
		||||
            return icon( "media/icon_settings.png" );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Icon edit() {
 | 
			
		||||
            return icon( "media/icon_edit.png" );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Icon avatar(final int index) {
 | 
			
		||||
            return icon( strf( "media/avatar-%d.png", index % avatars() ) );
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -470,6 +470,8 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
                                                                   "Show site settings." );
 | 
			
		||||
        private final JButton questionsButton = Components.button( Res.icons().question(), event -> showSiteQuestions(),
 | 
			
		||||
                                                                   "Show site recovery questions." );
 | 
			
		||||
        private final JButton editButton      = Components.button( Res.icons().edit(), event -> showEditSite(),
 | 
			
		||||
                                                                   "Set/save personal password/login." );
 | 
			
		||||
        private final JButton deleteButton    = Components.button( Res.icons().delete(), event -> deleteSite(),
 | 
			
		||||
                                                                   "Delete the site from the user." );
 | 
			
		||||
 | 
			
		||||
@@ -499,6 +501,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
 | 
			
		||||
            siteToolbar.add( settingsButton );
 | 
			
		||||
            siteToolbar.add( questionsButton );
 | 
			
		||||
            siteToolbar.add( editButton );
 | 
			
		||||
            siteToolbar.add( deleteButton );
 | 
			
		||||
            settingsButton.setEnabled( false );
 | 
			
		||||
            questionsButton.setEnabled( false );
 | 
			
		||||
@@ -587,12 +590,14 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
                            Components.strut() );
 | 
			
		||||
 | 
			
		||||
            components.add( Components.label( "Password Type:" ),
 | 
			
		||||
                            Components.comboBox( MPResultType.values(), MPResultType::getLongName,
 | 
			
		||||
                            Components.comboBox( MPResultType.values(), type -> getTypeDescription(
 | 
			
		||||
                                    type, user.getDefaultType(), user.getAlgorithm().mpw_default_result_type() ),
 | 
			
		||||
                                                 site.getResultType(), site::setResultType ),
 | 
			
		||||
                            Components.strut() );
 | 
			
		||||
 | 
			
		||||
            components.add( Components.label( "Login Type:" ),
 | 
			
		||||
                            Components.comboBox( MPResultType.values(), MPResultType::getLongName,
 | 
			
		||||
                            Components.comboBox( MPResultType.values(), type -> getTypeDescription(
 | 
			
		||||
                                    type, user.getAlgorithm().mpw_default_login_type() ),
 | 
			
		||||
                                                 site.getLoginType(), site::setLoginType ),
 | 
			
		||||
                            Components.strut() );
 | 
			
		||||
 | 
			
		||||
@@ -606,6 +611,15 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
                    BoxLayout.PAGE_AXIS, components.build().toArray( new Component[0] ) ) ) );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private String getTypeDescription(final MPResultType type, final MPResultType... defaults) {
 | 
			
		||||
            boolean isDefault = false;
 | 
			
		||||
            for (final MPResultType d : defaults)
 | 
			
		||||
                if (isDefault = type == d)
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
            return strf( "<html>%s%s%s, %s", isDefault? "<b>": "", type.getLongName(), isDefault? "</b>": "", type.getDescription() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void showSiteQuestions() {
 | 
			
		||||
            MPSite<?> site = sitesModel.getSelectedItem();
 | 
			
		||||
            if (site == null)
 | 
			
		||||
@@ -651,6 +665,51 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
            } );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void showEditSite() {
 | 
			
		||||
            MPSite<?> site = sitesModel.getSelectedItem();
 | 
			
		||||
            if (site == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                JTextField passwordField = Components.textField( site.getResult(), null );
 | 
			
		||||
                JTextField loginField    = Components.textField( site.getLogin(), null );
 | 
			
		||||
                passwordField.setEditable( site.getResultType().getTypeClass() == MPResultTypeClass.Stateful );
 | 
			
		||||
                loginField.setEditable( site.getLoginType().getTypeClass() == MPResultTypeClass.Stateful );
 | 
			
		||||
 | 
			
		||||
                if (JOptionPane.OK_OPTION == Components.showDialog( this, site.getSiteName(), new JOptionPane(
 | 
			
		||||
                        Components.panel(
 | 
			
		||||
                                BoxLayout.PAGE_AXIS,
 | 
			
		||||
                                Components.label( strf( "<html>Site Login (currently set to: <b>%s</b>):",
 | 
			
		||||
                                                        getTypeDescription( site.getLoginType() ) ) ),
 | 
			
		||||
                                loginField,
 | 
			
		||||
                                Components.strut(),
 | 
			
		||||
                                Components.label( strf( "<html>Site Password (currently set to: <b>%s</b>):",
 | 
			
		||||
                                                        getTypeDescription( site.getResultType() ) ) ),
 | 
			
		||||
                                passwordField,
 | 
			
		||||
                                Components.strut(),
 | 
			
		||||
                                Components.label( "<html>To save a personal value in these fields,\n" +
 | 
			
		||||
                                                  "change the type to <b>Saved</b> in the site's settings." ) ),
 | 
			
		||||
                        JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION ) {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void selectInitialValue() {
 | 
			
		||||
                        passwordField.requestFocusInWindow();
 | 
			
		||||
                    }
 | 
			
		||||
                } )) {
 | 
			
		||||
                    if (site instanceof MPFileSite) {
 | 
			
		||||
                        MPFileSite fileSite = (MPFileSite) site;
 | 
			
		||||
 | 
			
		||||
                        if (site.getResultType().getTypeClass() == MPResultTypeClass.Stateful)
 | 
			
		||||
                            fileSite.setSitePassword( site.getResultType(), passwordField.getText() );
 | 
			
		||||
                        if (site.getLoginType().getTypeClass() == MPResultTypeClass.Stateful)
 | 
			
		||||
                            fileSite.setLoginName( site.getLoginType(), loginField.getText() );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (final MPKeyUnavailableException | MPAlgorithmException e) {
 | 
			
		||||
                logger.err( e, "While computing site edit results." );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void deleteSite() {
 | 
			
		||||
            MPSite<?> site = sitesModel.getSelectedItem();
 | 
			
		||||
            if (site == null)
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.9 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.7 KiB  | 
@@ -58,30 +58,29 @@ public interface MPSite<Q extends MPQuestion> extends Comparable<MPSite<?>> {
 | 
			
		||||
 | 
			
		||||
    void setLoginType(@Nullable MPResultType loginType);
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    default String getResult()
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
 | 
			
		||||
        return getResult( MPKeyPurpose.Authentication );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    default String getResult(final MPKeyPurpose keyPurpose)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
        return getResult( keyPurpose, null );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    default String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
        return getResult( keyPurpose, keyContext, null );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    String getResult(MPKeyPurpose keyPurpose, @Nullable String keyContext, @Nullable String state)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException;
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    String getResult(MPKeyPurpose keyPurpose, @Nullable String keyContext,
 | 
			
		||||
                     @Nullable UnsignedInteger counter, MPResultType type, @Nullable String state)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException;
 | 
			
		||||
 
 | 
			
		||||
@@ -129,7 +129,7 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
 | 
			
		||||
        setChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext, @Nullable final String state)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
@@ -137,7 +137,7 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
 | 
			
		||||
        return getResult( keyPurpose, keyContext, getCounter(), getResultType(), state );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
			
		||||
                            @Nullable final UnsignedInteger counter, final MPResultType type, @Nullable final String state)
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ public class MPFileSite extends MPBasicSite<MPFileUser, MPFileQuestion> {
 | 
			
		||||
        setChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
 | 
			
		||||
            throws MPKeyUnavailableException, MPAlgorithmException {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user