Initial Java JSON serialization/deserialization.
This commit is contained in:
		@@ -38,6 +38,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
 | 
				
			|||||||
time_t mpw_mktime(
 | 
					time_t mpw_mktime(
 | 
				
			||||||
        const char *time) {
 | 
					        const char *time) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Support parsing timezone into tm_gmtoff
 | 
				
			||||||
    struct tm tm = { .tm_isdst = -1 };
 | 
					    struct tm tm = { .tm_isdst = -1 };
 | 
				
			||||||
    if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
 | 
					    if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
 | 
				
			||||||
            &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
 | 
					            &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,12 @@ public abstract class MPAlgorithm {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * mpw: defaults: password result type.
 | 
					     * mpw: defaults: password result type.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public abstract MPResultType mpw_default_type();
 | 
					    public abstract MPResultType mpw_default_password_type();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * mpw: defaults: login result type.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public abstract MPResultType mpw_default_login_type();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * mpw: defaults: initial counter value.
 | 
					     * mpw: defaults: initial counter value.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,8 +83,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
					    public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter,
 | 
				
			||||||
                          @Nullable final String keyContext) {
 | 
					                          final MPKeyPurpose keyPurpose, @Nullable final String keyContext) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        String keyScope = keyPurpose.getScope();
 | 
					        String keyScope = keyPurpose.getScope();
 | 
				
			||||||
        logger.trc( "keyScope: %s", keyScope );
 | 
					        logger.trc( "keyScope: %s", keyScope );
 | 
				
			||||||
@@ -117,8 +117,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
 | 
					    public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
 | 
				
			||||||
                             final MPKeyPurpose keyPurpose,
 | 
					                             final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
				
			||||||
                             @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
 | 
					                             final MPResultType resultType, @Nullable final String resultParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (resultType.getTypeClass()) {
 | 
					        switch (resultType.getTypeClass()) {
 | 
				
			||||||
            case Template:
 | 
					            case Template:
 | 
				
			||||||
@@ -133,8 +133,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
 | 
					    public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey,
 | 
				
			||||||
                                           @Nullable final String resultParam) {
 | 
					                                           final MPResultType resultType, @Nullable final String resultParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int[] _siteKey = new int[siteKey.length];
 | 
					        int[] _siteKey = new int[siteKey.length];
 | 
				
			||||||
        for (int i = 0; i < siteKey.length; ++i) {
 | 
					        for (int i = 0; i < siteKey.length; ++i) {
 | 
				
			||||||
@@ -168,8 +168,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
 | 
					    public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey,
 | 
				
			||||||
                                        @Nullable final String resultParam) {
 | 
					                                        final MPResultType resultType, @Nullable final String resultParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Preconditions.checkNotNull( resultParam );
 | 
					        Preconditions.checkNotNull( resultParam );
 | 
				
			||||||
        Preconditions.checkArgument( !resultParam.isEmpty() );
 | 
					        Preconditions.checkArgument( !resultParam.isEmpty() );
 | 
				
			||||||
@@ -192,8 +192,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
 | 
					    public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey,
 | 
				
			||||||
                                         @Nullable final String resultParam) {
 | 
					                                         final MPResultType resultType, @Nullable final String resultParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (resultType == MPResultType.DeriveKey) {
 | 
					        if (resultType == MPResultType.DeriveKey) {
 | 
				
			||||||
            int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
 | 
					            int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
 | 
				
			||||||
@@ -220,8 +220,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
 | 
					    public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
 | 
				
			||||||
                            final MPKeyPurpose keyPurpose,
 | 
					                            final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
				
			||||||
                            @Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
 | 
					                            final MPResultType resultType, final String resultParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // Encrypt
 | 
					            // Encrypt
 | 
				
			||||||
@@ -246,111 +246,77 @@ public class MPAlgorithmV0 extends MPAlgorithm {
 | 
				
			|||||||
        return MPMasterKey.Version.V0;
 | 
					        return MPMasterKey.Version.V0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: defaults: password result type.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPResultType mpw_default_type() {
 | 
					    public MPResultType mpw_default_password_type() {
 | 
				
			||||||
        return MPResultType.GeneratedLong;
 | 
					        return MPResultType.GeneratedLong;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    @Override
 | 
				
			||||||
     * mpw: defaults: initial counter value.
 | 
					    public MPResultType mpw_default_login_type() {
 | 
				
			||||||
     */
 | 
					        return MPResultType.GeneratedName;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public UnsignedInteger mpw_default_counter() {
 | 
					    public UnsignedInteger mpw_default_counter() {
 | 
				
			||||||
        return UnsignedInteger.ONE;
 | 
					        return UnsignedInteger.ONE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: validity for the time-based rolling counter.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public long mpw_otp_window() {
 | 
					    public long mpw_otp_window() {
 | 
				
			||||||
        return 5 * 60 /* s */;
 | 
					        return 5 * 60 /* s */;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Key ID hash.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MessageDigests mpw_hash() {
 | 
					    public MessageDigests mpw_hash() {
 | 
				
			||||||
        return MessageDigests.SHA256;
 | 
					        return MessageDigests.SHA256;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Site digest.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MessageAuthenticationDigests mpw_digest() {
 | 
					    public MessageAuthenticationDigests mpw_digest() {
 | 
				
			||||||
        return MessageAuthenticationDigests.HmacSHA256;
 | 
					        return MessageAuthenticationDigests.HmacSHA256;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Platform-agnostic byte order.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public ByteOrder mpw_byteOrder() {
 | 
					    public ByteOrder mpw_byteOrder() {
 | 
				
			||||||
        return ByteOrder.BIG_ENDIAN;
 | 
					        return ByteOrder.BIG_ENDIAN;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Input character encoding.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Charset mpw_charset() {
 | 
					    public Charset mpw_charset() {
 | 
				
			||||||
        return Charsets.UTF_8;
 | 
					        return Charsets.UTF_8;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Master key size (byte).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int mpw_dkLen() {
 | 
					    public int mpw_dkLen() {
 | 
				
			||||||
        return 64;
 | 
					        return 64;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Minimum size for derived keys (bit).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int mpw_keySize_min() {
 | 
					    public int mpw_keySize_min() {
 | 
				
			||||||
        return 128;
 | 
					        return 128;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * mpw: Maximum size for derived keys (bit).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int mpw_keySize_max() {
 | 
					    public int mpw_keySize_max() {
 | 
				
			||||||
        return 512;
 | 
					        return 512;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * scrypt: Parallelization parameter.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int scrypt_p() {
 | 
					    public int scrypt_p() {
 | 
				
			||||||
        return 2;
 | 
					        return 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * scrypt: Memory cost parameter.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int scrypt_r() {
 | 
					    public int scrypt_r() {
 | 
				
			||||||
        return 8;
 | 
					        return 8;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * scrypt: CPU cost parameter.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @SuppressWarnings("MagicNumber")
 | 
					    @SuppressWarnings("MagicNumber")
 | 
				
			||||||
    public int scrypt_N() {
 | 
					    public int scrypt_N() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,5 +42,5 @@ public final class MPConstant {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public static final int MS_PER_S = 1000;
 | 
					    public static final int MS_PER_S = 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
 | 
					    public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis().withZoneUTC();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
//==============================================================================
 | 
					 | 
				
			||||||
// This file is part of Master Password.
 | 
					 | 
				
			||||||
// Copyright (c) 2011-2017, Maarten Billemont.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Master Password is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
// it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
// the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
// (at your option) any later version.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Master Password is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
// GNU General Public License for more details.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// You can find a copy of the GNU General Public License in the
 | 
					 | 
				
			||||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
//==============================================================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package com.lyndir.masterpassword;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @author lhunath, 2017-09-21
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class MPInvalidatedException extends Exception {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -56,14 +56,14 @@ public class MPMasterKey {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Derive the master key for a user based on their name and master password.
 | 
					     * Derive the master key for a user based on their name and master password.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
 | 
					     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private byte[] masterKey(final MPAlgorithm algorithm)
 | 
					    private byte[] masterKey(final MPAlgorithm algorithm)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        Preconditions.checkArgument( masterPassword.length > 0 );
 | 
					        Preconditions.checkArgument( masterPassword.length > 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (invalidated)
 | 
					        if (invalidated)
 | 
				
			||||||
            throw new MPInvalidatedException();
 | 
					            throw new MPKeyUnavailableException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        byte[] key = keyByVersion.get( algorithm.version() );
 | 
					        byte[] key = keyByVersion.get( algorithm.version() );
 | 
				
			||||||
        if (key == null) {
 | 
					        if (key == null) {
 | 
				
			||||||
@@ -81,11 +81,11 @@ public class MPMasterKey {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Derive the master key for a user based on their name and master password.
 | 
					     * Derive the master key for a user based on their name and master password.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
 | 
					     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
					    private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
				
			||||||
                           @Nullable final String keyContext, final MPAlgorithm algorithm)
 | 
					                           @Nullable final String keyContext, final MPAlgorithm algorithm)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        Preconditions.checkArgument( !siteName.isEmpty() );
 | 
					        Preconditions.checkArgument( !siteName.isEmpty() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        byte[] masterKey = masterKey( algorithm );
 | 
					        byte[] masterKey = masterKey( algorithm );
 | 
				
			||||||
@@ -110,12 +110,12 @@ public class MPMasterKey {
 | 
				
			|||||||
     * @param resultParam A parameter for the resultType.  For stateful result types, the output of
 | 
					     * @param resultParam A parameter for the resultType.  For stateful result types, the output of
 | 
				
			||||||
     *                    {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
 | 
					     *                    {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
 | 
					     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
					    public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
				
			||||||
                             @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
 | 
					                             @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
 | 
				
			||||||
                             final MPAlgorithm algorithm)
 | 
					                             final MPAlgorithm algorithm)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        byte[] masterKey = masterKey( algorithm );
 | 
					        byte[] masterKey = masterKey( algorithm );
 | 
				
			||||||
        byte[] siteKey   = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
 | 
					        byte[] siteKey   = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
 | 
				
			||||||
@@ -139,12 +139,12 @@ public class MPMasterKey {
 | 
				
			|||||||
     * @param resultParam The result token desired from
 | 
					     * @param resultParam The result token desired from
 | 
				
			||||||
     *                    {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
 | 
					     *                    {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
 | 
					     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
					    public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
 | 
				
			||||||
                            @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
 | 
					                            @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
 | 
				
			||||||
                            final MPAlgorithm algorithm)
 | 
					                            final MPAlgorithm algorithm)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Preconditions.checkNotNull( resultParam );
 | 
					        Preconditions.checkNotNull( resultParam );
 | 
				
			||||||
        Preconditions.checkArgument( !resultParam.isEmpty() );
 | 
					        Preconditions.checkArgument( !resultParam.isEmpty() );
 | 
				
			||||||
@@ -169,10 +169,10 @@ public class MPMasterKey {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Calculate an identifier for the master key.
 | 
					     * Calculate an identifier for the master key.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
 | 
					     * @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public byte[] getKeyID(final MPAlgorithm algorithm)
 | 
					    public byte[] getKeyID(final MPAlgorithm algorithm)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return algorithm.toID( masterKey( algorithm ) );
 | 
					        return algorithm.toID( masterKey( algorithm ) );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.lyndir.masterpassword.model;
 | 
					package com.lyndir.masterpassword.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.common.primitives.UnsignedInteger;
 | 
					import com.google.common.primitives.UnsignedInteger;
 | 
				
			||||||
import com.lyndir.masterpassword.*;
 | 
					import com.lyndir.masterpassword.*;
 | 
				
			||||||
 | 
					import javax.annotation.Nonnull;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
import org.joda.time.Instant;
 | 
					import org.joda.time.Instant;
 | 
				
			||||||
 | 
					import org.joda.time.ReadableInstant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -29,22 +33,23 @@ import org.joda.time.Instant;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class MPFileSite extends MPSite {
 | 
					public class MPFileSite extends MPSite {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final MPFileUser      user;
 | 
					    private final MPFileUser user;
 | 
				
			||||||
    private       String          siteName;
 | 
					
 | 
				
			||||||
 | 
					    private String          siteName;
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private       String          siteContent;
 | 
					    private String          siteState;
 | 
				
			||||||
    private       UnsignedInteger siteCounter;
 | 
					    private UnsignedInteger siteCounter;
 | 
				
			||||||
    private       MPResultType    resultType;
 | 
					    private MPResultType    resultType;
 | 
				
			||||||
    private       MPAlgorithm     algorithm;
 | 
					    private MPAlgorithm     algorithm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private String       loginContent;
 | 
					    private String       loginState;
 | 
				
			||||||
    private MPResultType loginType;
 | 
					    private MPResultType loginType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private String  url;
 | 
					    private String          url;
 | 
				
			||||||
    private int     uses;
 | 
					    private int             uses;
 | 
				
			||||||
    private Instant lastUsed;
 | 
					    private ReadableInstant lastUsed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPFileSite(final MPFileUser user, final String siteName) {
 | 
					    public MPFileSite(final MPFileUser user, final String siteName) {
 | 
				
			||||||
        this( user, siteName, null, null, user.getAlgorithm() );
 | 
					        this( user, siteName, null, null, user.getAlgorithm() );
 | 
				
			||||||
@@ -56,45 +61,43 @@ public class MPFileSite extends MPSite {
 | 
				
			|||||||
              null, null, null, 0, new Instant() );
 | 
					              null, null, null, 0, new Instant() );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
 | 
					    protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteState,
 | 
				
			||||||
                         @Nullable final UnsignedInteger siteCounter, @Nullable final MPResultType resultType, final MPAlgorithm algorithm,
 | 
					                         @Nullable final UnsignedInteger siteCounter, @Nullable final MPResultType resultType, final MPAlgorithm algorithm,
 | 
				
			||||||
                         @Nullable final String loginContent, @Nullable final MPResultType loginType,
 | 
					                         @Nullable final String loginState, @Nullable final MPResultType loginType,
 | 
				
			||||||
                         @Nullable final String url, final int uses, final Instant lastUsed) {
 | 
					                         @Nullable final String url, final int uses, final ReadableInstant lastUsed) {
 | 
				
			||||||
        this.user = user;
 | 
					        this.user = user;
 | 
				
			||||||
        this.siteName = siteName;
 | 
					        this.siteName = siteName;
 | 
				
			||||||
        this.siteContent = siteContent;
 | 
					        this.siteState = siteState;
 | 
				
			||||||
        this.siteCounter = (siteCounter == null)? user.getAlgorithm().mpw_default_counter(): siteCounter;
 | 
					        this.siteCounter = ifNotNullElse( siteCounter, user.getAlgorithm().mpw_default_counter() );
 | 
				
			||||||
        this.resultType = (resultType == null)? user.getAlgorithm().mpw_default_type(): resultType;
 | 
					        this.resultType = ifNotNullElse( resultType, user.getAlgorithm().mpw_default_password_type() );
 | 
				
			||||||
        this.algorithm = algorithm;
 | 
					        this.algorithm = algorithm;
 | 
				
			||||||
        this.loginContent = loginContent;
 | 
					        this.loginState = loginState;
 | 
				
			||||||
        this.loginType = (loginType == null)? MPResultType.GeneratedName: loginType;
 | 
					        this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
 | 
				
			||||||
        this.url = url;
 | 
					        this.url = url;
 | 
				
			||||||
        this.uses = uses;
 | 
					        this.uses = uses;
 | 
				
			||||||
        this.lastUsed = lastUsed;
 | 
					        this.lastUsed = lastUsed;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String resultFor(final MPMasterKey masterKey)
 | 
					    public String getResult()
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return resultFor( masterKey, MPKeyPurpose.Authentication, null );
 | 
					        return getResult( MPKeyPurpose.Authentication, null );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
 | 
					    public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
 | 
					        return getResult( keyPurpose, keyContext, siteState );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String loginFor(final MPMasterKey masterKey)
 | 
					    public String getLogin()
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (loginType == null)
 | 
					        return getLogin( loginState );
 | 
				
			||||||
            loginType = MPResultType.GeneratedName;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return loginFor( masterKey, loginType, loginContent );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPFileUser getUser() {
 | 
					    @Override
 | 
				
			||||||
 | 
					    public MPUser<?> getUser() {
 | 
				
			||||||
        return user;
 | 
					        return user;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,18 +112,18 @@ public class MPFileSite extends MPSite {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    public String getSiteContent() {
 | 
					    public String getSiteState() {
 | 
				
			||||||
        return siteContent;
 | 
					        return siteState;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setSitePassword(final MPMasterKey masterKey, final MPResultType resultType, @Nullable final String result)
 | 
					    public void setSitePassword(final MPResultType resultType, @Nullable final String result)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        this.resultType = resultType;
 | 
					        this.resultType = resultType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (result == null)
 | 
					        if (result == null)
 | 
				
			||||||
            this.siteContent = null;
 | 
					            this.siteState = null;
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            this.siteContent = masterKey.siteState(
 | 
					            this.siteState = user.getMasterKey().siteState(
 | 
				
			||||||
                    siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
 | 
					                    siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,6 +147,17 @@ public class MPFileSite extends MPSite {
 | 
				
			|||||||
        this.resultType = resultType;
 | 
					        this.resultType = resultType;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public MPResultType getLoginType() {
 | 
				
			||||||
 | 
					        return loginType;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setLoginType(@Nullable final MPResultType loginType) {
 | 
				
			||||||
 | 
					        this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPAlgorithm getAlgorithm() {
 | 
					    public MPAlgorithm getAlgorithm() {
 | 
				
			||||||
        return algorithm;
 | 
					        return algorithm;
 | 
				
			||||||
@@ -154,25 +168,17 @@ public class MPFileSite extends MPSite {
 | 
				
			|||||||
        this.algorithm = algorithm;
 | 
					        this.algorithm = algorithm;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPResultType getLoginType() {
 | 
					 | 
				
			||||||
        return loginType;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    public String getLoginContent() {
 | 
					    public String getLoginState() {
 | 
				
			||||||
        return loginContent;
 | 
					        return loginState;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
 | 
					    public void setLoginName(@Nonnull final MPResultType loginType, @Nonnull final String loginName)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        this.loginType = loginType;
 | 
					        this.loginType = loginType;
 | 
				
			||||||
        if (this.loginType != null)
 | 
					        this.loginState = user.getMasterKey().siteState(
 | 
				
			||||||
            if (result == null)
 | 
					                siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null,
 | 
				
			||||||
                this.loginContent = null;
 | 
					                this.loginType, loginName, algorithm );
 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                this.loginContent = masterKey.siteState(
 | 
					 | 
				
			||||||
                        siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null, this.loginType, result,
 | 
					 | 
				
			||||||
                        algorithm );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
@@ -188,7 +194,7 @@ public class MPFileSite extends MPSite {
 | 
				
			|||||||
        return uses;
 | 
					        return uses;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Instant getLastUsed() {
 | 
					    public ReadableInstant getLastUsed() {
 | 
				
			||||||
        return lastUsed;
 | 
					        return lastUsed;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,9 +42,10 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
    private final Collection<MPFileSite> sites = Sets.newHashSet();
 | 
					    private final Collection<MPFileSite> sites = Sets.newHashSet();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    private byte[]          keyID;
 | 
					    private byte[]                   keyID;
 | 
				
			||||||
    private MPAlgorithm     algorithm;
 | 
					    private MPAlgorithm              algorithm;
 | 
				
			||||||
    private MPMarshalFormat format;
 | 
					    private MPMarshalFormat          format;
 | 
				
			||||||
 | 
					    private MPMarshaller.ContentMode contentMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private int             avatar;
 | 
					    private int             avatar;
 | 
				
			||||||
    private MPResultType    defaultType;
 | 
					    private MPResultType    defaultType;
 | 
				
			||||||
@@ -55,11 +56,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm) {
 | 
					    public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm) {
 | 
				
			||||||
        this( fullName, keyID, algorithm, 0, algorithm.mpw_default_type(), new Instant(), MPMarshalFormat.DEFAULT );
 | 
					        this( fullName, keyID, algorithm, 0, algorithm.mpw_default_password_type(), new Instant(),
 | 
				
			||||||
 | 
					              MPMarshalFormat.DEFAULT, MPMarshaller.ContentMode.PROTECTED );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
 | 
					    public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
 | 
				
			||||||
                      final MPResultType defaultType, final ReadableInstant lastUsed, final MPMarshalFormat format) {
 | 
					                      final MPResultType defaultType, final ReadableInstant lastUsed,
 | 
				
			||||||
 | 
					                      final MPMarshalFormat format, final MPMarshaller.ContentMode contentMode) {
 | 
				
			||||||
        this.fullName = fullName;
 | 
					        this.fullName = fullName;
 | 
				
			||||||
        this.keyID = (keyID == null)? null: keyID.clone();
 | 
					        this.keyID = (keyID == null)? null: keyID.clone();
 | 
				
			||||||
        this.algorithm = algorithm;
 | 
					        this.algorithm = algorithm;
 | 
				
			||||||
@@ -67,6 +70,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
        this.defaultType = defaultType;
 | 
					        this.defaultType = defaultType;
 | 
				
			||||||
        this.lastUsed = lastUsed;
 | 
					        this.lastUsed = lastUsed;
 | 
				
			||||||
        this.format = format;
 | 
					        this.format = format;
 | 
				
			||||||
 | 
					        this.contentMode = contentMode;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -74,6 +78,11 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
        return fullName;
 | 
					        return fullName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    public byte[] getKeyID() {
 | 
				
			||||||
 | 
					        return (keyID == null)? null: keyID.clone();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPAlgorithm getAlgorithm() {
 | 
					    public MPAlgorithm getAlgorithm() {
 | 
				
			||||||
        return algorithm;
 | 
					        return algorithm;
 | 
				
			||||||
@@ -91,6 +100,14 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
        this.format = format;
 | 
					        this.format = format;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public MPMarshaller.ContentMode getContentMode() {
 | 
				
			||||||
 | 
					        return contentMode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setContentMode(final MPMarshaller.ContentMode contentMode) {
 | 
				
			||||||
 | 
					        this.contentMode = contentMode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public int getAvatar() {
 | 
					    public int getAvatar() {
 | 
				
			||||||
        return avatar;
 | 
					        return avatar;
 | 
				
			||||||
@@ -164,13 +181,13 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return key;
 | 
					            return key;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (final MPInvalidatedException e) {
 | 
					        catch (final MPKeyUnavailableException e) {
 | 
				
			||||||
            throw logger.bug( e );
 | 
					            throw logger.bug( e );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void save()
 | 
					    void save()
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        MPFileUserManager.get().save( this, getMasterKey() );
 | 
					        MPFileUserManager.get().save( this, getMasterKey() );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ public class MPFileUserManager extends MPUserManager {
 | 
				
			|||||||
            for (final MPMarshalFormat format : MPMarshalFormat.values())
 | 
					            for (final MPMarshalFormat format : MPMarshalFormat.values())
 | 
				
			||||||
                if (userFile.getName().endsWith( format.fileSuffix() ))
 | 
					                if (userFile.getName().endsWith( format.fileSuffix() ))
 | 
				
			||||||
                    try {
 | 
					                    try {
 | 
				
			||||||
                        MPFileUser user         = format.unmarshaller().unmarshall( userFile );
 | 
					                        MPFileUser user         = format.unmarshaller().unmarshall( userFile, null );
 | 
				
			||||||
                        MPFileUser previousUser = users.put( user.getFullName(), user );
 | 
					                        MPFileUser previousUser = users.put( user.getFullName(), user );
 | 
				
			||||||
                        if ((previousUser != null) && (previousUser.getFormat().ordinal() > user.getFormat().ordinal()))
 | 
					                        if ((previousUser != null) && (previousUser.getFormat().ordinal() > user.getFormat().ordinal()))
 | 
				
			||||||
                            users.put( previousUser.getFullName(), previousUser );
 | 
					                            users.put( previousUser.getFullName(), previousUser );
 | 
				
			||||||
@@ -86,6 +86,9 @@ public class MPFileUserManager extends MPUserManager {
 | 
				
			|||||||
                    catch (final IOException | MPMarshalException e) {
 | 
					                    catch (final IOException | MPMarshalException e) {
 | 
				
			||||||
                        logger.err( e, "Couldn't read user from: %s", userFile );
 | 
					                        logger.err( e, "Couldn't read user from: %s", userFile );
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (final MPKeyUnavailableException | MPIncorrectMasterPasswordException e) {
 | 
				
			||||||
 | 
					                        logger.err( e, "Couldn't authenticate user for: %s", userFile );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return users.values();
 | 
					        return users.values();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -117,7 +120,7 @@ public class MPFileUserManager extends MPUserManager {
 | 
				
			|||||||
     * Write the current user state to disk.
 | 
					     * Write the current user state to disk.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void save(final MPFileUser user, final MPMasterKey masterKey)
 | 
					    public void save(final MPFileUser user, final MPMasterKey masterKey)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            final MPMarshalFormat format = user.getFormat();
 | 
					            final MPMarshalFormat format = user.getFormat();
 | 
				
			||||||
            new CharSink() {
 | 
					            new CharSink() {
 | 
				
			||||||
@@ -126,7 +129,7 @@ public class MPFileUserManager extends MPUserManager {
 | 
				
			|||||||
                        throws IOException {
 | 
					                        throws IOException {
 | 
				
			||||||
                    return new OutputStreamWriter( new FileOutputStream( getUserFile( user, format ) ), Charsets.UTF_8 );
 | 
					                    return new OutputStreamWriter( new FileOutputStream( getUserFile( user, format ) ), Charsets.UTF_8 );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }.write( format.marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
 | 
					            }.write( format.marshaller().marshall( user ) );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (final MPMarshalException | IOException e) {
 | 
					        catch (final MPMarshalException | IOException e) {
 | 
				
			||||||
            logger.err( e, "Unable to save sites for user: %s", user );
 | 
					            logger.err( e, "Unable to save sites for user: %s", user );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,11 +36,11 @@ public class MPFlatMarshaller implements MPMarshaller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
 | 
					    public String marshall(final MPFileUser user)
 | 
				
			||||||
            throws MPInvalidatedException, MPMarshalException {
 | 
					            throws MPKeyUnavailableException, MPMarshalException {
 | 
				
			||||||
        StringBuilder content = new StringBuilder();
 | 
					        StringBuilder content = new StringBuilder();
 | 
				
			||||||
        content.append( "# Master Password site export\n" );
 | 
					        content.append( "# Master Password site export\n" );
 | 
				
			||||||
        content.append( "#     " ).append( contentMode.description() ).append( '\n' );
 | 
					        content.append( "#     " ).append( user.getContentMode().description() ).append( '\n' );
 | 
				
			||||||
        content.append( "# \n" );
 | 
					        content.append( "# \n" );
 | 
				
			||||||
        content.append( "##\n" );
 | 
					        content.append( "##\n" );
 | 
				
			||||||
        content.append( "# Format: " ).append( FORMAT ).append( '\n' );
 | 
					        content.append( "# Format: " ).append( FORMAT ).append( '\n' );
 | 
				
			||||||
@@ -51,18 +51,18 @@ public class MPFlatMarshaller implements MPMarshaller {
 | 
				
			|||||||
        content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
 | 
					        content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
 | 
				
			||||||
        content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
 | 
					        content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
 | 
				
			||||||
        content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
 | 
					        content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
 | 
				
			||||||
        content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
 | 
					        content.append( "# Passwords: " ).append( user.getContentMode().name() ).append( '\n' );
 | 
				
			||||||
        content.append( "##\n" );
 | 
					        content.append( "##\n" );
 | 
				
			||||||
        content.append( "#\n" );
 | 
					        content.append( "#\n" );
 | 
				
			||||||
        content.append( "#               Last     Times  Password                      Login\t                     Site\tSite\n" );
 | 
					        content.append( "#               Last     Times  Password                      Login\t                     Site\tSite\n" );
 | 
				
			||||||
        content.append( "#               used      used      type                       name\t                     name\tpassword\n" );
 | 
					        content.append( "#               used      used      type                       name\t                     name\tpassword\n" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (final MPFileSite site : user.getSites()) {
 | 
					        for (final MPFileSite site : user.getSites()) {
 | 
				
			||||||
            String loginName = site.getLoginContent();
 | 
					            String loginName = site.getLoginState();
 | 
				
			||||||
            String password  = site.getSiteContent();
 | 
					            String password  = site.getSiteState();
 | 
				
			||||||
            if (!contentMode.isRedacted()) {
 | 
					            if (!user.getContentMode().isRedacted()) {
 | 
				
			||||||
                loginName = site.loginFor( masterKey );
 | 
					                loginName = site.getLogin();
 | 
				
			||||||
                password = site.resultFor( masterKey );
 | 
					                password = site.getResult();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            content.append( strf( "%s  %8d  %8s  %25s\t%25s\t%s\n", //
 | 
					            content.append( strf( "%s  %8d  %8s  %25s\t%25s\t%s\n", //
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ import java.io.*;
 | 
				
			|||||||
import java.util.regex.Matcher;
 | 
					import java.util.regex.Matcher;
 | 
				
			||||||
import java.util.regex.Pattern;
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
import javax.annotation.Nonnull;
 | 
					import javax.annotation.Nonnull;
 | 
				
			||||||
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
import org.joda.time.DateTime;
 | 
					import org.joda.time.DateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,17 +47,17 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPFileUser unmarshall(@Nonnull final File file)
 | 
					    public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
 | 
				
			||||||
            throws IOException, MPMarshalException {
 | 
					            throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
 | 
				
			||||||
        try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
 | 
					        try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
 | 
				
			||||||
            return unmarshall( CharStreams.toString( reader ) );
 | 
					            return unmarshall( CharStreams.toString( reader ), masterPassword );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPFileUser unmarshall(@Nonnull final String content)
 | 
					    public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
 | 
				
			||||||
            throws MPMarshalException {
 | 
					            throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
 | 
				
			||||||
        MPFileUser   user         = null;
 | 
					        MPFileUser   user         = null;
 | 
				
			||||||
        byte[]       keyID        = null;
 | 
					        byte[]       keyID        = null;
 | 
				
			||||||
        String       fullName     = null;
 | 
					        String       fullName     = null;
 | 
				
			||||||
@@ -74,7 +75,8 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
 | 
				
			|||||||
                else
 | 
					                else
 | 
				
			||||||
                    // Ends the header.
 | 
					                    // Ends the header.
 | 
				
			||||||
                    user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ).getAlgorithm(),
 | 
					                    user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ).getAlgorithm(),
 | 
				
			||||||
                                           avatar, defaultType, new DateTime( 0 ), MPMarshalFormat.Flat );
 | 
					                                           avatar, defaultType, new DateTime( 0 ), MPMarshalFormat.Flat,
 | 
				
			||||||
 | 
					                                           clearContent? MPMarshaller.ContentMode.VISIBLE : MPMarshaller.ContentMode.PROTECTED );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Comment.
 | 
					                // Comment.
 | 
				
			||||||
            else if (line.startsWith( "#" )) {
 | 
					            else if (line.startsWith( "#" )) {
 | 
				
			||||||
@@ -113,25 +115,31 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
 | 
				
			|||||||
                switch (importFormat) {
 | 
					                switch (importFormat) {
 | 
				
			||||||
                    case 0:
 | 
					                    case 0:
 | 
				
			||||||
                        site = new MPFileSite( user, //
 | 
					                        site = new MPFileSite( user, //
 | 
				
			||||||
                                               siteMatcher.group( 5 ), siteMatcher.group( 6 ),
 | 
					                                               siteMatcher.group( 5 ), clearContent? null: siteMatcher.group( 6 ),
 | 
				
			||||||
                                               user.getAlgorithm().mpw_default_counter(),
 | 
					                                               user.getAlgorithm().mpw_default_counter(),
 | 
				
			||||||
                                               MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
 | 
					                                               MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
 | 
				
			||||||
                                               MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
 | 
					                                               MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
 | 
				
			||||||
                                                       colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
 | 
					                                                       colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
 | 
				
			||||||
                                               null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
 | 
					                                               null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
 | 
				
			||||||
                                               MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
 | 
					                                               MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
 | 
				
			||||||
 | 
					                        if (clearContent)
 | 
				
			||||||
 | 
					                            site.setSitePassword( site.getResultType(), siteMatcher.group( 6 ) );
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case 1:
 | 
					                    case 1:
 | 
				
			||||||
                        site = new MPFileSite( user, //
 | 
					                        site = new MPFileSite( user, //
 | 
				
			||||||
                                               siteMatcher.group( 7 ), siteMatcher.group( 8 ),
 | 
					                                               siteMatcher.group( 7 ), clearContent? null: siteMatcher.group( 8 ),
 | 
				
			||||||
                                               UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
 | 
					                                               UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
 | 
				
			||||||
                                               MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
 | 
					                                               MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
 | 
				
			||||||
                                               MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
 | 
					                                               MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
 | 
				
			||||||
                                                       colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
 | 
					                                                       colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
 | 
				
			||||||
                                               siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
 | 
					                                               clearContent? null: siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
 | 
				
			||||||
                                               ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
 | 
					                                               ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
 | 
				
			||||||
                                               MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
 | 
					                                               MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
 | 
				
			||||||
 | 
					                        if (clearContent) {
 | 
				
			||||||
 | 
					                            site.setSitePassword( site.getResultType(), siteMatcher.group( 8 ) );
 | 
				
			||||||
 | 
					                            site.setLoginName( MPResultType.StoredPersonal, siteMatcher.group( 6 ) );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    default:
 | 
					                    default:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,8 +25,6 @@ import java.util.LinkedHashMap;
 | 
				
			|||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
import org.joda.time.Instant;
 | 
					import org.joda.time.Instant;
 | 
				
			||||||
import org.joda.time.format.DateTimeFormatter;
 | 
					 | 
				
			||||||
import org.joda.time.format.ISODateTimeFormat;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -34,74 +32,57 @@ import org.joda.time.format.ISODateTimeFormat;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class MPJSONFile {
 | 
					public class MPJSONFile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTimeNoMillis();
 | 
					    public MPJSONFile(final MPFileUser user)
 | 
				
			||||||
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
    Export export;
 | 
					 | 
				
			||||||
    User   user;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public MPJSONFile(final MPFileUser user, final MPMasterKey masterKey, final MPMarshaller.ContentMode contentMode)
 | 
					 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					 | 
				
			||||||
        //    if (!user.fullName || !strlen( user.fullName )) {
 | 
					 | 
				
			||||||
        //        *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
 | 
					 | 
				
			||||||
        //        return false;
 | 
					 | 
				
			||||||
        //    }
 | 
					 | 
				
			||||||
        //    if (!user.masterPassword || !strlen( user.masterPassword )) {
 | 
					 | 
				
			||||||
        //        *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
 | 
					 | 
				
			||||||
        //        return false;
 | 
					 | 
				
			||||||
        //    }
 | 
					 | 
				
			||||||
        //    if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user.algorithm, user.fullName, user.masterPassword )) {
 | 
					 | 
				
			||||||
        //        *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
 | 
					 | 
				
			||||||
        //        return false;
 | 
					 | 
				
			||||||
        //    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Section: "export"
 | 
					        // Section: "export"
 | 
				
			||||||
        Export fileExport = this.export = new Export();
 | 
					        Export fileExport = this.export = new Export();
 | 
				
			||||||
        fileExport.format = 1;
 | 
					        fileExport.format = 1;
 | 
				
			||||||
        fileExport.redacted = contentMode.isRedacted();
 | 
					        fileExport.redacted = user.getContentMode().isRedacted();
 | 
				
			||||||
        fileExport.date = dateFormatter.print( new Instant() );
 | 
					        fileExport.date = MPConstant.dateTimeFormatter.print( new Instant() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Section: "user"
 | 
					        // Section: "user"
 | 
				
			||||||
        User fileUser = this.user = new User();
 | 
					        User fileUser = this.user = new User();
 | 
				
			||||||
        fileUser.avatar = user.getAvatar();
 | 
					        fileUser.avatar = user.getAvatar();
 | 
				
			||||||
        fileUser.fullName = user.getFullName();
 | 
					        fileUser.full_name = user.getFullName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fileUser.lastUsed = dateFormatter.print( user.getLastUsed() );
 | 
					        fileUser.last_used = MPConstant.dateTimeFormatter.print( user.getLastUsed() );
 | 
				
			||||||
        fileUser.keyId = CodeUtils.encodeHex( masterKey.getKeyID( user.getAlgorithm() ) );
 | 
					        fileUser.key_id = CodeUtils.encodeHex( user.getKeyID() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fileUser.algorithm = user.getAlgorithm().version();
 | 
					        fileUser.algorithm = user.getAlgorithm().version();
 | 
				
			||||||
        fileUser.defaultType = user.getDefaultType();
 | 
					        fileUser.default_type = user.getDefaultType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Section "sites"
 | 
					        // Section "sites"
 | 
				
			||||||
        fileUser.sites = new LinkedHashMap<>();
 | 
					        sites = new LinkedHashMap<>();
 | 
				
			||||||
        for (final MPFileSite site : user.getSites()) {
 | 
					        for (final MPFileSite site : user.getSites()) {
 | 
				
			||||||
            Site   fileSite;
 | 
					            Site   fileSite;
 | 
				
			||||||
            String content = null, loginContent = null;
 | 
					            String content = null, loginContent = null;
 | 
				
			||||||
            if (!contentMode.isRedacted()) {
 | 
					            if (!fileExport.redacted) {
 | 
				
			||||||
                // Clear Text
 | 
					                // Clear Text
 | 
				
			||||||
                content = masterKey.siteResult( site.getSiteName(), site.getSiteCounter(),
 | 
					                content = site.getResult();
 | 
				
			||||||
                                                MPKeyPurpose.Authentication, null, site.getResultType(), site.getSiteContent(),
 | 
					                loginContent = user.getMasterKey().siteResult(
 | 
				
			||||||
                                                site.getAlgorithm() );
 | 
					                        site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
 | 
				
			||||||
                loginContent = masterKey.siteResult( site.getSiteName(), site.getAlgorithm().mpw_default_counter(),
 | 
					                        MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginState(), site.getAlgorithm() );
 | 
				
			||||||
                                                     MPKeyPurpose.Identification, null, site.getLoginType(), site.getLoginContent(),
 | 
					 | 
				
			||||||
                                                     site.getAlgorithm() );
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // Redacted
 | 
					                // Redacted
 | 
				
			||||||
                if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
 | 
					                if (site.getResultType().supportsTypeFeature( MPSiteFeature.ExportContent ))
 | 
				
			||||||
                    content = site.getSiteContent();
 | 
					                    content = site.getSiteState();
 | 
				
			||||||
                if (site.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
 | 
					                if (site.getLoginType().supportsTypeFeature( MPSiteFeature.ExportContent ))
 | 
				
			||||||
                    loginContent = site.getLoginContent();
 | 
					                    loginContent = site.getLoginState();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fileUser.sites.put( site.getSiteName(), fileSite = new Site() );
 | 
					            sites.put( site.getSiteName(), fileSite = new Site() );
 | 
				
			||||||
            fileSite.type = site.getResultType();
 | 
					            fileSite.type = site.getResultType();
 | 
				
			||||||
            fileSite.counter = site.getSiteCounter();
 | 
					            fileSite.counter = site.getSiteCounter().longValue();
 | 
				
			||||||
            fileSite.algorithm = site.getAlgorithm().version();
 | 
					            fileSite.algorithm = site.getAlgorithm().version();
 | 
				
			||||||
            fileSite.password = content;
 | 
					            fileSite.password = content;
 | 
				
			||||||
            fileSite.login_name = loginContent;
 | 
					            fileSite.login_name = loginContent;
 | 
				
			||||||
            fileSite.loginType = site.getLoginType();
 | 
					            fileSite.login_type = site.getLoginType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fileSite.uses = site.getUses();
 | 
					            fileSite.uses = site.getUses();
 | 
				
			||||||
            fileSite.lastUsed = dateFormatter.print( site.getLastUsed() );
 | 
					            fileSite.last_used = MPConstant.dateTimeFormatter.print( site.getLastUsed() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fileSite._ext_mpw = new Site.Ext();
 | 
				
			||||||
 | 
					            fileSite._ext_mpw.url = site.getUrl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fileSite.questions = new LinkedHashMap<>();
 | 
					            fileSite.questions = new LinkedHashMap<>();
 | 
				
			||||||
            //                for (size_t q = 0; q < site.questions_count; ++q) {
 | 
					            //                for (size_t q = 0; q < site.questions_count; ++q) {
 | 
				
			||||||
@@ -133,10 +114,44 @@ public class MPJSONFile {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MPFileUser toUser() {
 | 
					    public MPFileUser toUser(@Nullable final char[] masterPassword)
 | 
				
			||||||
        return new MPFileUser( user.fullName, CodeUtils.decodeHex( user.keyId ), user.algorithm.getAlgorithm(), user.avatar, user.defaultType, dateFormatter.parseDateTime( user.lastUsed ), MPMarshalFormat.JSON );
 | 
					            throws MPIncorrectMasterPasswordException, MPKeyUnavailableException {
 | 
				
			||||||
 | 
					        MPFileUser user = new MPFileUser(
 | 
				
			||||||
 | 
					                this.user.full_name, CodeUtils.decodeHex( this.user.key_id ), this.user.algorithm.getAlgorithm(),
 | 
				
			||||||
 | 
					                this.user.avatar, this.user.default_type, MPConstant.dateTimeFormatter.parseDateTime( this.user.last_used ),
 | 
				
			||||||
 | 
					                MPMarshalFormat.JSON, export.redacted? MPMarshaller.ContentMode.PROTECTED: MPMarshaller.ContentMode.VISIBLE );
 | 
				
			||||||
 | 
					        if (masterPassword != null)
 | 
				
			||||||
 | 
					            user.authenticate( masterPassword );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (final Map.Entry<String, Site> siteEntry : sites.entrySet()) {
 | 
				
			||||||
 | 
					            String siteName = siteEntry.getKey();
 | 
				
			||||||
 | 
					            Site   fileSite = siteEntry.getValue();
 | 
				
			||||||
 | 
					            MPFileSite site = new MPFileSite(
 | 
				
			||||||
 | 
					                    user, siteName, export.redacted? fileSite.password: null, UnsignedInteger.valueOf( fileSite.counter ),
 | 
				
			||||||
 | 
					                    fileSite.type, fileSite.algorithm.getAlgorithm(),
 | 
				
			||||||
 | 
					                    export.redacted? fileSite.login_name: null, fileSite.login_type,
 | 
				
			||||||
 | 
					                    fileSite._ext_mpw.url, fileSite.uses, MPConstant.dateTimeFormatter.parseDateTime( fileSite.last_used ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!export.redacted) {
 | 
				
			||||||
 | 
					                if (fileSite.password != null)
 | 
				
			||||||
 | 
					                    site.setSitePassword( fileSite.type, fileSite.password );
 | 
				
			||||||
 | 
					                if (fileSite.login_name != null)
 | 
				
			||||||
 | 
					                    site.setLoginName( fileSite.login_type, fileSite.login_name );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            user.addSite( site );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return user;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // -- Data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Export            export;
 | 
				
			||||||
 | 
					    User              user;
 | 
				
			||||||
 | 
					    Map<String, Site> sites;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static class Export {
 | 
					    public static class Export {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int     format;
 | 
					        int     format;
 | 
				
			||||||
@@ -147,47 +162,44 @@ public class MPJSONFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public static class User {
 | 
					    public static class User {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        String              fullName;
 | 
					        int                 avatar;
 | 
				
			||||||
 | 
					        String              full_name;
 | 
				
			||||||
 | 
					        String              last_used;
 | 
				
			||||||
 | 
					        String              key_id;
 | 
				
			||||||
        MPMasterKey.Version algorithm;
 | 
					        MPMasterKey.Version algorithm;
 | 
				
			||||||
        boolean             redacted;
 | 
					        MPResultType        default_type;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        int          avatar;
 | 
					 | 
				
			||||||
        MPResultType defaultType;
 | 
					 | 
				
			||||||
        String       lastUsed;
 | 
					 | 
				
			||||||
        String       keyId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Map<String, Site> sites;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static class Site {
 | 
					    public static class Site {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MPResultType        type;
 | 
				
			||||||
 | 
					        long                counter;
 | 
				
			||||||
 | 
					        MPMasterKey.Version algorithm;
 | 
				
			||||||
        @Nullable
 | 
					        @Nullable
 | 
				
			||||||
        String password;
 | 
					        String password;
 | 
				
			||||||
        @Nullable
 | 
					        @Nullable
 | 
				
			||||||
        String login_name;
 | 
					        String login_name;
 | 
				
			||||||
        String              name;
 | 
					        MPResultType login_type;
 | 
				
			||||||
        String              content;
 | 
					        int          uses;
 | 
				
			||||||
        MPResultType        type;
 | 
					        String       last_used;
 | 
				
			||||||
        UnsignedInteger     counter;
 | 
					 | 
				
			||||||
        MPMasterKey.Version algorithm;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String       loginContent;
 | 
					 | 
				
			||||||
        MPResultType loginType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        String url;
 | 
					 | 
				
			||||||
        int    uses;
 | 
					 | 
				
			||||||
        String lastUsed;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Map<String, Question> questions;
 | 
					        Map<String, Question> questions;
 | 
				
			||||||
    }
 | 
					
 | 
				
			||||||
 | 
					        Ext _ext_mpw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static class Question {
 | 
					        public static class Ext {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        String       keyword;
 | 
					            @Nullable
 | 
				
			||||||
        String       content;
 | 
					            String url;
 | 
				
			||||||
        MPResultType type;
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static class Question {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            MPResultType type;
 | 
				
			||||||
 | 
					            String       answer;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,14 +31,14 @@ public class MPJSONMarshaller implements MPMarshaller {
 | 
				
			|||||||
    private final Gson gson = new GsonBuilder()
 | 
					    private final Gson gson = new GsonBuilder()
 | 
				
			||||||
            .registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
 | 
					            .registerTypeAdapter( MPMasterKey.Version.class, new EnumOrdinalAdapter() )
 | 
				
			||||||
            .registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
 | 
					            .registerTypeAdapter( MPResultType.class, new MPResultTypeAdapter() )
 | 
				
			||||||
            .setFieldNamingStrategy( FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
 | 
					            .setFieldNamingStrategy( FieldNamingPolicy.IDENTITY )
 | 
				
			||||||
            .setPrettyPrinting().create();
 | 
					            .setPrettyPrinting().create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
 | 
					    public String marshall(final MPFileUser user)
 | 
				
			||||||
            throws MPInvalidatedException, MPMarshalException {
 | 
					            throws MPKeyUnavailableException, MPMarshalException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return gson.toJson( new MPJSONFile( user, masterKey, contentMode ) );
 | 
					        return gson.toJson( new MPJSONFile( user ) );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,11 +19,11 @@
 | 
				
			|||||||
package com.lyndir.masterpassword.model;
 | 
					package com.lyndir.masterpassword.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.*;
 | 
					import com.google.gson.*;
 | 
				
			||||||
import com.lyndir.masterpassword.MPMasterKey;
 | 
					import com.lyndir.masterpassword.*;
 | 
				
			||||||
import com.lyndir.masterpassword.MPResultType;
 | 
					 | 
				
			||||||
import java.io.*;
 | 
					import java.io.*;
 | 
				
			||||||
import java.nio.charset.StandardCharsets;
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
import javax.annotation.Nonnull;
 | 
					import javax.annotation.Nonnull;
 | 
				
			||||||
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -39,19 +39,29 @@ public class MPJSONUnmarshaller implements MPUnmarshaller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPFileUser unmarshall(@Nonnull final File file)
 | 
					    public MPFileUser unmarshall(@Nonnull final File file, @Nullable final char[] masterPassword)
 | 
				
			||||||
            throws IOException, MPMarshalException {
 | 
					            throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try (Reader reader = new InputStreamReader( new FileInputStream( file ), StandardCharsets.UTF_8 )) {
 | 
					        try (Reader reader = new InputStreamReader( new FileInputStream( file ), StandardCharsets.UTF_8 )) {
 | 
				
			||||||
            return gson.fromJson( reader, MPJSONFile.class ).toUser();
 | 
					            try {
 | 
				
			||||||
 | 
					                return gson.fromJson( reader, MPJSONFile.class ).toUser( masterPassword );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (final JsonSyntaxException e) {
 | 
				
			||||||
 | 
					                throw new MPMarshalException( "Couldn't parse JSON in: " + file, e );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPFileUser unmarshall(@Nonnull final String content)
 | 
					    public MPFileUser unmarshall(@Nonnull final String content, @Nullable final char[] masterPassword)
 | 
				
			||||||
            throws MPMarshalException {
 | 
					            throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return gson.fromJson( content, MPJSONFile.class ).toUser();
 | 
					        try {
 | 
				
			||||||
 | 
					            return gson.fromJson( content, MPJSONFile.class ).toUser( masterPassword );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (final JsonSyntaxException e) {
 | 
				
			||||||
 | 
					            throw new MPMarshalException( "Couldn't parse JSON", e );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.lyndir.masterpassword.model;
 | 
					package com.lyndir.masterpassword.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.lyndir.masterpassword.MPInvalidatedException;
 | 
					import com.lyndir.masterpassword.MPKeyUnavailableException;
 | 
				
			||||||
import com.lyndir.masterpassword.MPMasterKey;
 | 
					 | 
				
			||||||
import javax.annotation.Nonnull;
 | 
					import javax.annotation.Nonnull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,8 +28,8 @@ import javax.annotation.Nonnull;
 | 
				
			|||||||
public interface MPMarshaller {
 | 
					public interface MPMarshaller {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    String marshall(MPFileUser user, MPMasterKey masterKey, ContentMode contentMode)
 | 
					    String marshall(MPFileUser user)
 | 
				
			||||||
            throws MPInvalidatedException, MPMarshalException;
 | 
					            throws MPKeyUnavailableException, MPMarshalException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum ContentMode {
 | 
					    enum ContentMode {
 | 
				
			||||||
        PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
 | 
					        PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ import javax.annotation.Nullable;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class MPSite {
 | 
					public abstract class MPSite {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public abstract MPUser<?> getUser();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public abstract String getSiteName();
 | 
					    public abstract String getSiteName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public abstract void setSiteName(String siteName);
 | 
					    public abstract void setSiteName(String siteName);
 | 
				
			||||||
@@ -43,24 +45,28 @@ public abstract class MPSite {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public abstract void setResultType(MPResultType resultType);
 | 
					    public abstract void setResultType(MPResultType resultType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public abstract MPResultType getLoginType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public abstract void setLoginType(@Nullable MPResultType loginType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public abstract MPAlgorithm getAlgorithm();
 | 
					    public abstract MPAlgorithm getAlgorithm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public abstract void setAlgorithm(MPAlgorithm algorithm);
 | 
					    public abstract void setAlgorithm(MPAlgorithm algorithm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
					    public String getResult(final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
 | 
				
			||||||
                            @Nullable final String siteContent)
 | 
					                            @Nullable final String siteContent)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return masterKey.siteResult(
 | 
					        return getUser().getMasterKey().siteResult(
 | 
				
			||||||
                getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
 | 
					                getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
 | 
					    public String getLogin(@Nullable final String loginContent)
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return masterKey.siteResult(
 | 
					        return getUser().getMasterKey().siteResult(
 | 
				
			||||||
                getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null, loginType, loginContent,
 | 
					                getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null,
 | 
				
			||||||
                getAlgorithm() );
 | 
					                getLoginType(), loginContent, getAlgorithm() );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,9 +18,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.lyndir.masterpassword.model;
 | 
					package com.lyndir.masterpassword.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.lyndir.masterpassword.MPKeyUnavailableException;
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import javax.annotation.Nonnull;
 | 
					import javax.annotation.Nonnull;
 | 
				
			||||||
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -29,10 +31,10 @@ import javax.annotation.Nonnull;
 | 
				
			|||||||
public interface MPUnmarshaller {
 | 
					public interface MPUnmarshaller {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    MPFileUser unmarshall(@Nonnull File file)
 | 
					    MPFileUser unmarshall(@Nonnull File file, @Nullable char[] masterPassword)
 | 
				
			||||||
            throws IOException, MPMarshalException;
 | 
					            throws IOException, MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    MPFileUser unmarshall(@Nonnull String content)
 | 
					    MPFileUser unmarshall(@Nonnull String content, @Nullable char[] masterPassword)
 | 
				
			||||||
            throws MPMarshalException;
 | 
					            throws MPMarshalException, MPIncorrectMasterPasswordException, MPKeyUnavailableException;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,6 @@ package com.lyndir.masterpassword.model;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
					import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.common.base.Preconditions;
 | 
					 | 
				
			||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
 | 
					import com.lyndir.lhunath.opal.system.CodeUtils;
 | 
				
			||||||
import com.lyndir.masterpassword.*;
 | 
					import com.lyndir.masterpassword.*;
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
@@ -44,12 +43,16 @@ public abstract class MPUser<S extends MPSite> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    public MPMasterKey getMasterKey() {
 | 
					    public MPMasterKey getMasterKey()
 | 
				
			||||||
        return Preconditions.checkNotNull( key, "User is not authenticated: %s", getFullName() );
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
 | 
					        if (key == null)
 | 
				
			||||||
 | 
					            throw new MPKeyUnavailableException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return key;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public String exportKeyID()
 | 
					    public String exportKeyID()
 | 
				
			||||||
            throws MPInvalidatedException {
 | 
					            throws MPKeyUnavailableException {
 | 
				
			||||||
        return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
 | 
					        return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,7 @@ public class MPMasterKeyTest {
 | 
				
			|||||||
                    masterKey.getKeyID( testCase.getAlgorithm() );
 | 
					                    masterKey.getKeyID( testCase.getAlgorithm() );
 | 
				
			||||||
                    fail( "[testMasterKey] invalidate ineffective: " + testCase );
 | 
					                    fail( "[testMasterKey] invalidate ineffective: " + testCase );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (final MPInvalidatedException ignored) {
 | 
					                catch (final MPKeyUnavailableException ignored) {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                assertNotEquals(
 | 
					                assertNotEquals(
 | 
				
			||||||
                        masterPassword,
 | 
					                        masterPassword,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.lyndir.masterpassword;
 | 
					package com.lyndir.masterpassword;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.lyndir.masterpassword.model.MPJSONUnmarshaller;
 | 
					import com.google.common.base.Charsets;
 | 
				
			||||||
import java.io.File;
 | 
					import com.google.common.io.CharStreams;
 | 
				
			||||||
 | 
					import com.lyndir.masterpassword.model.*;
 | 
				
			||||||
 | 
					import java.io.*;
 | 
				
			||||||
 | 
					import org.testng.Assert;
 | 
				
			||||||
import org.testng.annotations.Test;
 | 
					import org.testng.annotations.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,7 +34,12 @@ public class MPModelTest {
 | 
				
			|||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    public void testMasterKey()
 | 
					    public void testMasterKey()
 | 
				
			||||||
            throws Exception {
 | 
					            throws Exception {
 | 
				
			||||||
        System.err.println( new MPJSONUnmarshaller().unmarshall(
 | 
					        File       file   = new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" );
 | 
				
			||||||
                new File( "/Users/lhunath/.mpw.d/Maarten Billemont.mpsites.json" ) ) );
 | 
					        String     orig   = CharStreams.toString( new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 ) );
 | 
				
			||||||
 | 
					        System.out.println(orig);
 | 
				
			||||||
 | 
					        MPFileUser user   = new MPJSONUnmarshaller().unmarshall( file, null );
 | 
				
			||||||
 | 
					        String     result = new MPJSONMarshaller().marshall( user );
 | 
				
			||||||
 | 
					        System.out.println(result);
 | 
				
			||||||
 | 
					        Assert.assertEquals( result, orig, "Marshalled sites do not match original sites." );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -316,7 +316,7 @@ public class EmergencyActivity extends Activity {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    } );
 | 
					                    } );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (final MPInvalidatedException ignored) {
 | 
					                catch (final MPKeyUnavailableException ignored) {
 | 
				
			||||||
                    sitePasswordField.setText( "" );
 | 
					                    sitePasswordField.setText( "" );
 | 
				
			||||||
                    progressView.setVisibility( View.INVISIBLE );
 | 
					                    progressView.setVisibility( View.INVISIBLE );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -148,7 +148,7 @@ public final class Preferences {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Nonnull
 | 
					    @Nonnull
 | 
				
			||||||
    public MPResultType getDefaultResultType() {
 | 
					    public MPResultType getDefaultResultType() {
 | 
				
			||||||
        return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_type().ordinal() )];
 | 
					        return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_password_type().ordinal() )];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean setDefaultVersion(final MPMasterKey.Version value) {
 | 
					    public boolean setDefaultVersion(final MPMasterKey.Version value) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package com.lyndir.masterpassword.gui.model;
 | 
					package com.lyndir.masterpassword.gui.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.common.primitives.UnsignedInteger;
 | 
					import com.google.common.primitives.UnsignedInteger;
 | 
				
			||||||
import com.lyndir.masterpassword.MPAlgorithm;
 | 
					import com.lyndir.masterpassword.MPAlgorithm;
 | 
				
			||||||
import com.lyndir.masterpassword.MPResultType;
 | 
					import com.lyndir.masterpassword.MPResultType;
 | 
				
			||||||
import com.lyndir.masterpassword.model.MPSite;
 | 
					import com.lyndir.masterpassword.model.MPSite;
 | 
				
			||||||
 | 
					import com.lyndir.masterpassword.model.MPUser;
 | 
				
			||||||
 | 
					import javax.annotation.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -29,19 +33,28 @@ import com.lyndir.masterpassword.model.MPSite;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public class IncognitoSite extends MPSite {
 | 
					public class IncognitoSite extends MPSite {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final IncognitoUser user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private String          siteName;
 | 
					    private String          siteName;
 | 
				
			||||||
    private UnsignedInteger siteCounter;
 | 
					    private UnsignedInteger siteCounter;
 | 
				
			||||||
    private MPResultType    resultType;
 | 
					    private MPResultType    resultType;
 | 
				
			||||||
 | 
					    private MPResultType loginType;
 | 
				
			||||||
    private MPAlgorithm     algorithm;
 | 
					    private MPAlgorithm     algorithm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
 | 
					    public IncognitoSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
 | 
				
			||||||
                         final MPAlgorithm algorithm) {
 | 
					                         final MPAlgorithm algorithm) {
 | 
				
			||||||
 | 
					        this.user = user;
 | 
				
			||||||
        this.siteName = siteName;
 | 
					        this.siteName = siteName;
 | 
				
			||||||
        this.siteCounter = siteCounter;
 | 
					        this.siteCounter = siteCounter;
 | 
				
			||||||
        this.resultType = resultType;
 | 
					        this.resultType = resultType;
 | 
				
			||||||
        this.algorithm = algorithm;
 | 
					        this.algorithm = algorithm;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public MPUser<?> getUser() {
 | 
				
			||||||
 | 
					        return user;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public String getSiteName() {
 | 
					    public String getSiteName() {
 | 
				
			||||||
        return siteName;
 | 
					        return siteName;
 | 
				
			||||||
@@ -62,6 +75,16 @@ public class IncognitoSite extends MPSite {
 | 
				
			|||||||
        this.resultType = resultType;
 | 
					        this.resultType = resultType;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public MPResultType getLoginType() {
 | 
				
			||||||
 | 
					        return loginType;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setLoginType(@Nullable final MPResultType loginType) {
 | 
				
			||||||
 | 
					        this.loginType = ifNotNullElse( loginType, getAlgorithm().mpw_default_login_type() );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public MPAlgorithm getAlgorithm() {
 | 
					    public MPAlgorithm getAlgorithm() {
 | 
				
			||||||
        return algorithm;
 | 
					        return algorithm;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,9 +86,8 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel<IncognitoU
 | 
				
			|||||||
        return new PasswordFrame<IncognitoUser, IncognitoSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
 | 
					        return new PasswordFrame<IncognitoUser, IncognitoSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
 | 
				
			||||||
            @Override
 | 
					            @Override
 | 
				
			||||||
            protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
 | 
					            protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
 | 
				
			||||||
                                               final MPResultType resultType,
 | 
					                                               final MPResultType resultType, final MPAlgorithm algorithm) {
 | 
				
			||||||
                                               final MPAlgorithm algorithm) {
 | 
					                return new IncognitoSite( user, siteName, siteCounter, resultType, algorithm );
 | 
				
			||||||
                return new IncognitoSite( siteName, siteCounter, resultType, algorithm );
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
 | 
				
			|||||||
                                                        siteCounterField = Components.spinner( siteCounterModel ) );
 | 
					                                                        siteCounterField = Components.spinner( siteCounterModel ) );
 | 
				
			||||||
        sitePanel.add( siteSettings );
 | 
					        sitePanel.add( siteSettings );
 | 
				
			||||||
        resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) );
 | 
					        resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) );
 | 
				
			||||||
        resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_type() );
 | 
					        resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_password_type() );
 | 
				
			||||||
        resultTypeField.addItemListener( new ItemListener() {
 | 
					        resultTypeField.addItemListener( new ItemListener() {
 | 
				
			||||||
            @Override
 | 
					            @Override
 | 
				
			||||||
            public void itemStateChanged(final ItemEvent e) {
 | 
					            public void itemStateChanged(final ItemEvent e) {
 | 
				
			||||||
 
 | 
				
			|||||||
 Submodule public/site updated: e886da7af0...54bd876ed6
									
								
							
		Reference in New Issue
	
	Block a user