2
0

Fix warnings and inspections.

This commit is contained in:
Maarten Billemont 2018-04-27 11:32:54 -04:00
parent 82e2d0b5ac
commit cb74b1f3fc
30 changed files with 225 additions and 142 deletions

View File

@ -18,7 +18,6 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.MessageDigests; import com.lyndir.lhunath.opal.system.MessageDigests;
@ -30,25 +29,28 @@ import javax.annotation.Nullable;
/** /**
* @see MPMasterKey.Version * @see MPMasterKey.Version
*/ */
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention" }) @SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" })
public abstract class MPAlgorithm { public abstract class MPAlgorithm {
public abstract byte[] masterKey(String fullName, char[] masterPassword); public abstract byte[] masterKey(String fullName, char[] masterPassword);
public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose, public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter,
@Nullable String keyContext); MPKeyPurpose keyPurpose, @Nullable String keyContext);
public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose, public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam); MPKeyPurpose keyPurpose, @Nullable String keyContext,
MPResultType resultType, @Nullable String resultParam);
public abstract String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam); public abstract String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey,
MPResultType resultType, @Nullable String resultParam);
public abstract String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam); public abstract String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
public abstract String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam); public abstract String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose, public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
@Nullable String keyContext, MPResultType resultType, String resultParam); MPKeyPurpose keyPurpose, @Nullable String keyContext,
MPResultType resultType, String resultParam);
// Configuration // Configuration

View File

@ -47,10 +47,10 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
// Calculate the master key. // Calculate the master key.
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )", logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
scrypt_N(), scrypt_r(), scrypt_p() ); scrypt_N(), scrypt_r(), scrypt_p() );
byte[] mpBytes = toBytes( masterPassword ); byte[] masterPasswordBytes = toBytes( masterPassword );
byte[] masterKey = scrypt( masterKeySalt, mpBytes ); byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
Arrays.fill( masterKeySalt, (byte) 0 ); Arrays.fill( masterKeySalt, (byte) 0 );
Arrays.fill( mpBytes, (byte) 0 ); Arrays.fill( masterPasswordBytes, (byte) 0 );
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( toID( masterKey ) ) ); logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( toID( masterKey ) ) );
return masterKey; return masterKey;

View File

@ -22,7 +22,6 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.primitives.UnsignedBytes; import com.google.common.primitives.UnsignedBytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*; import java.nio.*;

View File

@ -21,7 +21,8 @@ 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.*; 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;
@ -31,7 +32,7 @@ import org.jetbrains.annotations.Contract;
* *
* @author lhunath * @author lhunath
*/ */
@SuppressWarnings("RedundantTypeArguments" /* IDEA-191043 */) @SuppressWarnings({ "RedundantTypeArguments", "SpellCheckingInspection" })
public enum MPResultType { public enum MPResultType {
// bit 0-3 | MPResultTypeClass | MPSiteFeature // bit 0-3 | MPResultTypeClass | MPSiteFeature
@ -130,11 +131,11 @@ public enum MPResultType {
static final Logger logger = Logger.get( MPResultType.class ); static final Logger logger = Logger.get( MPResultType.class );
private final String shortName; private final String shortName;
private final String description; private final String description;
private final List<MPTemplate> templates; private final List<MPTemplate> templates;
private final MPResultTypeClass typeClass; private final MPResultTypeClass typeClass;
private final int typeIndex; private final int typeIndex;
private final ImmutableSet<MPSiteFeature> typeFeatures; private final ImmutableSet<MPSiteFeature> typeFeatures;
MPResultType(final String shortName, final String description, final List<MPTemplate> templates, MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
@ -167,7 +168,7 @@ public enum MPResultType {
return typeClass; return typeClass;
} }
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */ ) @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */)
public ImmutableSet<MPSiteFeature> getTypeFeatures() { public ImmutableSet<MPSiteFeature> getTypeFeatures() {
return typeFeatures; return typeFeatures;

View File

@ -27,6 +27,7 @@ import org.jetbrains.annotations.NonNls;
* *
* @author lhunath * @author lhunath
*/ */
@SuppressWarnings({ "HardcodedFileSeparator", "SpellCheckingInspection" })
public enum MPTemplateCharacterClass { public enum MPTemplateCharacterClass {
UpperVowel( 'V', "AEIOU" ), UpperVowel( 'V', "AEIOU" ),

View File

@ -29,13 +29,13 @@ import org.joda.time.Instant;
*/ */
public class MPFileSite extends MPSite { public class MPFileSite extends MPSite {
private final MPFileUser user; private final MPFileUser user;
private String siteName; private String siteName;
@Nullable @Nullable
private String siteContent; private String siteContent;
private UnsignedInteger siteCounter; private UnsignedInteger siteCounter;
private MPResultType resultType; private MPResultType resultType;
private MPAlgorithm algorithm; private MPAlgorithm algorithm;
@Nullable @Nullable
private String loginContent; private String loginContent;
@ -122,14 +122,15 @@ public class MPFileSite extends MPSite {
return siteContent; return siteContent;
} }
public void setSitePassword(final MPMasterKey masterKey, @Nullable final MPResultType resultType, @Nullable final String result) public void setSitePassword(final MPMasterKey masterKey, final MPResultType resultType, @Nullable final String result)
throws MPInvalidatedException { throws MPInvalidatedException {
this.resultType = resultType; this.resultType = resultType;
if (result == null) if (result == null)
this.siteContent = null; this.siteContent = null;
else else
this.siteContent = masterKey.siteState( this.siteContent = masterKey.siteState(
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, algorithm ); siteName, siteCounter, MPKeyPurpose.Authentication, null, resultType, result, algorithm );
} }
@Override @Override

View File

@ -32,6 +32,7 @@ import org.joda.time.ReadableInstant;
/** /**
* @author lhunath, 14-12-07 * @author lhunath, 14-12-07
*/ */
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> { public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@ -41,9 +42,9 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
private final Collection<MPFileSite> sites = Sets.newHashSet(); private final Collection<MPFileSite> sites = Sets.newHashSet();
@Nullable @Nullable
private byte[] keyID; private byte[] keyID;
private MPAlgorithm algorithm; private MPAlgorithm algorithm;
private MPMarshalFormat format; private MPMarshalFormat format;
private int avatar; private int avatar;
private MPResultType defaultType; private MPResultType defaultType;

View File

@ -36,6 +36,7 @@ import javax.annotation.Nonnull;
* *
* @author lhunath, 14-12-07 * @author lhunath, 14-12-07
*/ */
@SuppressWarnings("CallToSystemGetenv")
public class MPFileUserManager extends MPUserManager { public class MPFileUserManager extends MPUserManager {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@ -50,21 +51,20 @@ public class MPFileUserManager extends MPUserManager {
instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) ); instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
} }
private final File userFilesDirectory; private final File path;
public static MPFileUserManager get() { public static MPFileUserManager get() {
MPUserManager.instance = instance;
return instance; return instance;
} }
public static MPFileUserManager create(final File userFilesDirectory) { public static MPFileUserManager create(final File path) {
return new MPFileUserManager( userFilesDirectory ); return new MPFileUserManager( path );
} }
protected MPFileUserManager(final File userFilesDirectory) { protected MPFileUserManager(final File path) {
super( unmarshallUsers( userFilesDirectory ) ); super( unmarshallUsers( path ) );
this.userFilesDirectory = userFilesDirectory; this.path = path;
} }
private static Iterable<MPFileUser> unmarshallUsers(final File userFilesDirectory) { private static Iterable<MPFileUser> unmarshallUsers(final File userFilesDirectory) {
@ -76,7 +76,7 @@ public class MPFileUserManager extends MPUserManager {
Map<String, MPFileUser> users = new HashMap<>(); Map<String, MPFileUser> users = new HashMap<>();
for (final File userFile : listUserFiles( userFilesDirectory )) for (final File userFile : listUserFiles( userFilesDirectory ))
for (final MPMarshalFormat format : MPMarshalFormat.values()) for (final MPMarshalFormat format : MPMarshalFormat.values())
if (userFile.getName().endsWith( '.' + format.fileExtension() )) if (userFile.getName().endsWith( format.fileSuffix() ))
try { try {
MPFileUser user = format.unmarshaller().unmarshall( userFile ); MPFileUser user = format.unmarshaller().unmarshall( userFile );
MPFileUser previousUser = users.put( user.getFullName(), user ); MPFileUser previousUser = users.put( user.getFullName(), user );
@ -95,7 +95,7 @@ public class MPFileUserManager extends MPUserManager {
@Override @Override
public boolean accept(final File dir, final String name) { public boolean accept(final File dir, final String name) {
for (final MPMarshalFormat format : MPMarshalFormat.values()) for (final MPMarshalFormat format : MPMarshalFormat.values())
if (name.endsWith( '.' + format.fileExtension() )) if (name.endsWith( format.fileSuffix() ))
return true; return true;
return false; return false;
@ -134,13 +134,13 @@ public class MPFileUserManager extends MPUserManager {
@Nonnull @Nonnull
private File getUserFile(final MPFileUser user) { private File getUserFile(final MPFileUser user) {
return new File( userFilesDirectory, user.getFullName() + ".mpsites" ); return new File( path, user.getFullName() + ".mpsites" );
} }
/** /**
* @return The location on the file system where the user models are stored. * @return The location on the file system where the user models are stored.
*/ */
public File getPath() { public File getPath() {
return userFilesDirectory; return path;
} }
} }

View File

@ -29,6 +29,7 @@ import org.joda.time.Instant;
/** /**
* @author lhunath, 2017-09-20 * @author lhunath, 2017-09-20
*/ */
@SuppressWarnings({ "HardcodedLineSeparator", "MagicCharacter" })
public class MPFlatMarshaller implements MPMarshaller { public class MPFlatMarshaller implements MPMarshaller {
private static final int FORMAT = 1; private static final int FORMAT = 1;

View File

@ -39,8 +39,8 @@ public enum MPMarshalFormat {
} }
@Override @Override
public String fileExtension() { public String fileSuffix() {
return "mpsites"; return ".mpsites";
} }
}, },
@ -59,8 +59,8 @@ public enum MPMarshalFormat {
} }
@Override @Override
public String fileExtension() { public String fileSuffix() {
return "mpsites.json"; return ".mpsites.json";
} }
}; };
@ -70,5 +70,6 @@ public enum MPMarshalFormat {
public abstract MPUnmarshaller unmarshaller(); public abstract MPUnmarshaller unmarshaller();
public abstract String fileExtension(); @SuppressWarnings("MethodReturnAlwaysConstant")
public abstract String fileSuffix();
} }

View File

@ -33,14 +33,15 @@ public interface MPMarshaller {
throws MPInvalidatedException, MPMarshalException; throws MPInvalidatedException, MPMarshalException;
enum ContentMode { enum ContentMode {
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ), PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key.", true ),
VISIBLE( "Export of site names and passwords in clear-text." ); VISIBLE( "Export of site names and passwords in clear-text.", false );
private final String description; private final String description;
private boolean redacted; private final boolean redacted;
ContentMode(final String description) { ContentMode(final String description, final boolean redacted) {
this.description = description; this.description = description;
this.redacted = redacted;
} }
public String description() { public String description() {

View File

@ -45,7 +45,7 @@ public abstract class MPUser<S extends MPSite> {
@Nonnull @Nonnull
public MPMasterKey getMasterKey() { public MPMasterKey getMasterKey() {
return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() ); return Preconditions.checkNotNull( key, "User is not authenticated: %s", getFullName() );
} }
public String exportKeyID() public String exportKeyID()

View File

@ -29,11 +29,6 @@ import java.util.SortedSet;
public abstract class MPUserManager { public abstract class MPUserManager {
private final Map<String, MPFileUser> usersByName = Maps.newHashMap(); private final Map<String, MPFileUser> usersByName = Maps.newHashMap();
static MPUserManager instance;
public static MPUserManager get() {
return instance;
}
protected MPUserManager(final Iterable<MPFileUser> users) { protected MPUserManager(final Iterable<MPFileUser> users) {
for (final MPFileUser user : users) for (final MPFileUser user : users)

View File

@ -24,8 +24,8 @@ import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils; import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.io.IOException; import java.io.IOException;
import java.util.Deque; import java.net.URL;
import java.util.List; import java.util.*;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.xml.parsers.*; import javax.xml.parsers.*;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
@ -56,7 +56,8 @@ public class MPTestSuite implements Callable<Boolean> {
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();
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources( "." );
parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() { parser.parse( Thread.currentThread().getContextClassLoader().getResourceAsStream( resourceName ), new DefaultHandler2() {
private final Deque<String> currentTags = Lists.newLinkedList(); private final Deque<String> currentTags = Lists.newLinkedList();
private final Deque<StringBuilder> currentTexts = Lists.newLinkedList(); private final Deque<StringBuilder> currentTexts = Lists.newLinkedList();
@ -81,7 +82,7 @@ public class MPTestSuite implements Callable<Boolean> {
throws SAXException { throws SAXException {
super.endElement( uri, localName, qName ); super.endElement( uri, localName, qName );
Preconditions.checkState( qName.equals( currentTags.pop() ) ); Preconditions.checkState( qName.equals( currentTags.pop() ) );
String text = currentTexts.pop().toString(); String text = Preconditions.checkNotNull( currentTexts.pop() ).toString();
if ("case".equals( qName )) if ("case".equals( qName ))
tests.cases.add( currentCase ); tests.cases.add( currentCase );
@ -112,11 +113,11 @@ public class MPTestSuite implements Callable<Boolean> {
throws SAXException { throws SAXException {
super.characters( ch, start, length ); super.characters( ch, start, length );
currentTexts.peek().append( ch, start, length ); Preconditions.checkNotNull( currentTexts.peek() ).append( ch, start, length );
} }
} ); } );
} }
catch (IllegalArgumentException | ParserConfigurationException | SAXException | IOException e) { catch (final IllegalArgumentException | ParserConfigurationException | SAXException | IOException e) {
throw new UnavailableException( e ); throw new UnavailableException( e );
} }

View File

@ -28,6 +28,7 @@ import com.lyndir.lhunath.opal.system.util.NNSupplier;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.xml.bind.annotation.XmlTransient;
/** /**
@ -66,20 +67,23 @@ public class MPTests {
public static class Case { public static class Case {
String identifier; String identifier;
String parent; String parent;
Integer algorithm; @Nullable
String fullName; Integer algorithm;
String masterPassword; String fullName;
String keyID; String masterPassword;
String siteName; String keyID;
String siteName;
@Nullable
UnsignedInteger siteCounter; UnsignedInteger siteCounter;
String resultType; String resultType;
String keyPurpose; String keyPurpose;
String keyContext; String keyContext;
String result; String result;
private transient Case parentCase; @XmlTransient
private Case parentCase;
public void initializeParentHierarchy(final MPTests tests) { public void initializeParentHierarchy(final MPTests tests) {

View File

@ -108,7 +108,7 @@ public class MPMasterKeyTest {
char[] masterPassword = testCase.getMasterPassword().toCharArray(); char[] masterPassword = testCase.getMasterPassword().toCharArray();
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword ); MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
String password = randomString( 8 ); String password = randomString( 8 );
MPResultType resultType = MPResultType.StoredPersonal; MPResultType resultType = MPResultType.StoredPersonal;
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) { for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
MPAlgorithm algorithm = version.getAlgorithm(); MPAlgorithm algorithm = version.getAlgorithm();
@ -126,7 +126,7 @@ public class MPMasterKeyTest {
} }
} }
public static String randomString(int length) { private static String randomString(int length) {
Random random = new Random(); Random random = new Random();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true"> <configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
<module name="" /> <module name="masterpassword-tests" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" value="" /> <option name="SUITE_NAME" value="" />
@ -13,15 +13,12 @@
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" />
<option name="OUTPUT_DIRECTORY" value="" /> <option name="OUTPUT_DIRECTORY" value="" />
<option name="ANNOTATION_TYPE" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="wholeProject" /> <value defaultName="moduleWithDependencies" />
</option> </option>
<option name="USE_DEFAULT_REPORTERS" value="false" /> <option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" value="" /> <option name="PROPERTIES_FILE" value="" />
<envs />
<properties /> <properties />
<listeners /> <listeners />
<method /> <method />

View File

@ -50,7 +50,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 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( private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
@ -59,6 +59,7 @@ public class EmergencyActivity extends Activity {
MPResultType.forClass( MPResultTypeClass.Template ) ); MPResultType.forClass( MPResultTypeClass.Template ) );
private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() ); private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() );
@Nullable
private MPMasterKey masterKey; private MPMasterKey masterKey;
@BindView(R.id.progressView) @BindView(R.id.progressView)
@ -99,6 +100,7 @@ public class EmergencyActivity extends Activity {
private int id_userName; private int id_userName;
private int id_masterPassword; private int id_masterPassword;
@Nullable
private String sitePassword; private String sitePassword;
public static void start(final Context context) { public static void start(final Context context) {
@ -176,13 +178,13 @@ public class EmergencyActivity extends Activity {
} }
} ); } );
fullNameField.setTypeface( Res.get( this ).exo_Thin ); fullNameField.setTypeface( Res.get( this ).exo_Thin() );
fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight ); masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight() );
masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setTypeface( Res.get( this ).exo_Regular ); siteNameField.setTypeface( Res.get( this ).exo_Regular() );
siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black ); sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black() );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@ -257,8 +259,8 @@ public class EmergencyActivity extends Activity {
} }
private synchronized void updateMasterKey() { private synchronized void updateMasterKey() {
final String fullName = fullNameField.getText().toString(); String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray(); char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
if ((id_userName == fullName.hashCode()) if ((id_userName == fullName.hashCode())
&& (id_masterPassword == Arrays.hashCode( masterPassword ))) && (id_masterPassword == Arrays.hashCode( masterPassword )))
if (masterKey != null) if (masterKey != null)
@ -303,7 +305,8 @@ public class EmergencyActivity extends Activity {
@Override @Override
public void run() { public void run() {
try { try {
sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version.getAlgorithm() ); sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null,
version.getAlgorithm() );
runOnUiThread( new Runnable() { runOnUiThread( new Runnable() {
@Override @Override
@ -341,31 +344,39 @@ public class EmergencyActivity extends Activity {
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE ); final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE ); final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
if (clipboardManager == null)
return;
String title = strf( "Password for %s", siteNameField.getText() ); String title = strf( "Password for %s", siteNameField.getText() );
ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } ); ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) ); clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) );
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title ) if (notificationManager != null) {
.setContentText( "Paste the password into your app." ) Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
.setSmallIcon( R.drawable.icon ) .setContentText(
.setAutoCancel( true ); "Paste the password into your app." )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) .setSmallIcon( R.drawable.icon )
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET ) .setAutoCancel( true );
.setCategory( Notification.CATEGORY_RECOMMENDATION ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
.setLocalOnly( true ); notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() ); .setCategory( Notification.CATEGORY_RECOMMENDATION )
.setLocalOnly( true );
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
}
final Timer timer = new Timer(); final Timer timer = new Timer();
timer.schedule( new TimerTask() { timer.schedule( new TimerTask() {
@Override @Override
public void run() { public void run() {
ClipData clip = clipboardManager.getPrimaryClip(); ClipData clip = clipboardManager.getPrimaryClip();
for (int i = 0; i < clip.getItemCount(); ++i) for (int i = 0; i < clip.getItemCount(); ++i)
if (currentSitePassword.equals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) { if (currentSitePassword.contentEquals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
clipboardManager.setPrimaryClip( EMPTY_CLIP ); clipboardManager.setPrimaryClip( EMPTY_CLIP );
break; break;
} }
notificationManager.cancel( PASSWORD_NOTIFICATION );
if (notificationManager != null)
notificationManager.cancel( PASSWORD_NOTIFICATION );
timer.cancel(); timer.cancel();
} }
}, CLIPBOARD_CLEAR_DELAY ); }, CLIPBOARD_CLEAR_DELAY );

View File

@ -25,6 +25,7 @@ import com.google.common.collect.Sets;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.*; import java.util.concurrent.*;
import javax.annotation.Nonnull;
/** /**
@ -64,6 +65,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
shutdown = true; shutdown = true;
} }
@Nonnull
@Override @Override
public List<Runnable> shutdownNow() { public List<Runnable> shutdownNow() {
shutdown = true; shutdown = true;

View File

@ -25,14 +25,15 @@ import android.graphics.Typeface;
/** /**
* @author lhunath, 2014-08-25 * @author lhunath, 2014-08-25
*/ */
@SuppressWarnings("NewMethodNamingConvention")
public final class Res { public final class Res {
public final Typeface sourceCodePro_Black; private final Typeface sourceCodePro_Black;
public final Typeface sourceCodePro_ExtraLight; private final Typeface sourceCodePro_ExtraLight;
public final Typeface exo_Bold; private final Typeface exo_Bold;
public final Typeface exo_ExtraBold; private final Typeface exo_ExtraBold;
public final Typeface exo_Regular; private final Typeface exo_Regular;
public final Typeface exo_Thin; private final Typeface exo_Thin;
private static Res res; private static Res res;
@ -53,4 +54,28 @@ public final class Res {
exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" ); exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" );
exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" ); exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" );
} }
public Typeface sourceCodePro_Black() {
return sourceCodePro_Black;
}
public Typeface sourceCodePro_ExtraLight() {
return sourceCodePro_ExtraLight;
}
public Typeface exo_Bold() {
return exo_Bold;
}
public Typeface exo_ExtraBold() {
return exo_ExtraBold;
}
public Typeface exo_Regular() {
return exo_Regular;
}
public Typeface exo_Thin() {
return exo_Thin;
}
} }

View File

@ -25,6 +25,7 @@ import com.lyndir.masterpassword.MPConstant;
/** /**
* @author lhunath, 2014-08-31 * @author lhunath, 2014-08-31
*/ */
@SuppressWarnings("CallToSystemGetenv")
public class Config { public class Config {
private static final Config instance = new Config(); private static final Config instance = new Config();

View File

@ -18,6 +18,8 @@
package com.lyndir.masterpassword.gui; package com.lyndir.masterpassword.gui;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.io.CharSource; import com.google.common.io.CharSource;
@ -57,7 +59,7 @@ public class GUI implements UnlockFrame.SignInCallback {
try { try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() ); UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} }
catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException ignored) { catch (final UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException ignored) {
} }
try { try {
@ -69,7 +71,7 @@ public class GUI implements UnlockFrame.SignInCallback {
else // No special platform handling. else // No special platform handling.
new GUI().open(); new GUI().open();
} }
catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { catch (final IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw logger.bug( e ); throw logger.bug( e );
} }
} }
@ -77,29 +79,35 @@ public class GUI implements UnlockFrame.SignInCallback {
private static void checkUpdate() { private static void checkUpdate() {
try { try {
Enumeration<URL> manifestURLs = Thread.currentThread().getContextClassLoader().getResources( JarFile.MANIFEST_NAME ); Enumeration<URL> manifestURLs = Thread.currentThread().getContextClassLoader().getResources( JarFile.MANIFEST_NAME );
while (manifestURLs.hasMoreElements()) { while (manifestURLs.hasMoreElements())
InputStream manifestStream = manifestURLs.nextElement().openStream(); try (InputStream manifestStream = manifestURLs.nextElement().openStream()) {
Attributes attributes = new Manifest( manifestStream ).getMainAttributes(); Attributes attributes = new Manifest( manifestStream ).getMainAttributes();
if (!GUI.class.getCanonicalName().equals( attributes.getValue( Attributes.Name.MAIN_CLASS ) )) if (!GUI.class.getCanonicalName().equals( attributes.getValue( Attributes.Name.MAIN_CLASS ) ))
continue; continue;
String manifestRevision = attributes.getValue( Attributes.Name.IMPLEMENTATION_VERSION ); String manifestRevision = attributes.getValue( Attributes.Name.IMPLEMENTATION_VERSION );
String upstreamRevisionURL = "https://masterpasswordapp.com/masterpassword-gui.jar.rev"; String upstreamRevisionURL = "https://masterpasswordapp.com/masterpassword-gui.jar.rev";
CharSource upstream = Resources.asCharSource( URI.create( upstreamRevisionURL ).toURL(), Charsets.UTF_8 ); CharSource upstream = Resources.asCharSource( URI.create( upstreamRevisionURL ).toURL(), Charsets.UTF_8 );
String upstreamRevision = upstream.readFirstLine(); String upstreamRevision = upstream.readFirstLine();
if ((manifestRevision != null) && (upstreamRevision != null) && !manifestRevision.equalsIgnoreCase( upstreamRevision )) { if ((manifestRevision != null) && (upstreamRevision != null) && !manifestRevision.equalsIgnoreCase(
logger.inf( "Local Revision: <%s>", manifestRevision ); upstreamRevision )) {
logger.inf( "Upstream Revision: <%s>", upstreamRevision ); logger.inf( "Local Revision: <%s>", manifestRevision );
logger.wrn( "You are not running the current official version. Please update from:\n" logger.inf( "Upstream Revision: <%s>", upstreamRevision );
+ "https://masterpasswordapp.com/masterpassword-gui.jar" ); logger.wrn( "You are not running the current official version. Please update from:%n%s",
JOptionPane.showMessageDialog( null, "A new version of Master Password is available.\n" "https://masterpasswordapp.com/masterpassword-gui.jar" );
+ "Please download the latest version from http://masterpasswordapp.com", JOptionPane.showMessageDialog( null,
"Update Available", JOptionPane.WARNING_MESSAGE ); strf( "A new version of Master Password is available.%n "
+ "Please download the latest version from %s",
"https://masterpasswordapp.com" ),
"Update Available", JOptionPane.WARNING_MESSAGE );
}
}
catch (final IOException e) {
logger.wrn( e, "Couldn't check for version update." );
} }
}
} }
catch (final IOException e) { catch (final IOException e) {
logger.wrn( e, "Couldn't check for version update." ); logger.wrn( e, "Couldn't inspect JAR." );
} }
} }

View File

@ -47,7 +47,7 @@ import org.jetbrains.annotations.NonNls;
/** /**
* @author lhunath, 2014-06-11 * @author lhunath, 2014-06-11
*/ */
@SuppressWarnings("HardcodedFileSeparator") @SuppressWarnings({ "HardcodedFileSeparator", "MethodReturnAlwaysConstant", "SpellCheckingInspection" })
public abstract class Res { public abstract class Res {
private static final int AVATAR_COUNT = 19; private static final int AVATAR_COUNT = 19;
@ -210,7 +210,7 @@ public abstract class Res {
fontsByResourceName.put( fontResourceName, new SoftReference<>( fontsByResourceName.put( fontResourceName, new SoftReference<>(
font = Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( fontResourceName ).openStream() ) ) ); font = Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( fontResourceName ).openStream() ) ) );
} }
catch (FontFormatException | IOException e) { catch (final FontFormatException | IOException e) {
throw Throwables.propagate( e ); throw Throwables.propagate( e );
} }

View File

@ -19,7 +19,8 @@
package com.lyndir.masterpassword.gui.model; package com.lyndir.masterpassword.gui.model;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.model.MPSite; import com.lyndir.masterpassword.model.MPSite;

View File

@ -0,0 +1,25 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
/**
* @author lhunath, 2018-04-26
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword.gui.platform.mac;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -31,7 +31,7 @@ import javax.swing.border.CompoundBorder;
*/ */
public abstract class Components { public abstract class Components {
public static final float CONTROL_TEXT_SIZE = 12f; private static final float CONTROL_TEXT_SIZE = 12f;
public static GradientPanel boxLayout(final int axis, final Component... components) { public static GradientPanel boxLayout(final int axis, final Component... components) {
GradientPanel container = gradientPanel( null, null ); GradientPanel container = gradientPanel( null, null );

View File

@ -20,7 +20,8 @@ package com.lyndir.masterpassword.gui.view;
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.masterpassword.*; import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.model.IncognitoSite; import com.lyndir.masterpassword.gui.model.IncognitoSite;
import com.lyndir.masterpassword.gui.model.IncognitoUser; import com.lyndir.masterpassword.gui.model.IncognitoUser;

View File

@ -20,10 +20,12 @@ package com.lyndir.masterpassword.gui.view;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
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;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.*; import com.lyndir.masterpassword.model.*;
@ -171,7 +173,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
return; return;
if (JOptionPane.showConfirmDialog( ModelAuthenticationPanel.this, // if (JOptionPane.showConfirmDialog( ModelAuthenticationPanel.this, //
strf( "Are you sure you want to delete the user and sites remembered for:\n%s.", strf( "Are you sure you want to delete the user and sites remembered for:%n%s.",
deleteUser.getFullName() ), // deleteUser.getFullName() ), //
"Delete User", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE ) "Delete User", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE )
== JOptionPane.CANCEL_OPTION) == JOptionPane.CANCEL_OPTION)
@ -190,7 +192,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
@Override @Override
public void actionPerformed(final ActionEvent e) { public void actionPerformed(final ActionEvent e) {
JOptionPane.showMessageDialog( ModelAuthenticationPanel.this, // JOptionPane.showMessageDialog( ModelAuthenticationPanel.this, //
strf( "Reads users and sites from the directory at:\n%s", strf( "Reads users and sites from the directory at:%n%s",
MPFileUserManager.get().getPath().getAbsolutePath() ), // MPFileUserManager.get().getPath().getAbsolutePath() ), //
"Help", JOptionPane.INFORMATION_MESSAGE ); "Help", JOptionPane.INFORMATION_MESSAGE );
} }
@ -207,7 +209,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
@Override @Override
public PasswordFrame<MPFileUser, MPFileSite> newPasswordFrame() { public PasswordFrame<MPFileUser, MPFileSite> newPasswordFrame() {
return new PasswordFrame<MPFileUser, MPFileSite>( getSelectedUser() ) { return new PasswordFrame<MPFileUser, MPFileSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
@Override @Override
protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter,
final MPResultType resultType, final MPResultType resultType,

View File

@ -66,7 +66,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
private S currentSite; private S currentSite;
private boolean updatingUI; private boolean updatingUI;
@SuppressWarnings({ "MagicNumber", "OverridableMethodCallDuringObjectConstruction" }) @SuppressWarnings("MagicNumber")
protected PasswordFrame(final U user) { protected PasswordFrame(final U user) {
super( "Master Password" ); super( "Master Password" );
this.user = user; this.user = user;

View File

@ -19,12 +19,13 @@
package com.lyndir.masterpassword.gui.view; package com.lyndir.masterpassword.gui.view;
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.*;
import com.lyndir.masterpassword.MPIdenticon; import com.lyndir.masterpassword.MPIdenticon;
import com.lyndir.masterpassword.gui.*; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.model.MPUser;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException; import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
import com.lyndir.masterpassword.model.MPUser;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -47,6 +48,7 @@ public class UnlockFrame extends JFrame {
private AuthenticationPanel<?> authenticationPanel; private AuthenticationPanel<?> authenticationPanel;
private Future<?> identiconFuture; private Future<?> identiconFuture;
private boolean incognito; private boolean incognito;
@Nullable
private MPUser<?> user; private MPUser<?> user;
public UnlockFrame(final SignInCallback signInCallback) { public UnlockFrame(final SignInCallback signInCallback) {
@ -86,7 +88,7 @@ public class UnlockFrame extends JFrame {
authenticationContainer.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) ); authenticationContainer.setBorder( BorderFactory.createEmptyBorder( 20, 20, 20, 20 ) );
identiconLabel.setFont( Res.emoticonsFont().deriveFont( 14.f ) ); identiconLabel.setFont( Res.emoticonsFont().deriveFont( 14.f ) );
identiconLabel.setToolTipText( identiconLabel.setToolTipText(
"A representation of your identity across all Master Password apps.\nIt should always be the same." ); strf( "A representation of your identity across all Master Password apps.%nIt should always be the same." ) );
signInButton.addActionListener( new AbstractAction() { signInButton.addActionListener( new AbstractAction() {
@Override @Override
public void actionPerformed(final ActionEvent e) { public void actionPerformed(final ActionEvent e) {