forked from I2P_Developers/i2p.i2p
2005-03-23 jrandom
* New /configupdate.jsp page for controlling the update / notification process, as well as various minor related updates. Note that not all options are exposed yet, and the update detection code isn't in place in this commit - it currently says there is always an update available. * New EepGet component for reliable downloading, with a CLI exposed in java -cp lib/i2p.jar net.i2p.util.EepGet url * Added a default signing key to the TrustedUpdate component to be used for verifying updates. This signing key can be authenticated via gpg --verify i2p/core/java/src/net/i2p/crypto/TrustedUpdate.java * New public domain SHA1 implementation for the DSA code so that we can handle signing streams of arbitrary size without excess memory usage (thanks P.Verdy!) * Added some helpers to the TrustedUpdate to work off streams and to offer a minimal CLI: TrustedUpdate keygen pubKeyFile privKeyFile TrustedUpdate sign origFile signedFile privKeyFile TrustedUpdate verify signedFile
This commit is contained in:
@ -0,0 +1,157 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handle the request to update the router by firing off an EepGet call and
|
||||
* displaying its status to anyone who asks. After the download completes,
|
||||
* it is verified with the TrustedUpdate, and if it is authentic, the router
|
||||
* is restarted.
|
||||
*
|
||||
*/
|
||||
public class UpdateHandler {
|
||||
private static UpdateRunner _updateRunner;
|
||||
private RouterContext _context;
|
||||
private Log _log;
|
||||
private DecimalFormat _pct = new DecimalFormat("00.0%");
|
||||
|
||||
private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
|
||||
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
* @param contextId begging few characters of the routerHash, or null to pick
|
||||
* the first one we come across.
|
||||
*/
|
||||
public void setContextId(String contextId) {
|
||||
try {
|
||||
_context = ContextHelper.getContext(contextId);
|
||||
_log = _context.logManager().getLog(UpdateHandler.class);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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"))) {
|
||||
synchronized (UpdateHandler.class) {
|
||||
if (_updateRunner == null)
|
||||
_updateRunner = new UpdateRunner();
|
||||
if (_updateRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true");
|
||||
I2PThread update = new I2PThread(_updateRunner, "Update");
|
||||
update.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return _updateRunner.getStatus();
|
||||
}
|
||||
|
||||
public class UpdateRunner implements Runnable, EepGet.StatusListener {
|
||||
private boolean _isRunning;
|
||||
private String _status;
|
||||
private long _startedOn;
|
||||
private long _written;
|
||||
public UpdateRunner() {
|
||||
_isRunning = false;
|
||||
_status = "<b>Updating</b><br />";
|
||||
}
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
public String getStatus() { return _status; }
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
update();
|
||||
System.setProperty("net.i2p.router.web.ReseedHandler.updateInProgress", "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
private void update() {
|
||||
_startedOn = -1;
|
||||
_status = "<b>Updating</b><br />";
|
||||
String updateURL = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
|
||||
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;
|
||||
try {
|
||||
proxyPort = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
EepGet get = null;
|
||||
if (shouldProxy)
|
||||
get = new EepGet(_context, proxyHost, proxyPort, 10, SIGNED_UPDATE_FILE, updateURL);
|
||||
else
|
||||
get = new EepGet(_context, 10, SIGNED_UPDATE_FILE, updateURL);
|
||||
get.addStatusListener(UpdateRunner.this);
|
||||
_startedOn = _context.clock().now();
|
||||
get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Attempt failed on " + url, cause);
|
||||
_written = 0;
|
||||
// ignored
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
_written += currentWrite;
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
buf.append("<b>Updating</b> ");
|
||||
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
|
||||
synchronized (_pct) {
|
||||
buf.append(_pct.format(pct));
|
||||
}
|
||||
buf.append(":<br />\n").append(_written+alreadyTransferred);
|
||||
buf.append(" transferred<br />");
|
||||
_status = buf.toString();
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) {
|
||||
_status = "<b>Update downloaded</b><br />";
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
boolean ok = up.migrateVerified(SIGNED_UPDATE_FILE, "i2pupdate.zip");
|
||||
File f = new File(SIGNED_UPDATE_FILE);
|
||||
f.delete();
|
||||
if (ok) {
|
||||
_log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
|
||||
_status = "<b>Update verified</b><br />Restarting<br />";
|
||||
restart();
|
||||
} else {
|
||||
_log.log(Log.CRIT, "Update was INVALID - have you changed your keys?");
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_log.log(Log.CRIT, "Update did not download completely (" + bytesTransferred + " with "
|
||||
+ bytesRemaining + " after " + currentAttempt + " tries)");
|
||||
|
||||
_status = "<b>Transfer failed</b><br />";
|
||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||
}
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
_context.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
|
||||
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user