2
0

Apply 'Lhunath' code inspection fixes and improvements.

This commit is contained in:
Maarten Billemont 2017-04-04 20:39:18 -04:00
parent 86f956571d
commit b478691980
59 changed files with 452 additions and 320 deletions

View File

@ -10,7 +10,7 @@ import java.nio.charset.Charset;
/** /**
* @author lhunath, 2016-10-29 * @author lhunath, 2016-10-29
*/ */
public class MPConstant { public final class MPConstant {
/* Environment */ /* Environment */
@ -58,17 +58,24 @@ public class MPConstant {
/** /**
* mpw: Input character encoding. * mpw: Input character encoding.
*/ */
public static final Charset mpw_charset = Charsets.UTF_8; public static final Charset mpw_charset = Charsets.UTF_8;
/** /**
* mpw: Platform-agnostic byte order. * mpw: Platform-agnostic byte order.
*/ */
public static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN; public static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
/** /**
* mpw: Site digest. * mpw: Site digest.
*/ */
public static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256; public static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
/** /**
* mpw: Key ID hash. * mpw: Key ID hash.
*/ */
public static final MessageDigests mpw_hash = MessageDigests.SHA256; public static final MessageDigests mpw_hash = MessageDigests.SHA256;
/**
* mpw: validity for the time-based rolling counter.
*/
public static final int mpw_counter_timeout = 5 * 60 /* s */;
public static final int MS_PER_S = 1000;
} }

View File

@ -19,12 +19,12 @@ public class MPIdenticon {
private static final Logger logger = Logger.get( MPIdenticon.class ); private static final Logger logger = Logger.get( MPIdenticon.class );
private static final Charset charset = Charsets.UTF_8; private static final Charset charset = Charsets.UTF_8;
private static final Color[] colors = new Color[]{ private static final Color[] colors = {
Color.RED, Color.GREEN, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.MONO }; Color.RED, Color.GREEN, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.MONO };
private static final char[] leftArm = new char[]{ '╔', '╚', '╰', '═' }; private static final char[] leftArm = { '╔', '╚', '╰', '═' };
private static final char[] rightArm = new char[]{ '╗', '╝', '╯', '═' }; private static final char[] rightArm = { '╗', '╝', '╯', '═' };
private static final char[] body = new char[]{ '█', '░', '▒', '▓', '☺', '☻' }; private static final char[] body = { '█', '░', '▒', '▓', '☺', '☻' };
private static final char[] accessory = new char[]{ private static final char[] accessory = {
'◈', '◎', '◐', '◑', '◒', '◓', '☀', '☁', '☂', '☃', '☄', '★', '☆', '☎', '☏', '⎈', '⌂', '☘', '☢', '☣', '☕', '⌚', '⌛', '⏰', '⚡', '◈', '◎', '◐', '◑', '◒', '◓', '☀', '☁', '☂', '☃', '☄', '★', '☆', '☎', '☏', '⎈', '⌂', '☘', '☢', '☣', '☕', '⌚', '⌛', '⏰', '⚡',
'⛄', '⛅', '☔', '♔', '♕', '♖', '♗', '♘', '♙', '♚', '♛', '♜', '♝', '♞', '♟', '♨', '♩', '♪', '♫', '⚐', '⚑', '⚔', '⚖', '⚙', '⚠', '⛄', '⛅', '☔', '♔', '♕', '♖', '♗', '♘', '♙', '♚', '♛', '♜', '♝', '♞', '♟', '♨', '♩', '♪', '♫', '⚐', '⚑', '⚔', '⚖', '⚙', '⚠',
'⌘', '⏎', '✄', '✆', '✈', '✉', '✌' }; '⌘', '⏎', '✄', '✆', '✈', '✉', '✌' };
@ -33,11 +33,12 @@ public class MPIdenticon {
private final Color color; private final Color color;
private final String text; private final String text;
public MPIdenticon(String fullName, String masterPassword) { public MPIdenticon(final String fullName, final String masterPassword) {
this( fullName, masterPassword.toCharArray() ); this( fullName, masterPassword.toCharArray() );
} }
public MPIdenticon(String fullName, char[] masterPassword) { @SuppressWarnings("MethodCanBeVariableArityMethod")
public MPIdenticon(final String fullName, final char[] masterPassword) {
this.fullName = fullName; this.fullName = fullName;
byte[] masterPasswordBytes = charset.encode( CharBuffer.wrap( masterPassword ) ).array(); byte[] masterPasswordBytes = charset.encode( CharBuffer.wrap( masterPassword ) ).array();

View File

@ -3,10 +3,10 @@ package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List; import java.util.*;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/** /**
@ -17,12 +17,12 @@ import org.jetbrains.annotations.Contract;
public enum MPSiteType { public enum MPSiteType {
GeneratedMaximum( "Max", "20 characters, contains symbols.", // GeneratedMaximum( "Max", "20 characters, contains symbols.", //
ImmutableList.of( "x", "max", "maximum" ), // ImmutableList.of( "x", "max", "maximum" ), // NON-NLS
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), // ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPSiteTypeClass.Generated, 0x0 ), MPSiteTypeClass.Generated, 0x0 ),
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", // GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( "l", "long" ), // ImmutableList.of( "l", "long" ), // NON-NLS
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ), ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ), new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
@ -37,43 +37,43 @@ public enum MPSiteType {
MPSiteTypeClass.Generated, 0x1 ), MPSiteTypeClass.Generated, 0x1 ),
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", // GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
ImmutableList.of( "m", "med", "medium" ), // ImmutableList.of( "m", "med", "medium" ), // NON-NLS
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), // ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
MPSiteTypeClass.Generated, 0x2 ), MPSiteTypeClass.Generated, 0x2 ),
GeneratedBasic( "Basic", "8 characters, no symbols.", // GeneratedBasic( "Basic", "8 characters, no symbols.", //
ImmutableList.of( "b", "basic" ), // ImmutableList.of( "b", "basic" ), // NON-NLS
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), // ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
MPSiteTypeClass.Generated, 0x3 ), MPSiteTypeClass.Generated, 0x3 ),
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", // GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( "s", "short" ), // ImmutableList.of( "s", "short" ), // NON-NLS
ImmutableList.of( new MPTemplate( "Cvcn" ) ), // ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPSiteTypeClass.Generated, 0x4 ), MPSiteTypeClass.Generated, 0x4 ),
GeneratedPIN( "PIN", "4 numbers.", // GeneratedPIN( "PIN", "4 numbers.", //
ImmutableList.of( "i", "pin" ), // ImmutableList.of( "i", "pin" ), // NON-NLS
ImmutableList.of( new MPTemplate( "nnnn" ) ), // ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPSiteTypeClass.Generated, 0x5 ), MPSiteTypeClass.Generated, 0x5 ),
GeneratedName( "Name", "9 letter name.", // GeneratedName( "Name", "9 letter name.", //
ImmutableList.of( "n", "name" ), // ImmutableList.of( "n", "name" ), // NON-NLS
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), // ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPSiteTypeClass.Generated, 0xE ), MPSiteTypeClass.Generated, 0xE ),
GeneratedPhrase( "Phrase", "20 character sentence.", // GeneratedPhrase( "Phrase", "20 character sentence.", //
ImmutableList.of( "p", "phrase" ), // ImmutableList.of( "p", "phrase" ), // NON-NLS
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ), ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), // new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
MPSiteTypeClass.Generated, 0xF ), MPSiteTypeClass.Generated, 0xF ),
StoredPersonal( "Personal", "AES-encrypted, exportable.", // StoredPersonal( "Personal", "AES-encrypted, exportable.", //
ImmutableList.of( "personal" ), // ImmutableList.of( "personal" ), // NON-NLS
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ), MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", // StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
ImmutableList.of( "device" ), // ImmutableList.of( "device" ), // NON-NLS
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate ); MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
@ -129,7 +129,7 @@ public enum MPSiteType {
public int getType() { public int getType() {
int mask = typeIndex | typeClass.getMask(); int mask = typeIndex | typeClass.getMask();
for (MPSiteFeature typeFeature : typeFeatures) for (final MPSiteFeature typeFeature : typeFeatures)
mask |= typeFeature.getMask(); mask |= typeFeature.getMask();
return mask; return mask;
@ -143,7 +143,7 @@ public enum MPSiteType {
public static MPSiteType forOption(final String option) { public static MPSiteType forOption(final String option) {
for (final MPSiteType type : values()) for (final MPSiteType type : values())
if (type.getOptions().contains( option.toLowerCase() )) if (type.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
return type; return type;
throw logger.bug( "No type for option: %s", option ); throw logger.bug( "No type for option: %s", option );
@ -154,7 +154,7 @@ public enum MPSiteType {
* *
* @return The type registered with the given name. * @return The type registered with the given name.
*/ */
@Contract("!null -> !null, null -> null") @Contract("!null -> !null")
public static MPSiteType forName(@Nullable final String name) { public static MPSiteType forName(@Nullable final String name) {
if (name == null) if (name == null)
@ -189,7 +189,7 @@ public enum MPSiteType {
*/ */
public static MPSiteType forType(final int type) { public static MPSiteType forType(final int type) {
for (MPSiteType siteType : values()) for (final MPSiteType siteType : values())
if (siteType.getType() == type) if (siteType.getType() == type)
return siteType; return siteType;
@ -205,7 +205,7 @@ public enum MPSiteType {
int typeMask = mask & ~0xF; int typeMask = mask & ~0xF;
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder(); ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
for (MPSiteType siteType : values()) for (final MPSiteType siteType : values())
if (((siteType.getType() & ~0xF) & typeMask) != 0) if (((siteType.getType() & ~0xF) & typeMask) != 0)
types.add( siteType ); types.add( siteType );

View File

@ -3,8 +3,10 @@ package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List; import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/** /**
@ -12,11 +14,11 @@ import org.jetbrains.annotations.Contract;
*/ */
public enum MPSiteVariant { public enum MPSiteVariant {
Password( "Generate a key for authentication.", "Doesn't currently use a context.", // Password( "Generate a key for authentication.", "Doesn't currently use a context.", //
ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), // NON-NLS
Login( "Generate a name for identification.", "Doesn't currently use a context.", // Login( "Generate a name for identification.", "Doesn't currently use a context.", //
ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), // NON-NLS
Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", // Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", //
ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); // NON-NLS
static final Logger logger = Logger.get( MPSiteType.class ); static final Logger logger = Logger.get( MPSiteType.class );
@ -25,7 +27,7 @@ public enum MPSiteVariant {
private final List<String> options; private final List<String> options;
private final String scope; private final String scope;
MPSiteVariant(final String description, final String contextDescription, final List<String> options, final String scope) { MPSiteVariant(final String description, final String contextDescription, final List<String> options, @NonNls final String scope) {
this.contextDescription = contextDescription; this.contextDescription = contextDescription;
this.options = options; this.options = options;
@ -57,7 +59,7 @@ public enum MPSiteVariant {
public static MPSiteVariant forOption(final String option) { public static MPSiteVariant forOption(final String option) {
for (final MPSiteVariant variant : values()) for (final MPSiteVariant variant : values())
if (variant.getOptions().contains( option.toLowerCase() )) if (variant.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
return variant; return variant;
throw logger.bug( "No variant for option: %s", option ); throw logger.bug( "No variant for option: %s", option );
@ -67,7 +69,7 @@ public enum MPSiteVariant {
* *
* @return The variant registered with the given name. * @return The variant registered with the given name.
*/ */
@Contract("!null -> !null, null -> null") @Contract("!null -> !null")
public static MPSiteVariant forName(@Nullable final String name) { public static MPSiteVariant forName(@Nullable final String name) {
if (name == null) if (name == null)

View File

@ -4,7 +4,9 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.util.MetaObject; import com.lyndir.lhunath.opal.system.util.MetaObject;
import java.io.Serializable;
import java.util.List; import java.util.List;
import org.jetbrains.annotations.NonNls;
/** /**
@ -12,12 +14,14 @@ import java.util.List;
* *
* @author lhunath * @author lhunath
*/ */
public class MPTemplate extends MetaObject { public class MPTemplate extends MetaObject implements Serializable {
private final String templateString; private static final long serialVersionUID = 1L;
private final String templateString;
private final List<MPTemplateCharacterClass> template; private final List<MPTemplateCharacterClass> template;
MPTemplate(final String templateString) { MPTemplate(@NonNls final String templateString) {
ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.builder(); ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.builder();
for (int i = 0; i < templateString.length(); ++i) for (int i = 0; i < templateString.length(); ++i)

View File

@ -1,6 +1,7 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import org.jetbrains.annotations.NonNls;
/** /**
@ -27,7 +28,7 @@ public enum MPTemplateCharacterClass {
private final char identifier; private final char identifier;
private final char[] characters; private final char[] characters;
MPTemplateCharacterClass(final char identifier, final String characters) { MPTemplateCharacterClass(final char identifier, @NonNls final String characters) {
this.identifier = identifier; this.identifier = identifier;
this.characters = characters.toCharArray(); this.characters = characters.toCharArray();
@ -44,7 +45,7 @@ public enum MPTemplateCharacterClass {
} }
public static MPTemplateCharacterClass forIdentifier(final char identifier) { public static MPTemplateCharacterClass forIdentifier(final char identifier) {
for (MPTemplateCharacterClass characterClass : values()) for (final MPTemplateCharacterClass characterClass : values())
if (characterClass.getIdentifier() == identifier) if (characterClass.getIdentifier() == identifier)
return characterClass; return characterClass;

View File

@ -1,5 +1,7 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*; import com.lyndir.lhunath.opal.system.*;
@ -7,7 +9,6 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Arrays; import java.util.Arrays;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
/** /**
@ -26,13 +27,15 @@ public abstract class MasterKey {
@Nullable @Nullable
private byte[] masterKey; private byte[] masterKey;
@SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final String fullName, final char[] masterPassword) { public static MasterKey create(final String fullName, final char[] masterPassword) {
return create( Version.CURRENT, fullName, masterPassword ); return create( Version.CURRENT, fullName, masterPassword );
} }
@Nonnull @Nonnull
public static MasterKey create(Version version, final String fullName, final char[] masterPassword) { @SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final Version version, final String fullName, final char[] masterPassword) {
switch (version) { switch (version) {
case V0: case V0:
@ -45,7 +48,7 @@ public abstract class MasterKey {
return new MasterKeyV3( fullName ).revalidate( masterPassword ); return new MasterKeyV3( fullName ).revalidate( masterPassword );
} }
throw new UnsupportedOperationException( "Unsupported version: " + version ); throw new UnsupportedOperationException( strf( "Unsupported version: %s", version ) );
} }
public static boolean isAllowNativeByDefault() { public static boolean isAllowNativeByDefault() {
@ -65,18 +68,19 @@ public abstract class MasterKey {
allowNativeByDefault = allowNative; allowNativeByDefault = allowNative;
} }
protected MasterKey(@NotNull final String fullName) { protected MasterKey(@Nonnull final String fullName) {
this.fullName = fullName; this.fullName = fullName;
logger.trc( "fullName: %s", fullName ); logger.trc( "fullName: %s", fullName );
} }
@Nullable @Nullable
protected abstract byte[] deriveKey(final char[] masterPassword); @SuppressWarnings("MethodCanBeVariableArityMethod")
protected abstract byte[] deriveKey(char[] masterPassword);
public abstract Version getAlgorithmVersion(); public abstract Version getAlgorithmVersion();
@NotNull @Nonnull
public String getFullName() { public String getFullName() {
return fullName; return fullName;
@ -103,8 +107,8 @@ public abstract class MasterKey {
return idForBytes( getKey() ); return idForBytes( getKey() );
} }
public abstract String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull final UnsignedInteger siteCounter, public abstract String encode(@Nonnull String siteName, MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext); MPSiteVariant siteVariant, @Nullable String siteContext);
public boolean isValid() { public boolean isValid() {
return masterKey != null; return masterKey != null;
@ -118,6 +122,7 @@ public abstract class MasterKey {
} }
} }
@SuppressWarnings("MethodCanBeVariableArityMethod")
public MasterKey revalidate(final char[] masterPassword) { public MasterKey revalidate(final char[] masterPassword) {
invalidate(); invalidate();
@ -127,19 +132,19 @@ public abstract class MasterKey {
masterKey = deriveKey( masterPassword ); masterKey = deriveKey( masterPassword );
if (masterKey == null) if (masterKey == null)
logger.dbg( "masterKey calculation failed after %.2fs.", (System.currentTimeMillis() - start) / 1000D ); logger.dbg( "masterKey calculation failed after %.2fs.", (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
else else
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ), logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
(System.currentTimeMillis() - start) / 1000D ); (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
return this; return this;
} }
protected abstract byte[] bytesForInt(final int number); protected abstract byte[] bytesForInt(int number);
protected abstract byte[] bytesForInt(@Nonnull final UnsignedInteger number); protected abstract byte[] bytesForInt(@Nonnull UnsignedInteger number);
protected abstract byte[] idForBytes(final byte[] bytes); protected abstract byte[] idForBytes(byte[] bytes);
public enum Version { public enum Version {
/** /**
@ -190,7 +195,7 @@ public abstract class MasterKey {
return "2.2"; return "2.2";
} }
throw new UnsupportedOperationException( "Unsupported version: " + this ); throw new UnsupportedOperationException( strf( "Unsupported version: %s", this ) );
} }
} }
} }

View File

@ -58,6 +58,7 @@ public class MasterKeyV0 extends MasterKey {
return scrypt( masterKeySalt, mpBytes ); return scrypt( masterKeySalt, mpBytes );
} }
@Nullable
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) { protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try { try {
if (isAllowNative()) if (isAllowNative())
@ -65,7 +66,7 @@ public class MasterKeyV0 extends MasterKey {
else else
return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen ); return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
} }
catch (GeneralSecurityException e) { catch (final GeneralSecurityException e) {
logger.bug( e ); logger.bug( e );
return null; return null;
} }
@ -86,18 +87,18 @@ public class MasterKeyV0 extends MasterKey {
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType ); logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0) if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset ); byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); (siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)
@ -108,7 +109,7 @@ public class MasterKeyV0 extends MasterKey {
int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length]; int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) { for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN ); ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
Arrays.fill( buf.array(), sitePasswordSeedBytes[i] > 0? (byte) 0x00: (byte) 0xFF ); Arrays.fill( buf.array(), (byte) ((sitePasswordSeedBytes[i] > 0)? 0x00: 0xFF) );
buf.position( 2 ); buf.position( 2 );
buf.put( sitePasswordSeedBytes[i] ).rewind(); buf.put( sitePasswordSeedBytes[i] ).rewind();
sitePasswordSeed[i] = buf.getInt() & 0xFFFF; sitePasswordSeed[i] = buf.getInt() & 0xFFFF;

View File

@ -43,18 +43,18 @@ public class MasterKeyV1 extends MasterKeyV0 {
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType ); logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0) if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset ); byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); (siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)

View File

@ -42,18 +42,18 @@ public class MasterKeyV2 extends MasterKeyV1 {
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType ); logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0) if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length ); byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset ); byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); (siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)

View File

@ -6,7 +6,7 @@ plugins {
description = 'Master Password Site Model' description = 'Master Password Site Model'
dependencies { dependencies {
compile project(':masterpassword:algorithm') compile project(':masterpassword-algorithm')
compile group: 'joda-time', name: 'joda-time', version:'2.4' compile group: 'joda-time', name: 'joda-time', version:'2.4'
compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2' compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'

View File

@ -128,7 +128,7 @@ public class MPSite {
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return this == obj || obj instanceof MPSite && Objects.equals( siteName, ((MPSite) obj).siteName ); return (this == obj) || ((obj instanceof MPSite) && Objects.equals( siteName, ((MPSite) obj).siteName ));
} }
@Override @Override

View File

@ -26,7 +26,7 @@ public class MPSiteMarshaller {
public static MPSiteMarshaller marshallSafe(final MPUser user) { public static MPSiteMarshaller marshallSafe(final MPUser user) {
MPSiteMarshaller marshaller = new MPSiteMarshaller(); MPSiteMarshaller marshaller = new MPSiteMarshaller();
marshaller.marshallHeaderForSafeContent( user ); marshaller.marshallHeaderForSafeContent( user );
for (MPSite site : user.getSites()) for (final MPSite site : user.getSites())
marshaller.marshallSite( site ); marshaller.marshallSite( site );
return marshaller; return marshaller;
@ -35,7 +35,7 @@ public class MPSiteMarshaller {
public static MPSiteMarshaller marshallVisible(final MPUser user, final MasterKey masterKey) { public static MPSiteMarshaller marshallVisible(final MPUser user, final MasterKey masterKey) {
MPSiteMarshaller marshaller = new MPSiteMarshaller(); MPSiteMarshaller marshaller = new MPSiteMarshaller();
marshaller.marshallHeaderForVisibleContentWithKey( user, masterKey ); marshaller.marshallHeaderForVisibleContentWithKey( user, masterKey );
for (MPSite site : user.getSites()) for (final MPSite site : user.getSites())
marshaller.marshallSite( site ); marshaller.marshallSite( site );
return marshaller; return marshaller;
@ -77,7 +77,7 @@ public class MPSiteMarshaller {
return header.toString(); return header.toString();
} }
public String marshallSite(MPSite site) { public String marshallSite(final MPSite site) {
String exportLine = strf( "%s %8d %8s %25s\t%25s\t%s", // String exportLine = strf( "%s %8d %8s %25s\t%25s\t%s", //
rfc3339.print( site.getLastUsed() ), // lastUsed rfc3339.print( site.getLastUsed() ), // lastUsed
site.getUses(), // uses site.getUses(), // uses
@ -126,6 +126,6 @@ public class MPSiteMarshaller {
return description; return description;
} }
public abstract String contentForSite(final MPSite site, final MasterKey masterKey); public abstract String contentForSite(MPSite site, MasterKey masterKey);
} }
} }

View File

@ -22,7 +22,7 @@ public class MPSiteResult {
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return this == obj || obj instanceof MPSiteResult && Objects.equals( site, ((MPSiteResult) obj).site ); return (this == obj) || ((obj instanceof MPSiteResult) && Objects.equals( site, ((MPSiteResult) obj).site ));
} }
@Override @Override

View File

@ -2,6 +2,7 @@ package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
@ -31,26 +32,28 @@ public class MPSiteUnmarshaller {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPSite.class ); private static final Logger logger = Logger.get( MPSite.class );
private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis(); private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis();
private static final Pattern[] unmarshallFormats = new Pattern[]{ private static final Pattern[] unmarshallFormats = {
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ), Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ),
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) }; Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) };
private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" ); private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" );
private final int importFormat; private final int importFormat;
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
private final int mpVersion; private final int mpVersion;
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
private final boolean clearContent; private final boolean clearContent;
private final MPUser user; private final MPUser user;
@Nonnull @Nonnull
public static MPSiteUnmarshaller unmarshall(@Nonnull File file) public static MPSiteUnmarshaller unmarshall(@Nonnull final File file)
throws IOException { throws IOException {
try (Reader reader = new FileReader( file )) { try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
return unmarshall( CharStreams.readLines( reader ) ); return unmarshall( CharStreams.readLines( reader ) );
} }
} }
@Nonnull @Nonnull
public static MPSiteUnmarshaller unmarshall(@Nonnull List<String> lines) { public static MPSiteUnmarshaller unmarshall(@Nonnull final List<String> lines) {
byte[] keyID = null; byte[] keyID = null;
String fullName = null; String fullName = null;
int mpVersion = 0, importFormat = 0, avatar = 0; int mpVersion = 0, importFormat = 0, avatar = 0;
@ -59,7 +62,7 @@ public class MPSiteUnmarshaller {
MPSiteUnmarshaller marshaller = null; MPSiteUnmarshaller marshaller = null;
final ImmutableList.Builder<MPSite> sites = ImmutableList.builder(); final ImmutableList.Builder<MPSite> sites = ImmutableList.builder();
for (String line : lines) for (final String line : lines)
// Header delimitor. // Header delimitor.
if (line.startsWith( "##" )) if (line.startsWith( "##" ))
if (!headerStarted) if (!headerStarted)
@ -71,7 +74,7 @@ public class MPSiteUnmarshaller {
// Comment. // Comment.
else if (line.startsWith( "#" )) { else if (line.startsWith( "#" )) {
if (headerStarted && marshaller == null) { if (headerStarted && (marshaller == null)) {
// In header. // In header.
Matcher headerMatcher = headerFormat.matcher( line ); Matcher headerMatcher = headerFormat.matcher( line );
if (headerMatcher.matches()) { if (headerMatcher.matches()) {
@ -87,7 +90,7 @@ public class MPSiteUnmarshaller {
else if ("Avatar".equalsIgnoreCase( name )) else if ("Avatar".equalsIgnoreCase( name ))
avatar = ConversionUtils.toIntegerNN( value ); avatar = ConversionUtils.toIntegerNN( value );
else if ("Passwords".equalsIgnoreCase( name )) else if ("Passwords".equalsIgnoreCase( name ))
clearContent = value.equalsIgnoreCase( "visible" ); clearContent = "visible".equalsIgnoreCase( value );
else if ("Default Type".equalsIgnoreCase( name )) else if ("Default Type".equalsIgnoreCase( name ))
defaultType = MPSiteType.forType( ConversionUtils.toIntegerNN( value ) ); defaultType = MPSiteType.forType( ConversionUtils.toIntegerNN( value ) );
} }
@ -116,7 +119,7 @@ public class MPSiteUnmarshaller {
} }
@Nullable @Nullable
public MPSite unmarshallSite(@Nonnull String siteLine) { public MPSite unmarshallSite(@Nonnull final String siteLine) {
Matcher siteMatcher = unmarshallFormats[importFormat].matcher( siteLine ); Matcher siteMatcher = unmarshallFormats[importFormat].matcher( siteLine );
if (!siteMatcher.matches()) if (!siteMatcher.matches())
return null; return null;

View File

@ -39,16 +39,16 @@ public class MPUser implements Comparable<MPUser> {
public MPUser(final String fullName, @Nullable final byte[] keyID, final MasterKey.Version algorithmVersion, final int avatar, public MPUser(final String fullName, @Nullable final byte[] keyID, final MasterKey.Version algorithmVersion, final int avatar,
final MPSiteType defaultType, final ReadableInstant lastUsed) { final MPSiteType defaultType, final ReadableInstant lastUsed) {
this.fullName = fullName; this.fullName = fullName;
this.keyID = keyID; this.keyID = (keyID == null)? null: keyID.clone();
this.algorithmVersion = algorithmVersion; this.algorithmVersion = algorithmVersion;
this.avatar = avatar; this.avatar = avatar;
this.defaultType = defaultType; this.defaultType = defaultType;
this.lastUsed = lastUsed; this.lastUsed = lastUsed;
} }
public Collection<MPSiteResult> findSitesByName(String query) { public Collection<MPSiteResult> findSitesByName(final String query) {
ImmutableList.Builder<MPSiteResult> results = ImmutableList.builder(); ImmutableList.Builder<MPSiteResult> results = ImmutableList.builder();
for (MPSite site : getSites()) for (final MPSite site : getSites())
if (site.getSiteName().startsWith( query )) if (site.getSiteName().startsWith( query ))
results.add( new MPSiteResult( site ) ); results.add( new MPSiteResult( site ) );
@ -87,10 +87,11 @@ public class MPUser implements Comparable<MPUser> {
* @throws IncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID. * @throws IncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/ */
@Nonnull @Nonnull
@SuppressWarnings("MethodCanBeVariableArityMethod")
public MasterKey authenticate(final char[] masterPassword) public MasterKey authenticate(final char[] masterPassword)
throws IncorrectMasterPasswordException { throws IncorrectMasterPasswordException {
MasterKey masterKey = MasterKey.create( algorithmVersion, getFullName(), masterPassword ); MasterKey masterKey = MasterKey.create( algorithmVersion, getFullName(), masterPassword );
if (keyID == null || keyID.length == 0) if ((keyID == null) || (keyID.length == 0))
keyID = masterKey.getKeyID(); keyID = masterKey.getKeyID();
else if (!Arrays.equals( masterKey.getKeyID(), keyID )) else if (!Arrays.equals( masterKey.getKeyID(), keyID ))
throw new IncorrectMasterPasswordException( this ); throw new IncorrectMasterPasswordException( this );
@ -119,7 +120,7 @@ public class MPUser implements Comparable<MPUser> {
} }
public void updateLastUsed() { public void updateLastUsed() {
this.lastUsed = new Instant(); lastUsed = new Instant();
} }
public Iterable<MPSite> getSites() { public Iterable<MPSite> getSites() {
@ -128,7 +129,7 @@ public class MPUser implements Comparable<MPUser> {
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return this == obj || obj instanceof MPUser && Objects.equals( fullName, ((MPUser) obj).fullName ); return (this == obj) || ((obj instanceof MPUser) && Objects.equals( fullName, ((MPUser) obj).fullName ));
} }
@Override @Override

View File

@ -59,7 +59,7 @@ public class MPUserFileManager extends MPUserManager {
try { try {
return MPSiteUnmarshaller.unmarshall( Preconditions.checkNotNull( file ) ).getUser(); return MPSiteUnmarshaller.unmarshall( Preconditions.checkNotNull( file ) ).getUser();
} }
catch (IOException e) { catch (final IOException e) {
logger.err( e, "Couldn't read user from: %s", file ); logger.err( e, "Couldn't read user from: %s", file );
return null; return null;
} }
@ -99,16 +99,17 @@ public class MPUserFileManager extends MPUserManager {
@Override @Override
public Writer openStream() public Writer openStream()
throws IOException { throws IOException {
return new FileWriter( new File( userFilesDirectory, user.getFullName() + ".mpsites" ) ); File mpsitesFile = new File( userFilesDirectory, user.getFullName() + ".mpsites" );
return new OutputStreamWriter( new FileOutputStream( mpsitesFile ), Charsets.UTF_8 );
} }
}.write( MPSiteMarshaller.marshallSafe( user ).getExport() ); }.write( MPSiteMarshaller.marshallSafe( user ).getExport() );
} }
catch (IOException e) { catch (final IOException e) {
logger.err( e, "Unable to save sites for user: %s", user ); logger.err( e, "Unable to save sites for user: %s", user );
} }
// Remove deleted users. // Remove deleted users.
for (File userFile : listUserFiles( userFilesDirectory )) for (final File userFile : listUserFiles( userFilesDirectory ))
if (getUserNamed( userFile.getName().replaceFirst( "\\.mpsites$", "" ) ) == null) if (getUserNamed( userFile.getName().replaceFirst( "\\.mpsites$", "" ) ) == null)
if (!userFile.delete()) if (!userFile.delete())
logger.err( "Couldn't delete file: %s", userFile ); logger.err( "Couldn't delete file: %s", userFile );

View File

@ -17,7 +17,7 @@ public abstract class MPUserManager {
} }
protected MPUserManager(final Iterable<MPUser> users) { protected MPUserManager(final Iterable<MPUser> users) {
for (MPUser user : users) for (final MPUser user : users)
usersByName.put( user.getFullName(), user ); usersByName.put( user.getFullName(), user );
} }
@ -25,7 +25,7 @@ public abstract class MPUserManager {
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() ); return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
} }
public MPUser getUserNamed(String fullName) { public MPUser getUserNamed(final String fullName) {
return usersByName.get( fullName ); return usersByName.get( fullName );
} }

View File

@ -5,7 +5,7 @@ plugins {
description = 'Master Password Test Suite' description = 'Master Password Test Suite'
dependencies { dependencies {
compile project(':masterpassword:algorithm') compile project(':masterpassword-algorithm')
testCompile group: 'org.testng', name: 'testng', version:'6.8.5' testCompile group: 'org.testng', name: 'testng', version:'6.8.5'
testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2' testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'

View File

@ -20,29 +20,30 @@ import org.xml.sax.ext.DefaultHandler2;
/** /**
* @author lhunath, 2015-12-22 * @author lhunath, 2015-12-22
*/ */
@SuppressWarnings("HardCodedStringLiteral")
public class MPTestSuite implements Callable<Boolean> { public class MPTestSuite implements Callable<Boolean> {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPTestSuite.class ); private static final Logger logger = Logger.get( MPTestSuite.class );
private static final String DEFAULT_RESOURCE_NAME = "mpw_tests.xml"; private static final String DEFAULT_RESOURCE_NAME = "mpw_tests.xml";
private MPTests tests; private final MPTests tests;
private Listener listener; private Listener listener;
public MPTestSuite() public MPTestSuite()
throws UnavailableException { throws UnavailableException {
this( DEFAULT_RESOURCE_NAME ); this( DEFAULT_RESOURCE_NAME );
} }
public MPTestSuite(String resourceName) public MPTestSuite(final String resourceName)
throws UnavailableException { throws UnavailableException {
try { try {
tests = new MPTests(); tests = new MPTests();
tests.cases = Lists.newLinkedList(); tests.cases = Lists.newLinkedList();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() { parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() {
private Deque<String> currentTags = Lists.newLinkedList(); private final Deque<String> currentTags = Lists.newLinkedList();
private Deque<StringBuilder> currentTexts = Lists.newLinkedList(); private final Deque<StringBuilder> currentTexts = Lists.newLinkedList();
private MPTests.Case currentCase; private MPTests.Case currentCase;
@Override @Override
@ -103,7 +104,7 @@ public class MPTestSuite implements Callable<Boolean> {
throw new UnavailableException( e ); throw new UnavailableException( e );
} }
for (MPTests.Case testCase : tests.getCases()) for (final MPTests.Case testCase : tests.getCases())
testCase.initializeParentHierarchy( tests ); testCase.initializeParentHierarchy( tests );
} }
@ -115,7 +116,7 @@ public class MPTestSuite implements Callable<Boolean> {
return tests; return tests;
} }
public boolean forEach(String testName, NNFunctionNN<MPTests.Case, Boolean> testFunction) { public boolean forEach(final String testName, final NNFunctionNN<MPTests.Case, Boolean> testFunction) {
List<MPTests.Case> cases = tests.getCases(); List<MPTests.Case> cases = tests.getCases();
for (int c = 0; c < cases.size(); c++) { for (int c = 0; c < cases.size(); c++) {
MPTests.Case testCase = cases.get( c ); MPTests.Case testCase = cases.get( c );
@ -164,6 +165,8 @@ public class MPTestSuite implements Callable<Boolean> {
public static class UnavailableException extends Exception { public static class UnavailableException extends Exception {
private static final long serialVersionUID = 1L;
public UnavailableException(final Throwable cause) { public UnavailableException(final Throwable cause) {
super( cause ); super( cause );
} }

View File

@ -2,6 +2,7 @@ package com.lyndir.masterpassword;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
@ -28,20 +29,20 @@ public class MPTests {
return checkNotNull( cases ); return checkNotNull( cases );
} }
public Case getCase(String identifier) { public Case getCase(final String identifier) {
for (Case testCase : getCases()) for (final Case testCase : getCases())
if (identifier.equals( testCase.getIdentifier() )) if (identifier.equals( testCase.getIdentifier() ))
return testCase; return testCase;
throw new IllegalArgumentException( "No case for identifier: " + identifier ); throw new IllegalArgumentException( strf( "No case for identifier: %s", identifier ) );
} }
public Case getDefaultCase() { public Case getDefaultCase() {
try { try {
return getCase( ID_DEFAULT ); return getCase( ID_DEFAULT );
} }
catch (IllegalArgumentException e) { catch (final IllegalArgumentException e) {
throw new IllegalStateException( "Missing default case in test suite. Add a case with id: " + ID_DEFAULT, e ); throw new IllegalStateException( strf( "Missing default case in test suite. Add a case with id: %d", ID_DEFAULT ), e );
} }
} }
@ -62,7 +63,7 @@ public class MPTests {
private transient Case parentCase; private transient Case parentCase;
public void initializeParentHierarchy(MPTests tests) { public void initializeParentHierarchy(final MPTests tests) {
if (parent != null) { if (parent != null) {
parentCase = tests.getCase( parent ); parentCase = tests.getCase( parent );
@ -129,14 +130,14 @@ public class MPTests {
@Nonnull @Nonnull
@Override @Override
public String get() { public String get() {
return parentCase == null? "": checkNotNull( parentCase.siteContext ); return (parentCase == null)? "": checkNotNull( parentCase.siteContext );
} }
} ); } );
result = ifNotNullElse( result, new NNSupplier<String>() { result = ifNotNullElse( result, new NNSupplier<String>() {
@Nonnull @Nonnull
@Override @Override
public String get() { public String get() {
return parentCase == null? "": checkNotNull( parentCase.result ); return (parentCase == null)? "": checkNotNull( parentCase.result );
} }
} ); } );
} }

View File

@ -6,6 +6,7 @@ import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.NNFunctionNN; import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.jetbrains.annotations.NonNls;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -15,6 +16,7 @@ public class MasterKeyTest {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyTest.class ); private static final Logger logger = Logger.get( MasterKeyTest.class );
@NonNls
private MPTestSuite testSuite; private MPTestSuite testSuite;
@BeforeMethod @BeforeMethod
@ -86,7 +88,7 @@ public class MasterKeyTest {
fail( "[testInvalidate] Master key should have been invalidated, but was still usable." ); fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
} }
catch (IllegalStateException ignored) { catch (final IllegalStateException ignored) {
} }
} }
} }

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Lhunath" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="myName" value="GPLv3" />
<option name="notice" value="This file is part of &amp;#36;project.name.&#10;&#10;&amp;#36;project.name is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;(at your option) any later version.&#10;&#10;&amp;#36;project.name is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#10;GNU General Public License for more details.&#10;&#10;You can find a copy of the GNU General Public License in the&#10;LICENSE file. Alternatively, see &lt;http://www.gnu.org/licenses/&gt;." />
</copyright>
</component>

View File

@ -0,0 +1,8 @@
<component name="CopyrightManager">
<settings>
<LanguageOptions name="__TEMPLATE__">
<option name="separateBefore" value="true" />
<option name="separateAfter" value="true" />
</LanguageOptions>
</settings>
</component>

View File

@ -0,0 +1,9 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="projectProfile" value="Lhunath" />
<option name="useProjectProfile" value="false" />
<option name="PROJECT_PROFILE" value="Lhunath" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

40
gradle/.idea/misc.xml Normal file
View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/../../opal/pom.xml" />
</list>
</option>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="javax.annotation.Nullable" />
<option name="myDefaultNotNull" value="javax.annotation.Nonnull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" />
</component>
<component name="ThriftCompiler">
<compilers />
</component>
</project>

View File

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="masterpassword" pattern="com.lyndir.masterpassword.*" />
</component>

View File

@ -1,6 +1,6 @@
#Mon Mar 06 18:26:17 EST 2017 #Sun Mar 26 09:11:08 EDT 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

View File

@ -1,2 +0,0 @@
sdk.dir=/usr/local/opt/android-sdk
ndk.dir=/usr/local/opt/android-ndk

View File

@ -1,19 +1,19 @@
rootProject.name = ':masterpassword' rootProject.name = 'masterpassword'
include ':masterpassword:algorithm' include 'masterpassword-algorithm'
project(':masterpassword:algorithm').projectDir = new File( '../core/java/algorithm' ) project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
include ':masterpassword:model' include 'masterpassword-model'
project(':masterpassword:model').projectDir = new File( '../core/java/model' ) project(':masterpassword-model').projectDir = new File( '../core/java/model' )
include ':masterpassword:tests' include 'masterpassword-tests'
project(':masterpassword:tests').projectDir = new File( '../core/java/tests' ) project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
include ':masterpassword:android' include 'masterpassword-cli'
project(':masterpassword:android').projectDir = new File( '../platform-android' ) project(':masterpassword-cli').projectDir = new File( '../platform-independent/cli-java' )
include ':masterpassword:cli' include 'masterpassword-gui'
project(':masterpassword:cli').projectDir = new File( '../platform-independent/cli-java' ) project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
include ':masterpassword:gui' include 'masterpassword-android'
project(':masterpassword:gui').projectDir = new File( '../platform-independent/gui-java' ) project(':masterpassword-android').projectDir = new File( '../platform-android' )

View File

@ -36,8 +36,8 @@ android {
} }
dependencies { dependencies {
compile project( ':masterpassword:algorithm' ) compile project( ':masterpassword-algorithm' )
compile project( ':masterpassword:tests' ) compile project( ':masterpassword-tests' )
compile group: 'org.slf4j', name: 'slf4j-android', version:'1.7.13-underscore' compile group: 'org.slf4j', name: 'slf4j-android', version:'1.7.13-underscore'
compile group: 'com.jakewharton', name: 'butterknife', version:'8.5.1' compile group: 'com.jakewharton', name: 'butterknife', version:'8.5.1'

View File

@ -32,6 +32,7 @@ public class EmergencyActivity extends Activity {
private static final Logger logger = Logger.get( EmergencyActivity.class ); 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 ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
private static final int PASSWORD_NOTIFICATION = 0; private static final int PASSWORD_NOTIFICATION = 0;
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
private final Preferences preferences = Preferences.get( this ); private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() ); private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
@ -81,14 +82,13 @@ public class EmergencyActivity extends Activity {
private int id_version; private int id_version;
private String sitePassword; private String sitePassword;
public static void start(Context context) { public static void start(final Context context) {
context.startActivity( new Intent( context, EmergencyActivity.class ) ); context.startActivity( new Intent( context, EmergencyActivity.class ) );
} }
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate( savedInstanceState ); super.onCreate( savedInstanceState );
Res.init( getResources() );
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE ); getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
setContentView( R.layout.activity_emergency ); setContentView( R.layout.activity_emergency );
@ -157,13 +157,13 @@ public class EmergencyActivity extends Activity {
} }
} ); } );
fullNameField.setTypeface( Res.exo_Thin ); fullNameField.setTypeface( Res.get( this ).exo_Thin );
fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setTypeface( Res.sourceCodePro_ExtraLight ); masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight );
masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setTypeface( Res.exo_Regular ); siteNameField.setTypeface( Res.get( this ).exo_Regular );
siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setTypeface( Res.sourceCodePro_Black ); sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@ -243,9 +243,11 @@ public class EmergencyActivity extends Activity {
final String fullName = fullNameField.getText().toString(); final String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray(); final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag(); final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
if (fullName.hashCode() == id_userName && Arrays.hashCode( masterPassword ) == id_masterPassword && if ((id_userName == fullName.hashCode())
version.ordinal() == id_version && masterKeyFuture != null && !masterKeyFuture.isCancelled()) && (id_masterPassword == Arrays.hashCode( masterPassword ))
return; && (id_version == version.ordinal()))
if ((masterKeyFuture != null) && !masterKeyFuture.isCancelled())
return;
id_userName = fullName.hashCode(); id_userName = fullName.hashCode();
id_masterPassword = Arrays.hashCode( masterPassword ); id_masterPassword = Arrays.hashCode( masterPassword );
@ -257,7 +259,7 @@ public class EmergencyActivity extends Activity {
if (masterKeyFuture != null) if (masterKeyFuture != null)
masterKeyFuture.cancel( true ); masterKeyFuture.cancel( true );
if (fullName.isEmpty() || masterPassword.length == 0) { if (fullName.isEmpty() || (masterPassword.length == 0)) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
return; return;
@ -272,7 +274,7 @@ public class EmergencyActivity extends Activity {
try { try {
return MasterKey.create( version, fullName, masterPassword ); return MasterKey.create( version, fullName, masterPassword );
} }
catch (Exception e) { catch (final Exception e) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating master key." ); logger.err( e, "While generating master key." );
@ -297,7 +299,7 @@ public class EmergencyActivity extends Activity {
final MPSiteType type = (MPSiteType) siteTypeButton.getTag(); final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() ); final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
if (masterKeyFuture == null || siteName.isEmpty() || type == null) { if ((masterKeyFuture == null) || siteName.isEmpty() || (type == null)) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
@ -322,17 +324,17 @@ public class EmergencyActivity extends Activity {
} }
} ); } );
} }
catch (InterruptedException ignored) { catch (final InterruptedException ignored) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
} }
catch (ExecutionException e) { catch (final ExecutionException e) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." ); logger.err( e, "While generating site password." );
throw Throwables.propagate( e ); throw Throwables.propagate( e );
} }
catch (RuntimeException e) { catch (final RuntimeException e) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." ); logger.err( e, "While generating site password." );
@ -342,7 +344,7 @@ public class EmergencyActivity extends Activity {
} ); } );
} }
public void integrityTests(View view) { public void integrityTests(final View view) {
if (masterKeyFuture != null) { if (masterKeyFuture != null) {
masterKeyFuture.cancel( true ); masterKeyFuture.cancel( true );
masterKeyFuture = null; masterKeyFuture = null;
@ -350,8 +352,8 @@ public class EmergencyActivity extends Activity {
TestActivity.startNoSkip( this ); TestActivity.startNoSkip( this );
} }
public void copySitePassword(View view) { public void copySitePassword(final View view) {
final String currentSitePassword = this.sitePassword; final String currentSitePassword = sitePassword;
if (TextUtils.isEmpty( currentSitePassword )) if (TextUtils.isEmpty( currentSitePassword ))
return; return;
@ -384,7 +386,7 @@ public class EmergencyActivity extends Activity {
notificationManager.cancel( PASSWORD_NOTIFICATION ); notificationManager.cancel( PASSWORD_NOTIFICATION );
timer.cancel(); timer.cancel();
} }
}, 20000 ); }, CLIPBOARD_CLEAR_DELAY );
Intent startMain = new Intent( Intent.ACTION_MAIN ); Intent startMain = new Intent( Intent.ACTION_MAIN );
startMain.addCategory( Intent.CATEGORY_HOME ); startMain.addCategory( Intent.CATEGORY_HOME );
@ -392,7 +394,7 @@ public class EmergencyActivity extends Activity {
startActivity( startMain ); startActivity( startMain );
} }
private abstract class ValueChangedListener private abstract static class ValueChangedListener
implements TextWatcher, NumberPicker.OnValueChangeListener, AdapterView.OnItemSelectedListener, View.OnFocusChangeListener { implements TextWatcher, NumberPicker.OnValueChangeListener, AdapterView.OnItemSelectedListener, View.OnFocusChangeListener {
abstract void update(); abstract void update();

View File

@ -53,7 +53,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
synchronized (commands) { synchronized (commands) {
ImmutableList<Runnable> pendingTasks = ImmutableList.copyOf( commands ); ImmutableList<Runnable> pendingTasks = ImmutableList.copyOf( commands );
commands.clear(); commands.clear();
commands.notify(); commands.notifyAll();
return pendingTasks; return pendingTasks;
} }
} }

View File

@ -12,7 +12,7 @@ import javax.annotation.Nullable;
/** /**
* @author lhunath, 2016-02-20 * @author lhunath, 2016-02-20
*/ */
public class Preferences { public final class Preferences {
private static final String PREF_TESTS_PASSED = "integrityTestsPassed"; private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
private static final String PREF_NATIVE_KDF = "nativeKDF"; private static final String PREF_NATIVE_KDF = "nativeKDF";
@ -35,7 +35,7 @@ public class Preferences {
return instance; return instance;
} }
private Preferences(Context context) { private Preferences(final Context context) {
this.context = context; this.context = context;
} }
@ -47,7 +47,7 @@ public class Preferences {
return prefs; return prefs;
} }
public boolean setNativeKDFEnabled(boolean enabled) { public boolean setNativeKDFEnabled(final boolean enabled) {
if (isAllowNativeKDF() == enabled) if (isAllowNativeKDF() == enabled)
return false; return false;
@ -71,7 +71,7 @@ public class Preferences {
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() ); return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() );
} }
public boolean setRememberFullName(boolean enabled) { public boolean setRememberFullName(final boolean enabled) {
if (isRememberFullName() == enabled) if (isRememberFullName() == enabled)
return false; return false;
@ -83,7 +83,7 @@ public class Preferences {
return prefs().getBoolean( PREF_REMEMBER_FULL_NAME, false ); return prefs().getBoolean( PREF_REMEMBER_FULL_NAME, false );
} }
public boolean setForgetPassword(boolean enabled) { public boolean setForgetPassword(final boolean enabled) {
if (isForgetPassword() == enabled) if (isForgetPassword() == enabled)
return false; return false;
@ -95,7 +95,7 @@ public class Preferences {
return prefs().getBoolean( PREF_FORGET_PASSWORD, false ); return prefs().getBoolean( PREF_FORGET_PASSWORD, false );
} }
public boolean setMaskPassword(boolean enabled) { public boolean setMaskPassword(final boolean enabled) {
if (isMaskPassword() == enabled) if (isMaskPassword() == enabled)
return false; return false;
@ -107,7 +107,7 @@ public class Preferences {
return prefs().getBoolean( PREF_MASK_PASSWORD, false ); return prefs().getBoolean( PREF_MASK_PASSWORD, false );
} }
public boolean setFullName(@Nullable String value) { public boolean setFullName(@Nullable final String value) {
if (getFullName().equals( value )) if (getFullName().equals( value ))
return false; return false;
@ -120,8 +120,8 @@ public class Preferences {
return prefs().getString( PREF_FULL_NAME, "" ); return prefs().getString( PREF_FULL_NAME, "" );
} }
public boolean setDefaultSiteType(@Nonnull MPSiteType value) { public boolean setDefaultSiteType(@Nonnull final MPSiteType value) {
if (getDefaultSiteType().equals( value )) if (getDefaultSiteType() == value)
return false; return false;
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply(); prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
@ -133,8 +133,8 @@ public class Preferences {
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )]; return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
} }
public boolean setDefaultVersion(@Nonnull MasterKey.Version value) { public boolean setDefaultVersion(@Nonnull final MasterKey.Version value) {
if (getDefaultVersion().equals( value )) if (getDefaultVersion() == value)
return false; return false;
prefs().edit().putInt( PREF_ALGORITHM_VERSION, value.ordinal() ).apply(); prefs().edit().putInt( PREF_ALGORITHM_VERSION, value.ordinal() ).apply();

View File

@ -1,5 +1,6 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Typeface; import android.graphics.Typeface;
@ -7,28 +8,32 @@ import android.graphics.Typeface;
/** /**
* @author lhunath, 2014-08-25 * @author lhunath, 2014-08-25
*/ */
public class Res { public final class Res {
public static Typeface sourceCodePro_Black; public final Typeface sourceCodePro_Black;
public static Typeface sourceCodePro_ExtraLight; public final Typeface sourceCodePro_ExtraLight;
public static Typeface exo_Bold; public final Typeface exo_Bold;
public static Typeface exo_ExtraBold; public final Typeface exo_ExtraBold;
public static Typeface exo_Regular; public final Typeface exo_Regular;
public static Typeface exo_Thin; public final Typeface exo_Thin;
private static boolean initialized; private static Res res;
public static void init(Resources resources) { public static synchronized Res get(final Context context) {
if (res == null)
res = new Res( context );
if (initialized) return res;
return; }
initialized = true;
sourceCodePro_Black = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-Black.otf" ); @SuppressWarnings("HardCodedStringLiteral")
sourceCodePro_ExtraLight = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-ExtraLight.otf" ); private Res(final Context context) {
exo_Bold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Bold.otf" );
exo_ExtraBold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-ExtraBold.otf" ); sourceCodePro_Black = Typeface.createFromAsset( context.getResources().getAssets(), "SourceCodePro-Black.otf" );
exo_Regular = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Regular.otf" ); sourceCodePro_ExtraLight = Typeface.createFromAsset( context.getResources().getAssets(), "SourceCodePro-ExtraLight.otf" );
exo_Thin = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Thin.otf" ); exo_Bold = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Bold.otf" );
exo_ExtraBold = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-ExtraBold.otf" );
exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" );
exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" );
} }
} }

View File

@ -47,14 +47,13 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
private Runnable action; private Runnable action;
private ImmutableSet<String> testNames; private ImmutableSet<String> testNames;
public static void startNoSkip(Context context) { public static void startNoSkip(final Context context) {
context.startActivity( new Intent( context, TestActivity.class ) ); context.startActivity( new Intent( context, TestActivity.class ) );
} }
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate( savedInstanceState ); super.onCreate( savedInstanceState );
Res.init( getResources() );
setContentView( R.layout.activity_test ); setContentView( R.layout.activity_test );
ButterKnife.bind( this ); ButterKnife.bind( this );
@ -76,11 +75,11 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
@Nullable @Nullable
@Override @Override
public String apply(@Nullable final MPTests.Case input) { public String apply(@Nullable final MPTests.Case input) {
return input == null? null: input.identifier; return (input == null)? null: input.identifier;
} }
} ).filter( Predicates.notNull() ).toSet(); } ).filter( Predicates.notNull() ).toSet();
} }
catch (MPTestSuite.UnavailableException e) { catch (final MPTestSuite.UnavailableException e) {
logger.err( e, "While loading test suite" ); logger.err( e, "While loading test suite" );
setStatus( R.string.tests_unavailable, R.string.tests_btn_unavailable, new Runnable() { setStatus( R.string.tests_unavailable, R.string.tests_btn_unavailable, new Runnable() {
@Override @Override
@ -111,7 +110,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() { Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
@Override @Override
public void onSuccess(@Nullable final Boolean result) { public void onSuccess(@Nullable final Boolean result) {
if (result != null && result) if ((result != null) && result)
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() { setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -141,12 +140,12 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
}, mainExecutor ); }, mainExecutor );
} }
public void onAction(View v) { public void onAction(final View v) {
if (action != null) if (action != null)
action.run(); action.run();
} }
private void setStatus(int statusId, int buttonId, @Nullable Runnable action) { private void setStatus(final int statusId, final int buttonId, @Nullable final Runnable action) {
this.action = action; this.action = action;
if (statusId == 0) if (statusId == 0)
@ -166,7 +165,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
runOnUiThread( new Runnable() { runOnUiThread( new Runnable() {
@Override @Override
public void run() { public void run() {
logView.append( strf( '\n' + messageFormat, args ) ); logView.append( strf( "%n" + messageFormat, args ) );
progressView.setMax( max ); progressView.setMax( max );
progressView.setProgress( current ); progressView.setProgress( current );

View File

@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true" android:fillViewport="true">
android:background="@drawable/background">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true" android:fillViewport="true">
android:background="@drawable/background">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -53,6 +52,7 @@
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:gravity="bottom" android:gravity="bottom"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textIsSelectable="true"
android:textSize="9sp" android:textSize="9sp"
android:textColor="@android:color/tertiary_text_dark" /> android:textColor="@android:color/tertiary_text_dark" />

View File

@ -2,5 +2,6 @@
<resources> <resources>
<style name="MPTheme" parent="android:Theme.Holo.Dialog.MinWidth"> <style name="MPTheme" parent="android:Theme.Holo.Dialog.MinWidth">
<item name="android:windowBackground">@drawable/background</item>
</style> </style>
</resources> </resources>

View File

@ -8,7 +8,7 @@ description = 'Master Password CLI'
mainClassName = 'com.lyndir.masterpassword.CLI' mainClassName = 'com.lyndir.masterpassword.CLI'
dependencies { dependencies {
compile project(':masterpassword:algorithm') compile project(':masterpassword-algorithm')
compile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2' compile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
} }

View File

@ -19,6 +19,7 @@ package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.io.LineReader; import com.google.common.io.LineReader;
@ -35,9 +36,10 @@ import java.util.Map;
* *
* @author mbillemo * @author mbillemo
*/ */
public class CLI { @SuppressWarnings({ "UseOfSystemOutOrSystemErr", "HardCodedStringLiteral" })
public final class CLI {
public static void main(final String[] args) public static void main(final String... args)
throws IOException { throws IOException {
// Read information from the environment. // Read information from the environment.
@ -96,68 +98,68 @@ public class CLI {
// Help // Help
else if ("-h".equals( arg ) || "--help".equals( arg )) { else if ("-h".equals( arg ) || "--help".equals( arg )) {
System.out.println(); System.out.println();
System.out.format( "Usage: mpw [-u name] [-t type] [-c counter] site\n\n" ); System.out.format( "Usage: mpw [-u name] [-t type] [-c counter] site%n%n" );
System.out.format( " -u name Specify the full name of the user.\n" ); System.out.format( " -u name Specify the full name of the user.%n" );
System.out.format( " Defaults to %s in env.\n\n", MPConstant.env_userName ); System.out.format( " Defaults to %s in env.%n%n", MPConstant.env_userName );
System.out.format( " -t type Specify the password's template.\n" ); System.out.format( " -t type Specify the password's template.%n" );
System.out.format( " Defaults to %s in env or 'long' for password, 'name' for login.\n", MPConstant.env_siteType ); System.out.format( " Defaults to %s in env or 'long' for password, 'name' for login.%n", MPConstant.env_siteType );
int optionsLength = 0; int optionsLength = 0;
Map<String, MPSiteType> typeMap = Maps.newLinkedHashMap(); Map<String, MPSiteType> typeMap = Maps.newLinkedHashMap();
for (MPSiteType elementType : MPSiteType.values()) { for (final MPSiteType elementType : MPSiteType.values()) {
String options = Joiner.on( ", " ).join( elementType.getOptions() ); String options = Joiner.on( ", " ).join( elementType.getOptions() );
typeMap.put( options, elementType ); typeMap.put( options, elementType );
optionsLength = Math.max( optionsLength, options.length() ); optionsLength = Math.max( optionsLength, options.length() );
} }
for (Map.Entry<String, MPSiteType> entry : typeMap.entrySet()) { for (final Map.Entry<String, MPSiteType> entry : typeMap.entrySet()) {
String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() ); String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
String infoNewline = "\n" + StringUtils.repeat( " ", infoString.length() - 3 ) + " | "; String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
infoString += entry.getValue().getDescription().replaceAll( "\n", infoNewline ); infoString += entry.getValue().getDescription().replaceAll( strf( "%n" ), infoNewline );
System.out.println( infoString ); System.out.println( infoString );
} }
System.out.println(); System.out.println();
System.out.format( " -c counter The value of the counter.\n" ); System.out.format( " -c counter The value of the counter.%n" );
System.out.format( " Defaults to %s in env or '1'.\n\n", MPConstant.env_siteCounter ); System.out.format( " Defaults to %s in env or '1'.%n%n", MPConstant.env_siteCounter );
System.out.format( " -v variant The kind of content to generate.\n" ); System.out.format( " -v variant The kind of content to generate.%n" );
System.out.format( " Defaults to 'password'.\n" ); System.out.format( " Defaults to 'password'.%n" );
optionsLength = 0; optionsLength = 0;
Map<String, MPSiteVariant> variantMap = Maps.newLinkedHashMap(); Map<String, MPSiteVariant> variantMap = Maps.newLinkedHashMap();
for (MPSiteVariant elementVariant : MPSiteVariant.values()) { for (final MPSiteVariant elementVariant : MPSiteVariant.values()) {
String options = Joiner.on( ", " ).join( elementVariant.getOptions() ); String options = Joiner.on( ", " ).join( elementVariant.getOptions() );
variantMap.put( options, elementVariant ); variantMap.put( options, elementVariant );
optionsLength = Math.max( optionsLength, options.length() ); optionsLength = Math.max( optionsLength, options.length() );
} }
for (Map.Entry<String, MPSiteVariant> entry : variantMap.entrySet()) { for (final Map.Entry<String, MPSiteVariant> entry : variantMap.entrySet()) {
String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() ); String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
String infoNewline = "\n" + StringUtils.repeat( " ", infoString.length() - 3 ) + " | "; String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
infoString += entry.getValue().getDescription().replaceAll( "\n", infoNewline ); infoString += entry.getValue().getDescription().replaceAll( strf( "%n" ), infoNewline );
System.out.println( infoString ); System.out.println( infoString );
} }
System.out.println(); System.out.println();
System.out.format( " -C context A variant-specific context.\n" ); System.out.format( " -C context A variant-specific context.%n" );
System.out.format( " Defaults to empty.\n" ); System.out.format( " Defaults to empty.%n" );
for (Map.Entry<String, MPSiteVariant> entry : variantMap.entrySet()) { for (final Map.Entry<String, MPSiteVariant> entry : variantMap.entrySet()) {
String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() ); String infoString = strf( " -v %" + optionsLength + "s | ", entry.getKey() );
String infoNewline = "\n" + StringUtils.repeat( " ", infoString.length() - 3 ) + " | "; String infoNewline = strf( "%n%s | ", StringUtils.repeat( " ", infoString.length() - 3 ) );
infoString += entry.getValue().getContextDescription().replaceAll( "\n", infoNewline ); infoString += entry.getValue().getContextDescription().replaceAll( strf( "%n" ), infoNewline );
System.out.println( infoString ); System.out.println( infoString );
} }
System.out.println(); System.out.println();
System.out.format( " ENVIRONMENT\n\n" ); System.out.format( " ENVIRONMENT%n%n" );
System.out.format( " MP_USERNAME | The full name of the user.\n" ); System.out.format( " MP_USERNAME | The full name of the user.%n" );
System.out.format( " MP_SITETYPE | The default password template.\n" ); System.out.format( " MP_SITETYPE | The default password template.%n" );
System.out.format( " MP_SITECOUNTER | The default counter value.\n\n" ); System.out.format( " MP_SITECOUNTER | The default counter value.%n%n" );
return; return;
} else } else
siteName = arg; siteName = arg;
// Read missing information from the console. // Read missing information from the console.
Console console = System.console(); Console console = System.console();
try (InputStreamReader inReader = new InputStreamReader( System.in )) { try (InputStreamReader inReader = new InputStreamReader( System.in, Charsets.UTF_8 )) {
LineReader lineReader = new LineReader( inReader ); LineReader lineReader = new LineReader( inReader );
if (siteName == null) { if (siteName == null) {

View File

@ -8,7 +8,7 @@ description = 'Master Password GUI'
mainClassName = 'com.lyndir.masterpassword.gui.GUI' mainClassName = 'com.lyndir.masterpassword.gui.GUI'
dependencies { dependencies {
compile project(':masterpassword:model') compile project(':masterpassword-model')
compile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2' compile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
compile group: 'com.yuvimasory', name: 'orange-extensions', version:'1.3.0' compile group: 'com.yuvimasory', name: 'orange-extensions', version:'1.3.0'

View File

@ -46,8 +46,7 @@ public class GUI implements UnlockFrame.SignInCallback {
private final UnlockFrame unlockFrame = new UnlockFrame( this ); private final UnlockFrame unlockFrame = new UnlockFrame( this );
private PasswordFrame passwordFrame; private PasswordFrame passwordFrame;
public static void main(final String[] args) public static void main(final String... args) {
throws IOException {
if (Config.get().checkForUpdates()) if (Config.get().checkForUpdates())
checkUpdate(); checkUpdate();
@ -76,7 +75,7 @@ public class GUI implements UnlockFrame.SignInCallback {
String upstreamRevision = upstream.readFirstLine(); String upstreamRevision = upstream.readFirstLine();
logger.inf( "Local Revision: <%s>", manifestRevision ); logger.inf( "Local Revision: <%s>", manifestRevision );
logger.inf( "Upstream Revision: <%s>", upstreamRevision ); logger.inf( "Upstream Revision: <%s>", upstreamRevision );
if (manifestRevision != null && !manifestRevision.equalsIgnoreCase( upstreamRevision )) { if ((manifestRevision != null) && !manifestRevision.equalsIgnoreCase( upstreamRevision )) {
logger.wrn( "You are not running the current official version. Please update from:\n" logger.wrn( "You are not running the current official version. Please update from:\n"
+ "http://masterpasswordapp.com/masterpassword-gui.jar" ); + "http://masterpasswordapp.com/masterpassword-gui.jar" );
JOptionPane.showMessageDialog( null, "A new version of Master Password is available.\n" JOptionPane.showMessageDialog( null, "A new version of Master Password is available.\n"
@ -85,7 +84,7 @@ public class GUI implements UnlockFrame.SignInCallback {
} }
} }
} }
catch (IOException e) { catch (final IOException e) {
logger.wrn( e, "Couldn't check for version update." ); logger.wrn( e, "Couldn't check for version update." );
} }
} }

View File

@ -23,14 +23,17 @@ import java.util.concurrent.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.*; import javax.swing.*;
import org.jetbrains.annotations.NonNls;
/** /**
* @author lhunath, 2014-06-11 * @author lhunath, 2014-06-11
*/ */
@SuppressWarnings("HardcodedFileSeparator")
public abstract class Res { public abstract class Res {
private static final WeakHashMap<Window, ScheduledExecutorService> executorByWindow = new WeakHashMap<>(); private static final int AVATAR_COUNT = 19;
private static final Map<Window, ScheduledExecutorService> executorByWindow = new WeakHashMap<>();
private static final Logger logger = Logger.get( Res.class ); private static final Logger logger = Logger.get( Res.class );
private static final Colors colors = new Colors(); private static final Colors colors = new Colors();
@ -45,7 +48,7 @@ public abstract class Res {
try { try {
job.run(); job.run();
} }
catch (Throwable t) { catch (final Throwable t) {
logger.err( t, "Unexpected: %s", t.getLocalizedMessage() ); logger.err( t, "Unexpected: %s", t.getLocalizedMessage() );
} }
} }
@ -65,9 +68,9 @@ public abstract class Res {
try { try {
return job.call(); return job.call();
} }
catch (Throwable t) { catch (final Throwable t) {
logger.err( t, "Unexpected: %s", t.getLocalizedMessage() ); logger.err( t, "Unexpected: %s", t.getLocalizedMessage() );
throw t; throw Throwables.propagate( t );
} }
} }
}, delay, timeUnit ), executor ); }, delay, timeUnit ), executor );
@ -109,7 +112,7 @@ public abstract class Res {
} }
public static int avatars() { public static int avatars() {
return 19; return AVATAR_COUNT;
} }
public static Font emoticonsFont() { public static Font emoticonsFont() {
@ -180,10 +183,10 @@ public abstract class Res {
return font( "fonts/Arimo-Regular.ttf" ); return font( "fonts/Arimo-Regular.ttf" );
} }
private static Font font(String fontResourceName) { private static Font font(@NonNls final String fontResourceName) {
Map<String, SoftReference<Font>> fontsByResourceName = Maps.newHashMap(); Map<String, SoftReference<Font>> fontsByResourceName = Maps.newHashMap();
SoftReference<Font> fontRef = fontsByResourceName.get( fontResourceName ); SoftReference<Font> fontRef = fontsByResourceName.get( fontResourceName );
Font font = fontRef == null? null: fontRef.get(); Font font = (fontRef == null)? null: fontRef.get();
if (font == null) if (font == null)
try { try {
fontsByResourceName.put( fontResourceName, new SoftReference<>( fontsByResourceName.put( fontResourceName, new SoftReference<>(
@ -203,17 +206,15 @@ public abstract class Res {
private static final class RetinaIcon extends ImageIcon { private static final class RetinaIcon extends ImageIcon {
private static final Pattern scalePattern = Pattern.compile( ".*@(\\d+)x.[^.]+$" ); private static final Pattern scalePattern = Pattern.compile( ".*@(\\d+)x.[^.]+$" );
private static final long serialVersionUID = 1L;
private final float scale; private final float scale;
public RetinaIcon(final URL url) { private RetinaIcon(final URL url) {
super( url ); super( url );
Matcher scaleMatcher = scalePattern.matcher( url.getPath() ); Matcher scaleMatcher = scalePattern.matcher( url.getPath() );
if (scaleMatcher.matches()) scale = scaleMatcher.matches()? Float.parseFloat( scaleMatcher.group( 1 ) ): 1;
scale = Float.parseFloat( scaleMatcher.group( 1 ) );
else
scale = 1;
} }
//private static URL retinaURL(final URL url) { //private static URL retinaURL(final URL url) {
@ -242,13 +243,14 @@ public abstract class Res {
return (int) (super.getIconHeight() / scale); return (int) (super.getIconHeight() / scale);
} }
public synchronized void paintIcon(Component c, Graphics g, int x, int y) { @Override
public synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) {
ImageObserver observer = ifNotNullElse( getImageObserver(), c ); ImageObserver observer = ifNotNullElse( getImageObserver(), c );
Image image = getImage(); Image image = getImage();
int width = image.getWidth( observer ); int width = image.getWidth( observer );
int height = image.getHeight( observer ); int height = image.getHeight( observer );
final Graphics2D g2d = (Graphics2D) g.create( x, y, width, height ); Graphics2D g2d = (Graphics2D) g.create( x, y, width, height );
g2d.scale( 1 / scale, 1 / scale ); g2d.scale( 1 / scale, 1 / scale );
g2d.drawImage( image, 0, 0, observer ); g2d.drawImage( image, 0, 0, observer );
@ -276,7 +278,7 @@ public abstract class Res {
return controlBorder; return controlBorder;
} }
public Color fromIdenticonColor(MPIdenticon.Color identiconColor, BackgroundMode backgroundMode) { public Color fromIdenticonColor(final MPIdenticon.Color identiconColor, final BackgroundMode backgroundMode) {
switch (identiconColor) { switch (identiconColor) {
case RED: case RED:
switch (backgroundMode) { switch (backgroundMode) {

View File

@ -23,18 +23,22 @@ public class IncognitoSite extends Site {
this.algorithmVersion = algorithmVersion; this.algorithmVersion = algorithmVersion;
} }
@Override
public String getSiteName() { public String getSiteName() {
return siteName; return siteName;
} }
@Override
public void setSiteName(final String siteName) { public void setSiteName(final String siteName) {
this.siteName = siteName; this.siteName = siteName;
} }
@Override
public MPSiteType getSiteType() { public MPSiteType getSiteType() {
return siteType; return siteType;
} }
@Override
public void setSiteType(final MPSiteType siteType) { public void setSiteType(final MPSiteType siteType) {
this.siteType = siteType; this.siteType = siteType;
} }
@ -49,10 +53,12 @@ public class IncognitoSite extends Site {
this.algorithmVersion = algorithmVersion; this.algorithmVersion = algorithmVersion;
} }
@Override
public UnsignedInteger getSiteCounter() { public UnsignedInteger getSiteCounter() {
return siteCounter; return siteCounter;
} }
@Override
public void setSiteCounter(final UnsignedInteger siteCounter) { public void setSiteCounter(final UnsignedInteger siteCounter) {
this.siteCounter = siteCounter; this.siteCounter = siteCounter;
} }

View File

@ -11,12 +11,14 @@ import javax.annotation.Nullable;
public class IncognitoUser extends User { public class IncognitoUser extends User {
private final String fullName; private final String fullName;
@Nullable
private char[] masterPassword; private char[] masterPassword;
public IncognitoUser(final String fullName) { public IncognitoUser(final String fullName) {
this.fullName = fullName; this.fullName = fullName;
} }
@Override
public String getFullName() { public String getFullName() {
return fullName; return fullName;
} }
@ -30,7 +32,7 @@ public class IncognitoUser extends User {
@Override @Override
public void authenticate(final char[] masterPassword) public void authenticate(final char[] masterPassword)
throws IncorrectMasterPasswordException { throws IncorrectMasterPasswordException {
this.masterPassword = masterPassword; this.masterPassword = masterPassword.clone();
} }
@Override @Override
@ -43,6 +45,6 @@ public class IncognitoUser extends User {
} }
@Override @Override
public void deleteSite(Site site) { public void deleteSite(final Site site) {
} }
} }

View File

@ -14,13 +14,14 @@ public class ModelSite extends Site {
private final MPSite model; private final MPSite model;
public ModelSite(final MPSiteResult result) { public ModelSite(final MPSiteResult result) {
this.model = result.getSite(); model = result.getSite();
} }
public MPSite getModel() { public MPSite getModel() {
return model; return model;
} }
@Override
public String getSiteName() { public String getSiteName() {
return model.getSiteName(); return model.getSiteName();
} }
@ -31,6 +32,7 @@ public class ModelSite extends Site {
MPUserFileManager.get().save(); MPUserFileManager.get().save();
} }
@Override
public MPSiteType getSiteType() { public MPSiteType getSiteType() {
return model.getSiteType(); return model.getSiteType();
} }
@ -56,6 +58,7 @@ public class ModelSite extends Site {
} }
} }
@Override
public UnsignedInteger getSiteCounter() { public UnsignedInteger getSiteCounter() {
return model.getSiteCounter(); return model.getSiteCounter();
} }

View File

@ -19,7 +19,7 @@ public class ModelUser extends User {
@Nullable @Nullable
private char[] masterPassword; private char[] masterPassword;
public ModelUser(MPUser model) { public ModelUser(final MPUser model) {
this.model = model; this.model = model;
} }
@ -48,10 +48,11 @@ public class ModelUser extends User {
MPUserFileManager.get().save(); MPUserFileManager.get().save();
} }
@Override
public void authenticate(final char[] masterPassword) public void authenticate(final char[] masterPassword)
throws IncorrectMasterPasswordException { throws IncorrectMasterPasswordException {
putKey( model.authenticate( masterPassword ) ); putKey( model.authenticate( masterPassword ) );
this.masterPassword = masterPassword; this.masterPassword = masterPassword.clone();
MPUserFileManager.get().save(); MPUserFileManager.get().save();
} }
@ -66,8 +67,8 @@ public class ModelUser extends User {
} }
@Override @Override
public Iterable<Site> findSitesByName(final String query) { public Iterable<Site> findSitesByName(final String siteName) {
return FluentIterable.from( model.findSitesByName( query ) ).transform( new Function<MPSiteResult, Site>() { return FluentIterable.from( model.findSitesByName( siteName ) ).transform( new Function<MPSiteResult, Site>() {
@Nullable @Nullable
@Override @Override
public Site apply(@Nullable final MPSiteResult site) { public Site apply(@Nullable final MPSiteResult site) {
@ -84,7 +85,7 @@ public class ModelUser extends User {
} }
@Override @Override
public void deleteSite(Site site) { public void deleteSite(final Site site) {
if (site instanceof ModelSite) { if (site instanceof ModelSite) {
model.deleteSite(((ModelSite) site).getModel()); model.deleteSite(((ModelSite) site).getModel());
MPUserFileManager.get().save(); MPUserFileManager.get().save();

View File

@ -14,19 +14,19 @@ public abstract class Site {
public abstract String getSiteName(); public abstract String getSiteName();
public abstract void setSiteName(final String siteName); public abstract void setSiteName(String siteName);
public abstract MPSiteType getSiteType(); public abstract MPSiteType getSiteType();
public abstract void setSiteType(final MPSiteType siteType); public abstract void setSiteType(MPSiteType siteType);
public abstract MasterKey.Version getAlgorithmVersion(); public abstract MasterKey.Version getAlgorithmVersion();
public abstract void setAlgorithmVersion(final MasterKey.Version algorithmVersion); public abstract void setAlgorithmVersion(MasterKey.Version algorithmVersion);
public abstract UnsignedInteger getSiteCounter(); public abstract UnsignedInteger getSiteCounter();
public abstract void setSiteCounter(final UnsignedInteger siteCounter); public abstract void setSiteCounter(UnsignedInteger siteCounter);
@Override @Override
public String toString() { public String toString() {

View File

@ -4,8 +4,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.lyndir.masterpassword.MasterKey; import com.lyndir.masterpassword.MasterKey;
import com.lyndir.masterpassword.model.IncorrectMasterPasswordException; import com.lyndir.masterpassword.model.IncorrectMasterPasswordException;
import java.util.EnumMap; import java.util.*;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -16,14 +15,15 @@ import javax.annotation.Nullable;
public abstract class User { public abstract class User {
@Nonnull @Nonnull
private final EnumMap<MasterKey.Version, MasterKey> keyByVersion = Maps.newEnumMap( MasterKey.Version.class ); private final Map<MasterKey.Version, MasterKey> keyByVersion = Maps.newEnumMap( MasterKey.Version.class );
public abstract String getFullName(); public abstract String getFullName();
@Nullable @Nullable
protected abstract char[] getMasterPassword(); protected abstract char[] getMasterPassword();
public abstract void authenticate(final char[] masterPassword) @SuppressWarnings("MethodCanBeVariableArityMethod")
public abstract void authenticate(char[] masterPassword)
throws IncorrectMasterPasswordException; throws IncorrectMasterPasswordException;
public int getAvatar() { public int getAvatar() {
@ -35,7 +35,7 @@ public abstract class User {
} }
@Nonnull @Nonnull
public MasterKey getKey(MasterKey.Version algorithmVersion) { public MasterKey getKey(final MasterKey.Version algorithmVersion) {
char[] masterPassword = Preconditions.checkNotNull( getMasterPassword(), "User is not authenticated: " + getFullName() ); char[] masterPassword = Preconditions.checkNotNull( getMasterPassword(), "User is not authenticated: " + getFullName() );
MasterKey key = keyByVersion.get( algorithmVersion ); MasterKey key = keyByVersion.get( algorithmVersion );
@ -47,26 +47,26 @@ public abstract class User {
return key; return key;
} }
protected void putKey(MasterKey masterKey) { protected void putKey(final MasterKey masterKey) {
MasterKey oldKey = keyByVersion.put( masterKey.getAlgorithmVersion(), masterKey ); MasterKey oldKey = keyByVersion.put( masterKey.getAlgorithmVersion(), masterKey );
if (oldKey != null) if (oldKey != null)
oldKey.invalidate(); oldKey.invalidate();
} }
public void reset() { public void reset() {
for (MasterKey key : keyByVersion.values()) for (final MasterKey key : keyByVersion.values())
key.invalidate(); key.invalidate();
} }
public abstract Iterable<Site> findSitesByName(final String siteName); public abstract Iterable<Site> findSitesByName(String siteName);
public abstract void addSite(final Site site); public abstract void addSite(Site site);
public abstract void deleteSite(final Site site); public abstract void deleteSite(Site site);
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return this == obj || obj instanceof User && Objects.equals( getFullName(), ((User) obj).getFullName() ); return (this == obj) || ((obj instanceof User) && Objects.equals( getFullName(), ((User) obj).getFullName() ));
} }
@Override @Override

View File

@ -0,0 +1,9 @@
/**
*
* @author lhunath, 15-02-04
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword.gui.model;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -19,17 +19,17 @@ public class AppleGUI extends GUI {
application.addAppEventListener( new AppForegroundListener() { application.addAppEventListener( new AppForegroundListener() {
@Override @Override
public void appMovedToBackground(AppEvent.AppForegroundEvent arg0) { public void appMovedToBackground(final AppEvent.AppForegroundEvent arg0) {
} }
@Override @Override
public void appRaisedToForeground(AppEvent.AppForegroundEvent arg0) { public void appRaisedToForeground(final AppEvent.AppForegroundEvent arg0) {
open(); open();
} }
} ); } );
application.addAppEventListener( new AppReOpenedListener() { application.addAppEventListener( new AppReOpenedListener() {
@Override @Override
public void appReOpened(AppEvent.AppReOpenedEvent arg0) { public void appReOpened(final AppEvent.AppReOpenedEvent arg0) {
open(); open();
} }
} ); } );

View File

@ -13,11 +13,11 @@ import javax.swing.border.CompoundBorder;
*/ */
public abstract class Components { public abstract class Components {
public static GradientPanel boxLayout(int axis, Component... components) { public static GradientPanel boxLayout(final int axis, final Component... components) {
GradientPanel container = gradientPanel( null, null ); GradientPanel container = gradientPanel( null, null );
// container.setBackground( Color.red ); // container.setBackground( Color.red );
container.setLayout( new BoxLayout( container, axis ) ); container.setLayout( new BoxLayout( container, axis ) );
for (Component component : components) for (final Component component : components)
container.add( component ); container.add( component );
return container; return container;
@ -27,7 +27,7 @@ public abstract class Components {
return borderPanel( component, border, null ); return borderPanel( component, border, null );
} }
public static GradientPanel borderPanel(final JComponent component, @Nullable final Border border, @Nullable Color background) { public static GradientPanel borderPanel(final JComponent component, @Nullable final Border border, @Nullable final Color background) {
GradientPanel box = boxLayout( BoxLayout.LINE_AXIS, component ); GradientPanel box = boxLayout( BoxLayout.LINE_AXIS, component );
if (border != null) if (border != null)
@ -83,7 +83,7 @@ public abstract class Components {
}; };
} }
public static JButton button(String label) { public static JButton button(final String label) {
return new JButton( label ) { return new JButton( label ) {
{ {
setFont( Res.controlFont().deriveFont( 12f ) ); setFont( Res.controlFont().deriveFont( 12f ) );
@ -126,18 +126,18 @@ public abstract class Components {
}; };
} }
public static JLabel label(@Nullable String label) { public static JLabel label(@Nullable final String label) {
return label( label, SwingConstants.LEADING ); return label( label, SwingConstants.LEADING );
} }
/** /**
* @param horizontalAlignment One of the following constants * @param horizontalAlignment One of the following constants
* defined in <code>SwingConstants</code>: * defined in {@code SwingConstants}:
* <code>LEFT</code>, * {@code LEFT},
* <code>CENTER</code>, * {@code CENTER},
* <code>RIGHT</code>, * {@code RIGHT},
* <code>LEADING</code> or * {@code LEADING} or
* <code>TRAILING</code>. * {@code TRAILING}.
*/ */
public static JLabel label(@Nullable final String label, final int horizontalAlignment) { public static JLabel label(@Nullable final String label, final int horizontalAlignment) {
return new JLabel( label, horizontalAlignment ) { return new JLabel( label, horizontalAlignment ) {

View File

@ -9,7 +9,6 @@ import java.awt.*;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.*; import javax.swing.*;
import org.jetbrains.annotations.NotNull;
/** /**
@ -20,7 +19,7 @@ public abstract class AuthenticationPanel extends Components.GradientPanel {
protected final UnlockFrame unlockFrame; protected final UnlockFrame unlockFrame;
protected final JLabel avatarLabel; protected final JLabel avatarLabel;
public AuthenticationPanel(final UnlockFrame unlockFrame) { protected AuthenticationPanel(final UnlockFrame unlockFrame) {
super( null, null ); super( null, null );
this.unlockFrame = unlockFrame; this.unlockFrame = unlockFrame;
@ -39,7 +38,7 @@ public abstract class AuthenticationPanel extends Components.GradientPanel {
avatarLabel.setToolTipText( "The avatar for your user. Click to change it." ); avatarLabel.setToolTipText( "The avatar for your user. Click to change it." );
} }
protected void updateUser(boolean repack) { protected void updateUser(final boolean repack) {
unlockFrame.updateUser( getSelectedUser() ); unlockFrame.updateUser( getSelectedUser() );
validate(); validate();
@ -50,7 +49,6 @@ public abstract class AuthenticationPanel extends Components.GradientPanel {
@Nullable @Nullable
protected abstract User getSelectedUser(); protected abstract User getSelectedUser();
@NotNull
@Nonnull @Nonnull
public abstract char[] getMasterPassword(); public abstract char[] getMasterPassword();

View File

@ -7,10 +7,10 @@ import com.lyndir.masterpassword.gui.util.Components;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import javax.annotation.Nonnull;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import org.jetbrains.annotations.NotNull;
/** /**
@ -62,7 +62,7 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel implements
return new IncognitoUser( fullNameField.getText() ); return new IncognitoUser( fullNameField.getText() );
} }
@NotNull @Nonnull
@Override @Override
public char[] getMasterPassword() { public char[] getMasterPassword() {
return masterPasswordField.getPassword(); return masterPasswordField.getPassword();

View File

@ -13,12 +13,12 @@ import com.lyndir.masterpassword.model.MPUserFileManager;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.plaf.metal.MetalComboBoxEditor; import javax.swing.plaf.metal.MetalComboBoxEditor;
import org.jetbrains.annotations.NotNull;
/** /**
@ -109,7 +109,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite
return userField.getModel().getElementAt( selectedIndex ); return userField.getModel().getElementAt( selectedIndex );
} }
@NotNull @Nonnull
@Override @Override
public char[] getMasterPassword() { public char[] getMasterPassword() {
return masterPasswordField.getPassword(); return masterPasswordField.getPassword();
@ -175,7 +175,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel implements Ite
masterPasswordField.setText( "" ); masterPasswordField.setText( "" );
} }
private ModelUser[] readConfigUsers() { private static ModelUser[] readConfigUsers() {
return FluentIterable.from( MPUserFileManager.get().getUsers() ).transform( new Function<MPUser, ModelUser>() { return FluentIterable.from( MPUserFileManager.get().getUsers() ).transform( new Function<MPUser, ModelUser>() {
@Nullable @Nullable
@Override @Override

View File

@ -28,7 +28,7 @@ import javax.swing.event.*;
*/ */
public class PasswordFrame extends JFrame implements DocumentListener { public class PasswordFrame extends JFrame implements DocumentListener {
private final User user; @SuppressWarnings("FieldCanBeLocal")
private final Components.GradientPanel root; private final Components.GradientPanel root;
private final JTextField siteNameField; private final JTextField siteNameField;
private final JButton siteActionButton; private final JButton siteActionButton;
@ -41,13 +41,13 @@ public class PasswordFrame extends JFrame implements DocumentListener {
private final JCheckBox maskPasswordField; private final JCheckBox maskPasswordField;
private final char passwordEchoChar; private final char passwordEchoChar;
private final Font passwordEchoFont; private final Font passwordEchoFont;
private final User user;
@Nullable @Nullable
private Site currentSite; private Site currentSite;
private boolean updatingUI; private boolean updatingUI;
public PasswordFrame(User user) public PasswordFrame(final User user) {
throws HeadlessException {
super( "Master Password" ); super( "Master Password" );
this.user = user; this.user = user;
@ -104,7 +104,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
public void actionPerformed(final ActionEvent e) { public void actionPerformed(final ActionEvent e) {
if (currentSite == null) if (currentSite == null)
return; return;
else if (currentSite instanceof ModelSite) if (currentSite instanceof ModelSite)
PasswordFrame.this.user.deleteSite( currentSite ); PasswordFrame.this.user.deleteSite( currentSite );
else else
PasswordFrame.this.user.addSite( currentSite ); PasswordFrame.this.user.addSite( currentSite );
@ -160,7 +160,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
maskPasswordField.setSelected( true ); maskPasswordField.setSelected( true );
maskPasswordField.addItemListener( new ItemListener() { maskPasswordField.addItemListener( new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(final ItemEvent e) {
updateMask(); updateMask();
} }
} ); } );
@ -203,33 +203,33 @@ public class PasswordFrame extends JFrame implements DocumentListener {
} }
@Nonnull @Nonnull
private ListenableFuture<String> updatePassword(boolean allowNameCompletion) { private ListenableFuture<String> updatePassword(final boolean allowNameCompletion) {
final String siteNameQuery = siteNameField.getText(); final String siteNameQuery = siteNameField.getText();
if (updatingUI) if (updatingUI)
return Futures.immediateCancelledFuture(); return Futures.immediateCancelledFuture();
if (siteNameQuery == null || siteNameQuery.isEmpty() || !user.isKeyAvailable()) { if ((siteNameQuery == null) || siteNameQuery.isEmpty() || !user.isKeyAvailable()) {
siteActionButton.setVisible( false ); siteActionButton.setVisible( false );
tipLabel.setText( null ); tipLabel.setText( null );
passwordField.setText( null ); passwordField.setText( null );
return Futures.immediateCancelledFuture(); return Futures.immediateCancelledFuture();
} }
final MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() ); MPSiteType siteType = siteTypeField.getModel().getElementAt( siteTypeField.getSelectedIndex() );
final MasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() ); MasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() );
final UnsignedInteger siteCounter = siteCounterModel.getNumber(); UnsignedInteger siteCounter = siteCounterModel.getNumber();
Iterable<Site> siteResults = user.findSitesByName( siteNameQuery ); Iterable<Site> siteResults = user.findSitesByName( siteNameQuery );
if (!allowNameCompletion) if (!allowNameCompletion)
siteResults = FluentIterable.from( siteResults ).filter( new Predicate<Site>() { siteResults = FluentIterable.from( siteResults ).filter( new Predicate<Site>() {
@Override @Override
public boolean apply(@Nullable Site siteResult) { public boolean apply(@Nullable final Site siteResult) {
return siteResult != null && siteNameQuery.equals( siteResult.getSiteName() ); return (siteResult != null) && siteNameQuery.equals( siteResult.getSiteName() );
} }
} ); } );
final Site site = ifNotNullElse( Iterables.getFirst( siteResults, null ), final Site site = ifNotNullElse( Iterables.getFirst( siteResults, null ),
new IncognitoSite( siteNameQuery, siteType, siteCounter, siteVersion ) ); new IncognitoSite( siteNameQuery, siteType, siteCounter, siteVersion ) );
if (currentSite != null && currentSite.getSiteName().equals( site.getSiteName() )) { if ((currentSite != null) && currentSite.getSiteName().equals( site.getSiteName() )) {
site.setSiteType( siteType ); site.setSiteType( siteType );
site.setAlgorithmVersion( siteVersion ); site.setAlgorithmVersion( siteVersion );
site.setSiteCounter( siteCounter ); site.setSiteCounter( siteCounter );

View File

@ -28,22 +28,21 @@ public class UnlockFrame extends JFrame {
private AuthenticationPanel authenticationPanel; private AuthenticationPanel authenticationPanel;
private Future<?> identiconFuture; private Future<?> identiconFuture;
private boolean incognito; private boolean incognito;
public User user; private User user;
public UnlockFrame(final SignInCallback signInCallback) public UnlockFrame(final SignInCallback signInCallback) {
throws HeadlessException {
super( "Unlock Master Password" ); super( "Unlock Master Password" );
this.signInCallback = signInCallback; this.signInCallback = signInCallback;
setDefaultCloseOperation( DISPOSE_ON_CLOSE ); setDefaultCloseOperation( DISPOSE_ON_CLOSE );
addWindowFocusListener( new WindowAdapter() { addWindowFocusListener( new WindowAdapter() {
@Override @Override
public void windowGainedFocus(WindowEvent e) { public void windowGainedFocus(final WindowEvent e) {
root.setGradientColor( Res.colors().frameBg() ); root.setGradientColor( Res.colors().frameBg() );
} }
@Override @Override
public void windowLostFocus(WindowEvent e) { public void windowLostFocus(final WindowEvent e) {
root.setGradientColor( Color.RED ); root.setGradientColor( Color.RED );
} }
} ); } );
@ -118,7 +117,7 @@ public class UnlockFrame extends JFrame {
JComponent toolsPanel = Components.boxLayout( BoxLayout.LINE_AXIS, incognitoCheckBox, Box.createGlue() ); JComponent toolsPanel = Components.boxLayout( BoxLayout.LINE_AXIS, incognitoCheckBox, Box.createGlue() );
authenticationContainer.add( toolsPanel ); authenticationContainer.add( toolsPanel );
for (JButton button : authenticationPanel.getButtons()) { for (final JButton button : authenticationPanel.getButtons()) {
toolsPanel.add( button ); toolsPanel.add( button );
button.setBorder( BorderFactory.createEmptyBorder() ); button.setBorder( BorderFactory.createEmptyBorder() );
button.setMargin( new Insets( 0, 0, 0, 0 ) ); button.setMargin( new Insets( 0, 0, 0, 0 ) );
@ -138,7 +137,7 @@ public class UnlockFrame extends JFrame {
} ); } );
} }
void updateUser(@Nullable User user) { void updateUser(@Nullable final User user) {
this.user = user; this.user = user;
checkSignIn(); checkSignIn();
} }
@ -152,10 +151,10 @@ public class UnlockFrame extends JFrame {
SwingUtilities.invokeLater( new Runnable() { SwingUtilities.invokeLater( new Runnable() {
@Override @Override
public void run() { public void run() {
String fullName = user == null? "": user.getFullName(); String fullName = (user == null)? "": user.getFullName();
char[] masterPassword = authenticationPanel.getMasterPassword(); char[] masterPassword = authenticationPanel.getMasterPassword();
if (fullName.isEmpty() || masterPassword.length == 0) { if (fullName.isEmpty() || (masterPassword.length == 0)) {
identiconLabel.setText( " " ); identiconLabel.setText( " " );
return; return;
} }
@ -169,9 +168,9 @@ public class UnlockFrame extends JFrame {
} }
}, 300, TimeUnit.MILLISECONDS ); }, 300, TimeUnit.MILLISECONDS );
String fullName = user == null? "": user.getFullName(); String fullName = (user == null)? "": user.getFullName();
char[] masterPassword = authenticationPanel.getMasterPassword(); char[] masterPassword = authenticationPanel.getMasterPassword();
boolean enabled = !fullName.isEmpty() && masterPassword.length > 0; boolean enabled = !fullName.isEmpty() && (masterPassword.length > 0);
signInButton.setEnabled( enabled ); signInButton.setEnabled( enabled );
return enabled; return enabled;
@ -181,7 +180,7 @@ public class UnlockFrame extends JFrame {
if (!checkSignIn()) if (!checkSignIn())
return; return;
for (JComponent signInComponent : signInComponents) for (final JComponent signInComponent : signInComponents)
signInComponent.setEnabled( false ); signInComponent.setEnabled( false );
signInButton.setEnabled( false ); signInButton.setEnabled( false );
@ -208,7 +207,7 @@ public class UnlockFrame extends JFrame {
JOptionPane.showMessageDialog( null, e.getLocalizedMessage(), "Sign In Failed", JOptionPane.ERROR_MESSAGE ); JOptionPane.showMessageDialog( null, e.getLocalizedMessage(), "Sign In Failed", JOptionPane.ERROR_MESSAGE );
authenticationPanel.reset(); authenticationPanel.reset();
signInButton.setText( "Sign In" ); signInButton.setText( "Sign In" );
for (JComponent signInComponent : signInComponents) for (final JComponent signInComponent : signInComponents)
signInComponent.setEnabled( true ); signInComponent.setEnabled( true );
checkSignIn(); checkSignIn();
} }