From 3febcf6043a5a0e6506dd8f275fc7a046fc7763b Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 9 Aug 2009 14:28:20 +0000 Subject: [PATCH] * Updater: - Add new unsigned update option, triggered by last-modified date, using the new EepHead. Buttons still are not hidden after download complete. - Make the .sud updater use the temp dir when proxied - Several cleanups --- .../i2p/router/web/ConfigUpdateHandler.java | 30 ++++- .../i2p/router/web/ConfigUpdateHelper.java | 17 ++- .../src/net/i2p/router/web/NewsFetcher.java | 120 +++++++++++++++++- .../src/net/i2p/router/web/SummaryHelper.java | 11 ++ .../i2p/router/web/UnsignedUpdateHandler.java | 119 +++++++++++++++++ .../src/net/i2p/router/web/UpdateHandler.java | 47 ++++--- apps/routerconsole/jsp/configupdate.jsp | 6 + apps/routerconsole/jsp/summarynoframe.jsp | 11 +- 8 files changed, 320 insertions(+), 41 deletions(-) create mode 100644 apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java index db20396ca..256babbe3 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java @@ -16,6 +16,8 @@ public class ConfigUpdateHandler extends FormHandler { private String _proxyPort; private boolean _updateThroughProxy; private String _trustedKeys; + private boolean _updateUnsigned; + private String _zipURL; public static final String PROP_NEWS_URL = "router.newsURL"; // public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD"; @@ -30,7 +32,12 @@ public class ConfigUpdateHandler extends FormHandler { public static final String PROP_PROXY_HOST = "router.updateProxyHost"; public static final String DEFAULT_PROXY_HOST = "127.0.0.1"; public static final String PROP_PROXY_PORT = "router.updateProxyPort"; - public static final String DEFAULT_PROXY_PORT = "4444"; + public static final int DEFAULT_PROXY_PORT_INT = 4444; + public static final String DEFAULT_PROXY_PORT = "" + DEFAULT_PROXY_PORT_INT; + /** default false */ + public static final String PROP_UPDATE_UNSIGNED = "router.updateUnsigned"; + /** no default */ + public static final String PROP_ZIP_URL = "router.updateUnsignedURL"; public static final String PROP_UPDATE_URL = "router.updateURL"; public static final String DEFAULT_UPDATE_URL = @@ -46,7 +53,9 @@ public class ConfigUpdateHandler extends FormHandler { if ("Check for update now".equals(_action)) { NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext()); fetcher.fetchNews(); - if (fetcher.updateAvailable()) { + if (fetcher.shouldFetchUnsigned()) + fetcher.fetchUnsigned(); + if (fetcher.updateAvailable() || fetcher.unsignedUpdateAvailable()) { if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) ) addFormNotice("Update available, attempting to download now"); else @@ -79,11 +88,8 @@ public class ConfigUpdateHandler extends FormHandler { } } - if (_updateThroughProxy) { - _context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.TRUE.toString()); - } else { - _context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.FALSE.toString()); - } + _context.router().setConfigSetting(PROP_SHOULD_PROXY, "" + _updateThroughProxy); + _context.router().setConfigSetting(PROP_UPDATE_UNSIGNED, "" + _updateUnsigned); String oldFreqStr = _context.router().getConfigSetting(PROP_REFRESH_FREQUENCY); long oldFreq = -1; @@ -119,6 +125,14 @@ public class ConfigUpdateHandler extends FormHandler { } } + if ( (_zipURL != null) && (_zipURL.length() > 0) ) { + String oldURL = _context.router().getConfigSetting(PROP_ZIP_URL); + if ( (oldURL == null) || (!_zipURL.equals(oldURL)) ) { + _context.router().setConfigSetting(PROP_ZIP_URL, _zipURL); + addFormNotice("Updating unsigned update URL to " + _zipURL); + } + } + _context.router().saveConfig(); } @@ -132,4 +146,6 @@ public class ConfigUpdateHandler extends FormHandler { public void setUpdateThroughProxy(String foo) { _updateThroughProxy = true; } public void setProxyHost(String host) { _proxyHost = host; } public void setProxyPort(String port) { _proxyPort = port; } + public void setUpdateUnsigned(String foo) { _updateUnsigned = true; } + public void setZipURL(String url) { _zipURL = url; } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java index 5d03d9024..263e98937 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java @@ -44,10 +44,17 @@ public class ConfigUpdateHelper extends HelperBase { if (Boolean.valueOf(proxy).booleanValue()) return ""; else - return ""; } + public String getUpdateUnsigned() { + String foo = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED); + if (Boolean.valueOf(foo).booleanValue()) + return ""; + else + return ""; + } + private static final long PERIODS[] = new long[] { 12*60*60*1000l, 24*60*60*1000l, 48*60*60*1000l, -1l }; public String getRefreshFrequencySelectBox() { @@ -105,11 +112,11 @@ public class ConfigUpdateHelper extends HelperBase { return new TrustedUpdate(_context).getTrustedKeysString(); } + public String getZipURL() { + return _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL, ""); + } + public String getNewsStatus() { return NewsFetcher.getInstance(_context).status(); } - - public String getUpdateVersion() { - return NewsFetcher.getInstance(_context).updateVersion(); - } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java index 0a83f65ac..447273a88 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java @@ -3,7 +3,11 @@ package net.i2p.router.web; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.List; +import java.util.Locale; import net.i2p.I2PAppContext; import net.i2p.crypto.TrustedUpdate; @@ -12,6 +16,7 @@ import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.RouterVersion; import net.i2p.util.EepGet; +import net.i2p.util.EepHead; import net.i2p.util.FileUtil; import net.i2p.util.Log; @@ -23,9 +28,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { private I2PAppContext _context; private Log _log; private boolean _updateAvailable; + private boolean _unsignedUpdateAvailable; private long _lastFetch; private long _lastUpdated; private String _updateVersion; + private String _unsignedUpdateVersion; private String _lastModified; private File _newsFile; private File _tempFile; @@ -63,6 +70,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { public boolean updateAvailable() { return _updateAvailable; } public String updateVersion() { return _updateVersion; } + public boolean unsignedUpdateAvailable() { return _unsignedUpdateAvailable; } + public String unsignedUpdateVersion() { return _unsignedUpdateVersion; } public String status() { long now = _context.clock().now(); @@ -75,8 +84,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { try { Thread.sleep(_context.random().nextLong(5*60*1000)); } catch (InterruptedException ie) {} while (true) { if (!_updateAvailable) checkForUpdates(); - if (shouldFetchNews()) + if (shouldFetchNews()) { fetchNews(); + if (shouldFetchUnsigned()) + fetchUnsignedHead(); + } try { Thread.sleep(10*60*1000); } catch (InterruptedException ie) {} } } @@ -91,9 +103,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { private boolean shouldFetchNews() { updateLastFetched(); - String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY); - if (freq == null) - freq = ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY; + String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY, + ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY); try { long ms = Long.parseLong(freq); if (ms <= 0) @@ -116,13 +127,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { String newsURL = ConfigUpdateHelper.getNewsURL(_context); boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); - String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT); + int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT); if (_tempFile.exists()) _tempFile.delete(); - int proxyPort = -1; try { - proxyPort = Integer.parseInt(port); EepGet get = null; if (shouldProxy) get = new EepGet(_context, true, proxyHost, proxyPort, 2, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified); @@ -136,6 +145,103 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { } } + public boolean shouldFetchUnsigned() { + String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL); + return url != null && url.length() > 0 && + Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED)).booleanValue(); + } + + /** + * HEAD the update url, and if the last-mod time is newer than the last update we + * downloaded, as stored in the properties, then we download it using eepget. + */ + public void fetchUnsignedHead() { + String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL); + if (url == null || url.length() <= 0) + return; + // assume always proxied for now + //boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); + String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); + int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT); + + try { + EepHead get = new EepHead(_context, proxyHost, proxyPort, 0, url); + if (get.fetch()) { + String lastmod = get.getLastModified(); + if (lastmod != null) { + if (!(_context instanceof RouterContext)) return; + long modtime = parse822Date(lastmod); + if (modtime <= 0) return; + String lastUpdate = _context.getProperty(UpdateHandler.PROP_LAST_UPDATE_TIME); + if (lastUpdate == null) { + // we don't know what version you have, so stamp it with the current time, + // and we'll look for something newer next time around. + ((RouterContext)_context).router().setConfigSetting(UpdateHandler.PROP_LAST_UPDATE_TIME, + "" + _context.clock().now()); + ((RouterContext)_context).router().saveConfig(); + return; + } + long ms = 0; + try { + ms = Long.parseLong(lastUpdate); + } catch (NumberFormatException nfe) {} + if (ms <= 0) return; + if (modtime > ms) { + _unsignedUpdateAvailable = true; + // '07-Jul 21:09' with month name in the system locale + _unsignedUpdateVersion = (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime)); + if (shouldInstall()) + fetchUnsigned(); + } + } + } + } catch (Throwable t) { + _log.error("Error fetching the unsigned update", t); + } + } + + public void fetchUnsigned() { + String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL); + if (url == null || url.length() <= 0) + return; + UpdateHandler handler = new UnsignedUpdateHandler((RouterContext)_context, url, + _unsignedUpdateVersion); + handler.update(); + } + + /** + * http://jimyjoshi.com/blog/2007/08/rfc822dateparsinginjava.html + * Apparently public domain + * Probably don't need all of these... + */ + private static final SimpleDateFormat rfc822DateFormats[] = new SimpleDateFormat[] { + new SimpleDateFormat("EEE, d MMM yy HH:mm:ss z", Locale.US), + new SimpleDateFormat("EEE, d MMM yy HH:mm z", Locale.US), + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.US), + new SimpleDateFormat("EEE, d MMM yyyy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yy HH:mm:ss z", Locale.US), + new SimpleDateFormat("d MMM yyyy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US) + }; + + /** + * new Date(String foo) is deprecated, so let's do this the hard way + * + * @param s non-null + * @return -1 on failure + */ + public static long parse822Date(String s) { + for (int i = 0; i < rfc822DateFormats.length; i++) { + try { + Date date = rfc822DateFormats[i].parse(s); + if (date != null) + return date.getTime(); + } catch (ParseException pe) {} + } + return -1; + } + private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\""; private static final String VERSION_PREFIX = "version=\""; private void checkForUpdates() { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 10169ac9f..0982c7c9e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -525,4 +525,15 @@ public class SummaryHelper extends HelperBase { return NewsFetcher.getInstance(_context).updateAvailable(); } + public boolean unsignedUpdateAvailable() { + return NewsFetcher.getInstance(_context).unsignedUpdateAvailable(); + } + + public String getUpdateVersion() { + return NewsFetcher.getInstance(_context).updateVersion(); + } + + public String getUnsignedUpdateVersion() { + return NewsFetcher.getInstance(_context).unsignedUpdateVersion(); + } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java new file mode 100644 index 000000000..0d812d0ec --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java @@ -0,0 +1,119 @@ +package net.i2p.router.web; + +import java.io.File; + +import net.i2p.I2PAppContext; +import net.i2p.router.Router; +import net.i2p.router.RouterContext; +import net.i2p.util.EepGet; +import net.i2p.util.FileUtil; +import net.i2p.util.I2PAppThread; +import net.i2p.util.Log; + +/** + *

Handles the request to update the router by firing off an + * {@link net.i2p.util.EepGet} call to download the latest unsigned zip file + * and displaying the status to anyone who asks. + *

+ *

After the download completes the signed update file is copied to the + * router directory, and if configured the router is restarted to complete + * the update process. + *

+ */ +public class UnsignedUpdateHandler extends UpdateHandler { + private String _zipURL; + private String _zipVersion; + + public UnsignedUpdateHandler(RouterContext ctx, String zipURL, String version) { + super(ctx); + _zipURL = zipURL; + _zipVersion = version; + _updateFile = (new File(ctx.getTempDir(), "tmp" + ctx.random().nextInt() + Router.UPDATE_FILE)).getAbsolutePath(); + } + + @Override + public void update() { + // don't block waiting for the other one to finish + if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) { + _log.error("Update already running"); + return; + } + synchronized (UpdateHandler.class) { + if (_updateRunner == null) { + _updateRunner = new UnsignedUpdateRunner(); + } + if (_updateRunner.isRunning()) { + return; + } else { + System.setProperty(PROP_UPDATE_IN_PROGRESS, "true"); + I2PAppThread update = new I2PAppThread(_updateRunner, "Update"); + update.start(); + } + } + } + + /** + * Eepget the .zip file to the temp dir, then copy it over + */ + public class UnsignedUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener { + public UnsignedUpdateRunner() { + super(); + } + + /** Get the file */ + @Override + protected void update() { + _status = "Updating"; + // always proxy for now + //boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); + String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); + int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT); + try { + // 40 retries!! + _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, _zipURL, false); + _get.addStatusListener(UnsignedUpdateRunner.this); + _get.fetch(); + } catch (Throwable t) { + _context.logManager().getLog(UpdateHandler.class).error("Error updating", t); + } + } + + /** eepget listener callback Overrides */ + @Override + public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { + _status = "Update downloaded"; + // we should really verify zipfile integrity here but there's no easy way to do it + String to = (new File(_context.getBaseDir(), Router.UPDATE_FILE)).getAbsolutePath(); + boolean copied = FileUtil.copy(_updateFile, to, true); + if (copied) { + (new File(_updateFile)).delete(); + String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); + this.done = true; + String lastmod = _get.getLastModified(); + long modtime = 0; + if (lastmod != null) + modtime = NewsFetcher.parse822Date(lastmod); + if (modtime <= 0) + modtime = _context.clock().now(); + _context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime); + _context.router().saveConfig(); + if ("install".equals(policy)) { + _log.log(Log.CRIT, "Update was downloaded, restarting to install it"); + _status = "Update downloaded
Restarting"; + restart(); + } else { + _log.log(Log.CRIT, "Update was downloaded, will be installed at next restart"); + _status = "Update downloaded
"; + if (System.getProperty("wrapper.version") != null) + _status += "Click Restart to install"; + else + _status += "Click Shutdown and restart to install"; + _status += " Version " + _zipVersion; + } + } else { + _log.log(Log.CRIT, "Failed copy to " + to); + _status = "Failed copy to " + to + ""; + } + } + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index 257e93f12..f8890482d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -30,11 +30,12 @@ public class UpdateHandler { protected static UpdateRunner _updateRunner; protected RouterContext _context; protected Log _log; - protected DecimalFormat _pct = new DecimalFormat("00.0%"); protected String _updateFile; + private String _action; protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; protected static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress"; + protected static final String PROP_LAST_UPDATE_TIME = "router.updateLastDownloaded"; public UpdateHandler() { this(ContextHelper.getContext(null)); @@ -48,7 +49,7 @@ public class UpdateHandler { /** * Configure this bean to query a particular router context * - * @param contextId begging few characters of the routerHash, or null to pick + * @param contextId beginning few characters of the routerHash, or null to pick * the first one we come across. */ public void setContextId(String contextId) { @@ -60,18 +61,25 @@ public class UpdateHandler { } } + public void setUpdateAction(String val) { _action = val; } public void setUpdateNonce(String nonce) { if (nonce == null) return; if (nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) || nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) { - update(); + if (_action != null && _action.contains("Unsigned")) { + // Not us, have NewsFetcher instantiate the correct class. + NewsFetcher fetcher = NewsFetcher.getInstance(_context); + fetcher.fetchUnsigned(); + } else { + update(); + } } } public void update() { // don't block waiting for the other one to finish - if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) { + if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS))) { _log.error("Update already running"); return; } @@ -106,6 +114,9 @@ public class UpdateHandler { protected boolean _isRunning; protected boolean done; protected String _status; + protected EepGet _get; + private final DecimalFormat _pct = new DecimalFormat("0.0%"); + public UpdateRunner() { _isRunning = false; this.done = false; @@ -129,22 +140,15 @@ public class UpdateHandler { _log.debug("Selected update URL: " + updateURL); boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); - String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT); - int proxyPort = -1; + int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT); try { - proxyPort = Integer.parseInt(port); - } catch (NumberFormatException nfe) { - return; - } - try { - EepGet get = null; if (shouldProxy) // 40 retries!! - get = new EepGet(_context, proxyHost, proxyPort, 40, SIGNED_UPDATE_FILE, updateURL, false); + _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false); else - get = new EepGet(_context, 1, _updateFile, updateURL, false); - get.addStatusListener(UpdateRunner.this); - get.fetch(); + _get = new EepGet(_context, 1, _updateFile, updateURL, false); + _get.addStatusListener(UpdateRunner.this); + _get.fetch(); } catch (Throwable t) { _context.logManager().getLog(UpdateHandler.class).error("Error updating", t); } @@ -177,6 +181,15 @@ public class UpdateHandler { if (err == null) { String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); this.done = true; + // So unsigned update handler doesn't overwrite unless newer. + String lastmod = _get.getLastModified(); + long modtime = 0; + if (lastmod != null) + modtime = NewsFetcher.parse822Date(lastmod); + if (modtime <= 0) + modtime = _context.clock().now(); + _context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime); + _context.router().saveConfig(); if ("install".equals(policy)) { _log.log(Log.CRIT, "Update was VERIFIED, restarting to install it"); _status = "Update verified
Restarting"; @@ -208,7 +221,7 @@ public class UpdateHandler { public void attempting(String url) {} } - private void restart() { + protected void restart() { _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART)); _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART); } diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index d82600da2..136876d37 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -63,6 +63,12 @@ Trusted keys: + + Update with unsigned development builds? + + + Unsigned Build URL: + ">
diff --git a/apps/routerconsole/jsp/summarynoframe.jsp b/apps/routerconsole/jsp/summarynoframe.jsp index 1713a6336..f00389042 100644 --- a/apps/routerconsole/jsp/summarynoframe.jsp +++ b/apps/routerconsole/jsp/summarynoframe.jsp @@ -12,9 +12,6 @@ " /> - - -" />
I2P Router Console

<% java.io.File lpath = new java.io.File(net.i2p.I2PAppContext.getGlobalContext().getBaseDir(), "docs/toolbar.html"); @@ -50,7 +47,7 @@ Uptime:
Reachability: <% - if (helper.updateAvailable()) { + if (helper.updateAvailable() || helper.unsignedUpdateAvailable()) { // display all the time so we display the final failure message out.print("
" + update.getStatus()); if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress"))) { @@ -65,7 +62,11 @@ String uri = request.getRequestURI(); out.print("

\n"); out.print("\n"); - out.print("

\n"); + if (helper.updateAvailable()) + out.print("\n"); + if (helper.unsignedUpdateAvailable()) + out.print("\n"); + out.print("

\n"); } } %>