Warning fixes and spotbug configuration tweaks.
This commit is contained in:
parent
36692ac10d
commit
fd1014926c
14
build.gradle
14
build.gradle
@ -1,3 +1,6 @@
|
||||
import com.github.spotbugs.SpotBugsTask
|
||||
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
@ -27,14 +30,23 @@ subprojects {
|
||||
}
|
||||
dependencies {
|
||||
spotbugsPlugins group: 'com.h3xstream.findsecbugs', name: 'findsecbugs-plugin', version: '1.9.0'
|
||||
//spotbugsPlugins group: 'com.mebigfatguy.sb-contrib', name: 'sb-contrib', version: '7.4.6'
|
||||
}
|
||||
spotbugs {
|
||||
effort 'max'
|
||||
showProgress true
|
||||
}
|
||||
|
||||
tasks.withType( JavaCompile ) {
|
||||
options.encoding = 'UTF-8'
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
if (it.name != JavaPlugin.COMPILE_JAVA_TASK_NAME) {
|
||||
options.compilerArgs << '-Xlint:deprecation'
|
||||
}
|
||||
tasks.withType( com.github.spotbugs.SpotBugsTask ) {
|
||||
}
|
||||
tasks.withType( SpotBugsTask ) {
|
||||
reports {
|
||||
xml.enabled = false
|
||||
html.enabled = true
|
||||
|
@ -24,6 +24,7 @@ import com.google.common.base.Charsets;
|
||||
import com.google.common.primitives.UnsignedBytes;
|
||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.nio.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
@ -57,6 +58,7 @@ public class MPIdenticon {
|
||||
this( fullName, masterPassword.toCharArray() );
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("CLI_CONSTANT_LIST_INDEX")
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
public MPIdenticon(final String fullName, final char[] masterPassword) {
|
||||
this.fullName = fullName;
|
||||
|
@ -60,17 +60,14 @@ public class MPAlgorithmV0 extends MPAlgorithm {
|
||||
ByteBuffer masterPasswordBuffer = ByteBuffer.wrap( masterPasswordBytes );
|
||||
|
||||
CoderResult result = encoder.encode( CharBuffer.wrap( masterPassword ), masterPasswordBuffer, true );
|
||||
if (!result.isUnderflow())
|
||||
result.throwException();
|
||||
if (result.isError())
|
||||
throw new IllegalStateException( result.toString() );
|
||||
result = encoder.flush( masterPasswordBuffer );
|
||||
if (!result.isUnderflow())
|
||||
result.throwException();
|
||||
if (result.isError())
|
||||
throw new IllegalStateException( result.toString() );
|
||||
|
||||
return _masterKey( fullName, masterPasswordBytes, version().toInt() );
|
||||
}
|
||||
catch (final CharacterCodingException e) {
|
||||
throw new IllegalStateException( e );
|
||||
}
|
||||
finally {
|
||||
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public final class Native {
|
||||
private static final char EXTENSION_SEPARATOR = '.';
|
||||
private static final String NATIVES_PATH = "lib";
|
||||
|
||||
@SuppressFBWarnings("PATH_TRAVERSAL_IN")
|
||||
@SuppressFBWarnings({"PATH_TRAVERSAL_IN", "IOI_USE_OF_FILE_STREAM_CONSTRUCTORS", "EXS_EXCEPTION_SOFTENING_RETURN_FALSE"})
|
||||
@SuppressWarnings({ "HardcodedFileSeparator", "LoadLibraryWithNonConstantString" })
|
||||
public static boolean load(final Class<?> context, final String name) {
|
||||
|
||||
@ -89,7 +89,7 @@ public final class Native {
|
||||
return true;
|
||||
}
|
||||
catch (@SuppressWarnings("ErrorNotRethrown") final IOException | UnsatisfiedLinkError e) {
|
||||
logger.dbg( e, "Couldn't load library: %s", libraryResource );
|
||||
logger.wrn( e, "Couldn't load library: %s", libraryResource );
|
||||
|
||||
if (libraryFile != null)
|
||||
if (libraryFile.exists() && !libraryFile.delete())
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.lyndir.masterpassword.gui;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||
import com.lyndir.masterpassword.gui.util.State;
|
||||
import com.lyndir.masterpassword.model.MPConfig;
|
||||
import com.lyndir.masterpassword.model.MPModelConstants;
|
||||
|
||||
@ -43,7 +44,7 @@ public class MPGuiConfig extends MPConfig {
|
||||
|
||||
public void setCheckForUpdates(final boolean checkForUpdates) {
|
||||
this.checkForUpdates = checkForUpdates;
|
||||
MasterPassword.get().updateCheck();
|
||||
State.get().updateCheck();
|
||||
setChanged();
|
||||
}
|
||||
|
||||
|
@ -50,40 +50,14 @@ public final class MasterPassword {
|
||||
private static final MasterPassword instance = new MasterPassword();
|
||||
|
||||
private final Provider keyMaster = Provider.getCurrentProvider( true );
|
||||
private final Collection<Listener> listeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
@Nullable
|
||||
private MasterPasswordFrame frame;
|
||||
@Nullable
|
||||
private MPUser<?> activeUser;
|
||||
|
||||
public static MasterPassword get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addListener(final Listener listener) {
|
||||
if (listeners.add( listener ))
|
||||
listener.onUserSelected( activeUser );
|
||||
}
|
||||
|
||||
public void removeListener(final Listener listener) {
|
||||
listeners.remove( listener );
|
||||
}
|
||||
|
||||
public void activateUser(final MPUser<?> user) {
|
||||
if (ObjectUtils.equals( activeUser, user ))
|
||||
return;
|
||||
|
||||
activeUser = user;
|
||||
for (final Listener listener : listeners)
|
||||
listener.onUserSelected( activeUser );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String version() {
|
||||
return MasterPassword.class.getPackage().getImplementationVersion();
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Res.ui( () -> {
|
||||
if (frame == null)
|
||||
@ -110,43 +84,10 @@ public final class MasterPassword {
|
||||
|
||||
// Create and open the UI.
|
||||
get().open();
|
||||
|
||||
// UI features.
|
||||
get().updateResidence();
|
||||
get().updateCheck();
|
||||
}
|
||||
|
||||
public void updateCheck() {
|
||||
if (!MPGuiConfig.get().checkForUpdates())
|
||||
return;
|
||||
|
||||
try {
|
||||
String implementationVersion = version();
|
||||
String latestVersion = new ByteSource() {
|
||||
@Override
|
||||
public InputStream openStream()
|
||||
throws IOException {
|
||||
URL url = URI.create( "https://masterpassword.app/masterpassword-gui.jar.rev" ).toURL();
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.addRequestProperty( "User-Agent", "masterpassword-gui" );
|
||||
return conn.getInputStream();
|
||||
}
|
||||
}.asCharSource( Charsets.UTF_8 ).readFirstLine();
|
||||
|
||||
if ((implementationVersion != null) && !implementationVersion.equalsIgnoreCase( latestVersion )) {
|
||||
logger.inf( "Implementation: <%s>", implementationVersion );
|
||||
logger.inf( "Latest : <%s>", latestVersion );
|
||||
logger.wrn( "You are not running the current official version. Please update from:%n%s",
|
||||
"https://masterpassword.app/masterpassword-gui.jar" );
|
||||
JOptionPane.showMessageDialog( null, Components.linkLabel( strf(
|
||||
"A new version of Master Password is available."
|
||||
+ "<p>Please download the latest version from <a href='https://masterpassword.app'>https://masterpassword.app</a>." ) ),
|
||||
"Update Available", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
}
|
||||
catch (final IOException e) {
|
||||
logger.wrn( e, "Couldn't check for version update." );
|
||||
}
|
||||
// Background.
|
||||
State.get().updateCheck();
|
||||
}
|
||||
|
||||
public void updateResidence() {
|
||||
@ -154,10 +95,4 @@ public final class MasterPassword {
|
||||
Platform.get().installAppReopenHandler( get()::open );
|
||||
keyMaster.register( MPGuiConstants.ui_hotkey, hotKey -> get().open() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
|
||||
public interface Listener {
|
||||
|
||||
void onUserSelected(@Nullable MPUser<?> user);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||
|
||||
import com.lyndir.masterpassword.MPResultType;
|
||||
import com.lyndir.masterpassword.model.impl.MPBasicQuestion;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
|
@ -145,17 +145,15 @@ public abstract class Components {
|
||||
return ((selectedFiles != null) && (selectedFiles.length > 0))? selectedFiles[0]: null;
|
||||
}
|
||||
|
||||
public static JDialog showDialog(@Nullable final Component owner, @Nullable final String title, final Container content) {
|
||||
public static void showDialog(@Nullable final Component owner, @Nullable final String title, final Container content) {
|
||||
JDialog dialog = new JDialog( (owner != null)? SwingUtilities.windowForComponent( owner ): null,
|
||||
title, Dialog.ModalityType.DOCUMENT_MODAL );
|
||||
dialog.setMinimumSize( new Dimension( 320, 0 ) );
|
||||
dialog.setLocationRelativeTo( owner );
|
||||
dialog.setContentPane( content );
|
||||
|
||||
return showDialog( dialog );
|
||||
}
|
||||
|
||||
private static JDialog showDialog(final JDialog dialog) {
|
||||
private static void showDialog(final JDialog dialog) {
|
||||
// OpenJDK does not correctly implement this setting in native code.
|
||||
dialog.getRootPane().putClientProperty( "apple.awt.documentModalSheet", Boolean.TRUE );
|
||||
dialog.getRootPane().putClientProperty( "Window.style", "small" );
|
||||
@ -163,8 +161,6 @@ public abstract class Components {
|
||||
|
||||
dialog.setLocationByPlatform( true );
|
||||
dialog.setVisible( true );
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static JTextField textField() {
|
||||
|
@ -226,7 +226,7 @@ public abstract class Res {
|
||||
return get( Font.PLAIN, size );
|
||||
}
|
||||
|
||||
Font get(final int style, final int size) {
|
||||
synchronized Font get(final int style, final int size) {
|
||||
if (!registered)
|
||||
register();
|
||||
|
||||
@ -234,7 +234,7 @@ public abstract class Res {
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("URLCONNECTION_SSRF_FD")
|
||||
private void register() {
|
||||
private synchronized void register() {
|
||||
try {
|
||||
Font font = Font.createFont( Font.TRUETYPE_FONT, Resources.getResource( resourceName ).openStream() );
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont( font );
|
||||
|
@ -0,0 +1,94 @@
|
||||
package com.lyndir.masterpassword.gui.util;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.ObjectUtils;
|
||||
import com.lyndir.masterpassword.gui.MPGuiConfig;
|
||||
import com.lyndir.masterpassword.model.MPUser;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.*;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
public class State {
|
||||
|
||||
private static final Logger logger = Logger.get( State.class );
|
||||
private static final State instance = new State();
|
||||
|
||||
private final Collection<Listener> listeners = new CopyOnWriteArraySet<>();
|
||||
@Nullable
|
||||
private MPUser<?> activeUser;
|
||||
|
||||
public static State get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addListener(final Listener listener) {
|
||||
if (listeners.add( listener ))
|
||||
listener.onUserSelected( activeUser );
|
||||
}
|
||||
|
||||
public void removeListener(final Listener listener) {
|
||||
listeners.remove( listener );
|
||||
}
|
||||
|
||||
public void activateUser(final MPUser<?> user) {
|
||||
if (ObjectUtils.equals( activeUser, user ))
|
||||
return;
|
||||
|
||||
activeUser = user;
|
||||
for (final Listener listener : listeners)
|
||||
listener.onUserSelected( activeUser );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String version() {
|
||||
return State.class.getPackage().getImplementationVersion();
|
||||
}
|
||||
|
||||
public void updateCheck() {
|
||||
if (!MPGuiConfig.get().checkForUpdates())
|
||||
return;
|
||||
|
||||
try {
|
||||
String implementationVersion = version();
|
||||
String latestVersion = new ByteSource() {
|
||||
@Override
|
||||
public InputStream openStream()
|
||||
throws IOException {
|
||||
URL url = URI.create( "https://masterpassword.app/masterpassword-gui.jar.rev" ).toURL();
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.addRequestProperty( "User-Agent", "masterpassword-gui" );
|
||||
return conn.getInputStream();
|
||||
}
|
||||
}.asCharSource( Charsets.UTF_8 ).readFirstLine();
|
||||
|
||||
if ((implementationVersion != null) && !implementationVersion.equalsIgnoreCase( latestVersion )) {
|
||||
logger.inf( "Implementation: <%s>", implementationVersion );
|
||||
logger.inf( "Latest : <%s>", latestVersion );
|
||||
logger.wrn( "You are not running the current official version. Please update from:%n%s",
|
||||
"https://masterpassword.app/masterpassword-gui.jar" );
|
||||
JOptionPane.showMessageDialog( null, Components.linkLabel( strf(
|
||||
"A new version of Master Password is available."
|
||||
+ "<p>Please download the latest version from <a href='https://masterpassword.app'>https://masterpassword.app</a>." ) ),
|
||||
"Update Available", JOptionPane.INFORMATION_MESSAGE );
|
||||
}
|
||||
}
|
||||
catch (final IOException e) {
|
||||
logger.wrn( e, "Couldn't check for version update." );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("InterfaceMayBeAnnotatedFunctional")
|
||||
public interface Listener {
|
||||
|
||||
void onUserSelected(@Nullable MPUser<?> user);
|
||||
}
|
||||
}
|
@ -124,15 +124,13 @@ public class UnsignedIntegerModel extends SpinnerNumberModel implements Selectab
|
||||
return new JFormattedTextField.AbstractFormatter() {
|
||||
@Override
|
||||
@Nullable
|
||||
public Object stringToValue(@Nullable final String text)
|
||||
throws ParseException {
|
||||
public Object stringToValue(@Nullable final String text) {
|
||||
return (text != null)? UnsignedInteger.valueOf( text ): null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String valueToString(final Object value)
|
||||
throws ParseException {
|
||||
public String valueToString(final Object value) {
|
||||
return (value != null)? value.toString(): null;
|
||||
}
|
||||
};
|
||||
|
@ -17,13 +17,13 @@ import javax.swing.*;
|
||||
* @author lhunath, 2018-07-14
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FilesPanel extends JPanel implements MPFileUserManager.Listener, MasterPassword.Listener {
|
||||
public class FilesPanel extends JPanel implements MPFileUserManager.Listener, State.Listener {
|
||||
|
||||
private final JButton avatarButton = Components.button( Res.icons().avatar( 0 ), event -> setAvatar(),
|
||||
"Click to change the user's avatar." );
|
||||
|
||||
private final CollectionListModel<MPUser<?>> usersModel =
|
||||
new CollectionListModel<MPUser<?>>( MPFileUserManager.get().getFiles() ).selection( MasterPassword.get()::activateUser );
|
||||
new CollectionListModel<MPUser<?>>( MPFileUserManager.get().getFiles() ).selection( State.get()::activateUser );
|
||||
|
||||
protected FilesPanel() {
|
||||
setOpaque( false );
|
||||
@ -45,7 +45,7 @@ public class FilesPanel extends JPanel implements MPFileUserManager.Listener, Ma
|
||||
add( Components.comboBox( usersModel, user -> ifNotNull( user, MPUser::getFullName ) ) );
|
||||
|
||||
MPFileUserManager.get().addListener( this );
|
||||
MasterPassword.get().addListener( this );
|
||||
State.get().addListener( this );
|
||||
}
|
||||
|
||||
private void setAvatar() {
|
||||
|
@ -41,7 +41,7 @@ import javax.swing.text.PlainDocument;
|
||||
* @author lhunath, 2018-07-14
|
||||
*/
|
||||
@SuppressWarnings("SerializableStoresNonSerializable")
|
||||
public class UserContentPanel extends JPanel implements MasterPassword.Listener, MPUser.Listener {
|
||||
public class UserContentPanel extends JPanel implements State.Listener, MPUser.Listener {
|
||||
|
||||
private static final Random random = new SecureRandom();
|
||||
private static final int SIZE_RESULT = 48;
|
||||
@ -72,7 +72,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
|
||||
setBorder( Components.marginBorder() );
|
||||
showUser( null );
|
||||
|
||||
MasterPassword.get().addListener( this );
|
||||
State.get().addListener( this );
|
||||
}
|
||||
|
||||
protected JComponent getUserToolbar() {
|
||||
@ -155,9 +155,9 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
|
||||
return;
|
||||
|
||||
if (incognitoField.isSelected())
|
||||
MasterPassword.get().activateUser( new MPIncognitoUser( fullName ) );
|
||||
State.get().activateUser( new MPIncognitoUser( fullName ) );
|
||||
else
|
||||
MasterPassword.get().activateUser( MPFileUserManager.get().add( fullName ) );
|
||||
State.get().activateUser( MPFileUserManager.get().add( fullName ) );
|
||||
}
|
||||
|
||||
private void importUser() {
|
||||
@ -200,7 +200,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
|
||||
Res.format( importUser.getLastUsed() ) ) )))
|
||||
return;
|
||||
|
||||
MasterPassword.get().activateUser( MPFileUserManager.get().add( importUser ) );
|
||||
State.get().activateUser( MPFileUserManager.get().add( importUser ) );
|
||||
}
|
||||
catch (final MPIncorrectMasterPasswordException | MPAlgorithmException e) {
|
||||
JOptionPane.showMessageDialog(
|
||||
@ -242,7 +242,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
|
||||
+ "Some people even configure this location to be synced between their different computers "
|
||||
+ "using services such as those provided by SpiderOak or Dropbox.</p>"
|
||||
+ "<hr><p><a href='https://masterpassword.app'>https://masterpassword.app</a> — by Maarten Billemont</p>",
|
||||
MasterPassword.get().version(),
|
||||
State.get().version(),
|
||||
InputEvent.getModifiersExText( MPGuiConstants.ui_hotkey.getModifiers() ),
|
||||
KeyEvent.getKeyText( MPGuiConstants.ui_hotkey.getKeyCode() ),
|
||||
MPFileUserManager.get().getPath().getAbsolutePath() ) ),
|
||||
|
Loading…
Reference in New Issue
Block a user