propagate from branch 'i2p.i2p.zzz.test2' (head 5c1b78bd78845b0c8b90fbb60412c68e7dc4f3e6)

to branch 'i2p.i2p' (head 8bdc25c8e6f40491f20b533d94eacab012adba35)
This commit is contained in:
zzz
2013-10-13 11:48:12 +00:00
135 changed files with 19078 additions and 16810 deletions

View File

@ -121,6 +121,7 @@
<!-- Update the messages_*.po files.
We need to supply the bat file for windows, and then change the fail property to true -->
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
<env key="JAVA_HOME" value="${java.home}" />
<arg value="./bundle-messages.sh" />
</exec>
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >
@ -167,6 +168,7 @@
<target name="bundle-news" unless="no.bundle">
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
<env key="JAVA_HOME" value="${java.home}" />
<arg value="./bundle-messages-news.sh" />
</exec>
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >

View File

@ -15,6 +15,10 @@ TMPFILE=build/javafiles-news.txt
export TZ=UTC
RC=0
if ! $(which javac > /dev/null 2>&1); then
export JAVAC=${JAVA_HOME}/../bin/javac
fi
if [ "$1" = "-p" ]
then
POUPDATE=1

View File

@ -15,6 +15,10 @@ TMPFILE=build/javafiles.txt
export TZ=UTC
RC=0
if ! $(which javac > /dev/null 2>&1); then
export JAVAC=${JAVA_HOME}/../bin/javac
fi
if [ "$1" = "-p" ]
then
POUPDATE=1

View File

@ -19,6 +19,7 @@ import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SU3File;
import net.i2p.crypto.TrustedUpdate;
import net.i2p.data.DataHelper;
import net.i2p.router.Router;
@ -69,6 +70,7 @@ public class ConsoleUpdateManager implements UpdateManager {
private final Map<UpdateItem, Version> _downloaded;
/** downloaded AND installed */
private final Map<UpdateItem, Version> _installed;
private final boolean _allowTorrent;
private static final DecimalFormat _pct = new DecimalFormat("0.0%");
private volatile String _status;
@ -90,6 +92,13 @@ public class ConsoleUpdateManager implements UpdateManager {
_downloaded = new ConcurrentHashMap();
_installed = new ConcurrentHashMap();
_status = "";
// DEBUG slow start for snark updates
// For 0.9.4 update, only for dev builds
// For 0.9.5 update, only for dev builds and 1% more
// For 0.9.6 update, only for dev builds and 3% more
// For 0.9.8 update, only for dev builds and 30% more
// Remove this for 100%
_allowTorrent = RouterVersion.BUILD != 0 || _context.random().nextInt(100) < 30;
}
public static ConsoleUpdateManager getInstance() {
@ -99,6 +108,7 @@ public class ConsoleUpdateManager implements UpdateManager {
public void start() {
notifyInstalled(NEWS, "", Long.toString(NewsHelper.lastUpdated(_context)));
notifyInstalled(ROUTER_SIGNED, "", RouterVersion.VERSION);
notifyInstalled(ROUTER_SIGNED_SU3, "", RouterVersion.VERSION);
// hack to init from the current news file... do this before we register Updaters
// This will not kick off any Updaters as none are yet registered
(new NewsFetcher(_context, this, Collections.EMPTY_LIST)).checkForUpdates();
@ -122,6 +132,15 @@ public class ConsoleUpdateManager implements UpdateManager {
register(c, ROUTER_SIGNED, HTTP, 0); // news is an update checker for the router
Updater u = new UpdateHandler(_context, this);
register(u, ROUTER_SIGNED, HTTP, 0);
if (ConfigUpdateHandler.USE_SU3_UPDATE) {
register(c, ROUTER_SIGNED_SU3, HTTP, 0);
register(u, ROUTER_SIGNED_SU3, HTTP, 0);
// todo
//register(c, ROUTER_SIGNED_SU3, HTTPS_CLEARNET, 0);
//register(u, ROUTER_SIGNED_SU3, HTTPS_CLEARNET, -10);
//register(c, ROUTER_SIGNED_SU3, HTTP_CLEARNET, 0);
//register(u, ROUTER_SIGNED_SU3, HTTP_CLEARNET, -20);
}
// TODO see NewsFetcher
//register(u, ROUTER_SIGNED, HTTPS_CLEARNET, -5);
//register(u, ROUTER_SIGNED, HTTP_CLEARNET, -10);
@ -560,18 +579,18 @@ public class ConsoleUpdateManager implements UpdateManager {
* Call once for each type/method pair.
*/
public void register(Updater updater, UpdateType type, UpdateMethod method, int priority) {
if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED) && NewsHelper.dontInstall(_context)) {
if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED || type == ROUTER_SIGNED_SU3) &&
NewsHelper.dontInstall(_context)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Ignoring registration for " + type + ", router updates disabled");
return;
}
// DEBUG slow start for snark updates
// For 0.9.4 update, only for dev builds
// For 0.9.5 update, only for dev builds and 1% more
// For 0.9.6 update, only for dev builds and 3% more
// For 0.9.8 update, only for dev builds and 30% more
// Remove this for 100%
if (method == TORRENT && RouterVersion.BUILD == 0 && _context.random().nextInt(100) > 29) {
if (type == ROUTER_SIGNED_SU3 && !ConfigUpdateHandler.USE_SU3_UPDATE) {
if (_log.shouldLog(Log.WARN))
_log.warn("Ignoring registration for " + type + ", SU3 updates disabled");
return;
}
if (method == TORRENT && !_allowTorrent) {
if (_log.shouldLog(Log.WARN))
_log.warn("Ignoring torrent registration");
return;
@ -725,8 +744,10 @@ public class ConsoleUpdateManager implements UpdateManager {
// fall through
case ROUTER_SIGNED:
case ROUTER_SIGNED_SU3:
if (shouldInstall() &&
!(isUpdateInProgress(ROUTER_SIGNED) ||
isUpdateInProgress(ROUTER_SIGNED_SU3) ||
isUpdateInProgress(ROUTER_UNSIGNED))) {
if (_log.shouldLog(Log.INFO))
_log.info("Updating " + ui + " after notify");
@ -810,6 +831,7 @@ public class ConsoleUpdateManager implements UpdateManager {
switch (task.getType()) {
case NEWS:
case ROUTER_SIGNED:
case ROUTER_SIGNED_SU3:
case ROUTER_UNSIGNED:
// ConfigUpdateHandler, SummaryHelper, SummaryBarRenderer handle status display
break;
@ -926,6 +948,12 @@ public class ConsoleUpdateManager implements UpdateManager {
notifyDownloaded(task.getType(), task.getID(), actualVersion);
break;
case ROUTER_SIGNED_SU3:
rv = handleSu3File(task.getURI(), actualVersion, file);
if (rv)
notifyDownloaded(task.getType(), task.getID(), actualVersion);
break;
case ROUTER_UNSIGNED:
rv = handleUnsignedFile(task.getURI(), actualVersion, file);
if (rv) {
@ -981,10 +1009,30 @@ public class ConsoleUpdateManager implements UpdateManager {
_log.info(ui + " " + ver + " downloaded");
_downloaded.put(ui, ver);
// one trumps the other
if (type == ROUTER_SIGNED)
if (type == ROUTER_SIGNED) {
_downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, ""));
else if (type == ROUTER_UNSIGNED)
_downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, ""));
// remove available from other type
UpdateItem altui = new UpdateItem(ROUTER_SIGNED_SU3, id);
Version old = _available.get(altui);
if (old != null && old.compareTo(ver) <= 0)
_available.remove(altui);
// ... and declare the alt downloaded as well
_downloaded.put(altui, ver);
} else if (type == ROUTER_SIGNED_SU3) {
_downloaded.remove(new UpdateItem(ROUTER_SIGNED, ""));
_downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, ""));
// remove available from other type
UpdateItem altui = new UpdateItem(ROUTER_SIGNED, id);
Version old = _available.get(altui);
if (old != null && old.compareTo(ver) <= 0)
_available.remove(altui);
// ... and declare the alt downloaded as well
_downloaded.put(altui, ver);
} else if (type == ROUTER_UNSIGNED) {
_downloaded.remove(new UpdateItem(ROUTER_SIGNED, ""));
_downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, ""));
}
Version old = _available.get(ui);
if (old != null && old.compareTo(ver) <= 0)
_available.remove(ui);
@ -1018,6 +1066,7 @@ public class ConsoleUpdateManager implements UpdateManager {
break;
case ROUTER_SIGNED:
{ // avoid dup variables in next case
String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
List<URI> rv = new ArrayList();
@ -1028,6 +1077,21 @@ public class ConsoleUpdateManager implements UpdateManager {
}
Collections.shuffle(rv, _context.random());
return rv;
}
case ROUTER_SIGNED_SU3:
{
String URLs = ConfigUpdateHandler.SU3_UPDATE_URLS;
StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
List<URI> rv = new ArrayList();
while (tok.hasMoreTokens()) {
try {
rv.add(new URI(tok.nextToken().trim()));
} catch (URISyntaxException use) {}
}
Collections.shuffle(rv, _context.random());
return rv;
}
case ROUTER_UNSIGNED:
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
@ -1072,14 +1136,59 @@ public class ConsoleUpdateManager implements UpdateManager {
* @return success
*/
private boolean handleSudFile(URI uri, String actualVersion, File f) {
return handleRouterFile(uri, actualVersion, f, false);
}
/**
* @return success
* @since 0.9.9
*/
private boolean handleSu3File(URI uri, String actualVersion, File f) {
return handleRouterFile(uri, actualVersion, f, true);
}
/**
* Process sud, su2, or su3
* @return success
* @since 0.9.9
*/
private boolean handleRouterFile(URI uri, String actualVersion, File f, boolean isSU3) {
String url = uri.toString();
// Process the .sud/.su2 file
updateStatus("<b>" + _("Update downloaded") + "</b>");
TrustedUpdate up = new TrustedUpdate(_context);
File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
String err = up.migrateVerified(RouterVersion.VERSION, f, to);
///////////
// caller must delete now.. why?
String err;
// Process the file
if (isSU3) {
SU3File up = new SU3File(_context, f);
File temp = new File(_context.getTempDir(), "su3out-" + _context.random().nextLong() + ".zip");
try {
if (up.verifyAndMigrate(temp)) {
String ver = up.getVersionString();
int type = up.getContentType();
if (ver == null || VersionComparator.comp(RouterVersion.VERSION, ver) >= 0)
err = "Old version " + ver;
else if (type != SU3File.CONTENT_ROUTER)
err = "Bad su3 content type " + type;
else if (!FileUtil.copy(temp, to, true, false))
err = "Failed copy to " + to;
else
err = null; // success
} else {
err = "Signature failed, signer " + DataHelper.stripHTML(up.getSignerString()) +
' ' + up.getSigType();
}
} catch (IOException ioe) {
_log.error("SU3 extract error", ioe);
err = DataHelper.stripHTML(ioe.toString());
} finally {
temp.delete();
}
} else {
TrustedUpdate up = new TrustedUpdate(_context);
err = up.migrateVerified(RouterVersion.VERSION, f, to);
}
// caller must delete.. could be an active torrent
//f.delete();
if (err == null) {
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
@ -1346,6 +1455,8 @@ public class ConsoleUpdateManager implements UpdateManager {
@Override
public String toString() {
if ("".equals(id))
return "UpdateItem " + type;
return "UpdateItem " + type + ' ' + id;
}
}

View File

@ -48,13 +48,10 @@ class DummyHandler implements Checker, Updater {
private final long _delay;
public DummyRunner(RouterContext ctx, ConsoleUpdateManager mgr, long maxTime) {
super(ctx, mgr, Collections.EMPTY_LIST);
super(ctx, mgr, UpdateType.TYPE_DUMMY, Collections.EMPTY_LIST);
_delay = maxTime;
}
@Override
public UpdateType getType() { return UpdateType.TYPE_DUMMY; }
@Override
public UpdateMethod getMethod() { return UpdateMethod.METHOD_DUMMY; }

View File

@ -32,6 +32,7 @@ import net.i2p.util.EepHead;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.VersionComparator;
import net.i2p.util.SSLEepGet;
/**
* Task to fetch updates to the news.xml, and to keep
@ -50,7 +51,7 @@ class NewsFetcher extends UpdateRunner {
private static final String TEMP_NEWS_FILE = "news.xml.temp";
public NewsFetcher(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
super(ctx, mgr, uris);
super(ctx, mgr, NEWS, uris);
_newsFile = new File(ctx.getRouterDir(), NewsHelper.NEWS_FILE);
_tempFile = new File(ctx.getTempDir(), "tmp-" + ctx.random().nextLong() + TEMP_NEWS_FILE);
long lastMod = NewsHelper.lastChecked(ctx);
@ -73,7 +74,7 @@ class NewsFetcher extends UpdateRunner {
}
public void fetchNews() {
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY_NEWS, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY_NEWS);
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
int proxyPort = ConfigUpdateHandler.proxyPort(_context);
@ -88,6 +89,9 @@ class NewsFetcher extends UpdateRunner {
EepGet get;
if (shouldProxy)
get = new EepGet(_context, true, proxyHost, proxyPort, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
else if ("https".equals(uri.getScheme()))
// no constructor w/ last mod check
get = new SSLEepGet(_context, _tempFile.getAbsolutePath(), newsURL);
else
get = new EepGet(_context, false, null, 0, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
get.addStatusListener(this);
@ -113,9 +117,11 @@ class NewsFetcher extends UpdateRunner {
private static final String MIN_JAVA_VERSION_KEY = "minjavaversion";
private static final String SUD_KEY = "sudtorrent";
private static final String SU2_KEY = "su2torrent";
// following are unused
private static final String SU3_KEY = "su3torrent";
private static final String CLEARNET_SUD_KEY = "sudclearnet";
private static final String CLEARNET_SU2_KEY = "su2clearnet";
private static final String CLEARNET_HTTP_SU3_KEY = "su3clearnet";
private static final String CLEARNET_HTTPS_SU3_KEY = "su3ssl";
private static final String I2P_SUD_KEY = "sudi2p";
private static final String I2P_SU2_KEY = "su2i2p";
@ -175,20 +181,24 @@ class NewsFetcher extends UpdateRunner {
// and look for a second entry with clearnet URLs
// TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET
Map<UpdateMethod, List<URI>> sourceMap = new HashMap(4);
// Must do su3 first
if (ConfigUpdateHandler.USE_SU3_UPDATE) {
sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED_SU3, "", HTTP));
addMethod(TORRENT, args.get(SU3_KEY), sourceMap);
addMethod(HTTP_CLEARNET, args.get(CLEARNET_HTTP_SU3_KEY), sourceMap);
addMethod(HTTPS_CLEARNET, args.get(CLEARNET_HTTPS_SU3_KEY), sourceMap);
// notify about all sources at once
_mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED_SU3,
"", sourceMap, ver, "");
sourceMap.clear();
}
// now do sud/su2
sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP));
String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY;
String murl = args.get(key);
if (murl != null) {
List<URI> uris = tokenize(murl);
if (!uris.isEmpty()) {
Collections.shuffle(uris, _context.random());
sourceMap.put(TORRENT, uris);
}
}
addMethod(TORRENT, args.get(key), sourceMap);
// notify about all sources at once
_mgr.notifyVersionAvailable(this, _currentURI,
ROUTER_SIGNED, "", sourceMap,
ver, "");
_mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED,
"", sourceMap, ver, "");
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Our version is current");
@ -292,6 +302,21 @@ class NewsFetcher extends UpdateRunner {
return rv;
}
/**
* Parse URLs and add to the map
* @param urls may be null
* @since 0.9.9
*/
private void addMethod(UpdateMethod method, String urls, Map<UpdateMethod, List<URI>> map) {
if (urls != null) {
List<URI> uris = tokenize(urls);
if (!uris.isEmpty()) {
Collections.shuffle(uris, _context.random());
map.put(method, uris);
}
}
}
/** override to prevent status update */
@Override
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}

View File

@ -35,16 +35,13 @@ class PluginUpdateChecker extends UpdateRunner {
public PluginUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
List<URI> uris, String appName, String oldVersion ) {
super(ctx, mgr, uris, oldVersion);
super(ctx, mgr, UpdateType.PLUGIN, uris, oldVersion);
if (!uris.isEmpty())
_currentURI = uris.get(0);
_appName = appName;
_oldVersion = oldVersion;
}
@Override
public UpdateType getType() { return UpdateType.PLUGIN; }
@Override
public String getID() { return _appName; }

View File

@ -60,7 +60,7 @@ class PluginUpdateRunner extends UpdateRunner {
public PluginUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris,
String appName, String oldVersion ) {
super(ctx, mgr, uris);
super(ctx, mgr, UpdateType.PLUGIN, uris);
if (uris.isEmpty())
throw new IllegalArgumentException("uri cannot be empty");
else
@ -70,12 +70,6 @@ class PluginUpdateRunner extends UpdateRunner {
_oldVersion = oldVersion;
}
@Override
public UpdateType getType() {
return UpdateType.PLUGIN;
}
@Override
public URI getURI() { return _uri; }
@ -104,7 +98,7 @@ class PluginUpdateRunner extends UpdateRunner {
} else {
updateStatus("<b>" + _("Downloading plugin from {0}", _xpi2pURL) + "</b>");
// use the same settings as for updater
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
int proxyPort = ConfigUpdateHandler.proxyPort(_context);
try {

View File

@ -28,17 +28,10 @@ class UnsignedUpdateChecker extends UpdateRunner {
public UnsignedUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
List<URI> uris, long lastUpdateTime) {
super(ctx, mgr, uris);
super(ctx, mgr, UpdateType.ROUTER_UNSIGNED, uris);
_ms = lastUpdateTime;
}
//////// begin UpdateTask methods
@Override
public UpdateType getType() { return UpdateType.ROUTER_UNSIGNED; }
//////// end UpdateTask methods
@Override
public void run() {
_isRunning = true;

View File

@ -25,16 +25,12 @@ import net.i2p.util.Log;
class UnsignedUpdateRunner extends UpdateRunner {
public UnsignedUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
super(ctx, mgr, uris);
super(ctx, mgr, ROUTER_UNSIGNED, uris);
if (!uris.isEmpty())
_currentURI = uris.get(0);
}
@Override
public UpdateType getType() { return ROUTER_UNSIGNED; }
/** Get the file */
@Override
protected void update() {

View File

@ -4,7 +4,10 @@ import java.net.URI;
import java.util.List;
import net.i2p.router.RouterContext;
import net.i2p.router.web.ConfigUpdateHandler;
import net.i2p.update.*;
import static net.i2p.update.UpdateType.*;
import static net.i2p.update.UpdateMethod.*;
/**
* <p>Handles the request to update the router by firing one or more
@ -38,10 +41,13 @@ class UpdateHandler implements Updater {
*/
public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
String id, String newVersion, long maxTime) {
if (type != UpdateType.ROUTER_SIGNED ||
method != UpdateMethod.HTTP || updateSources.isEmpty())
boolean shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
if ((type != ROUTER_SIGNED && type != ROUTER_SIGNED_SU3) ||
(shouldProxy && method != HTTP) ||
((!shouldProxy) && method != HTTP_CLEARNET && method != HTTPS_CLEARNET) ||
updateSources.isEmpty())
return null;
UpdateRunner update = new UpdateRunner(_context, _mgr, updateSources);
UpdateRunner update = new UpdateRunner(_context, _mgr, type, method, updateSources);
// set status before thread to ensure UI feedback
_mgr.notifyProgress(update, "<b>" + _mgr._("Updating") + "</b>");
return update;

View File

@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import net.i2p.crypto.TrustedUpdate;
@ -13,10 +14,12 @@ import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion;
import net.i2p.router.web.ConfigUpdateHandler;
import net.i2p.update.*;
import static net.i2p.update.UpdateMethod.*;
import net.i2p.util.EepGet;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.PartialEepGet;
import net.i2p.util.SSLEepGet;
import net.i2p.util.VersionComparator;
/**
@ -30,6 +33,8 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
protected final RouterContext _context;
protected final Log _log;
protected final ConsoleUpdateManager _mgr;
protected final UpdateType _type;
protected final UpdateMethod _method;
protected final List<URI> _urls;
protected final String _updateFile;
protected volatile boolean _isRunning;
@ -53,20 +58,42 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
/**
* Uses router version for partial checks
*/
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
this(ctx, mgr, uris, RouterVersion.VERSION);
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type, List<URI> uris) {
this(ctx, mgr, type, uris, RouterVersion.VERSION);
}
/**
* Uses router version for partial checks
* @since 0.9.9
*/
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
UpdateMethod method, List<URI> uris) {
this(ctx, mgr, type, method, uris, RouterVersion.VERSION);
}
/**
* @param currentVersion used for partial checks
* @since 0.9.7
*/
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris, String currentVersion) {
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
List<URI> uris, String currentVersion) {
this(ctx, mgr, type, HTTP, uris, currentVersion);
}
/**
* @param method HTTP, HTTP_CLEARNET, or HTTPS_CLEARNET
* @param currentVersion used for partial checks
* @since 0.9.9
*/
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, UpdateType type,
UpdateMethod method, List<URI> uris, String currentVersion) {
super("Update Runner");
setDaemon(true);
_context = ctx;
_log = ctx.logManager().getLog(getClass());
_mgr = mgr;
_type = type;
_method = method;
_urls = uris;
_baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
_updateFile = (new File(ctx.getTempDir(), "update" + ctx.random().nextInt() + ".tmp")).getAbsolutePath();
@ -82,9 +109,9 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
interrupt();
}
public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
public UpdateType getType() { return _type; }
public UpdateMethod getMethod() { return UpdateMethod.HTTP; }
public UpdateMethod getMethod() { return _method; }
public URI getURI() { return _currentURI; }
@ -117,9 +144,32 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
// Alternative: In bytesTransferred(), Check the data in the output file after
// we've received at least 56 bytes. Need a cancel() method in EepGet ?
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 = ConfigUpdateHandler.proxyPort(_context);
boolean shouldProxy;
String proxyHost;
int proxyPort;
boolean isSSL = false;
if (_method == HTTP) {
shouldProxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
if (shouldProxy) {
proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
proxyPort = ConfigUpdateHandler.proxyPort(_context);
} else {
// TODO, wrong method, fail
proxyHost = null;
proxyPort = 0;
}
} else if (_method == HTTP_CLEARNET) {
shouldProxy = false;
proxyHost = null;
proxyPort = 0;
} else if (_method == HTTPS_CLEARNET) {
shouldProxy = false;
proxyHost = null;
proxyPort = 0;
isSSL = true;
} else {
throw new IllegalArgumentException();
}
if (_urls.isEmpty()) {
// not likely, don't bother translating
@ -132,12 +182,24 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
for (URI uri : _urls) {
_currentURI = uri;
String updateURL = uri.toString();
if ((_method == HTTP && !"http".equals(uri.getScheme())) ||
(_method == HTTP_CLEARNET && !"http".equals(uri.getScheme())) ||
(_method == HTTPS_CLEARNET && !"https".equals(uri.getScheme())) ||
uri.getHost() == null ||
(_method != HTTP && uri.getHost().toLowerCase(Locale.US).endsWith(".i2p"))) {
if (_log.shouldLog(Log.WARN))
_log.warn("Bad update URI " + uri + " for method " + _method);
continue;
}
updateStatus("<b>" + _("Updating from {0}", linkify(updateURL)) + "</b>");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Selected update URL: " + updateURL);
// Check the first 56 bytes for the version
if (shouldProxy) {
// FIXME PartialEepGet works with clearnet but not with SSL
_newVersion = null;
if (!isSSL) {
_isPartial = true;
_baos.reset();
try {
@ -157,6 +219,8 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
if (shouldProxy)
// 40 retries!!
_get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
else if (isSSL)
_get = new SSLEepGet(_context, _updateFile, updateURL);
else
_get = new EepGet(_context, 1, _updateFile, updateURL, false);
_get.addStatusListener(UpdateRunner.this);
@ -208,6 +272,9 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
return;
}
// FIXME if we didn't do a partial, we don't know
if (_newVersion == null)
_newVersion = "unknown";
File tmp = new File(_updateFile);
if (_mgr.notifyComplete(this, _newVersion, tmp))
this.done = true;

View File

@ -14,8 +14,6 @@ public class ConfigTunnelsHelper extends HelperBase {
private static final String HOPS = ngettext("1 hop", "{0} hops");
private static final String TUNNELS = ngettext("1 tunnel", "{0} tunnels");
static final String PROP_ADVANCED = "routerconsole.advanced";
public String getForm() {
StringBuilder buf = new StringBuilder(1024);
// HTML: <input> cannot be inside a <table>
@ -69,7 +67,7 @@ public class ConfigTunnelsHelper extends HelperBase {
private void renderForm(StringBuilder buf, int index, String prefix, String name, TunnelPoolSettings in, TunnelPoolSettings out) {
boolean advanced = _context.getBooleanProperty(PROP_ADVANCED);
boolean advanced = isAdvanced();
buf.append("<tr><th colspan=\"3\"><a name=\"").append(prefix).append("\">");
buf.append(name).append("</a></th></tr>\n");

View File

@ -1,5 +1,6 @@
package net.i2p.router.web;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@ -22,6 +23,7 @@ public class ConfigUpdateHandler extends FormHandler {
private String _proxyHost;
private String _proxyPort;
private boolean _updateThroughProxy;
private boolean _newsThroughProxy;
private String _trustedKeys;
private boolean _updateUnsigned;
private String _zipURL;
@ -36,7 +38,11 @@ public class ConfigUpdateHandler extends FormHandler {
public static final String PROP_UPDATE_POLICY = "router.updatePolicy";
public static final String DEFAULT_UPDATE_POLICY = "download";
public static final String PROP_SHOULD_PROXY = "router.updateThroughProxy";
public static final String DEFAULT_SHOULD_PROXY = Boolean.TRUE.toString();
public static final boolean DEFAULT_SHOULD_PROXY = true;
/** @since 0.9.9 */
public static final String PROP_SHOULD_PROXY_NEWS = "router.fetchNewsThroughProxy";
/** @since 0.9.9 */
public static final boolean DEFAULT_SHOULD_PROXY_NEWS = true;
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";
@ -50,6 +56,7 @@ public class ConfigUpdateHandler extends FormHandler {
public static final String PROP_ZIP_URL = "router.updateUnsignedURL";
public static final String PROP_UPDATE_URL = "router.updateURL";
/**
* Changed as of release 0.8 to support both .sud and .su2
* Some JVMs (IcedTea) don't have pack200
@ -75,6 +82,10 @@ public class ConfigUpdateHandler extends FormHandler {
"http://update.killyourtv.i2p/i2pupdate.sud\r\n" +
"http://update.postman.i2p/i2pupdate.sud" ;
/**
* These are only for .sud and .su2.
* Do NOT use this for .su3
*/
public static final String DEFAULT_UPDATE_URL;
static {
if (FileUtil.isPack200Supported())
@ -83,6 +94,34 @@ public class ConfigUpdateHandler extends FormHandler {
DEFAULT_UPDATE_URL = NO_PACK200_URLS;
}
private static final String SU3_CERT_DIR = "certificates/router";
/**
* Only enabled if we have pack200 and trusted public key certificates installed
* @since 0.9.9
*/
public static final boolean USE_SU3_UPDATE;
static {
String[] files = (new File(I2PAppContext.getGlobalContext().getBaseDir(), SU3_CERT_DIR)).list();
USE_SU3_UPDATE = FileUtil.isPack200Supported() && files != null && files.length > 0;
}
private static final String DEFAULT_SU3_UPDATE_URLS =
"http://echelon.i2p/i2p/i2pupdate.su3\r\n" +
"http://inr.i2p/i2p/i2pupdate.su3\r\n" +
"http://meeh.i2p/i2pupdate/i2pupdate.su3\r\n" +
"http://stats.i2p/i2p/i2pupdate.su3\r\n" +
"http://www.i2p2.i2p/_static/i2pupdate.su3\r\n" +
"http://update.dg.i2p/files/i2pupdate.su3\r\n" +
"http://update.killyourtv.i2p/i2pupdate.su3\r\n" +
"http://update.postman.i2p/i2pupdate.su3" ;
/**
* Empty string if disabled. Cannot be overridden by config.
* @since 0.9.9
*/
public static final String SU3_UPDATE_URLS = USE_SU3_UPDATE ? DEFAULT_SU3_UPDATE_URLS : "";
public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys";
/**
@ -130,6 +169,8 @@ public class ConfigUpdateHandler extends FormHandler {
Map<String, String> changes = new HashMap();
if ( (_newsURL != null) && (_newsURL.length() > 0) ) {
if (_newsURL.startsWith("https"))
_newsThroughProxy = false;
String oldURL = ConfigUpdateHelper.getNewsURL(_context);
if ( (oldURL == null) || (!_newsURL.equals(oldURL)) ) {
changes.put(PROP_NEWS_URL, _newsURL);
@ -155,8 +196,9 @@ public class ConfigUpdateHandler extends FormHandler {
}
}
changes.put(PROP_SHOULD_PROXY, "" + _updateThroughProxy);
changes.put(PROP_UPDATE_UNSIGNED, "" + _updateUnsigned);
changes.put(PROP_SHOULD_PROXY, Boolean.toString(_updateThroughProxy));
changes.put(PROP_SHOULD_PROXY_NEWS, Boolean.toString(_newsThroughProxy));
changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned));
String oldFreqStr = _context.getProperty(PROP_REFRESH_FREQUENCY, DEFAULT_REFRESH_FREQUENCY);
long oldFreq = DEFAULT_REFRESH_FREQ;
@ -218,4 +260,6 @@ public class ConfigUpdateHandler extends FormHandler {
public void setProxyPort(String port) { _proxyPort = port; }
public void setUpdateUnsigned(String foo) { _updateUnsigned = true; }
public void setZipURL(String url) { _zipURL = url; }
/** @since 0.9.9 */
public void setNewsThroughProxy(String foo) { _newsThroughProxy = true; }
}

View File

@ -73,13 +73,20 @@ public class ConfigUpdateHelper extends HelperBase {
}
public String getUpdateThroughProxy() {
String proxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY);
if (Boolean.parseBoolean(proxy))
if (_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY))
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" checked=\"checked\" >";
else
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" >";
}
/** @since 0.9.9 */
public String getNewsThroughProxy() {
if (_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY_NEWS, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY_NEWS))
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"newsThroughProxy\" checked=\"checked\" >";
else
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"newsThroughProxy\" >";
}
public String getUpdateUnsigned() {
if (_context.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED))
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateUnsigned\" checked=\"checked\" >";

View File

@ -11,6 +11,8 @@ public abstract class HelperBase {
protected RouterContext _context;
protected Writer _out;
static final String PROP_ADVANCED = "routerconsole.advanced";
/**
* Configure this bean to query a particular router context
*
@ -25,6 +27,11 @@ public abstract class HelperBase {
}
}
/** @since 0.9.9 */
public boolean isAdvanced() {
return _context.getBooleanProperty(PROP_ADVANCED);
}
/** might be useful in the jsp's */
//public RouterContext getContext() { return _context; }

View File

@ -49,6 +49,7 @@ public class NewsHelper extends ContentHelper {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return false;
return mgr.isUpdateInProgress(ROUTER_SIGNED) ||
mgr.isUpdateInProgress(ROUTER_SIGNED_SU3) ||
mgr.isUpdateInProgress(ROUTER_UNSIGNED) ||
mgr.isUpdateInProgress(TYPE_DUMMY);
}
@ -60,7 +61,8 @@ public class NewsHelper extends ContentHelper {
public static boolean isUpdateAvailable() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return false;
return mgr.getUpdateAvailable(ROUTER_SIGNED) != null;
return mgr.getUpdateAvailable(ROUTER_SIGNED) != null ||
mgr.getUpdateAvailable(ROUTER_SIGNED_SU3) != null;
}
/**
@ -71,6 +73,9 @@ public class NewsHelper extends ContentHelper {
public static String updateVersion() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return null;
String rv = mgr.getUpdateAvailable(ROUTER_SIGNED_SU3);
if (rv != null)
return rv;
return mgr.getUpdateAvailable(ROUTER_SIGNED);
}
@ -93,6 +98,9 @@ public class NewsHelper extends ContentHelper {
public static String updateVersionDownloaded() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return null;
String rv = mgr.getUpdateDownloaded(ROUTER_SIGNED_SU3);
if (rv != null)
return rv;
return mgr.getUpdateDownloaded(ROUTER_SIGNED);
}

View File

@ -0,0 +1,37 @@
package net.i2p.router.web;
import java.util.Date;
import net.i2p.data.DataHelper;
import net.i2p.data.RouterAddress;
import net.i2p.data.RouterInfo;
import net.i2p.data.Signature;
/**
* Sign a statement about this router.
* @since 0.9.8
*/
public class ProofHelper extends HelperBase {
public String getProof() {
StringBuilder buf = new StringBuilder(512);
RouterInfo us = _context.router().getRouterInfo();
buf.append("Hash: ").append(us.getIdentity().calculateHash().toBase64()).append('\n');
//buf.append("Ident: ").append(us.getIdentity().toBase64()).append('\n');
for (RouterAddress addr : us.getAddresses()) {
buf.append(addr.getTransportStyle()).append(": ").append(addr.getHost()).append('\n');
}
buf.append("Caps: ").append(us.getCapabilities()).append('\n');
buf.append("Date: ").append(new Date()); // no trailing newline
String msg = buf.toString();
byte[] data = DataHelper.getUTF8(msg);
Signature sig = _context.dsa().sign(data, _context.keyManager().getSigningPrivateKey());
buf.setLength(0);
buf.append("---BEGIN I2P SIGNED MESSAGE---\n");
buf.append(msg);
buf.append("\n---BEGIN I2P SIGNATURE---\n");
buf.append(sig.toBase64());
buf.append("\n---END I2P SIGNATURE---");
return buf.toString();
}
}

View File

@ -27,6 +27,7 @@ import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.apps.systray.SysTray;
import net.i2p.crypto.KeyStoreUtil;
import net.i2p.data.Base32;
import net.i2p.data.DataHelper;
import net.i2p.jetty.I2PLogger;
@ -38,8 +39,6 @@ import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.PortMapper;
import net.i2p.util.SecureDirectory;
import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.ShellCommand;
import net.i2p.util.SystemVersion;
import net.i2p.util.VersionComparator;
@ -677,12 +676,6 @@ public class RouterConsoleRunner implements RouterApp {
System.err.println("Console SSL error, must set " + PROP_KEY_PASSWORD + " in " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
return rv;
}
File dir = ks.getParentFile();
if (!dir.exists()) {
File sdir = new SecureDirectory(dir.getAbsolutePath());
if (!sdir.mkdir())
return false;
}
return createKeyStore(ks);
}
@ -697,31 +690,13 @@ public class RouterConsoleRunner implements RouterApp {
*/
private boolean createKeyStore(File ks) {
// make a random 48 character password (30 * 8 / 5)
byte[] rand = new byte[30];
_context.random().nextBytes(rand);
String keyPassword = Base32.encode(rand);
String keyPassword = KeyStoreUtil.randomString();
// and one for the cname
_context.random().nextBytes(rand);
String cname = Base32.encode(rand) + ".console.i2p.net";
String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
String[] args = new String[] {
keytool,
"-genkey", // -genkeypair preferred in newer keytools, but this works with more
"-storetype", KeyStore.getDefaultType(),
"-keystore", ks.getAbsolutePath(),
"-storepass", DEFAULT_KEYSTORE_PASSWORD,
"-alias", "console",
"-dname", "CN=" + cname + ",OU=Console,O=I2P Anonymous Network,L=XX,ST=XX,C=XX",
"-validity", "3652", // 10 years
"-keyalg", "DSA",
"-keysize", "1024",
"-keypass", keyPassword};
boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30); // 30 secs
String cname = KeyStoreUtil.randomString() + ".console.i2p.net";
boolean success = KeyStoreUtil.createKeys(ks, "console", cname, "Console", keyPassword);
if (success) {
success = ks.exists();
if (success) {
SecureFileOutputStream.setPerms(ks);
try {
Map<String, String> changes = new HashMap();
changes.put(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
@ -735,13 +710,8 @@ public class RouterConsoleRunner implements RouterApp {
"The certificate name was generated randomly, and is not associated with your " +
"IP address, host name, router identity, or destination keys.");
} else {
System.err.println("Failed to create console SSL keystore using command line:");
StringBuilder buf = new StringBuilder(256);
for (int i = 0; i < args.length; i++) {
buf.append('"').append(args[i]).append("\" ");
}
System.err.println(buf.toString());
System.err.println("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
System.err.println("Failed to create console SSL keystore.\n" +
"This is for the Sun/Oracle keytool, others may be incompatible.\n" +
"If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
" to " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
}

View File

@ -39,7 +39,7 @@ public class TunnelRenderer {
Map<Hash, TunnelPool> clientInboundPools = _context.tunnelManager().getInboundClientPools();
Map<Hash, TunnelPool> clientOutboundPools = _context.tunnelManager().getOutboundClientPools();
destinations = new ArrayList(clientInboundPools.keySet());
boolean debug = _context.getBooleanProperty(ConfigTunnelsHelper.PROP_ADVANCED);
boolean debug = _context.getBooleanProperty(HelperBase.PROP_ADVANCED);
for (int i = 0; i < destinations.size(); i++) {
Hash client = destinations.get(i);
boolean isLocal = _context.clientManager().isLocal(client);

View File

@ -66,6 +66,8 @@ public class UpdateHandler {
_nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) {
if (_action.contains("Unsigned")) {
update(ROUTER_UNSIGNED);
} else if (ConfigUpdateHandler.USE_SU3_UPDATE) {
update(ROUTER_SIGNED_SU3);
} else {
update(ROUTER_SIGNED);
}
@ -76,7 +78,8 @@ public class UpdateHandler {
ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
if (mgr == null)
return;
if (mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_UNSIGNED)) {
if (mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_UNSIGNED) ||
mgr.isUpdateInProgress(ROUTER_SIGNED_SU3)) {
_log.error("Update already running");
return;
}