From 8195460ee2f395abdb85d9c99ce0078a738b0743 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 4 Sep 2018 12:17:30 -0700 Subject: [PATCH] Remove obsolete Applet code. --- applet/pom.xml | 51 --- .../getdown/launcher/GetdownApplet.java | 348 --------------- .../getdown/launcher/GetdownAppletConfig.java | 416 ------------------ .../threerings/getdown/data/Application.java | 44 +- .../threerings/getdown/launcher/Getdown.java | 118 +---- .../getdown/launcher/ImageLoader.java | 18 - .../getdown/launcher/RotatingBackgrounds.java | 18 +- pom.xml | 1 - .../getdown/tools/AppletParamSigner.java | 62 --- 9 files changed, 23 insertions(+), 1053 deletions(-) delete mode 100644 applet/pom.xml delete mode 100644 applet/src/main/java/com/threerings/getdown/launcher/GetdownApplet.java delete mode 100644 applet/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java delete mode 100644 launcher/src/main/java/com/threerings/getdown/launcher/ImageLoader.java delete mode 100644 tools/src/main/java/com/threerings/getdown/tools/AppletParamSigner.java diff --git a/applet/pom.xml b/applet/pom.xml deleted file mode 100644 index 2b3fff9..0000000 --- a/applet/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - 4.0.0 - - com.threerings - getdown - 1.7.2-SNAPSHOT - - - getdown-app - jar - Getdown Applet - The Getdown installer applet (obsolete) - - - - com.threerings - getdown-launcher - ${project.version} - - - java - plugin - 1.5 - system - ${plugin.jar.path} - - - - - - - standard-jdk - - ${java.home}/lib/plugin.jar - - - ${java.home}/lib/plugin.jar - - - - icedtea-web - - /usr/share/icedtea-web/plugin.jar - - - /usr/share/icedtea-web/plugin.jar - - - - diff --git a/applet/src/main/java/com/threerings/getdown/launcher/GetdownApplet.java b/applet/src/main/java/com/threerings/getdown/launcher/GetdownApplet.java deleted file mode 100644 index 7f1d32a..0000000 --- a/applet/src/main/java/com/threerings/getdown/launcher/GetdownApplet.java +++ /dev/null @@ -1,348 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2016 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - -package com.threerings.getdown.launcher; - -import java.awt.Container; -import java.awt.Image; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; - -import javax.swing.JApplet; -import javax.swing.JPanel; - -import netscape.javascript.JSObject; - -import com.threerings.getdown.data.Application; -import com.threerings.getdown.data.Properties; - -import static com.threerings.getdown.Log.log; - -/** - * An applet that can be used to launch a Getdown application (when signed and given privileges). - */ -public class GetdownApplet extends JApplet - implements ImageLoader -{ - /** - * Sets the JavaScript callback to invoke when a message is received from the launched app. - * The callback should be a function that accepts a single string parameter (the received - * message). - */ - public synchronized void setMessageCallback (JSObject callback) - { - _messageCallback = callback; - } - - /** - * Attempts to send a message to the launched app. - * - * @return true if we succeeded in sending the message, false if the launched app has not (yet) - * established a connection to Getdown, or the send failed. - */ - public synchronized boolean sendMessage (String message) - { - if (_connectOut != null) { - try { - _connectOut.writeUTF(message); - return true; - } catch (IOException e) { - log.warning("Error sending message to app.", "message", message, e); - } - } - return false; - } - - @Override // documentation inherited - public void init () - { - _config = new GetdownAppletConfig(this); - - try { - - try { - // Check our permissions, download getdown.txt, etc. - _config.init(); - } catch (Exception e) { - _errmsg = e.getMessage(); - } - - List signers = new ArrayList<>(); - Certificate cert = loadCertificate("resource.crt"); - if (cert != null) { - signers.add(cert); - } else { - // getSigners() returns all certificates used to sign this applet which may allow a - // third party to insert a trusted certificate. This should be avoided. - log.warning("No resource certificate found, falling back to class signers"); - Object[] candidates = GetdownApplet.class.getSigners(); - if (candidates != null) { - for (Object signer : candidates) { - if (signer instanceof Certificate) { - signers.add((Certificate)signer); - } - } - } - } - _getdown = new Getdown(_config.appdir, null, signers, - _config.jvmargs, _config.appargs) { - @Override - protected Container createContainer () { - getContentPane().removeAll(); - getContentPane().setBackground(_ifc.background); - return getContentPane(); - } - @Override - protected RotatingBackgrounds getBackground () { - return _config.getBackgroundImages(GetdownApplet.this); - } - @Override - protected void showContainer () { - ((JPanel)getContentPane()).revalidate(); - } - @Override - protected void disposeContainer () { - // nothing to do as we're in an applet - } - @Override - protected boolean invokeDirect () { - return _config.invokeDirect; - } - @Override - protected JApplet getApplet () { - return GetdownApplet.this; - } - @Override - protected void showDocument (String url) { - try { - getAppletContext().showDocument(new URL(url), "_blank"); - } catch (MalformedURLException e) { - log.warning("Invalid document url.", "url", url, e); - } - } - @Override - protected void launch () { - // if so configured, create a server socket to listen - // for a connection from the app - if (_config.allowConnect) { - try { - startConnectServer(); - } catch (IOException e) { - log.warning("Failed to start connect server.", e); - } - } - super.launch(); - } - @Override - protected void exit (int exitCode) { - _status.stopThrob(); - _app.releaseLock(); - _config.redirect(); - } - }; - - // set up our user interface - _config.config(_getdown); - _getdown.preInit(); - - } catch (Exception e) { - // assume that if we already encountered an error, that is the root cause that we want - // to report back to the user - if (_errmsg == null) { - _errmsg = e.getMessage(); - } - log.warning("init() failed.", e); - } - } - - /** - * Attempts to start the server that will accept a connection from the launched app, allowing - * it to exchange messages with the JavaScript context. - */ - protected void startConnectServer () - throws IOException - { - // bind and set a property with the local port that will be passed through to the app - _serverSocket = new ServerSocket(0, 0, InetAddress.getByName(null)); - String port = String.valueOf(_serverSocket.getLocalPort()); - log.info("Listening for connections from launched app.", "port", port); - System.setProperty(Application.PROP_PASSTHROUGH_PREFIX + Properties.CONNECT_PORT, port); - Thread thread = new Thread("ConnectServer") { - @Override - public void run () { - while (true) { - try { - acceptConnection(); - } catch (IOException e) { - if (!_serverSocket.isClosed()) { - log.warning("Error accepting connection.", e); - } - break; - } - } - } - protected void acceptConnection () throws IOException { - Socket socket = _serverSocket.accept(); - log.info("App connected.", "port", socket.getPort()); - DataInputStream connectIn = new DataInputStream(socket.getInputStream()); - synchronized (GetdownApplet.this) { - _connectOut = new DataOutputStream(socket.getOutputStream()); - } - while (true) { - try { - String message = connectIn.readUTF(); - synchronized (GetdownApplet.this) { - if (message.equals("CLOSE")) { - socket.close(); - log.info("App closed connection."); - break; - } else if (_messageCallback != null) { - _messageCallback.call("call", - new Object[] { _messageCallback, message }); - } - } - } catch (IOException e) { - if (!socket.isClosed()) { - log.warning("Error reading message.", e); - } - break; - } - } - synchronized (GetdownApplet.this) { - _connectOut = null; - } - } - }; - thread.setDaemon(true); - thread.start(); - } - - // implemented from ImageLoader - @Override - public Image loadImage (String path) - { - try { - return getImage(new URL(getDocumentBase(), path)); - } catch (MalformedURLException e) { - log.warning("Failed to load background image", "path", path, e); - return null; - } - } - - @Override // documentation inherited - public void start () - { - if (_errmsg != null) { - _getdown.fail(_errmsg); - } else { - try { - _getdown.start(); - } catch (Exception e) { - log.warning("start() failed.", e); - } - } - } - - @Override // documentation inherited - public void stop () - { - // Interrupt the getdown thread to tell it to kill its current downloading or verifying - // before launching - _getdown.interrupt(); - // release the lock if the applet window is closed or replaced - _getdown._app.releaseLock(); - } - - @Override // documentation inherited - public synchronized void destroy () - { - if (_serverSocket != null) { - try { - _serverSocket.close(); - } catch (IOException e) { - log.warning("Error closing server socket.", e); - } - } - if (_connectOut != null) { - try { - _connectOut.writeUTF("CLOSE"); - _connectOut.close(); - log.info("Disconnected from app."); - } catch (IOException e) { - log.warning("Error closing connect socket/output stream.", e); - } - } - } - - /** - * Creates the specified file and writes the supplied contents to it. - */ - protected boolean writeToFile (File tofile, String contents) - { - try (FileOutputStream fos = new FileOutputStream(tofile); - PrintStream out = new PrintStream(fos)) { - out.println(contents); - return true; - } catch (IOException ioe) { - log.warning("Failed to create '" + tofile + "'.", ioe); - return false; - } - } - - protected static Certificate loadCertificate (String path) - { - try { - ClassLoader classLoader = GetdownApplet.class.getClassLoader(); - if (classLoader == null) { - return null; - } - URL keyUrl = classLoader.getResource(path); - if (keyUrl == null) { - return null; - } - try (InputStream is = keyUrl.openStream()) { - return CertificateFactory.getInstance("X.509").generateCertificate(is); - } - } catch (CertificateException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /** The Getdown configuration as pulled from the applet params */ - protected GetdownAppletConfig _config; - - /** Handles all the actual getting down. */ - protected Getdown _getdown; - - /** An error encountered during initialization. */ - protected String _errmsg; - - /** The message callback registered by JavaScript on the containing page, if any. */ - protected JSObject _messageCallback; - - /** The server socket on which we listen for connections, if any. */ - protected ServerSocket _serverSocket; - - /** The output stream to the launched app, if a connection has been established. */ - protected DataOutputStream _connectOut; -} diff --git a/applet/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java b/applet/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java deleted file mode 100644 index bfea47b..0000000 --- a/applet/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java +++ /dev/null @@ -1,416 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2016 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - -package com.threerings.getdown.launcher; - -import java.awt.Color; -import java.awt.Rectangle; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import javax.swing.JApplet; - -import com.samskivert.util.RunAnywhere; -import com.samskivert.util.StringUtil; -import com.threerings.getdown.launcher.ImageLoader; -import com.threerings.getdown.launcher.RotatingBackgrounds; -import com.threerings.getdown.util.Config; - -import static com.threerings.getdown.Log.log; - -public class GetdownAppletConfig -{ - public static final String APPBASE = "appbase"; - public static final String APPNAME = "appname"; - public static final String BGIMAGE = "bgimage"; - public static final String ERRORBGIMAGE = "errorbgimage"; - public static final String PARAM_DELIMITER = "."; - public static final String DIRECT = "direct"; - public static final String CONNECT = "connect"; - public static final String REDIRECT_ON_FINISH = "redirect_on_finish"; - public static final String REDIRECT_ON_FINISH_TARGET = "redirect_on_finish_target"; - - /** Used to specify the names of additional jvmargs properties. Each jvmarg property will - * be suffixed by a monotonically increasing integer starting at zero, e.g. - *
{@code
-     * 
-     * 
-     * }
- * When a number is reached for which no value exists, we stop looking. */ - public static final String JVMARG_PREFIX = "jvmargs"; - - /** A property specifying the names of additional appargs properties. Each apparg property will - * be suffixed by a monotonically increasing integer starting at zero, e.g. - *
{@code
-     * 
-     * 
-     * }
- * When a number is reached for which no value exists, we stop looking. */ - public static final String APPARG_PREFIX = "appargs"; - - public String appbase; - - public String appname; - - /** The list of background images and their display time */ - public String imgpath; - - /** The error background image */ - public String errorimgpath; - - public File appdir; - - /** Additional jvmargs to supply to the launching app. */ - public String[] jvmargs; - - /** Additional appargs to supply to the launching app. */ - public String[] appargs; - - /** An optional URL to which the applet should redirect when done. */ - public URL redirectUrl; - - public String redirectTarget; - - public String installerFileContents; - - /** Indicates whether the downloaded app should be launched in the parent applet (true) or as a - * separate java process (false). */ - public boolean invokeDirect; - - /** Indicates whether Getdown should allow the launched app to connect to it through a server - * socket bound to localhost on any available port in order to allow interaction with - * JavaScript code on the page containing the applet. */ - public boolean allowConnect; - - /** Optional default bounds for the status panel. */ - public Rectangle statusBounds; - - public Color statusColor; - - public GetdownAppletConfig (JApplet applet) - { - this(applet, null); - } - - public GetdownAppletConfig (JApplet applet, String paramPrefix) - { - _applet = applet; - _prefix = paramPrefix; - - appbase = getParameter(APPBASE, ""); - appname = getParameter(APPNAME, ""); - log.info("App Base: " + appbase); - log.info("App Name: " + appname); - - imgpath = getParameter(BGIMAGE); - errorimgpath = getParameter(ERRORBGIMAGE); - - // DEPRECATED LEGACY CRAP: extract system properties to set in applet JVM (not app JVM) - String props = getParameter("properties"); - if (props != null) { - String[] proparray = props.split(" "); - for (String property : proparray) { - String key = property.substring(property.indexOf("-D") + 2, property.indexOf("=")); - String value = property.substring(property.indexOf("=") + 1); - _properties.setProperty(key, value); - } - } - // END DLC - - String root; - if (RunAnywhere.isWindows()) { - root = "Application Data"; - String verStr = System.getProperty("os.version"); - try { - if (Float.parseFloat(verStr) >= 6.0f) { - // Vista makes us write it here.... Yay. - root = "AppData" + File.separator + "LocalLow"; - } - } catch (Exception e) { - log.warning("Couldn't parse OS version", "vers", verStr, "error", e); - } - } else if (RunAnywhere.isMacOS()) { - root = "Library" + File.separator + "Application Support"; - } else /* isLinux() or something wacky */{ - root = ".getdown"; - } - appdir = new File(System.getProperty("user.home") + File.separator + root + File.separator - + appname); - - installerFileContents = getParameter("installer"); - - // extract arguments to be added to getdown.txt's jvmargs - List jvmalist = parseArgList(JVMARG_PREFIX); - // DEPRECATED LEGACY CRAP: extract system properties to set in app JVM - String appprops = getParameter("app_properties"); - if (appprops != null) { - for (String jvmarg : appprops.split(",")) { - jvmalist.add("-D" + jvmarg); - } - } - // END DLC - jvmargs = jvmalist.toArray(new String[jvmalist.size()]); - - // extract arguments to be added to getdown.txt's appargs - List appalist = parseArgList(APPARG_PREFIX); - appargs = appalist.toArray(new String[appalist.size()]); - - String direct = getParameter(DIRECT, "false"); - invokeDirect = Boolean.valueOf(direct); - - String connect = getParameter(CONNECT, "false"); - allowConnect = Boolean.valueOf(connect); - - String redirectURL = getParameter(REDIRECT_ON_FINISH); - if (redirectURL != null) { - try { - redirectUrl = new URL(redirectURL); - redirectTarget = getParameter(REDIRECT_ON_FINISH_TARGET); - } catch (MalformedURLException e) { - log.warning("URL in " + REDIRECT_ON_FINISH + " param is malformed: " + e); - } - } - - // This allows us to configure the status panel from applet parameters in case something - // goes horribly wrong before we get a chance to read getdown.txt (like when the user - // rejects write permission for the applet) - statusBounds = Config.parseRect("ui.status", getParameter("ui.status")); - statusColor = Config.parseColor(getParameter("ui.status_text")); - } - - /** - * Does all the fiddly initialization of Getdown and throws an exception if something goes - * horribly wrong. - */ - public void init () throws Exception - { - securityCheck(); - setSystemProperties(); - ensureAppdirExists(); - createFiles(); - - // record a few things for posterity - log.info("------------------ VM Info ------------------"); - log.info("-- OS Name: " + System.getProperty("os.name")); - log.info("-- OS Arch: " + System.getProperty("os.arch")); - log.info("-- OS Vers: " + System.getProperty("os.version")); - log.info("-- Java Vers: " + System.getProperty("java.version")); - log.info("-- Java Home: " + System.getProperty("java.home")); - log.info("-- User Name: " + System.getProperty("user.name")); - log.info("-- User Home: " + System.getProperty("user.home")); - log.info("-- Cur dir: " + System.getProperty("user.dir")); - log.info("---------------------------------------------"); - } - - /** - * Sets getdown status panel size and text color from applet params. - */ - public void config (Getdown getdown) - { - if (statusBounds != null) { - getdown._ifc.status = statusBounds; - } - if (statusColor != null) { - getdown._ifc.statusText = statusColor; - } - } - - /** - * Gets the value of the named parameter. If the param is not set, this will return null. - */ - public String getParameter (String param) - { - return (_prefix == null) ? - _applet.getParameter(param) : - _applet.getParameter(_prefix + PARAM_DELIMITER + param); - } - - /** - * Gets the value of an optional Applet parameter. If the param is not set, the default value is - * returned. - */ - public String getParameter (String param, String defaultValue) - { - String value = getParameter(param); - return (value == null) ? defaultValue : value; - } - - /** - * Uses the Applet context to redirect the browser to a URL (intended for use when the applet - * is done downloading). If the redirect_on_finish parameter was not set, this does nothing. - */ - public void redirect () - { - if (redirectUrl != null) { - if (redirectTarget == null) { - _applet.getAppletContext().showDocument(redirectUrl); - } else { - _applet.getAppletContext().showDocument(redirectUrl, redirectTarget); - } - } - } - - /** - * Gets the rotation background images and error image.The given image loader will be used if - * the images have not been loaded yet. The locations of the images are pulled from the Applet - * parameters. - */ - public RotatingBackgrounds getBackgroundImages (ImageLoader loader) - { - if (bgimages == null) { - // Load background images - bgimages = getBackgroundImages(imgpath, errorimgpath, loader); - } - return bgimages; - } - - /** - * Gets the rotation background images and error image.The given image loader will be used if - * the images have not been loaded yet. - */ - public static RotatingBackgrounds getBackgroundImages (String imageParam, - String errorImagePath, ImageLoader loader) - { - // Parse the image parameter and load the background images - RotatingBackgrounds images; - if (imageParam == null) { - images = new RotatingBackgrounds(); - } else if (imageParam.indexOf(",") > -1) { - images = new RotatingBackgrounds(imageParam.split(","), errorImagePath, loader); - } else { - images = new RotatingBackgrounds(loader.loadImage(imageParam)); - } - return images; - } - - /** - * Parses parameters named {@code prefix0}, {@code prefix1}, ... into a list. - */ - protected List parseArgList (String prefix) - { - List arglist = new ArrayList<>(); - String value; - for (int ii = 0; (value = getParameter(prefix + ii)) != null; ii++) { - arglist.add(value); - } - return arglist; - } - - /** - * This checks whether the user has accepted our signed - */ - protected final void securityCheck () throws Exception - { - // getdown requires full read/write permissions to the system; if we don't have this, then - // we need to not do anything unsafe, and display a message to the user telling them they - // need to (groan) close out of the web browser entirely and re-launch the browser, go to - // our site, and accept the certificate - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPropertiesAccess(); - sm.checkWrite("getdown"); - } catch (SecurityException se) { - log.warning("Signed applet rejected by user", "se", se); - throw new Exception("m.insufficient_permissions_error"); - } - } - } - - /** - * Dumps the contents of the properties into the System properties. - */ - protected void setSystemProperties () - { - System.getProperties().putAll(_properties); - } - - /** - * Makes sire that the appdir directory exists, creating it if necessary. Throws an exception if - * the directory does not exist and cannot be created. - */ - protected void ensureAppdirExists () throws Exception - { - // if our application directory does not exist, auto-create it - if ((!appdir.exists() || !appdir.isDirectory()) && !appdir.mkdirs()) { - throw new Exception("m.create_appdir_failed"); - } - } - - /** - * Writes the installer.txt and getdown.txt files to the local file system as needed. - */ - protected void createFiles () throws Exception - { - // if an installer.txt file is desired, create that - if (!StringUtil.isBlank(installerFileContents)) { - File infile = new File(appdir, "installer.txt"); - if (!infile.exists()) { - writeToFile(infile, installerFileContents); - } - } - - // if our getdown.txt file does not exist, or it is corrupt, auto-/recreate it - File gdfile = new File(appdir, "getdown.txt"); - boolean createGetdown = !gdfile.exists(); - if (!createGetdown) { - try { - Config config = Config.parseConfig(gdfile, Config.createOpts(false)); - String oappbase = StringUtil.trim(config.getString(APPBASE)); - createGetdown = (appbase != null && !appbase.trim().equals(oappbase)); - if (createGetdown) { - log.warning("Recreating getdown.txt due to appbase mismatch", - "nappbase", appbase, "oappbase", oappbase); - } - } catch (Exception e) { - log.warning("Failure checking validity of getdown.txt, forcing recreate.", - "error", e); - createGetdown = true; - } - } - if (createGetdown) { - if (StringUtil.isBlank(appbase)) { - throw new Exception("m.missing_appbase"); - } - if (!writeToFile(gdfile, "appbase = " + appbase)) { - throw new Exception("m.create_getdown_failed"); - } - } - } - - /** - * Creates the specified file and writes the supplied contents to it. - */ - protected boolean writeToFile (File tofile, String contents) - { - try (FileOutputStream fos = new FileOutputStream(tofile); - PrintStream out = new PrintStream(fos)) { - out.println(contents); - return true; - } catch (IOException ioe) { - log.warning("Failed to create '" + tofile + "'.", ioe); - return false; - } - } - - /** A reference to the Applet in which Getdown is running */ - protected JApplet _applet; - - /** An optional prefix to prepend when looking for Getdown Applet params */ - protected String _prefix; - - /** The background images displayed on the status panel as Getdown is getting down. */ - protected RotatingBackgrounds bgimages; - - /** System properties to set in the applet JVM. */ - protected Properties _properties = new Properties(); -} diff --git a/core/src/main/java/com/threerings/getdown/data/Application.java b/core/src/main/java/com/threerings/getdown/data/Application.java index 30204c3..28818ab 100644 --- a/core/src/main/java/com/threerings/getdown/data/Application.java +++ b/core/src/main/java/com/threerings/getdown/data/Application.java @@ -25,8 +25,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; -import javax.swing.JApplet; - import com.samskivert.io.StreamUtil; import com.samskivert.text.MessageUtil; import com.samskivert.util.ArrayUtil; @@ -141,12 +139,6 @@ public class Application /** The patch notes URL. */ public String patchNotesUrl; - /** The dimensions of the play again button. */ - public Rectangle playAgain; - - /** The path (relative to the appdir) to a single play again image. */ - public String playAgainImage; - /** Whether window decorations are hidden for the UI. */ public boolean hideDecorations; @@ -172,7 +164,6 @@ public class Application ", pb=" + progressBar + ", srect=" + status + ", st=" + statusText + ", shadow=" + textShadow + ", err=" + installError + ", nrect=" + patchNotes + ", notes=" + patchNotesUrl + ", stepPercentages=" + stepPercentages + - ", parect=" + playAgain + ", paimage=" + playAgainImage + ", hideProgressText" + hideProgressText + ", minShow=" + minShowSeconds + "]"; } @@ -753,10 +744,6 @@ public class Application ui.patchNotes = config.getRect("ui.patch_notes", ui.patchNotes); ui.patchNotesUrl = config.getUrl("ui.patch_notes_url", null); - // the play again bits - ui.playAgain = config.getRect("ui.play_again", ui.playAgain); - ui.playAgainImage = config.getString("ui.play_again_image"); - // step progress percentages for (UpdateInterface.Step step : UpdateInterface.Step.values()) { String spec = config.getString("ui.percents." + step.name()); @@ -1058,7 +1045,7 @@ public class Application /** * Runs this application directly in the current VM. */ - public void invokeDirect (JApplet applet) throws IOException + public void invokeDirect () throws IOException { ClassPath classPath = ClassPaths.buildClassPath(this); URL[] jarUrls = classPath.asUrls(); @@ -1103,9 +1090,6 @@ public class Application System.setProperty(entry.getKey(), entry.getValue()); } - // make a note that we're running in "applet" mode - System.setProperty("applet", "true"); - // prepare our app arguments String[] args = new String[_appargs.size()]; for (int ii = 0; ii < args.length; ii++) args[ii] = processArg(_appargs.get(ii)); @@ -1113,17 +1097,9 @@ public class Application try { log.info("Loading " + _class); Class appclass = loader.loadClass(_class); - Method main; - try { - // first see if the class has a special applet-aware main - main = appclass.getMethod("main", JApplet.class, SA_PROTO.getClass()); - log.info("Invoking main(JApplet, {" + StringUtil.join(args, ", ") + "})"); - main.invoke(null, new Object[] { applet, args }); - } catch (NoSuchMethodException nsme) { - main = appclass.getMethod("main", SA_PROTO.getClass()); - log.info("Invoking main({" + StringUtil.join(args, ", ") + "})"); - main.invoke(null, new Object[] { args }); - } + Method main = appclass.getMethod("main", SA_PROTO.getClass()); + log.info("Invoking main({" + StringUtil.join(args, ", ") + "})"); + main.invoke(null, new Object[] { args }); } catch (Exception e) { e.printStackTrace(System.err); } @@ -1321,9 +1297,6 @@ public class Application for (int ii = 0; ii < sizes.length; ii++) { final Resource rsrc = rsrcs.get(ii); - if (Thread.interrupted()) { - throw new InterruptedException("m.applet_stopped"); - } final int index = ii; exec.execute(new Runnable() { public void run () { @@ -1414,9 +1387,6 @@ public class Application ProgressAggregator pagg = new ProgressAggregator(obs, sizes); for (int ii = 0; ii < sizes.length; ii++) { - if (Thread.interrupted()) { - throw new InterruptedException("m.applet_stopped"); - } Resource rsrc = rsrcs.get(ii); ProgressObserver pobs = pagg.startElement(ii); try { @@ -1539,12 +1509,6 @@ public class Application * Downloads a new copy of the specified control file, optionally validating its signature. * If the download is successful, moves it over the old file on the filesystem. * - *

We implement simple signing of the digest.txt file for use with the Getdown applet, but - * this should never be used as-is with a non-applet getdown installation, as the signing - * format has no provisions for declaring arbitrary signing key IDs, signature algorithm, et al - * -- it is entirely reliant on the ability to upgrade the Getdown applet, and its signature - * validation implementation, at-will (ie, via an Applet). - * *

TODO: Switch to PKCS #7 or CMS. * * @param sigVersion if {@code 0} no validation will be performed, if {@code > 0} then this diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java index 3c434be..08330b3 100644 --- a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -18,7 +18,6 @@ import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.ImageIcon; -import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLayeredPane; @@ -70,7 +69,7 @@ import static com.threerings.getdown.Log.log; * Manages the main control for the Getdown application updater and deployment system. */ public abstract class Getdown extends Thread - implements Application.StatusDisplay, ImageLoader + implements Application.StatusDisplay, RotatingBackgrounds.ImageLoader { public static void main (String[] args) { @@ -128,7 +127,7 @@ public abstract class Getdown extends Thread /** * Installs the currently pending new resources. */ - public void install () throws IOException, InterruptedException + public void install () throws IOException { if (SysProps.noInstall()) { log.info("Skipping install due to 'no_install' sysprop."); @@ -136,9 +135,6 @@ public abstract class Getdown extends Thread log.info("Installing " + _toInstallResources.size() + " downloaded resources:"); for (Resource resource : _toInstallResources) { resource.install(); - if (Thread.interrupted()) { - throw new InterruptedException("m.applet_stopped"); - } } _toInstallResources.clear(); _readyToInstall = false; @@ -148,21 +144,6 @@ public abstract class Getdown extends Thread } } - /** - * This is used by the applet which always needs a user interface and wants to load it as soon - * as possible. - */ - public void preInit () - { - try { - _ifc = _app.init(true); - createInterfaceAsync(true); - } catch (Exception e) { - log.warning("Failed to preinit: " + e); - createInterfaceAsync(true); - } - } - @Override public void run () { @@ -530,10 +511,6 @@ public abstract class Getdown extends Thread // Only launch if we aren't in silent mode. Some mystery program starting out // of the blue would be disconcerting. if (!_silent || _launchInSilent) { - if (Thread.interrupted()) { - // One last interrupted check so we don't launch as the applet aborts - throw new InterruptedException("m.applet_stopped"); - } // And another final check for the lock. It'll already be held unless // we're in silent mode. _app.lockForUpdates(); @@ -611,7 +588,7 @@ public abstract class Getdown extends Thread * running with the necessary Java version. */ protected void updateJava () - throws IOException, InterruptedException + throws IOException { Resource vmjar = _app.getJavaVMResource(); if (vmjar == null) { @@ -652,7 +629,7 @@ public abstract class Getdown extends Thread * Called if the application is determined to be of an old version. */ protected void update () - throws IOException, InterruptedException + throws IOException { // first clear all validation markers _app.clearValidationMarkers(); @@ -724,7 +701,7 @@ public abstract class Getdown extends Thread * Called if the application is determined to require resource downloads. */ protected void download (Collection resources) - throws IOException, InterruptedException + throws IOException { // create our user interface createInterfaceAsync(false); @@ -746,12 +723,6 @@ public abstract class Getdown extends Thread } _lastCheck = percent; } - if (Thread.currentThread().isInterrupted()) { - // The applet interrupts when it stops, so abort the download and quit. Use - // isInterrupted so the containing code can call interrupted outside of here - // to check if this was the reason for aborting. - return false; - } setStatusAsync("m.downloading", stepToGlobalPercent(percent), remaining, true); if (percent > 0) { reportTrackingEvent("progress", percent); @@ -772,9 +743,6 @@ public abstract class Getdown extends Thread // start the download and wait for it to complete Downloader dl = new HTTPDownloader(resources, obs); if (!dl.download()) { - if (Thread.interrupted()) { - throw new InterruptedException("m.applet_stopped"); - } throw new MultipleGetdownRunning(); } } @@ -789,11 +757,10 @@ public abstract class Getdown extends Thread try { if (invokeDirect()) { - // if we're in applet mode, this will NOOP; if we're in app mode and are invoking - // direct, we want to close the Getdown window, as the app is launching + // we want to close the Getdown window, as the app is launching disposeContainer(); _app.releaseLock(); - _app.invokeDirect(getApplet()); + _app.invokeDirect(); } else { Process proc; @@ -864,17 +831,6 @@ public abstract class Getdown extends Thread setStatusAsync(null, 100, -1L, false); exit(0); - if (_playAgain != null && _playAgain.isEnabled()) { - // wait a little time before showing the button - Timer timer = new Timer("playAgain", true); - timer.schedule(new TimerTask() { - @Override public void run () { - initPlayAgain(); - _playAgain.setVisible(true); - } - }, PLAY_AGAIN_TIME); - } - } catch (Exception e) { log.warning("launch() failed.", e); } @@ -909,26 +865,6 @@ public abstract class Getdown extends Thread }); _patchNotes.setFont(StatusPanel.FONT); _layers.add(_patchNotes); - - if (getApplet() != null) { - _playAgain = new JButton(); - _playAgain.setEnabled(false); - _playAgain.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - _playAgain.setFont(StatusPanel.FONT); - _playAgain.addActionListener(new ActionListener() { - @Override public void actionPerformed (ActionEvent event) { - _playAgain.setVisible(false); - _stepMinPercent = _lastGlobalPercent = 0; - EventQueue.invokeLater(new Runnable() { - public void run () { - getdown(); - } - }); - } - }); - _layers.add(_playAgain); - } - _status = new StatusPanel(_msgs); _layers.add(_status); initInterface(); @@ -957,37 +893,12 @@ public abstract class Getdown extends Thread _patchNotes.setBounds(_ifc.patchNotes); _patchNotes.setVisible(false); - initPlayAgain(); - // we were displaying progress while the UI wasn't up. Now that it is, whatever progress // is left is scaled into a 0-100 DISPLAYED progress. _uiDisplayPercent = _lastGlobalPercent; _stepMinPercent = _lastGlobalPercent = 0; } - protected void initPlayAgain () - { - if (_playAgain != null) { - Image image = loadImage(_ifc.playAgainImage); - boolean hasImage = image != null; - if (hasImage) { - _playAgain.setIcon(new ImageIcon(image)); - _playAgain.setText(""); - } else { - _playAgain.setText(_msgs.getString("m.play_again")); - _playAgain.setIcon(null); - } - _playAgain.setBorderPainted(!hasImage); - _playAgain.setOpaque(!hasImage); - _playAgain.setContentAreaFilled(!hasImage); - if (_ifc.playAgain != null) { - _playAgain.setBounds(_ifc.playAgain); - _playAgain.setEnabled(true); - } - _playAgain.setVisible(false); - } - } - protected RotatingBackgrounds getBackground () { if (_ifc.rotatingBackgrounds != null) { @@ -1140,27 +1051,16 @@ public abstract class Getdown extends Thread */ protected boolean invokeDirect () { - // by default check a sysprop (which itself defaults to false); in applet mode this is - // overridden to check the applet config return SysProps.direct(); } - /** - * Provides access to the applet that we'll pass on to our application when we're in "invoke - * direct" mode. - */ - protected JApplet getApplet () - { - return null; - } - /** * Requests to show the document at the specified URL in a new window. */ protected abstract void showDocument (String url); /** - * Requests that Getdown exit. In applet mode this does nothing. + * Requests that Getdown exit. */ protected abstract void exit (int exitCode); @@ -1238,7 +1138,6 @@ public abstract class Getdown extends Thread protected JLayeredPane _layers; protected StatusPanel _status; protected JButton _patchNotes; - protected JButton _playAgain; protected AbortPanel _abort; protected RotatingBackgrounds _background; @@ -1263,7 +1162,6 @@ public abstract class Getdown extends Thread protected static final int MAX_LOOPS = 5; protected static final long FALLBACK_CHECK_TIME = 1000L; - protected static final long PLAY_AGAIN_TIME = 3000L; protected static final String PROXY_REGISTRY = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; } diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/ImageLoader.java b/launcher/src/main/java/com/threerings/getdown/launcher/ImageLoader.java deleted file mode 100644 index 641b608..0000000 --- a/launcher/src/main/java/com/threerings/getdown/launcher/ImageLoader.java +++ /dev/null @@ -1,18 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2016 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - -package com.threerings.getdown.launcher; - -import java.awt.Image; - -/** - * Abstracts away the process of loading an image so that it can be done differently in the app and - * applet. - */ -public interface ImageLoader -{ - /** Loads and returns the image with the supplied path. */ - public Image loadImage (String path); -} diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/RotatingBackgrounds.java b/launcher/src/main/java/com/threerings/getdown/launcher/RotatingBackgrounds.java index 9c5552a..580d565 100644 --- a/launcher/src/main/java/com/threerings/getdown/launcher/RotatingBackgrounds.java +++ b/launcher/src/main/java/com/threerings/getdown/launcher/RotatingBackgrounds.java @@ -11,6 +11,10 @@ import static com.threerings.getdown.Log.log; public class RotatingBackgrounds { + public interface ImageLoader { + /** Loads and returns the image with the supplied path. */ + public Image loadImage (String path); + } /** * Creates a placeholder if there are no images. Just returns null from getImage every time. @@ -31,7 +35,7 @@ public class RotatingBackgrounds /** * Create a sequence of images to be rotated through from backgrounds. - * + * * Each String in backgrounds should be the path to the image, a semicolon, and the minimum * amount of time to display the image in seconds. Each image will be active for an equal * percentage of the download process, unless one hasn't been active for its minimum display @@ -78,7 +82,7 @@ public class RotatingBackgrounds } long now = System.currentTimeMillis(); if (current != images.length - 1 - && (current == -1 || (progress >= percentages[current + 1] && + && (current == -1 || (progress >= percentages[current + 1] && (now - currentDisplayStart) / 1000 > minDisplayTime[current]))) { current++; currentDisplayStart = now; @@ -110,18 +114,18 @@ public class RotatingBackgrounds /** Time at which the currently displayed image was first displayed in millis. */ protected long currentDisplayStart; - + /** The index of the currently displayed image or -1 if we haven't displayed any. */ protected int current = -1; - + protected Image[] images; - + /** The image to display if getdown has failed due to an error. */ protected Image errorImage; - + /** Percentage at which each image should be displayed. */ protected int[] percentages; - + /** Time to show each image in seconds. */ protected int[] minDisplayTime; } diff --git a/pom.xml b/pom.xml index c5ab586..efbff29 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,6 @@ core tools launcher - ant diff --git a/tools/src/main/java/com/threerings/getdown/tools/AppletParamSigner.java b/tools/src/main/java/com/threerings/getdown/tools/AppletParamSigner.java deleted file mode 100644 index 15d540d..0000000 --- a/tools/src/main/java/com/threerings/getdown/tools/AppletParamSigner.java +++ /dev/null @@ -1,62 +0,0 @@ -// -// Getdown - application installer, patcher and launcher -// Copyright (C) 2004-2016 Getdown authors -// https://github.com/threerings/getdown/blob/master/LICENSE - -package com.threerings.getdown.tools; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.Signature; - -import com.threerings.getdown.data.Digest; -import com.threerings.getdown.util.Base64; - -import static java.nio.charset.StandardCharsets.UTF_8; - -/** - * Produces a signed hash of the appbase, appname, and image path to ensure that signed copies of - * Getdown are not hijacked to run malicious code. - */ -public class AppletParamSigner -{ - public static void main (String[] args) - { - if (args.length != 7) { - System.err.println("AppletParamSigner keystore storepass alias keypass " + - "appbase appname imgpath"); - System.exit(255); - } - - String keystore = args[0]; - String storepass = args[1]; - String alias = args[2]; - String keypass = args[3]; - String appbase = args[4]; - String appname = args[5]; - String imgpath = args[6]; - String params = appbase + appname + imgpath; - - try (FileInputStream fis = new FileInputStream(keystore); - BufferedInputStream bis = new BufferedInputStream(fis)) { - - KeyStore store = KeyStore.getInstance("JKS"); - store.load(bis, storepass.toCharArray()); - PrivateKey key = (PrivateKey)store.getKey(alias, keypass.toCharArray()); - Signature sig = Signature.getInstance(Digest.sigAlgorithm(Digest.VERSION)); - sig.initSign(key); - sig.update(params.getBytes(UTF_8)); - String signed = Base64.encodeToString(sig.sign(), Base64.DEFAULT); - System.out.println(""); - System.out.println(""); - System.out.println(""); - System.out.println(""); - - } catch (Exception e) { - System.err.println("Failed to produce signature."); - e.printStackTrace(); - } - } -}