Apply 'Lhunath' code inspection fixes and improvements.
This commit is contained in:
parent
86f956571d
commit
b478691980
@ -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 */
|
||||||
|
|
||||||
@ -71,4 +71,11 @@ public class MPConstant {
|
|||||||
* 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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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 );
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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 static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final String templateString;
|
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)
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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 );
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
@ -20,13 +20,14 @@ 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()
|
||||||
@ -34,15 +35,15 @@ public class MPTestSuite implements Callable<Boolean> {
|
|||||||
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 );
|
||||||
}
|
}
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
gradle/.idea/codeStyleSettings.xml
Normal file
9
gradle/.idea/codeStyleSettings.xml
Normal 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>
|
6
gradle/.idea/copyright/GPLv3.xml
Normal file
6
gradle/.idea/copyright/GPLv3.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<copyright>
|
||||||
|
<option name="myName" value="GPLv3" />
|
||||||
|
<option name="notice" value="This file is part of &#36;project.name. &#36;project.name is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. &#36;project.name is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can find a copy of the GNU General Public License in the LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>." />
|
||||||
|
</copyright>
|
||||||
|
</component>
|
8
gradle/.idea/copyright/profiles_settings.xml
Normal file
8
gradle/.idea/copyright/profiles_settings.xml
Normal 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>
|
9
gradle/.idea/inspectionProfiles/profiles_settings.xml
Normal file
9
gradle/.idea/inspectionProfiles/profiles_settings.xml
Normal 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
40
gradle/.idea/misc.xml
Normal 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>
|
3
gradle/.idea/scopes/masterpassword.xml
Normal file
3
gradle/.idea/scopes/masterpassword.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<scope name="masterpassword" pattern="com.lyndir.masterpassword.*" />
|
||||||
|
</component>
|
@ -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
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
sdk.dir=/usr/local/opt/android-sdk
|
|
||||||
ndk.dir=/usr/local/opt/android-ndk
|
|
@ -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' )
|
||||||
|
@ -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'
|
||||||
|
@ -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,8 +243,10 @@ 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 ))
|
||||||
|
&& (id_version == version.ordinal()))
|
||||||
|
if ((masterKeyFuture != null) && !masterKeyFuture.isCancelled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
id_userName = fullName.hashCode();
|
id_userName = fullName.hashCode();
|
||||||
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 );
|
||||||
|
@ -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"
|
||||||
|
@ -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" />
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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'
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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'
|
||||||
|
@ -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." );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author lhunath, 15-02-04
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package com.lyndir.masterpassword.gui.model;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
@ -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();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
@ -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 ) {
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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 );
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user