Unsafe public fields in UpdateInterface class: make public fields final

This commit makes the UpdateInterface class immutable. The Config -> UpdateInterface initialization is moved to the UpdateInterface constructor. Default values for the fields are moved to the constructor as well. Instances of String[] are changed to List<String> and made immutable. Instances of java.awt.Rectangle (which is mutable) are replaced with a new immutable com.threerings.getdown.util.Rectangle class.

Although java.awt.Color is (sort of) immutable, it was also removed and replaced with a new immutable com.threerings.getdown.util.Color class, since it was the last dependency from the getdown core module to anything in the java.awt package, which means that when we migrate to Java 9+ the core module should no longer require a dependency on the java.desktop module.

The assertions and expected values in ColorTest have been verified against the corresponding java.awt.Color values.

(Triggered by internal security audit and Fortify analysis.)
This commit is contained in:
Daniel Gredler
2018-09-05 17:07:58 -04:00
parent 31c8315c1f
commit 1f2c736564
9 changed files with 331 additions and 97 deletions
@@ -7,17 +7,15 @@ package com.threerings.getdown.launcher;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
@@ -890,7 +888,9 @@ public abstract class Getdown extends Thread
_status.setSize(size);
_layers.setPreferredSize(size);
_patchNotes.setBounds(_ifc.patchNotes);
Rectangle patchNotes = new Rectangle(_ifc.patchNotes.x, _ifc.patchNotes.y,
_ifc.patchNotes.width, _ifc.patchNotes.height);
_patchNotes.setBounds(patchNotes);
_patchNotes.setVisible(false);
// we were displaying progress while the UI wasn't up. Now that it is, whatever progress
@@ -1131,7 +1131,7 @@ public abstract class Getdown extends Thread
};
protected Application _app;
protected Application.UpdateInterface _ifc = new Application.UpdateInterface();
protected Application.UpdateInterface _ifc = new Application.UpdateInterface(Config.EMPTY);
protected ResourceBundle _msgs;
protected Container _container;
@@ -142,7 +142,7 @@ public class GetdownApp
});
_frame.setUndecorated(_ifc.hideDecorations);
try {
_frame.setBackground(_ifc.background);
_frame.setBackground(new Color(_ifc.background.rgba(), true));
} catch (UnsupportedOperationException e) {
log.warning("Failed to set background", e);
} catch (IllegalComponentStateException e) {
@@ -6,6 +6,7 @@
package com.threerings.getdown.launcher;
import java.awt.Image;
import java.util.List;
import static com.threerings.getdown.Log.log;
@@ -42,15 +43,15 @@ public class RotatingBackgrounds
* time when the next should be shown. In that case, it's left up until its been there for its
* minimum display time and then the next one gets to come up.
*/
public RotatingBackgrounds (String[] backgrounds, String errorBackground, ImageLoader loader)
public RotatingBackgrounds (List<String> backgrounds, String errorBackground, ImageLoader loader)
{
percentages = new int[backgrounds.length];
minDisplayTime = new int[backgrounds.length];
images = new Image[backgrounds.length];
for (int ii = 0; ii < backgrounds.length; ii++) {
String[] pieces = backgrounds[ii].split(";");
percentages = new int[backgrounds.size()];
minDisplayTime = new int[backgrounds.size()];
images = new Image[backgrounds.size()];
for (int ii = 0; ii < backgrounds.size(); ii++) {
String[] pieces = backgrounds.get(ii).split(";");
if (pieces.length != 2) {
log.warning("Unable to parse background image '" + backgrounds[ii] + "'");
log.warning("Unable to parse background image '" + backgrounds.get(ii) + "'");
makeEmpty();
return;
}
@@ -59,11 +60,11 @@ public class RotatingBackgrounds
minDisplayTime[ii] = Integer.parseInt(pieces[1]);
} catch (NumberFormatException e) {
log.warning("Unable to parse background image display time '" +
backgrounds[ii] + "'");
backgrounds.get(ii) + "'");
makeEmpty();
return;
}
percentages[ii] = (int)((ii/(float)backgrounds.length) * 100);
percentages[ii] = (int)((ii/(float)backgrounds.size()) * 100);
}
if (errorBackground == null) {
errorImage = images[0];
@@ -64,7 +64,9 @@ public class StatusPanel extends JComponent
int width = img == null ? -1 : img.getWidth(this);
int height = img == null ? -1 : img.getHeight(this);
if (width == -1 || height == -1) {
Rectangle bounds = ifc.progress.union(ifc.status);
Rectangle progress = new Rectangle(ifc.progress.x, ifc.progress.y, ifc.progress.width, ifc.progress.height);
Rectangle status = new Rectangle(ifc.status.x, ifc.status.y, ifc.status.width, ifc.status.height);
Rectangle bounds = progress.union(status);
// assume the x inset defines the frame padding; add it on the left, right, and bottom
_psize = new Dimension(bounds.x + bounds.width + bounds.x,
bounds.y + bounds.height + bounds.x);
@@ -107,7 +109,7 @@ public class StatusPanel extends JComponent
_progress = percent;
if (!_ifc.hideProgressText) {
String msg = MessageFormat.format(get("m.complete"), percent);
_newplab = createLabel(msg, _ifc.progressText);
_newplab = createLabel(msg, new Color(_ifc.progressText.rgba(), true));
}
needsRepaint = true;
}
@@ -132,7 +134,7 @@ public class StatusPanel extends JComponent
int minutes = (int)(remaining / 60), seconds = (int)(remaining % 60);
String remstr = minutes + ":" + ((seconds < 10) ? "0" : "") + seconds;
String msg = MessageFormat.format(get("m.remain"), remstr);
_newrlab = createLabel(msg, _ifc.statusText);
_newrlab = createLabel(msg, new Color(_ifc.statusText.rgba(), true));
}
needsRepaint = true;
@@ -226,7 +228,7 @@ public class StatusPanel extends JComponent
gfx.drawImage(_barimg, _ifc.progress.x, _ifc.progress.y, null);
gfx.setClip(null);
} else {
gfx.setColor(_ifc.progressBar);
gfx.setColor(new Color(_ifc.progressBar.rgba(), true));
gfx.fillRect(_ifc.progress.x, _ifc.progress.y,
_progress * _ifc.progress.width / 100,
_ifc.progress.height);
@@ -270,7 +272,7 @@ public class StatusPanel extends JComponent
status += " .";
}
}
_newlab = createLabel(status, _ifc.statusText);
_newlab = createLabel(status, new Color(_ifc.statusText.rgba(), true));
// set the width of the label to the width specified
int width = _ifc.status.width;
if (width == 0) {
@@ -305,7 +307,7 @@ public class StatusPanel extends JComponent
{
Label label = new Label(text, color, FONT);
if (_ifc.textShadow != null) {
label.setAlternateColor(_ifc.textShadow);
label.setAlternateColor(new Color(_ifc.textShadow.rgba(), true));
label.setStyle(LabelStyleConstants.SHADOW);
}
return label;