2
0

Warning fixes and spotbug configuration tweaks.

This commit is contained in:
Maarten Billemont 2019-09-24 13:06:40 -04:00
parent 36692ac10d
commit fd1014926c
13 changed files with 134 additions and 100 deletions

View File

@ -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

View File

@ -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;

View File

@ -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 );
}

View File

@ -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())

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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() {

View File

@ -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 );

View File

@ -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);
}
}

View File

@ -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;
}
};

View File

@ -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() {

View File

@ -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() ) ),