Fix warnings and inspections.
This commit is contained in:
		@@ -18,7 +18,6 @@
 | 
			
		||||
 | 
			
		||||
package com.lyndir.masterpassword;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Charsets;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.MessageDigests;
 | 
			
		||||
@@ -30,25 +29,28 @@ import javax.annotation.Nullable;
 | 
			
		||||
/**
 | 
			
		||||
 * @see MPMasterKey.Version
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention" })
 | 
			
		||||
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" })
 | 
			
		||||
public abstract class MPAlgorithm {
 | 
			
		||||
 | 
			
		||||
    public abstract byte[] masterKey(String fullName, char[] masterPassword);
 | 
			
		||||
 | 
			
		||||
    public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
 | 
			
		||||
                   @Nullable String keyContext);
 | 
			
		||||
    public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter,
 | 
			
		||||
                                   MPKeyPurpose keyPurpose, @Nullable String keyContext);
 | 
			
		||||
 | 
			
		||||
    public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
 | 
			
		||||
                      @Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
    public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
 | 
			
		||||
                                      MPKeyPurpose keyPurpose, @Nullable String keyContext,
 | 
			
		||||
                                      MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
 | 
			
		||||
    public abstract String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
    public abstract String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey,
 | 
			
		||||
                                                    MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
 | 
			
		||||
    public abstract String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
 | 
			
		||||
    public abstract String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
 | 
			
		||||
 | 
			
		||||
    public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
 | 
			
		||||
                     @Nullable String keyContext, MPResultType resultType, String resultParam);
 | 
			
		||||
    public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
 | 
			
		||||
                                     MPKeyPurpose keyPurpose, @Nullable String keyContext,
 | 
			
		||||
                                     MPResultType resultType, String resultParam);
 | 
			
		||||
 | 
			
		||||
    // Configuration
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,10 +47,10 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
 | 
			
		||||
        // Calculate the master key.
 | 
			
		||||
        logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
 | 
			
		||||
                    scrypt_N(), scrypt_r(), scrypt_p() );
 | 
			
		||||
        byte[] mpBytes   = toBytes( masterPassword );
 | 
			
		||||
        byte[] masterKey = scrypt( masterKeySalt, mpBytes );
 | 
			
		||||
        byte[] masterPasswordBytes = toBytes( masterPassword );
 | 
			
		||||
        byte[] masterKey           = scrypt( masterKeySalt, masterPasswordBytes );
 | 
			
		||||
        Arrays.fill( masterKeySalt, (byte) 0 );
 | 
			
		||||
        Arrays.fill( mpBytes, (byte) 0 );
 | 
			
		||||
        Arrays.fill( masterPasswordBytes, (byte) 0 );
 | 
			
		||||
        logger.trc( "  => masterKey.id: %s", CodeUtils.encodeHex( toID( masterKey ) ) );
 | 
			
		||||
 | 
			
		||||
        return masterKey;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Charsets;
 | 
			
		||||
import com.google.common.primitives.UnsignedBytes;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import java.nio.*;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,8 @@ package com.lyndir.masterpassword;
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jetbrains.annotations.Contract;
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +32,7 @@ import org.jetbrains.annotations.Contract;
 | 
			
		||||
 *
 | 
			
		||||
 * @author lhunath
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("RedundantTypeArguments" /* IDEA-191043 */)
 | 
			
		||||
@SuppressWarnings({ "RedundantTypeArguments", "SpellCheckingInspection" })
 | 
			
		||||
public enum MPResultType {
 | 
			
		||||
    // bit 0-3 | MPResultTypeClass | MPSiteFeature
 | 
			
		||||
 | 
			
		||||
@@ -130,11 +131,11 @@ public enum MPResultType {
 | 
			
		||||
 | 
			
		||||
    static final Logger logger = Logger.get( MPResultType.class );
 | 
			
		||||
 | 
			
		||||
    private final String             shortName;
 | 
			
		||||
    private final String             description;
 | 
			
		||||
    private final List<MPTemplate>   templates;
 | 
			
		||||
    private final MPResultTypeClass  typeClass;
 | 
			
		||||
    private final int                typeIndex;
 | 
			
		||||
    private final String                      shortName;
 | 
			
		||||
    private final String                      description;
 | 
			
		||||
    private final List<MPTemplate>            templates;
 | 
			
		||||
    private final MPResultTypeClass           typeClass;
 | 
			
		||||
    private final int                         typeIndex;
 | 
			
		||||
    private final ImmutableSet<MPSiteFeature> typeFeatures;
 | 
			
		||||
 | 
			
		||||
    MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
 | 
			
		||||
@@ -167,7 +168,7 @@ public enum MPResultType {
 | 
			
		||||
        return typeClass;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */ )
 | 
			
		||||
    @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */)
 | 
			
		||||
    public ImmutableSet<MPSiteFeature> getTypeFeatures() {
 | 
			
		||||
 | 
			
		||||
        return typeFeatures;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NonNls;
 | 
			
		||||
 *
 | 
			
		||||
 * @author lhunath
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings({ "HardcodedFileSeparator", "SpellCheckingInspection" })
 | 
			
		||||
public enum MPTemplateCharacterClass {
 | 
			
		||||
 | 
			
		||||
    UpperVowel( 'V', "AEIOU" ),
 | 
			
		||||
 
 | 
			
		||||
@@ -29,13 +29,13 @@ import org.joda.time.Instant;
 | 
			
		||||
 */
 | 
			
		||||
public class MPFileSite extends MPSite {
 | 
			
		||||
 | 
			
		||||
    private final MPFileUser          user;
 | 
			
		||||
    private       String              siteName;
 | 
			
		||||
    private final MPFileUser      user;
 | 
			
		||||
    private       String          siteName;
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private       String              siteContent;
 | 
			
		||||
    private       UnsignedInteger     siteCounter;
 | 
			
		||||
    private       MPResultType        resultType;
 | 
			
		||||
    private       MPAlgorithm algorithm;
 | 
			
		||||
    private       String          siteContent;
 | 
			
		||||
    private       UnsignedInteger siteCounter;
 | 
			
		||||
    private       MPResultType    resultType;
 | 
			
		||||
    private       MPAlgorithm     algorithm;
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private String       loginContent;
 | 
			
		||||
@@ -122,14 +122,15 @@ public class MPFileSite extends MPSite {
 | 
			
		||||
        return siteContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSitePassword(final MPMasterKey masterKey, @Nullable final MPResultType resultType, @Nullable final String result)
 | 
			
		||||
    public void setSitePassword(final MPMasterKey masterKey, final MPResultType resultType, @Nullable final String result)
 | 
			
		||||
            throws MPInvalidatedException {
 | 
			
		||||
        this.resultType = resultType;
 | 
			
		||||
 | 
			
		||||
        if (result == null)
 | 
			
		||||
            this.siteContent = null;
 | 
			
		||||
        else
 | 
			
		||||
            this.siteContent = masterKey.siteState(
 | 
			
		||||
                    getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, algorithm );
 | 
			
		||||
                    siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ import org.joda.time.ReadableInstant;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 14-12-07
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
 | 
			
		||||
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("UnusedDeclaration")
 | 
			
		||||
@@ -41,9 +42,9 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
 | 
			
		||||
    private final Collection<MPFileSite> sites = Sets.newHashSet();
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private byte[]              keyID;
 | 
			
		||||
    private MPAlgorithm algorithm;
 | 
			
		||||
    private MPMarshalFormat     format;
 | 
			
		||||
    private byte[]          keyID;
 | 
			
		||||
    private MPAlgorithm     algorithm;
 | 
			
		||||
    private MPMarshalFormat format;
 | 
			
		||||
 | 
			
		||||
    private int             avatar;
 | 
			
		||||
    private MPResultType    defaultType;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@ import javax.annotation.Nonnull;
 | 
			
		||||
 *
 | 
			
		||||
 * @author lhunath, 14-12-07
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("CallToSystemGetenv")
 | 
			
		||||
public class MPFileUserManager extends MPUserManager {
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("UnusedDeclaration")
 | 
			
		||||
@@ -50,21 +51,20 @@ public class MPFileUserManager extends MPUserManager {
 | 
			
		||||
            instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final File userFilesDirectory;
 | 
			
		||||
    private final File path;
 | 
			
		||||
 | 
			
		||||
    public static MPFileUserManager get() {
 | 
			
		||||
        MPUserManager.instance = instance;
 | 
			
		||||
        return instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static MPFileUserManager create(final File userFilesDirectory) {
 | 
			
		||||
        return new MPFileUserManager( userFilesDirectory );
 | 
			
		||||
    public static MPFileUserManager create(final File path) {
 | 
			
		||||
        return new MPFileUserManager( path );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected MPFileUserManager(final File userFilesDirectory) {
 | 
			
		||||
    protected MPFileUserManager(final File path) {
 | 
			
		||||
 | 
			
		||||
        super( unmarshallUsers( userFilesDirectory ) );
 | 
			
		||||
        this.userFilesDirectory = userFilesDirectory;
 | 
			
		||||
        super( unmarshallUsers( path ) );
 | 
			
		||||
        this.path = path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Iterable<MPFileUser> unmarshallUsers(final File userFilesDirectory) {
 | 
			
		||||
@@ -76,7 +76,7 @@ public class MPFileUserManager extends MPUserManager {
 | 
			
		||||
        Map<String, MPFileUser> users = new HashMap<>();
 | 
			
		||||
        for (final File userFile : listUserFiles( userFilesDirectory ))
 | 
			
		||||
            for (final MPMarshalFormat format : MPMarshalFormat.values())
 | 
			
		||||
                if (userFile.getName().endsWith( '.' + format.fileExtension() ))
 | 
			
		||||
                if (userFile.getName().endsWith( format.fileSuffix() ))
 | 
			
		||||
                    try {
 | 
			
		||||
                        MPFileUser user         = format.unmarshaller().unmarshall( userFile );
 | 
			
		||||
                        MPFileUser previousUser = users.put( user.getFullName(), user );
 | 
			
		||||
@@ -95,7 +95,7 @@ public class MPFileUserManager extends MPUserManager {
 | 
			
		||||
            @Override
 | 
			
		||||
            public boolean accept(final File dir, final String name) {
 | 
			
		||||
                for (final MPMarshalFormat format : MPMarshalFormat.values())
 | 
			
		||||
                    if (name.endsWith( '.' + format.fileExtension() ))
 | 
			
		||||
                    if (name.endsWith( format.fileSuffix() ))
 | 
			
		||||
                        return true;
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
@@ -134,13 +134,13 @@ public class MPFileUserManager extends MPUserManager {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private File getUserFile(final MPFileUser user) {
 | 
			
		||||
        return new File( userFilesDirectory, user.getFullName() + ".mpsites" );
 | 
			
		||||
        return new File( path, user.getFullName() + ".mpsites" );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return The location on the file system where the user models are stored.
 | 
			
		||||
     */
 | 
			
		||||
    public File getPath() {
 | 
			
		||||
        return userFilesDirectory;
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ import org.joda.time.Instant;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2017-09-20
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings({ "HardcodedLineSeparator", "MagicCharacter" })
 | 
			
		||||
public class MPFlatMarshaller implements MPMarshaller {
 | 
			
		||||
 | 
			
		||||
    private static final int FORMAT = 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -39,8 +39,8 @@ public enum MPMarshalFormat {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String fileExtension() {
 | 
			
		||||
            return "mpsites";
 | 
			
		||||
        public String fileSuffix() {
 | 
			
		||||
            return ".mpsites";
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -59,8 +59,8 @@ public enum MPMarshalFormat {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String fileExtension() {
 | 
			
		||||
            return "mpsites.json";
 | 
			
		||||
        public String fileSuffix() {
 | 
			
		||||
            return ".mpsites.json";
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -70,5 +70,6 @@ public enum MPMarshalFormat {
 | 
			
		||||
 | 
			
		||||
    public abstract MPUnmarshaller unmarshaller();
 | 
			
		||||
 | 
			
		||||
    public abstract String fileExtension();
 | 
			
		||||
    @SuppressWarnings("MethodReturnAlwaysConstant")
 | 
			
		||||
    public abstract String fileSuffix();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,14 +33,15 @@ public interface MPMarshaller {
 | 
			
		||||
            throws MPInvalidatedException, MPMarshalException;
 | 
			
		||||
 | 
			
		||||
    enum ContentMode {
 | 
			
		||||
        PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ),
 | 
			
		||||
        VISIBLE( "Export of site names and passwords in clear-text." );
 | 
			
		||||
        PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
 | 
			
		||||
        VISIBLE( "Export of site names and passwords in clear-text.", false );
 | 
			
		||||
 | 
			
		||||
        private final String  description;
 | 
			
		||||
        private       boolean redacted;
 | 
			
		||||
        private final boolean redacted;
 | 
			
		||||
 | 
			
		||||
        ContentMode(final String description) {
 | 
			
		||||
        ContentMode(final String description, final boolean redacted) {
 | 
			
		||||
            this.description = description;
 | 
			
		||||
            this.redacted = redacted;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String description() {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ public abstract class MPUser<S extends MPSite> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public MPMasterKey getMasterKey() {
 | 
			
		||||
        return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() );
 | 
			
		||||
        return Preconditions.checkNotNull( key, "User is not authenticated: %s", getFullName() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String exportKeyID()
 | 
			
		||||
 
 | 
			
		||||
@@ -29,11 +29,6 @@ import java.util.SortedSet;
 | 
			
		||||
public abstract class MPUserManager {
 | 
			
		||||
 | 
			
		||||
    private final Map<String, MPFileUser> usersByName = Maps.newHashMap();
 | 
			
		||||
    static        MPUserManager           instance;
 | 
			
		||||
 | 
			
		||||
    public static MPUserManager get() {
 | 
			
		||||
        return instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected MPUserManager(final Iterable<MPFileUser> users) {
 | 
			
		||||
        for (final MPFileUser user : users)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,8 @@ import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Deque;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.Callable;
 | 
			
		||||
import javax.xml.parsers.*;
 | 
			
		||||
import org.xml.sax.Attributes;
 | 
			
		||||
@@ -56,7 +56,8 @@ public class MPTestSuite implements Callable<Boolean> {
 | 
			
		||||
        try {
 | 
			
		||||
            tests = new MPTests();
 | 
			
		||||
            tests.cases = Lists.newLinkedList();
 | 
			
		||||
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
 | 
			
		||||
            SAXParser        parser    = SAXParserFactory.newInstance().newSAXParser();
 | 
			
		||||
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources( "." );
 | 
			
		||||
            parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() {
 | 
			
		||||
                private final Deque<String> currentTags = Lists.newLinkedList();
 | 
			
		||||
                private final Deque<StringBuilder> currentTexts = Lists.newLinkedList();
 | 
			
		||||
@@ -81,7 +82,7 @@ public class MPTestSuite implements Callable<Boolean> {
 | 
			
		||||
                        throws SAXException {
 | 
			
		||||
                    super.endElement( uri, localName, qName );
 | 
			
		||||
                    Preconditions.checkState( qName.equals( currentTags.pop() ) );
 | 
			
		||||
                    String text = currentTexts.pop().toString();
 | 
			
		||||
                    String text = Preconditions.checkNotNull( currentTexts.pop() ).toString();
 | 
			
		||||
 | 
			
		||||
                    if ("case".equals( qName ))
 | 
			
		||||
                        tests.cases.add( currentCase );
 | 
			
		||||
@@ -112,11 +113,11 @@ public class MPTestSuite implements Callable<Boolean> {
 | 
			
		||||
                        throws SAXException {
 | 
			
		||||
                    super.characters( ch, start, length );
 | 
			
		||||
 | 
			
		||||
                    currentTexts.peek().append( ch, start, length );
 | 
			
		||||
                    Preconditions.checkNotNull( currentTexts.peek() ).append( ch, start, length );
 | 
			
		||||
                }
 | 
			
		||||
            } );
 | 
			
		||||
        }
 | 
			
		||||
        catch (IllegalArgumentException | ParserConfigurationException | SAXException | IOException e) {
 | 
			
		||||
        catch (final IllegalArgumentException | ParserConfigurationException | SAXException | IOException e) {
 | 
			
		||||
            throw new UnavailableException( e );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ import com.lyndir.lhunath.opal.system.util.NNSupplier;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.xml.bind.annotation.XmlTransient;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -66,20 +67,23 @@ public class MPTests {
 | 
			
		||||
 | 
			
		||||
    public static class Case {
 | 
			
		||||
 | 
			
		||||
        String          identifier;
 | 
			
		||||
        String          parent;
 | 
			
		||||
        Integer         algorithm;
 | 
			
		||||
        String          fullName;
 | 
			
		||||
        String          masterPassword;
 | 
			
		||||
        String          keyID;
 | 
			
		||||
        String          siteName;
 | 
			
		||||
        String identifier;
 | 
			
		||||
        String parent;
 | 
			
		||||
        @Nullable
 | 
			
		||||
        Integer algorithm;
 | 
			
		||||
        String fullName;
 | 
			
		||||
        String masterPassword;
 | 
			
		||||
        String keyID;
 | 
			
		||||
        String siteName;
 | 
			
		||||
        @Nullable
 | 
			
		||||
        UnsignedInteger siteCounter;
 | 
			
		||||
        String          resultType;
 | 
			
		||||
        String          keyPurpose;
 | 
			
		||||
        String          keyContext;
 | 
			
		||||
        String          result;
 | 
			
		||||
        String resultType;
 | 
			
		||||
        String keyPurpose;
 | 
			
		||||
        String keyContext;
 | 
			
		||||
        String result;
 | 
			
		||||
 | 
			
		||||
        private transient Case parentCase;
 | 
			
		||||
        @XmlTransient
 | 
			
		||||
        private Case parentCase;
 | 
			
		||||
 | 
			
		||||
        public void initializeParentHierarchy(final MPTests tests) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ public class MPMasterKeyTest {
 | 
			
		||||
        char[]       masterPassword = testCase.getMasterPassword().toCharArray();
 | 
			
		||||
        MPMasterKey  masterKey      = new MPMasterKey( testCase.getFullName(), masterPassword );
 | 
			
		||||
 | 
			
		||||
        String password = randomString( 8 );
 | 
			
		||||
        String       password   = randomString( 8 );
 | 
			
		||||
        MPResultType resultType = MPResultType.StoredPersonal;
 | 
			
		||||
        for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
 | 
			
		||||
            MPAlgorithm algorithm = version.getAlgorithm();
 | 
			
		||||
@@ -126,7 +126,7 @@ public class MPMasterKeyTest {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String randomString(int length) {
 | 
			
		||||
    private static String randomString(int length) {
 | 
			
		||||
        Random        random  = new Random();
 | 
			
		||||
        StringBuilder builder = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								gradle/.idea/runConfigurations/Tests.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								gradle/.idea/runConfigurations/Tests.xml
									
									
									
										generated
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
 | 
			
		||||
    <module name="" />
 | 
			
		||||
    <module name="masterpassword-tests" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
 | 
			
		||||
    <option name="ALTERNATIVE_JRE_PATH" />
 | 
			
		||||
    <option name="SUITE_NAME" value="" />
 | 
			
		||||
@@ -13,15 +13,12 @@
 | 
			
		||||
    <option name="PARAMETERS" value="" />
 | 
			
		||||
    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" />
 | 
			
		||||
    <option name="OUTPUT_DIRECTORY" value="" />
 | 
			
		||||
    <option name="ANNOTATION_TYPE" />
 | 
			
		||||
    <option name="ENV_VARIABLES" />
 | 
			
		||||
    <option name="PASS_PARENT_ENVS" value="true" />
 | 
			
		||||
    <option name="TEST_SEARCH_SCOPE">
 | 
			
		||||
      <value defaultName="wholeProject" />
 | 
			
		||||
      <value defaultName="moduleWithDependencies" />
 | 
			
		||||
    </option>
 | 
			
		||||
    <option name="USE_DEFAULT_REPORTERS" value="false" />
 | 
			
		||||
    <option name="PROPERTIES_FILE" value="" />
 | 
			
		||||
    <envs />
 | 
			
		||||
    <properties />
 | 
			
		||||
    <listeners />
 | 
			
		||||
    <method />
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
    private static final Logger   logger                = Logger.get( EmergencyActivity.class );
 | 
			
		||||
    private static final ClipData EMPTY_CLIP            = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
 | 
			
		||||
    private static final int      PASSWORD_NOTIFICATION = 0;
 | 
			
		||||
    public static final  int      CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
 | 
			
		||||
    private static final int      CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
 | 
			
		||||
 | 
			
		||||
    private final Preferences                        preferences    = Preferences.get( this );
 | 
			
		||||
    private final ListeningExecutorService           executor       = MoreExecutors.listeningDecorator(
 | 
			
		||||
@@ -59,6 +59,7 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
            MPResultType.forClass( MPResultTypeClass.Template ) );
 | 
			
		||||
    private final ImmutableList<MPMasterKey.Version> allVersions    = ImmutableList.copyOf( MPMasterKey.Version.values() );
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private MPMasterKey masterKey;
 | 
			
		||||
 | 
			
		||||
    @BindView(R.id.progressView)
 | 
			
		||||
@@ -99,6 +100,7 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    private int    id_userName;
 | 
			
		||||
    private int    id_masterPassword;
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private String sitePassword;
 | 
			
		||||
 | 
			
		||||
    public static void start(final Context context) {
 | 
			
		||||
@@ -176,13 +178,13 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
            }
 | 
			
		||||
        } );
 | 
			
		||||
 | 
			
		||||
        fullNameField.setTypeface( Res.get( this ).exo_Thin );
 | 
			
		||||
        fullNameField.setTypeface( Res.get( this ).exo_Thin() );
 | 
			
		||||
        fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
 | 
			
		||||
        masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight );
 | 
			
		||||
        masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight() );
 | 
			
		||||
        masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
 | 
			
		||||
        siteNameField.setTypeface( Res.get( this ).exo_Regular );
 | 
			
		||||
        siteNameField.setTypeface( Res.get( this ).exo_Regular() );
 | 
			
		||||
        siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
 | 
			
		||||
        sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black );
 | 
			
		||||
        sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black() );
 | 
			
		||||
        sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
 | 
			
		||||
 | 
			
		||||
        rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
 | 
			
		||||
@@ -257,8 +259,8 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private synchronized void updateMasterKey() {
 | 
			
		||||
        final String fullName       = fullNameField.getText().toString();
 | 
			
		||||
        final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
 | 
			
		||||
        String fullName       = fullNameField.getText().toString();
 | 
			
		||||
        char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
 | 
			
		||||
        if ((id_userName == fullName.hashCode())
 | 
			
		||||
            && (id_masterPassword == Arrays.hashCode( masterPassword )))
 | 
			
		||||
            if (masterKey != null)
 | 
			
		||||
@@ -303,7 +305,8 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                try {
 | 
			
		||||
                    sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version.getAlgorithm() );
 | 
			
		||||
                    sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null,
 | 
			
		||||
                                                         version.getAlgorithm() );
 | 
			
		||||
 | 
			
		||||
                    runOnUiThread( new Runnable() {
 | 
			
		||||
                        @Override
 | 
			
		||||
@@ -341,31 +344,39 @@ public class EmergencyActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
        final ClipboardManager    clipboardManager    = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
 | 
			
		||||
        final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
 | 
			
		||||
        if (clipboardManager == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        String          title       = strf( "Password for %s", siteNameField.getText() );
 | 
			
		||||
        ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
 | 
			
		||||
        clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) );
 | 
			
		||||
 | 
			
		||||
        Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
 | 
			
		||||
                                                                                   .setContentText( "Paste the password into your app." )
 | 
			
		||||
                                                                                   .setSmallIcon( R.drawable.icon )
 | 
			
		||||
                                                                                   .setAutoCancel( true );
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
 | 
			
		||||
            notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
 | 
			
		||||
                               .setCategory( Notification.CATEGORY_RECOMMENDATION )
 | 
			
		||||
                               .setLocalOnly( true );
 | 
			
		||||
        notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
 | 
			
		||||
        if (notificationManager != null) {
 | 
			
		||||
            Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
 | 
			
		||||
                                                                                       .setContentText(
 | 
			
		||||
                                                                                               "Paste the password into your app." )
 | 
			
		||||
                                                                                       .setSmallIcon( R.drawable.icon )
 | 
			
		||||
                                                                                       .setAutoCancel( true );
 | 
			
		||||
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
 | 
			
		||||
                notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
 | 
			
		||||
                                   .setCategory( Notification.CATEGORY_RECOMMENDATION )
 | 
			
		||||
                                   .setLocalOnly( true );
 | 
			
		||||
            notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final Timer timer = new Timer();
 | 
			
		||||
        timer.schedule( new TimerTask() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                ClipData clip = clipboardManager.getPrimaryClip();
 | 
			
		||||
                for (int i = 0; i < clip.getItemCount(); ++i)
 | 
			
		||||
                    if (currentSitePassword.equals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
 | 
			
		||||
                    if (currentSitePassword.contentEquals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
 | 
			
		||||
                        clipboardManager.setPrimaryClip( EMPTY_CLIP );
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                notificationManager.cancel( PASSWORD_NOTIFICATION );
 | 
			
		||||
 | 
			
		||||
                if (notificationManager != null)
 | 
			
		||||
                    notificationManager.cancel( PASSWORD_NOTIFICATION );
 | 
			
		||||
                timer.cancel();
 | 
			
		||||
            }
 | 
			
		||||
        }, CLIPBOARD_CLEAR_DELAY );
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ import com.google.common.collect.Sets;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.concurrent.*;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -64,6 +65,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
 | 
			
		||||
        shutdown = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Runnable> shutdownNow() {
 | 
			
		||||
        shutdown = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,14 +25,15 @@ import android.graphics.Typeface;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2014-08-25
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("NewMethodNamingConvention")
 | 
			
		||||
public final class Res {
 | 
			
		||||
 | 
			
		||||
    public final Typeface sourceCodePro_Black;
 | 
			
		||||
    public final Typeface sourceCodePro_ExtraLight;
 | 
			
		||||
    public final Typeface exo_Bold;
 | 
			
		||||
    public final Typeface exo_ExtraBold;
 | 
			
		||||
    public final Typeface exo_Regular;
 | 
			
		||||
    public final Typeface exo_Thin;
 | 
			
		||||
    private final Typeface sourceCodePro_Black;
 | 
			
		||||
    private final Typeface sourceCodePro_ExtraLight;
 | 
			
		||||
    private final Typeface exo_Bold;
 | 
			
		||||
    private final Typeface exo_ExtraBold;
 | 
			
		||||
    private final Typeface exo_Regular;
 | 
			
		||||
    private final Typeface exo_Thin;
 | 
			
		||||
 | 
			
		||||
    private static Res res;
 | 
			
		||||
 | 
			
		||||
@@ -53,4 +54,28 @@ public final class Res {
 | 
			
		||||
        exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" );
 | 
			
		||||
        exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface sourceCodePro_Black() {
 | 
			
		||||
        return sourceCodePro_Black;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface sourceCodePro_ExtraLight() {
 | 
			
		||||
        return sourceCodePro_ExtraLight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface exo_Bold() {
 | 
			
		||||
        return exo_Bold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface exo_ExtraBold() {
 | 
			
		||||
        return exo_ExtraBold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface exo_Regular() {
 | 
			
		||||
        return exo_Regular;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Typeface exo_Thin() {
 | 
			
		||||
        return exo_Thin;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ import com.lyndir.masterpassword.MPConstant;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2014-08-31
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("CallToSystemGetenv")
 | 
			
		||||
public class Config {
 | 
			
		||||
 | 
			
		||||
    private static final Config instance = new Config();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,8 @@
 | 
			
		||||
 | 
			
		||||
package com.lyndir.masterpassword.gui;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Charsets;
 | 
			
		||||
import com.google.common.base.Optional;
 | 
			
		||||
import com.google.common.io.CharSource;
 | 
			
		||||
@@ -57,7 +59,7 @@ public class GUI implements UnlockFrame.SignInCallback {
 | 
			
		||||
        try {
 | 
			
		||||
            UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
 | 
			
		||||
        }
 | 
			
		||||
        catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException ignored) {
 | 
			
		||||
        catch (final UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException ignored) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
@@ -69,7 +71,7 @@ public class GUI implements UnlockFrame.SignInCallback {
 | 
			
		||||
            else // No special platform handling.
 | 
			
		||||
                new GUI().open();
 | 
			
		||||
        }
 | 
			
		||||
        catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
 | 
			
		||||
        catch (final IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
 | 
			
		||||
            throw logger.bug( e );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -77,29 +79,35 @@ public class GUI implements UnlockFrame.SignInCallback {
 | 
			
		||||
    private static void checkUpdate() {
 | 
			
		||||
        try {
 | 
			
		||||
            Enumeration<URL> manifestURLs = Thread.currentThread().getContextClassLoader().getResources( JarFile.MANIFEST_NAME );
 | 
			
		||||
            while (manifestURLs.hasMoreElements()) {
 | 
			
		||||
                InputStream manifestStream = manifestURLs.nextElement().openStream();
 | 
			
		||||
                Attributes  attributes     = new Manifest( manifestStream ).getMainAttributes();
 | 
			
		||||
                if (!GUI.class.getCanonicalName().equals( attributes.getValue( Attributes.Name.MAIN_CLASS ) ))
 | 
			
		||||
                    continue;
 | 
			
		||||
            while (manifestURLs.hasMoreElements())
 | 
			
		||||
                try (InputStream manifestStream = manifestURLs.nextElement().openStream()) {
 | 
			
		||||
                    Attributes attributes = new Manifest( manifestStream ).getMainAttributes();
 | 
			
		||||
                    if (!GUI.class.getCanonicalName().equals( attributes.getValue( Attributes.Name.MAIN_CLASS ) ))
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                String     manifestRevision    = attributes.getValue( Attributes.Name.IMPLEMENTATION_VERSION );
 | 
			
		||||
                String     upstreamRevisionURL = "https://masterpasswordapp.com/masterpassword-gui.jar.rev";
 | 
			
		||||
                CharSource upstream            = Resources.asCharSource( URI.create( upstreamRevisionURL ).toURL(), Charsets.UTF_8 );
 | 
			
		||||
                String     upstreamRevision    = upstream.readFirstLine();
 | 
			
		||||
                if ((manifestRevision != null) && (upstreamRevision != null) && !manifestRevision.equalsIgnoreCase( upstreamRevision )) {
 | 
			
		||||
                    logger.inf( "Local Revision:    <%s>", manifestRevision );
 | 
			
		||||
                    logger.inf( "Upstream Revision: <%s>", upstreamRevision );
 | 
			
		||||
                    logger.wrn( "You are not running the current official version.  Please update from:\n"
 | 
			
		||||
                                + "https://masterpasswordapp.com/masterpassword-gui.jar" );
 | 
			
		||||
                    JOptionPane.showMessageDialog( null, "A new version of Master Password is available.\n"
 | 
			
		||||
                                                         + "Please download the latest version from http://masterpasswordapp.com",
 | 
			
		||||
                                                   "Update Available", JOptionPane.WARNING_MESSAGE );
 | 
			
		||||
                    String     manifestRevision    = attributes.getValue( Attributes.Name.IMPLEMENTATION_VERSION );
 | 
			
		||||
                    String     upstreamRevisionURL = "https://masterpasswordapp.com/masterpassword-gui.jar.rev";
 | 
			
		||||
                    CharSource upstream            = Resources.asCharSource( URI.create( upstreamRevisionURL ).toURL(), Charsets.UTF_8 );
 | 
			
		||||
                    String     upstreamRevision    = upstream.readFirstLine();
 | 
			
		||||
                    if ((manifestRevision != null) && (upstreamRevision != null) && !manifestRevision.equalsIgnoreCase(
 | 
			
		||||
                            upstreamRevision )) {
 | 
			
		||||
                        logger.inf( "Local Revision:    <%s>", manifestRevision );
 | 
			
		||||
                        logger.inf( "Upstream Revision: <%s>", upstreamRevision );
 | 
			
		||||
                        logger.wrn( "You are not running the current official version.  Please update from:%n%s",
 | 
			
		||||
                                    "https://masterpasswordapp.com/masterpassword-gui.jar" );
 | 
			
		||||
                        JOptionPane.showMessageDialog( null,
 | 
			
		||||
                                                       strf( "A new version of Master Password is available.%n "
 | 
			
		||||
                                                             + "Please download the latest version from %s",
 | 
			
		||||
                                                             "https://masterpasswordapp.com" ),
 | 
			
		||||
                                                       "Update Available", JOptionPane.WARNING_MESSAGE );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (final IOException e) {
 | 
			
		||||
                    logger.wrn( e, "Couldn't check for version update." );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (final IOException e) {
 | 
			
		||||
            logger.wrn( e, "Couldn't check for version update." );
 | 
			
		||||
            logger.wrn( e, "Couldn't inspect JAR." );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ import org.jetbrains.annotations.NonNls;
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2014-06-11
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("HardcodedFileSeparator")
 | 
			
		||||
@SuppressWarnings({ "HardcodedFileSeparator", "MethodReturnAlwaysConstant", "SpellCheckingInspection" })
 | 
			
		||||
public abstract class Res {
 | 
			
		||||
 | 
			
		||||
    private static final int                                   AVATAR_COUNT     = 19;
 | 
			
		||||
@@ -210,7 +210,7 @@ public abstract class Res {
 | 
			
		||||
                fontsByResourceName.put( fontResourceName, new SoftReference<>(
 | 
			
		||||
                        font = Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( fontResourceName ).openStream() ) ) );
 | 
			
		||||
            }
 | 
			
		||||
            catch (FontFormatException | IOException e) {
 | 
			
		||||
            catch (final FontFormatException | IOException e) {
 | 
			
		||||
                throw Throwables.propagate( e );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,8 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import com.lyndir.masterpassword.MPAlgorithm;
 | 
			
		||||
import com.lyndir.masterpassword.MPResultType;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPSite;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
//==============================================================================
 | 
			
		||||
// 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/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lhunath, 2018-04-26
 | 
			
		||||
 */
 | 
			
		||||
@ParametersAreNonnullByDefault
 | 
			
		||||
package com.lyndir.masterpassword.gui.platform.mac;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.ParametersAreNonnullByDefault;
 | 
			
		||||
@@ -31,7 +31,7 @@ import javax.swing.border.CompoundBorder;
 | 
			
		||||
 */
 | 
			
		||||
public abstract class Components {
 | 
			
		||||
 | 
			
		||||
    public static final float CONTROL_TEXT_SIZE = 12f;
 | 
			
		||||
    private static final float CONTROL_TEXT_SIZE = 12f;
 | 
			
		||||
 | 
			
		||||
    public static GradientPanel boxLayout(final int axis, final Component... components) {
 | 
			
		||||
        GradientPanel container = gradientPanel( null, null );
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,8 @@ package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Preconditions;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import com.lyndir.masterpassword.MPAlgorithm;
 | 
			
		||||
import com.lyndir.masterpassword.MPResultType;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.IncognitoSite;
 | 
			
		||||
import com.lyndir.masterpassword.gui.model.IncognitoUser;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,12 @@ package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.Preconditions;
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import com.lyndir.masterpassword.MPAlgorithm;
 | 
			
		||||
import com.lyndir.masterpassword.MPResultType;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.model.*;
 | 
			
		||||
@@ -171,7 +173,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        if (JOptionPane.showConfirmDialog( ModelAuthenticationPanel.this, //
 | 
			
		||||
                                                           strf( "Are you sure you want to delete the user and sites remembered for:\n%s.",
 | 
			
		||||
                                                           strf( "Are you sure you want to delete the user and sites remembered for:%n%s.",
 | 
			
		||||
                                                                 deleteUser.getFullName() ), //
 | 
			
		||||
                                                           "Delete User", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE )
 | 
			
		||||
                            == JOptionPane.CANCEL_OPTION)
 | 
			
		||||
@@ -190,7 +192,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void actionPerformed(final ActionEvent e) {
 | 
			
		||||
                        JOptionPane.showMessageDialog( ModelAuthenticationPanel.this, //
 | 
			
		||||
                                                       strf( "Reads users and sites from the directory at:\n%s",
 | 
			
		||||
                                                       strf( "Reads users and sites from the directory at:%n%s",
 | 
			
		||||
                                                             MPFileUserManager.get().getPath().getAbsolutePath() ), //
 | 
			
		||||
                                                       "Help", JOptionPane.INFORMATION_MESSAGE );
 | 
			
		||||
                    }
 | 
			
		||||
@@ -207,7 +209,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PasswordFrame<MPFileUser, MPFileSite> newPasswordFrame() {
 | 
			
		||||
        return new PasswordFrame<MPFileUser, MPFileSite>( getSelectedUser() ) {
 | 
			
		||||
        return new PasswordFrame<MPFileUser, MPFileSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
 | 
			
		||||
            @Override
 | 
			
		||||
            protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter,
 | 
			
		||||
                                            final MPResultType resultType,
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
 | 
			
		||||
    private S       currentSite;
 | 
			
		||||
    private boolean updatingUI;
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings({ "MagicNumber", "OverridableMethodCallDuringObjectConstruction" })
 | 
			
		||||
    @SuppressWarnings("MagicNumber")
 | 
			
		||||
    protected PasswordFrame(final U user) {
 | 
			
		||||
        super( "Master Password" );
 | 
			
		||||
        this.user = user;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,12 +19,13 @@
 | 
			
		||||
package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.lyndir.masterpassword.MPIdenticon;
 | 
			
		||||
import com.lyndir.masterpassword.gui.*;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPUser;
 | 
			
		||||
import com.lyndir.masterpassword.gui.Res;
 | 
			
		||||
import com.lyndir.masterpassword.gui.util.Components;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
 | 
			
		||||
import com.lyndir.masterpassword.model.MPUser;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
@@ -47,6 +48,7 @@ public class UnlockFrame extends JFrame {
 | 
			
		||||
    private       AuthenticationPanel<?>   authenticationPanel;
 | 
			
		||||
    private       Future<?>                identiconFuture;
 | 
			
		||||
    private       boolean                  incognito;
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private       MPUser<?>                user;
 | 
			
		||||
 | 
			
		||||
    public UnlockFrame(final SignInCallback signInCallback) {
 | 
			
		||||
@@ -86,7 +88,7 @@ public class UnlockFrame extends JFrame {
 | 
			
		||||
        authenticationContainer.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
 | 
			
		||||
        identiconLabel.setFont( Res.emoticonsFont().deriveFont( 14.f ) );
 | 
			
		||||
        identiconLabel.setToolTipText(
 | 
			
		||||
                "A representation of your identity across all Master Password apps.\nIt should always be the same." );
 | 
			
		||||
                strf( "A representation of your identity across all Master Password apps.%nIt should always be the same." ) );
 | 
			
		||||
        signInButton.addActionListener( new AbstractAction() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void actionPerformed(final ActionEvent e) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user