I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 6f053287 authored by zzz's avatar zzz
Browse files

* Update:

      - Fix problems where a requested unsigned update would actually
        kick off a signed update
      - Fix problem when policy set to notify, and clicking
        check for update, incorrectly causing unsigned update download
        and bad messages
      - Verify zip integrity of unsigned updates
      - Move zip files to router dir, not base dir
      - More tweaks and cleanup
parent 5bc2dab1
No related branches found
No related tags found
No related merge requests found
...@@ -54,7 +54,7 @@ public class ConfigUpdateHandler extends FormHandler { ...@@ -54,7 +54,7 @@ public class ConfigUpdateHandler extends FormHandler {
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext()); NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
fetcher.fetchNews(); fetcher.fetchNews();
if (fetcher.shouldFetchUnsigned()) if (fetcher.shouldFetchUnsigned())
fetcher.fetchUnsigned(); fetcher.fetchUnsignedHead();
if (fetcher.updateAvailable() || fetcher.unsignedUpdateAvailable()) { if (fetcher.updateAvailable() || fetcher.unsignedUpdateAvailable()) {
if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) ) if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) )
addFormNotice("Update available, attempting to download now"); addFormNotice("Update available, attempting to download now");
......
...@@ -188,8 +188,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { ...@@ -188,8 +188,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
if (ms <= 0) return; if (ms <= 0) return;
if (modtime > ms) { if (modtime > ms) {
_unsignedUpdateAvailable = true; _unsignedUpdateAvailable = true;
// '07-Jul 21:09' with month name in the system locale // '07-Jul 21:09 UTC' with month name in the system locale
_unsignedUpdateVersion = (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime)); _unsignedUpdateVersion = (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime)) + " UTC";
if (shouldInstall()) if (shouldInstall())
fetchUnsigned(); fetchUnsigned();
} }
......
...@@ -21,6 +21,7 @@ import net.i2p.util.Log; ...@@ -21,6 +21,7 @@ import net.i2p.util.Log;
* </p> * </p>
*/ */
public class UnsignedUpdateHandler extends UpdateHandler { public class UnsignedUpdateHandler extends UpdateHandler {
private static UnsignedUpdateRunner _unsignedUpdateRunner;
private String _zipURL; private String _zipURL;
private String _zipVersion; private String _zipVersion;
...@@ -34,19 +35,19 @@ public class UnsignedUpdateHandler extends UpdateHandler { ...@@ -34,19 +35,19 @@ public class UnsignedUpdateHandler extends UpdateHandler {
@Override @Override
public void update() { public void update() {
// don't block waiting for the other one to finish // 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"); _log.error("Update already running");
return; return;
} }
synchronized (UpdateHandler.class) { synchronized (UpdateHandler.class) {
if (_updateRunner == null) { if (_unsignedUpdateRunner == null) {
_updateRunner = new UnsignedUpdateRunner(); _unsignedUpdateRunner = new UnsignedUpdateRunner();
} }
if (_updateRunner.isRunning()) { if (_unsignedUpdateRunner.isRunning()) {
return; return;
} else { } else {
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true"); System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
I2PAppThread update = new I2PAppThread(_updateRunner, "Update"); I2PAppThread update = new I2PAppThread(_unsignedUpdateRunner, "UnsignedUpdate");
update.start(); update.start();
} }
} }
...@@ -64,6 +65,8 @@ public class UnsignedUpdateHandler extends UpdateHandler { ...@@ -64,6 +65,8 @@ public class UnsignedUpdateHandler extends UpdateHandler {
@Override @Override
protected void update() { protected void update() {
_status = "<b>Updating</b>"; _status = "<b>Updating</b>";
if (_log.shouldLog(Log.DEBUG))
_log.debug("Starting unsigned update URL: " + _zipURL);
// always proxy for now // always proxy for now
//boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); //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 proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
...@@ -74,19 +77,26 @@ public class UnsignedUpdateHandler extends UpdateHandler { ...@@ -74,19 +77,26 @@ public class UnsignedUpdateHandler extends UpdateHandler {
_get.addStatusListener(UnsignedUpdateRunner.this); _get.addStatusListener(UnsignedUpdateRunner.this);
_get.fetch(); _get.fetch();
} catch (Throwable t) { } catch (Throwable t) {
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t); _log.error("Error updating", t);
} }
} }
/** eepget listener callback Overrides */ /** eepget listener callback Overrides */
@Override @Override
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
_status = "<b>Update downloaded</b>"; File updFile = new File(_updateFile);
// we should really verify zipfile integrity here but there's no easy way to do it if (FileUtil.verifyZip(updFile)) {
String to = (new File(_context.getBaseDir(), Router.UPDATE_FILE)).getAbsolutePath(); _status = "<b>Update downloaded</b>";
} else {
updFile.delete();
_status = "<b>Unsigned update file is corrupt</b> from " + url;
_log.log(Log.CRIT, "Corrupt zip file from " + url);
return;
}
String to = (new File(_context.getRouterDir(), Router.UPDATE_FILE)).getAbsolutePath();
boolean copied = FileUtil.copy(_updateFile, to, true); boolean copied = FileUtil.copy(_updateFile, to, true);
if (copied) { if (copied) {
(new File(_updateFile)).delete(); updFile.delete();
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
this.done = true; this.done = true;
String lastmod = _get.getLastModified(); String lastmod = _get.getLastModified();
......
...@@ -8,11 +8,12 @@ import java.util.StringTokenizer; ...@@ -8,11 +8,12 @@ import java.util.StringTokenizer;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.crypto.TrustedUpdate; import net.i2p.crypto.TrustedUpdate;
import net.i2p.data.DataHelper;
import net.i2p.router.Router; import net.i2p.router.Router;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion; import net.i2p.router.RouterVersion;
import net.i2p.util.EepGet; import net.i2p.util.EepGet;
import net.i2p.util.I2PThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
...@@ -31,7 +32,9 @@ public class UpdateHandler { ...@@ -31,7 +32,9 @@ public class UpdateHandler {
protected RouterContext _context; protected RouterContext _context;
protected Log _log; protected Log _log;
protected String _updateFile; protected String _updateFile;
protected static String _status = "";
private String _action; private String _action;
private String _nonce;
protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; 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_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress";
...@@ -61,13 +64,22 @@ public class UpdateHandler { ...@@ -61,13 +64,22 @@ public class UpdateHandler {
} }
} }
public void setUpdateAction(String val) { _action = val; } /** these two can be set in either order, so call checkUpdateAction() twice */
public void setUpdateAction(String val) {
_action = val;
checkUpdateAction();
}
public void setUpdateNonce(String nonce) { public void setUpdateNonce(String nonce) {
if (nonce == null) return; _nonce = nonce;
if (nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) || checkUpdateAction();
nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) { }
if (_action != null && _action.contains("Unsigned")) {
private void checkUpdateAction() {
if (_nonce == null || _action == null) return;
if (_nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) ||
_nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) {
if (_action.contains("Unsigned")) {
// Not us, have NewsFetcher instantiate the correct class. // Not us, have NewsFetcher instantiate the correct class.
NewsFetcher fetcher = NewsFetcher.getInstance(_context); NewsFetcher fetcher = NewsFetcher.getInstance(_context);
fetcher.fetchUnsigned(); fetcher.fetchUnsigned();
...@@ -90,16 +102,14 @@ public class UpdateHandler { ...@@ -90,16 +102,14 @@ public class UpdateHandler {
return; return;
} else { } else {
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true"); System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
I2PThread update = new I2PThread(_updateRunner, "Update"); I2PAppThread update = new I2PAppThread(_updateRunner, "SignedUpdate");
update.start(); update.start();
} }
} }
} }
public String getStatus() { public static String getStatus() {
if (_updateRunner == null) return _status;
return "";
return _updateRunner.getStatus();
} }
public boolean isDone() { public boolean isDone() {
...@@ -113,7 +123,6 @@ public class UpdateHandler { ...@@ -113,7 +123,6 @@ public class UpdateHandler {
public class UpdateRunner implements Runnable, EepGet.StatusListener { public class UpdateRunner implements Runnable, EepGet.StatusListener {
protected boolean _isRunning; protected boolean _isRunning;
protected boolean done; protected boolean done;
protected String _status;
protected EepGet _get; protected EepGet _get;
private final DecimalFormat _pct = new DecimalFormat("0.0%"); private final DecimalFormat _pct = new DecimalFormat("0.0%");
...@@ -126,7 +135,6 @@ public class UpdateHandler { ...@@ -126,7 +135,6 @@ public class UpdateHandler {
public boolean isDone() { public boolean isDone() {
return this.done; return this.done;
} }
public String getStatus() { return _status; }
public void run() { public void run() {
_isRunning = true; _isRunning = true;
update(); update();
...@@ -150,7 +158,7 @@ public class UpdateHandler { ...@@ -150,7 +158,7 @@ public class UpdateHandler {
_get.addStatusListener(UpdateRunner.this); _get.addStatusListener(UpdateRunner.this);
_get.fetch(); _get.fetch();
} catch (Throwable t) { } catch (Throwable t) {
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t); _log.error("Error updating", t);
} }
} }
...@@ -167,15 +175,16 @@ public class UpdateHandler { ...@@ -167,15 +175,16 @@ public class UpdateHandler {
synchronized (_pct) { synchronized (_pct) {
buf.append(_pct.format(pct)); buf.append(_pct.format(pct));
} }
buf.append(":<br />\n" + (currentWrite + alreadyTransferred)); buf.append(":<br>\n");
buf.append(" transferred"); buf.append(DataHelper.formatSize(currentWrite + alreadyTransferred));
buf.append("B transferred");
_status = buf.toString(); _status = buf.toString();
} }
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
_status = "<b>Update downloaded</b>"; _status = "<b>Update downloaded</b>";
TrustedUpdate up = new TrustedUpdate(_context); TrustedUpdate up = new TrustedUpdate(_context);
File f = new File(_updateFile); File f = new File(_updateFile);
File to = new File(_context.getBaseDir(), Router.UPDATE_FILE); File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
String err = up.migrateVerified(RouterVersion.VERSION, f, to); String err = up.migrateVerified(RouterVersion.VERSION, f, to);
f.delete(); f.delete();
if (err == null) { if (err == null) {
...@@ -233,9 +242,9 @@ public class UpdateHandler { ...@@ -233,9 +242,9 @@ public class UpdateHandler {
while (tok.hasMoreTokens()) while (tok.hasMoreTokens())
URLList.add(tok.nextToken().trim()); URLList.add(tok.nextToken().trim());
int size = URLList.size(); int size = URLList.size();
_log.log(Log.DEBUG, "Picking update source from " + size + " candidates."); //_log.log(Log.DEBUG, "Picking update source from " + size + " candidates.");
if (size <= 0) { if (size <= 0) {
_log.log(Log.WARN, "Update list is empty - no update available"); _log.log(Log.CRIT, "Update source list is empty - cannot download update");
return null; return null;
} }
int index = I2PAppContext.getGlobalContext().random().nextInt(size); int index = I2PAppContext.getGlobalContext().random().nextInt(size);
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
<% <%
if (helper.updateAvailable() || helper.unsignedUpdateAvailable()) { if (helper.updateAvailable() || helper.unsignedUpdateAvailable()) {
// display all the time so we display the final failure message // display all the time so we display the final failure message
out.print("<br />" + update.getStatus()); out.print("<br>" + net.i2p.router.web.UpdateHandler.getStatus());
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress"))) { if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress"))) {
} else if((!update.isDone()) && } else if((!update.isDone()) &&
request.getParameter("action") == null && request.getParameter("action") == null &&
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
if (helper.updateAvailable()) if (helper.updateAvailable())
out.print("<button type=\"submit\" name=\"updateAction\" value=\"signed\" >Download " + helper.getUpdateVersion() + " Update</button>\n"); out.print("<button type=\"submit\" name=\"updateAction\" value=\"signed\" >Download " + helper.getUpdateVersion() + " Update</button>\n");
if (helper.unsignedUpdateAvailable()) if (helper.unsignedUpdateAvailable())
out.print("<button type=\"submit\" name=\"updateAction\" value=\"Unsigned\" >Download Unsigned<br />" + helper.getUnsignedUpdateVersion() + " Update</button>\n"); out.print("<button type=\"submit\" name=\"updateAction\" value=\"Unsigned\" >Download Unsigned<br>Update " + helper.getUnsignedUpdateVersion() + "</button>\n");
out.print("</form></p>\n"); out.print("</form></p>\n");
} }
} }
......
...@@ -137,6 +137,56 @@ public class FileUtil { ...@@ -137,6 +137,56 @@ public class FileUtil {
} }
} }
/**
* Verify the integrity of a zipfile.
* There doesn't seem to be any library function to do this,
* so we basically go through all the motions of extractZip() above,
* unzipping everything but throwing away the data.
*
* @return true if ok
*/
public static boolean verifyZip(File zipfile) {
ZipFile zip = null;
try {
byte buf[] = new byte[16*1024];
zip = new ZipFile(zipfile);
Enumeration entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry)entries.nextElement();
if (entry.getName().indexOf("..") != -1) {
//System.err.println("ERROR: Refusing to extract a zip entry with '..' in it [" + entry.getName() + "]");
return false;
}
if (entry.isDirectory()) {
// noop
} else {
try {
InputStream in = zip.getInputStream(entry);
int read = 0;
while ( (read = in.read(buf)) != -1) {
// throw the data away
}
//System.err.println("INFO: File [" + entry.getName() + "] extracted");
in.close();
} catch (IOException ioe) {
//System.err.println("ERROR: Error extracting the zip entry (" + entry.getName() + "]");
//ioe.printStackTrace();
return false;
}
}
}
return true;
} catch (IOException ioe) {
//System.err.println("ERROR: Unable to extract the zip file");
//ioe.printStackTrace();
return false;
} finally {
if (zip != null) {
try { zip.close(); } catch (IOException ioe) {}
}
}
}
/** /**
* Read in the last few lines of a (newline delimited) textfile, or null if * Read in the last few lines of a (newline delimited) textfile, or null if
* the file doesn't exist. * the file doesn't exist.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment