- Fixes for Jetty 9

- Convert I2PControlController to RouterApp
- Remove all static references
- Don't stop all running threads on shutdown
- Set restrictive permissions on configuration file
- Disable changing host/port/password via RPC
- Use I2P lib for setting supported ciphers
- Update makeplugin.sh
- Change signer and update URLs in plugin.config
- Don't include license, readme, and clients.config in the update
- Bundle i2pcontrol.py test script
- Make constants static and final
- Comment out unused methods
- Remove tabs in build.xml
- Remove unused dependencies in build.xml
- Clean up imports
This commit is contained in:
zzz
2018-02-01 15:14:03 +00:00
parent 44263d9b26
commit 37251cbcb3
22 changed files with 691 additions and 330 deletions

View File

@ -4,12 +4,12 @@
<target name="all" depends="clean,plugin,release" />
<target name="local" depends="clean,plugin">
<property name="i2p.plugindir" value="${user.home}/.i2p/plugins/I2PControl" />
<delete dir="${i2p.plugindir}"/>
<mkdir dir="${i2p.plugindir}"/>
<mkdir dir="${i2p.plugindir}/lib"/>
<property name="i2p.plugindir" value="${user.home}/.i2p/plugins/I2PControl" />
<delete dir="${i2p.plugindir}"/>
<mkdir dir="${i2p.plugindir}"/>
<mkdir dir="${i2p.plugindir}/lib"/>
<copy file="src/build/I2PControl.jar" todir="${i2p.plugindir}/lib" overwrite="true" />
<copy todir="${i2p.plugindir}" >
<copy todir="${i2p.plugindir}" >
<fileset dir="plugin" includes="**"/>
</copy>
</target>
@ -24,10 +24,7 @@
<property name="release.number" value="0.11" />
<!-- make the update xpi2p -->
<mkdir dir="plugin/lib"/>
<copy file="LICENSE.txt" todir="plugin/" overwrite="true" />
<copy file="README.txt" todir="plugin/" overwrite="true" />
<copy file="scripts/clients.config" todir="plugin/" overwrite="true" />
<mkdir dir="plugin/lib"/>
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
<exec executable="pack200" failonerror="true">
@ -46,14 +43,17 @@
</exec>
<!-- make the install xpi2p -->
<copy file="LICENSE.txt" todir="plugin/" overwrite="true" />
<copy file="README.txt" todir="plugin/" overwrite="true" />
<copy file="scripts/clients.config" todir="plugin/" overwrite="true" />
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
<copy file="scripts/i2pcontrol.py" todir="plugin/" overwrite="true" />
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
<arg value="version=${release.number}-b${build.number}" />
</exec>
</target>
<target name="release" depends="plugin">
<input message="Enter su3 signing key password:" addproperty="release.password.su3" />
<fail message="You must enter a password." >
<condition>
@ -84,7 +84,7 @@
<ant dir="src" target="clean" />
<delete file="plugin/clients.config" />
<delete file="plugin/plugin.config" />
<delete file="plugin/console/webapp.config" />
<delete file="plugin/console/webapp.config" />
<delete file="plugin/lib/I2PControl.jar.pack" />
<delete file="plugin/console/webapps/I2PControl.war.pack" />
<delete file="plugin/LICENSE.txt" />

209
scripts/i2pcontrol.py Executable file
View File

@ -0,0 +1,209 @@
#!/usr/bin/env python
#
# If it fails "No module named yaml"
# then sudo apt install python-yaml
#
import argparse
import json
import urllib2
import httplib
import socket
import ssl
import sys
import yaml
from urllib2 import HTTPError, URLError
from string import whitespace
# Info about requestable data can be found at https://geti2p.net/i2pcontrol.html & https://geti2p.net/ratestats.html
address = "127.0.0.1" # Default I2PControl Address
port = 7650 # Default I2PControl Port
apiPassword = "itoopie" # Default I2PControl password
## Do not edit below
apiVersion = 1 # Default API Version
msgId = 1
token = None
def checkToken():
global token
if (token == None):
token = getToken()
if (token == None):
print("Unable to login. Quitting..")
sys.exit()
def getToken():
loginStr = "{\"id\":" + str(msgId) + ", \"method\":\"Authenticate\",\"params\":{\"API\":" + str(apiVersion) + ", \"Password\":\"" + apiPassword + "\"}, \"jsonrpc\":\"2.0\"}"
try:
jsonResp = sendMsg(loginStr)
return jsonResp.get("result").get("Token")
except HTTPError, e:
print("HTTPError: %s" % e.reason)
except URLError, e:
print("URLError: %s" % e.reason)
def getRate(rateName, ratePeriod):
checkToken()
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"GetRate\",\"params\":{\"Stat\":\"" + rateName + "\", \"Period\":" + str(ratePeriod) + ", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
return jsonResp.get("result").get("Result")
def getRouterInfo(infoName):
checkToken()
## The parameter names in 'params' defines which answers are requested
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"RouterInfo\",\"params\":{\""+infoName+"\":\"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
return jsonResp.get("result").get(infoName)
def sendMsg(jsonStr):
global msgId
https_handler = UnauthenticatedHTTPSHandler()
url_opener = urllib2.build_opener(https_handler)
handle = url_opener.open("https://"+address+":"+ str(port) + "/jsonrpc", jsonStr)
response = handle.read()
handle.close()
msgId = msgId + 1;
jsonResp = json.loads(response)
if (jsonResp.has_key("error")):
print ("Remote server: I2PControl Error: " + str(jsonResp.get("error").get("code")) + ", " + jsonResp.get("error").get("message"))
sys.exit()
return jsonResp
###
# Overrides the version in httplib so that we can ignore server certificate authenticity
###
class UnauthenticatedHTTPSConnection(httplib.HTTPSConnection):
def connect(self):
#
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock,
cert_reqs=ssl.CERT_NONE)
###
# HTTPS handler which uses SSLv3 and ignores server cert authenticity
###
class UnauthenticatedHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, connection_class = UnauthenticatedHTTPSConnection):
self.specialized_conn_class = connection_class
urllib2.HTTPSHandler.__init__(self)
def https_open(self, req):
return self.do_open(self.specialized_conn_class, req)
def zabbix_config(fileName, outfile):
yamlDict = dict()
for line in open(fileName):
li=line.strip()
if li.startswith("UserParameter"):
i2pCtrlOpt = li.strip("UserParameter=").split(",")
i2pCtrlOpt[1] = i2pCtrlOpt[1].split()
i2pCtrlOpt[1].pop(0) # Remove path of this script (i2pcontrol)
i2pCtrlParams = i2pCtrlOpt[1]
#print i2pCtrlOpt #Delete me!
result = ""
if (i2pCtrlParams[0] == "-i" or i2pCtrlParams[0] == "--router-info"):
result = getRouterInfo(i2pCtrlParams[1])
elif (i2pCtrlParams[0] == "-s" or i2pCtrlParams[0] == "--rate-stat"):
result = getRate(i2pCtrlParams[1], i2pCtrlParams[2])
else:
result = "Bad query syntax."
yamlDict[i2pCtrlParams[1]] = result
#print yaml.dump(yamlDict)
yaml.dump(yamlDict, open(outfile,'w'))
def from_file(infile, parameter):
try:
yamlDict = yaml.load(open(infile,'r'))
print yamlDict[parameter]
except IOError, e:
print "File \""+ infile +"\" couldn't be read."
def main():
parser = argparse.ArgumentParser(description='Fetch I2P info via the I2PControl API.')
parser.add_argument("-i",
"--router-info",
nargs=1,
metavar="router-info-id",
dest="router_info",
action="store",
help="Request info such as I2P version and uptime. Returned info can be of any type. Full list of options at https://geti2p.net/i2pcontrol.html. Usage: \"-i i2p.router.version\"")
parser.add_argument("-s",
"--rate-stat",
nargs=2,
metavar=("rateStatName", "period"),
dest="rate_stat",
action="store",
help="Request info such as bandwidth, number active peers, clock skew, etc.. The period is measured in ms and must be longer than 60s. Full list at https://geti2p.net/ratestats.html. Usage: \"-s bw.receiveBps 3600000\"")
parser.add_argument("-z",
"--zabbix",
nargs=2,
metavar=("\"path to zabbix_agent.conf\"", "\"path to output file\""),
dest="zabbix",
action="store",
help="Parse options to request, by reading a zabbix config file for \"UserParameter\"s relating to I2P. Usage: \"-z /etc/zabbix/zabbix_agent.conf\"")
parser.add_argument("-f",
"--from-file",
nargs=1,
metavar=("\"path to input file\""),
dest="from_file",
action="store",
help="Parse options to request, by reading a zabbix config file for \"UserParameter\"s relating to I2P. Usage: \"-z /etc/zabbix/zabbix_agent.conf\"")
if (len(sys.argv) == 1):
parser.parse_args(["-h"])
options = parser.parse_args()
if ((options.rate_stat != None) and (options.router_info != None)):
print("Error: Choose _one_ option. \n\n")
parser.parse_args(["-h"])
if ((options.zabbix != None) and ((options.rate_stat != None) or (options.router_info != None) or (options.from_file != None))):
print("Error: Don't combine option --zabbix with other options.\n")
parser.parse_args(["-h"])
# From-file can only be used when either router-info or rate-stat is enabled.
if ((options.from_file != None) and (options.rate_stat == None) and (options.router_info == None)):
print("Error: --from-file must be used with either --router-info or --rate-stat.\n")
parser.parse_args(["-h"])
if (options.from_file != None):
if (options.router_info != None):
from_file(options.from_file[0], options.router_info[0])
if (options.rate_stat != None):
from_file(options.from_file[0], options.rate_stat[0])
sys.exit()
if (options.rate_stat != None):
try:
period = int(options.rate_stat[1])
if (period < 60000):
raise ValueError
print getRate(options.rate_stat[0], period)
except ValueError, e:
print("Error: \""+options.rate_stat[1]+"\" is not an integer > 60000 \n\n")
parser.parse_args(["-h"])
sys.exit()
if (options.router_info != None):
print getRouterInfo(options.router_info[0])
sys.exit()
if (options.zabbix != None):
zabbix_config(options.zabbix[0], options.zabbix[1])
sys.exit()
if __name__ == "__main__":
main()

View File

@ -7,6 +7,18 @@
# zzz 2010-02
# zzz 2014-08 added support for su3 files
#
if [ -z "$I2P" -a -d "$PWD/../i2p/pkg-temp" ]; then
export I2P=$PWD/../i2p/pkg-temp
fi
if [ ! -d "$I2P" ]; then
echo "Can't locate your I2P installation. Please add a environment variable named I2P with the path to the folder as value"
echo "On OSX this solved with running: export I2P=/Applications/i2p if default install directory is used."
exit 1
fi
CPATH=$I2P/lib/i2p.jar:/usr/share/java/gnu-getopt.jar
PUBKEYDIR=$HOME/.i2p-plugin-keys
PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key
PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key
@ -15,60 +27,59 @@ PUBKEYSTORE=$PUBKEYDIR/plugin-su3-public-signing.crt
PRIVKEYSTORE=$PUBKEYDIR/plugin-su3-keystore.ks
KEYTYPE=RSA_SHA512_4096
export I2P=../i2p.i2p/pkg-temp
# put your files in here
PLUGINDIR=${1:-plugin}
PC=plugin.config
PCT=${PC}.tmp
if [ ! -d $PLUGINDIR ]
if [ ! -d "$PLUGINDIR" ]
then
echo "You must have a $PLUGINDIR directory"
exit 1
fi
if [ ! -f $PLUGINDIR/$PC ]
if [ ! -f "$PLUGINDIR/$PC" ]
then
echo "You must have a $PLUGINDIR/$PC file"
exit 1
fi
SIGNER=`grep '^signer=' $PLUGINDIR/$PC`
SIGNER=`grep '^signer=' "$PLUGINDIR/$PC"`
if [ "$?" -ne "0" ]
then
echo "You must have a plugin name in $PC"
echo "You must have a signer name in $PC"
echo 'For example name=foo'
exit 1
fi
SIGNER=`echo $SIGNER | cut -f 2 -d '='`
if [ ! -f $PRIVKEYFILE ]
if [ ! -f "$PRIVKEYFILE" ]
then
echo "Creating new XPI2P DSA keys"
mkdir -p $PUBKEYDIR || exit 1
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate keygen $PUBKEYFILE $PRIVKEYFILE || exit 1
java -cp $I2P/lib/i2p.jar net.i2p.data.Base64 encode $PUBKEYFILE $B64KEYFILE || exit 1
mkdir -p "$PUBKEYDIR" || exit 1
java -cp "$CPATH" net.i2p.crypto.TrustedUpdate keygen "$PUBKEYFILE" "$PRIVKEYFILE" || exit 1
java -cp "$CPATH" net.i2p.data.Base64 encode "$PUBKEYFILE" "$B64KEYFILE" || exit 1
rm -rf logs/
chmod 444 $PUBKEYFILE $B64KEYFILE
chmod 400 $PRIVKEYFILE
chmod 444 "$PUBKEYFILE" "$B64KEYFILE"
chmod 400 "$PRIVKEYFILE"
echo "Created new XPI2P keys: $PUBKEYFILE $PRIVKEYFILE"
fi
if [ ! -f $PRIVKEYSTORE ]
if [ ! -f "$PRIVKEYSTORE" ]
then
echo "Creating new SU3 $KEYTYPE keys for $SIGNER"
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File keygen -t $KEYTYPE $PUBKEYSTORE $PRIVKEYSTORE $SIGNER || exit 1
java -cp "$CPATH" net.i2p.crypto.SU3File keygen -t $KEYTYPE "$PUBKEYSTORE" "$PRIVKEYSTORE" $SIGNER || exit 1
echo '*** Save your password in a safe place!!! ***'
rm -rf logs/
# copy to the router dir so verify will work
CDIR=$I2P/certificates/plugin
mkdir -p $CDIR || exit 1
mkdir -p "$CDIR" || exit 1
CFILE=$CDIR/`echo $SIGNER | sed s/@/_at_/`.crt
cp $PUBKEYSTORE $CFILE
chmod 444 $PUBKEYSTORE
chmod 400 $PRIVKEYSTORE
chmod 644 $CFILE
cp "$PUBKEYSTORE" "$CFILE"
chmod 444 "$PUBKEYSTORE"
chmod 400 "$PRIVKEYSTORE"
chmod 644 "$CFILE"
echo "Created new SU3 keys: $PUBKEYSTORE $PRIVKEYSTORE"
echo "Copied public key to $CFILE for testing"
fi
@ -76,7 +87,7 @@ fi
rm -f plugin.zip
OPWD=$PWD
cd $PLUGINDIR
cd "$PLUGINDIR"
grep -q '^name=' $PC
if [ "$?" -ne "0" ]
@ -97,17 +108,17 @@ fi
# update the date
grep -v '^date=' $PC > $PCT
DATE=`date '+%s000'`
echo "date=$DATE" >> $PCT
echo "date=$DATE" >> $PCT || exit 1
mv $PCT $PC || exit 1
# add our Base64 key
grep -v '^key=' $PC > $PCT
B64KEY=`cat $B64KEYFILE`
B64KEY=`cat "$B64KEYFILE"`
echo "key=$B64KEY" >> $PCT || exit 1
mv $PCT $PC || exit 1
# zip it
zip -r $OPWD/plugin.zip * || exit 1
zip -r "$OPWD/plugin.zip" * || exit 1
# get the version and use it for the sud header
VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
@ -115,24 +126,24 @@ VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
NAME=`grep '^name=' $PC | cut -f 2 -d '='`
XPI2P=${NAME}.xpi2p
SU3=${NAME}.su3
cd $OPWD
cd "$OPWD"
# sign it
echo 'Signing. ...'
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign plugin.zip $XPI2P $PRIVKEYFILE $VERSION || exit 1
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File sign -c PLUGIN -t $KEYTYPE plugin.zip $SU3 $PRIVKEYSTORE $VERSION $SIGNER || exit 1
java -cp "$CPATH" net.i2p.crypto.TrustedUpdate sign plugin.zip "$XPI2P" "$PRIVKEYFILE" "$VERSION" || exit 1
java -cp "$CPATH" net.i2p.crypto.SU3File sign -c PLUGIN -t $KEYTYPE plugin.zip "$SU3" "$PRIVKEYSTORE" "$VERSION" "$SIGNER" || exit 1
rm -f plugin.zip
# verify
echo 'Verifying. ...'
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion $XPI2P || exit 1
java -cp $I2P/lib/i2p.jar -Drouter.trustedUpdateKeys=$B64KEY net.i2p.crypto.TrustedUpdate verifysig $XPI2P || exit 1
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File showversion $SU3 || exit 1
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File verifysig -k $PUBKEYSTORE $SU3 || exit 1
java -cp "$CPATH" net.i2p.crypto.TrustedUpdate showversion "$XPI2P" || exit 1
java -cp "$CPATH" -Drouter.trustedUpdateKeys=$B64KEY net.i2p.crypto.TrustedUpdate verifysig "$XPI2P" || exit 1
java -cp "$CPATH" net.i2p.crypto.SU3File showversion "$SU3" || exit 1
java -cp "$CPATH" net.i2p.crypto.SU3File verifysig -k "$PUBKEYSTORE" "$SU3" || exit 1
rm -rf logs/
echo 'Plugin files created: '
wc -c $XPI2P
wc -c $SU3
wc -c "$XPI2P"
wc -c "$SU3"
exit 0

View File

@ -1,11 +1,11 @@
name=I2PControl
signer=dev@robertfoss.se
signer=zzz-plugin@mail.i2p
consoleLinkName=I2PControl
description=Remote Control Service
author=hottuna
websiteURL=http://itoopie.i2p/
updateURL=http://itoopie.i2p/files/I2PControl-update.xpi2p
websiteURL=http://zzz.i2p/forums/16
updateURL=http://zzz.i2p/i2p/plugins/I2PControl-update.xpi2p
updateURL.su3=http://zzz.i2p/i2p/plugins/I2PControl-update.su3
license=Apache 2.0
min-jetty-version=7
max-jetty-version=8.9999
min-i2p-version=0.9.20
min-jetty-version=9
min-i2p-version=0.9.30

View File

@ -3,24 +3,15 @@
<property name="i2pbase" value="../../i2p.i2p"/>
<property name="i2plib" value="${i2pbase}/build"/>
<property name="jettylib" value="${i2pbase}/apps/jetty/jettylib"/>
<property name="wrapperlib" value="${i2pbase}/installer/lib/wrapper/all"/>
<property name="wrapperlib" value="${i2pbase}/installer/lib/wrapper/all"/>
<path id="cp">
<pathelement path="${java.class.path}" />
<pathelement location="${i2plib}/i2p.jar" />
<pathelement location="${i2plib}/router.jar" />
<pathelement location="${i2plib}/i2ptunnel.jar" />
<pathelement location="${i2plib}/org.mortbay.jetty.jar" />
<pathelement location="${i2plib}/javax.servlet.jar" />
<pathelement location="${ant.home}/lib/ant.jar"/>
<pathelement location="${jettylib}/jetty-http.jar" />
<pathelement location="${jettylib}/jetty-server.jar"/>
<pathelement location="${jettylib}/jetty-servlet.jar" />
<pathelement location="${jettylib}/jetty-servlets.jar" />
<pathelement location="${jettylib}/jetty-util.jar" />
<pathelement location="${jettylib}/jasper-compiler.jar" />
<pathelement location="${jettylib}/jasper-runtime.jar" />
<pathelement location="${jettylib}/commons-logging.jar" />
<pathelement location="${wrapperlib}/wrapper.jar" />
</path>
@ -41,7 +32,7 @@
destdir="./build/obj"
classpath="${cp}">
<compilerarg line="${javac.compilerargs}" />
<classpath refid="cp"/>
<classpath refid="cp"/>
</javac>
</target>

View File

@ -18,13 +18,13 @@ public class JSONRPC2ParseException extends Exception {
* Indicates a parse exception caused by a JSON message not conforming
* to the JSON-RPC 2.0 protocol.
*/
public static int PROTOCOL = 0;
public static final int PROTOCOL = 0;
/**
* Indicates a parse exception caused by invalid JSON.
*/
public static int JSON = 1;
public static final int JSON = 1;
/**

View File

@ -17,16 +17,29 @@ package net.i2p.i2pcontrol;
*/
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
import net.i2p.i2pcontrol.security.KeyStoreProvider;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.JSONRPC2Servlet;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import net.i2p.util.Log;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import java.io.File;
import java.io.IOException;
@ -45,14 +58,109 @@ import java.security.KeyStore;
*
* @author hottuna
*/
public class I2PControlController {
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PControlController.class);
private static String _pluginDir = "";
private static ConfigurationManager _conf;
private static SecurityManager _secMan;
private static Server _server;
public class I2PControlController implements RouterApp {
// non-null
private final I2PAppContext _appContext;
// warning, null in app context
private final RouterContext _context;
private final ClientAppManager _mgr;
private final Log _log;
private final String _pluginDir;
private final ConfigurationManager _conf;
private final KeyStoreProvider _ksp;
private final SecurityManager _secMan;
private final Server _server;
private ClientAppState _state = UNINITIALIZED;
// only for main()
private static I2PControlController _instance;
public I2PControlController(RouterContext ctx, ClientAppManager mgr, String args[]) {
_appContext = _context = ctx;
_mgr = mgr;
_log = _appContext.logManager().getLog(I2PControlController.class);
File pluginDir = new File(_context.getAppDir(), "plugins/I2PControl");
_pluginDir = pluginDir.getAbsolutePath();
_conf = new ConfigurationManager(_pluginDir);
_ksp = new KeyStoreProvider(_pluginDir);
_secMan = new SecurityManager(_ksp, _conf);
_server = buildServer();
_state = INITIALIZED;
}
/**
* From main()
*/
public I2PControlController(File pluginDir) {
_appContext = I2PAppContext.getGlobalContext();
if (_appContext instanceof RouterContext)
_context = (RouterContext) _appContext;
else
_context = null;
_mgr = null;
_log = _appContext.logManager().getLog(I2PControlController.class);
_pluginDir = pluginDir.getAbsolutePath();
_conf = new ConfigurationManager(_pluginDir);
_ksp = new KeyStoreProvider(_pluginDir);
_secMan = new SecurityManager(_ksp, _conf);
_server = buildServer();
_state = INITIALIZED;
}
/////// ClientApp methods
public synchronized void startup() {
changeState(STARTING);
try {
start(null);
changeState(RUNNING);
} catch (Exception e) {
changeState(START_FAILED, "Failed to start", e);
_log.error("Unable to start jetty server", e);
}
}
public synchronized void shutdown(String[] args) {
if (_state == STOPPED)
return;
changeState(STOPPING);
stop();
changeState(STOPPED);
}
public synchronized ClientAppState getState() {
return _state;
}
public String getName() {
return "I2PControl";
}
public String getDisplayName() {
return "I2PControl";
}
/////// end ClientApp methods
private void changeState(ClientAppState state) {
changeState(state, null, null);
}
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
_state = state;
if (_mgr != null)
_mgr.notify(this, state, msg, e);
if (_context == null) {
if (msg != null)
System.out.println(state + ": " + msg);
if (e != null)
e.printStackTrace();
}
}
/**
* Deprecated, use constructor
*/
public static void main(String args[]) {
if (args.length != 3 || (!"-d".equals(args[0])))
throw new IllegalArgumentException("Usage: PluginController -d $PLUGINDIR [start|stop]");
@ -61,37 +169,33 @@ public class I2PControlController {
File pluginDir = new File(args[1]);
if (!pluginDir.exists())
throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist");
_pluginDir = pluginDir.getAbsolutePath();
ConfigurationManager.setConfDir(pluginDir.getAbsolutePath());
_conf = ConfigurationManager.getInstance();
_secMan = SecurityManager.getInstance();
start(args);
//stop(); // Delete Me
} else if ("stop".equals(args[2]))
stop();
else
synchronized(I2PControlController.class) {
if (_instance != null)
throw new IllegalStateException();
I2PControlController i2pcc = new I2PControlController(pluginDir);
try {
i2pcc.startup();
_instance = i2pcc;
} catch (Exception e) {
e.printStackTrace();
}
}
} else if ("stop".equals(args[2])) {
synchronized(I2PControlController.class) {
if (_instance != null) {
_instance.shutdown(null);
_instance = null;
}
}
} else {
throw new IllegalArgumentException("Usage: PluginController -d $PLUGINDIR [start|stop]");
}
}
private static void start(String args[]) {
I2PAppContext.getGlobalContext().logManager().getLog(JSONRPC2Servlet.class).setMinimumPriority(Log.DEBUG);
try {
Connector ssl = buildDefaultListenter();
_server = buildServer(ssl);
} catch (IOException e) {
_log.error("Unable to add listener " + _conf.getConf("i2pcontrol.listen.address", "127.0.0.1") + ":" + _conf.getConf("i2pcontrol.listen.port", 7560) + " - " + e.getMessage());
} catch (ClassNotFoundException e) {
_log.error("Unable to find class net.i2p.i2pcontrol.JSONRPCServlet: " + e.getMessage());
} catch (InstantiationException e) {
_log.error("Unable to instantiate class net.i2p.i2pcontrol.JSONRPCServlet: " + e.getMessage());
} catch (IllegalAccessException e) {
_log.error("Illegal access: " + e.getMessage());
} catch (Exception e) {
_log.error("Unable to start jetty server: " + e.getMessage());
}
private synchronized void start(String args[]) throws Exception {
_appContext.logManager().getLog(JSONRPC2Servlet.class).setMinimumPriority(Log.DEBUG);
_server.start();
}
@ -99,10 +203,9 @@ public class I2PControlController {
/**
* Builds a new server. Used for changing ports during operation and such.
* @return Server - A new server built from current configuration.
* @throws UnknownHostException
*/
public static Connector buildDefaultListenter() throws UnknownHostException {
SslSocketConnector ssl = buildSslListener(_conf.getConf("i2pcontrol.listen.address", "127.0.0.1"),
private Connector buildDefaultListener(Server server) {
Connector ssl = buildSslListener(server, _conf.getConf("i2pcontrol.listen.address", "127.0.0.1"),
_conf.getConf("i2pcontrol.listen.port", 7650));
return ssl;
}
@ -110,20 +213,19 @@ public class I2PControlController {
/**
* Builds a new server. Used for changing ports during operation and such.
*
* Does NOT start the server. Must call start() on the returned server.
*
* @return Server - A new server built from current configuration.
* @throws UnknownHostException
* @throws Exception
* @throws InstantiationException
* @throws IllegalAccessException
*/
public static Server buildServer(Connector ssl) throws UnknownHostException, Exception, InstantiationException, IllegalAccessException {
public Server buildServer() {
Server server = new Server();
Connector ssl = buildDefaultListener(server);
server.addConnector(ssl);
ServletHandler sh = new ServletHandler();
sh.addServletWithMapping(net.i2p.i2pcontrol.servlets.JSONRPC2Servlet.class, "/");
sh.addServletWithMapping(new ServletHolder(new JSONRPC2Servlet(_context, _secMan)), "/");
server.getServer().setHandler(sh);
server.start();
return server;
}
@ -134,24 +236,38 @@ public class I2PControlController {
* @param address - The address the listener will listen to.
* @param port - The port the listener will listen to.
* @return - Newly created listener
* @throws UnknownHostException
*/
public static SslSocketConnector buildSslListener(String address, int port) throws UnknownHostException {
private Connector buildSslListener(Server server, String address, int port) {
int listeners = 0;
if (_server != null) {
listeners = _server.getConnectors().length;
if (server != null) {
listeners = server.getConnectors().length;
}
SslSocketConnector ssl = new SslSocketConnector();
ssl.setProvider(_secMan.getSecurityProvider());
//ssl.setCipherSuites(_secMan.getSupprtedSSLCipherSuites()); Removed in Jetty 5->6 port.
// the keystore path and password
SslContextFactory sslFactory = new SslContextFactory(_ksp.getKeyStoreLocation());
sslFactory.setKeyStorePassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
// the X.509 cert password (if not present, verifyKeyStore() returned false)
sslFactory.setKeyManagerPassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
sslFactory.addExcludeProtocols(I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.size()]));
sslFactory.addExcludeCipherSuites(I2PSSLSocketFactory.EXCLUDE_CIPHERS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_CIPHERS.size()]));
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
httpConfig.setSecurePort(port);
httpConfig.addCustomizer(new SecureRequestCustomizer());
// number of acceptors, (default) number of selectors
ServerConnector ssl = new ServerConnector(server, 1, 0,
new SslConnectionFactory(sslFactory, "http/1.1"),
new HttpConnectionFactory(httpConfig));
ssl.setHost(address);
ssl.setPort(port);
ssl.setWantClientAuth(false); // Don't care about client authentication.
ssl.setPassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
ssl.setKeyPassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
ssl.setKeystoreType(KeyStore.getDefaultType());
ssl.setKeystore(KeyStoreProvider.getKeyStoreLocation());
ssl.setIdleTimeout(90*1000); // default 10 sec
// all with same name will use the same thread pool
//ssll.setName("ConsoleSocket");
ssl.setName("I2PControl");
ssl.setName("SSL Listener-" + ++listeners);
return ssl;
@ -166,36 +282,45 @@ public class I2PControlController {
* @param listener
* @throws Exception
*/
public static void replaceListener(Connector listener) throws Exception {
/****
public synchronized void replaceListener(Connector listener) throws Exception {
if (_server != null) {
stopServer();
}
_server = buildServer(listener);
}
****/
/**
* Get all listeners of the server.
* @return
*/
public static Connector[] getListeners() {
/****
public synchronized Connector[] getListeners() {
if (_server != null) {
return _server.getConnectors();
}
return new Connector[0];
}
****/
/**
* Removes all listeners
*/
public static void clearListeners() {
/****
public synchronized void clearListeners() {
if (_server != null) {
for (Connector listen : getListeners()) {
_server.removeConnector(listen);
}
}
}
****/
private static void stopServer()
/**
* Stop it
*/
private synchronized void stopServer()
{
try {
if (_server != null) {
@ -204,21 +329,18 @@ public class I2PControlController {
listener.stop();
}
_server.destroy();
_server = null;
}
} catch (Exception e) {
_log.error("Stopping server" + e);
_log.error("Stopping server", e);
}
}
private static void stop() {
ConfigurationManager.writeConfFile();
if (_secMan != null) {
_secMan.stopTimedEvents();
}
private synchronized void stop() {
_conf.writeConfFile();
_secMan.stopTimedEvents();
stopServer();
/****
// Get and stop all running threads
ThreadGroup threadgroup = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[threadgroup.activeCount() + 3];
@ -237,9 +359,10 @@ public class I2PControlController {
threadgroup.interrupt();
//Thread.currentThread().getThreadGroup().destroy();
****/
}
public static String getPluginDir() {
public String getPluginDir() {
return _pluginDir;
}
}

View File

@ -1,33 +0,0 @@
package net.i2p.i2pcontrol.router;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
/**
* Handle communications with the router instance.
* @author mathias
*
*/
public class RouterManager {
private final static Log _log = new Log(RouterManager.class);
private static I2PAppContext context = I2PAppContext.getCurrentContext();
private static boolean startedTestRouter = false;
private final static String I2P_DIR = "/home/hottuna/Apps/i2p/";
private final static String I2P_CONFIG_FILE = "/home/hottuna/.i2p/router.config";
public static I2PAppContext getAppContext() {
return context;
}
public static RouterContext getRouterContext() throws Exception {
// If not running as a plugin from within I2P.
if (context.isRouterContext()) {
return (RouterContext) context;
} else {
throw new Exception("No RouterContext available!");
}
}
}

View File

@ -11,8 +11,8 @@ public class AuthToken {
private String id;
private Date expiry;
public AuthToken(String password) {
_secMan = SecurityManager.getInstance();
public AuthToken(SecurityManager secMan, String password) {
_secMan = secMan;
String hash = _secMan.getPasswdHash(password);
this.id = _secMan.getHash(hash + Calendar.getInstance().getTimeInMillis());
Calendar expiry = Calendar.getInstance();

View File

@ -1,9 +1,13 @@
package net.i2p.i2pcontrol.security;
import net.i2p.crypto.KeyStoreUtil;
import net.i2p.i2pcontrol.I2PControlController;
import java.io.*;
import java.security.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@ -15,10 +19,14 @@ public class KeyStoreProvider {
public final static String DEFAULT_CERTIFICATE_ALIAS = "I2PControl CA";
public static final String DEFAULT_KEYSTORE_NAME = "key.store";
public static final String DEFAULT_KEYSTORE_PASSWORD = "nut'nfancy";
private static KeyStore _keystore = null;
private final String _pluginDir;
private KeyStore _keystore;
public KeyStoreProvider(String pluginDir) {
_pluginDir = pluginDir;
}
public static void initialize() {
public void initialize() {
KeyStoreUtil.createKeys(new File(getKeyStoreLocation()),
DEFAULT_KEYSTORE_PASSWORD,
DEFAULT_CERTIFICATE_ALIAS,
@ -30,6 +38,10 @@ public class KeyStoreProvider {
DEFAULT_KEYSTORE_PASSWORD);
}
/**
* @param password unused
* @return null on failure
*/
public static X509Certificate readCert(KeyStore ks, String certAlias, String password) {
try {
X509Certificate cert = (X509Certificate) ks.getCertificate(certAlias);
@ -51,6 +63,11 @@ public class KeyStoreProvider {
return null;
}
/**
* @param password for the keystore
* @return null on failure
*/
/****
public static X509Certificate readCert(File keyStoreFile, String certAlias, String password) {
try {
KeyStore ks = getDefaultKeyStore();
@ -81,7 +98,13 @@ public class KeyStoreProvider {
}
return null;
}
****/
/**
* @param password for the key
* @return null on failure, or throws RuntimeException...
*/
/****
public static PrivateKey readPrivateKey(KeyStore ks, String alias, String password) {
try {
// load the key entry from the keystore
@ -102,7 +125,12 @@ public class KeyStoreProvider {
}
return null;
}
****/
/**
* @return null on failure
*/
/****
public static PrivateKey readPrivateKey(String alias, File keyStoreFile, String keyStorePassword, String keyPassword) {
try {
KeyStore ks = getDefaultKeyStore();
@ -120,7 +148,12 @@ public class KeyStoreProvider {
}
return null;
}
****/
/**
* @return null on failure
*/
/****
public static KeyStore writeCACertToKeyStore(KeyStore keyStore, String keyPassword, String alias, PrivateKey caPrivKey, X509Certificate caCert) {
try {
X509Certificate[] chain = new X509Certificate[1];
@ -143,8 +176,12 @@ public class KeyStoreProvider {
}
return null;
}
****/
public static synchronized KeyStore getDefaultKeyStore() {
/**
* @return null on failure
*/
public synchronized KeyStore getDefaultKeyStore() {
if (_keystore == null) {
File keyStoreFile = new File(getKeyStoreLocation());
@ -157,7 +194,6 @@ public class KeyStoreProvider {
}
initialize();
_keystore = KeyStore.getInstance(KeyStore.getDefaultType());
if (keyStoreFile.exists()) {
InputStream is = new FileInputStream(keyStoreFile);
_keystore.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
@ -174,8 +210,8 @@ public class KeyStoreProvider {
}
}
public static String getKeyStoreLocation() {
File keyStoreFile = new File(I2PControlController.getPluginDir() + File.separator + DEFAULT_KEYSTORE_NAME);
public String getKeyStoreLocation() {
File keyStoreFile = new File(_pluginDir, DEFAULT_KEYSTORE_NAME);
return keyStoreFile.getAbsolutePath();
}
}

View File

@ -35,24 +35,16 @@ import java.util.*;
* Manage the password storing for I2PControl.
*/
public class SecurityManager {
private final static String SSL_PROVIDER = "SunJSSE";
private final static String DEFAULT_AUTH_BCRYPT_SALT = "$2a$11$5aOLx2x/8i4fNaitoCSSWu";
private final static String DEFAULT_AUTH_PASSWORD = "$2a$11$5aOLx2x/8i4fNaitoCSSWuut2wEl3Hupuca8DCT.NXzvH9fq1pBU.";
private HashMap<String, AuthToken> authTokens;
private Timer timer;
private String[] SSL_CIPHER_SUITES;
private KeyStore _ks;
private Log _log;
private static SecurityManager _securityManager;
private final HashMap<String, AuthToken> authTokens;
private final Timer timer;
private final KeyStore _ks;
private final Log _log;
private final ConfigurationManager _conf;
public static SecurityManager getInstance() {
if (_securityManager == null) {
_securityManager = new SecurityManager();
}
return _securityManager;
}
private SecurityManager() {
public SecurityManager(KeyStoreProvider ksp, ConfigurationManager conf) {
_conf = conf;
_log = I2PAppContext.getGlobalContext().logManager().getLog(SecurityManager.class);
authTokens = new HashMap<String, AuthToken>();
@ -60,23 +52,7 @@ public class SecurityManager {
// Start running periodic task after 20 minutes, run periodically every 10th minute.
timer.scheduleAtFixedRate(new Sweeper(), 1000 * 60 * 20, 1000 * 60 * 10);
// Get supported SSL cipher suites.
SocketFactory SSLF = SSLSocketFactory.getDefault();
try {
SSL_CIPHER_SUITES = ((SSLSocket)SSLF.createSocket()).getSupportedCipherSuites();
} catch (Exception e) {
_log.log(Log.CRIT, "Unable to create SSLSocket used for fetching supported ssl cipher suites.", e);
}
_ks = KeyStoreProvider.getDefaultKeyStore();
}
public String[] getSupprtedSSLCipherSuites() {
return SSL_CIPHER_SUITES;
}
public String getSecurityProvider() {
return SSL_PROVIDER;
_ks = ksp.getDefaultKeyStore();
}
public void stopTimedEvents() {
@ -116,7 +92,7 @@ public class SecurityManager {
* @return BCrypt hash of salt and input string
*/
public String getPasswdHash(String pwd) {
return BCrypt.hashpw(pwd, ConfigurationManager.getInstance().getConf("auth.salt", DEFAULT_AUTH_BCRYPT_SALT));
return BCrypt.hashpw(pwd, _conf.getConf("auth.salt", DEFAULT_AUTH_BCRYPT_SALT));
}
/**
@ -138,9 +114,9 @@ public class SecurityManager {
* @return Returns AuthToken if password is valid. If password is invalid null will be returned.
*/
public AuthToken validatePasswd(String pwd) {
String storedPass = ConfigurationManager.getInstance().getConf("auth.password", DEFAULT_AUTH_PASSWORD);
String storedPass = _conf.getConf("auth.password", DEFAULT_AUTH_PASSWORD);
if (getPasswdHash(pwd).equals(storedPass)) {
AuthToken token = new AuthToken(pwd);
AuthToken token = new AuthToken(this, pwd);
synchronized (authTokens) {
authTokens.put(token.getId(), token);
}
@ -157,10 +133,10 @@ public class SecurityManager {
*/
public boolean setPasswd(String newPasswd) {
String newHash = getPasswdHash(newPasswd);
String oldHash = ConfigurationManager.getInstance().getConf("auth.password", DEFAULT_AUTH_PASSWORD);
String oldHash = _conf.getConf("auth.password", DEFAULT_AUTH_PASSWORD);
if (!newHash.equals(oldHash)) {
ConfigurationManager.getInstance().setConf("auth.password", newHash);
_conf.setConf("auth.password", newHash);
synchronized (authTokens) {
authTokens.clear();
}

View File

@ -18,17 +18,27 @@ package net.i2p.i2pcontrol.servlets;
import com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.Dispatcher;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.i2pcontrol.I2PControlVersion;
import net.i2p.i2pcontrol.servlets.jsonrpc2handlers.*;
import net.i2p.util.Log;
import net.i2p.i2pcontrol.security.SecurityManager;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
/**
@ -38,25 +48,33 @@ public class JSONRPC2Servlet extends HttpServlet {
private static final long serialVersionUID = -45075606818515212L;
private static final int BUFFER_LENGTH = 2048;
private static Dispatcher disp;
private static char[] readBuffer;
private static Log _log;
private Dispatcher disp;
private Log _log;
private final SecurityManager _secMan;
private final JSONRPC2Helper _helper;
private final RouterContext _context;
public JSONRPC2Servlet(RouterContext ctx, SecurityManager secMan) {
_context = ctx;
_secMan = secMan;
_helper = new JSONRPC2Helper(_secMan);
if (ctx != null)
_log = ctx.logManager().getLog(JSONRPC2Servlet.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(JSONRPC2Servlet.class);
}
@Override
public void init() {
_log = I2PAppContext.getGlobalContext().logManager().getLog(JSONRPC2Servlet.class);
readBuffer = new char[BUFFER_LENGTH];
disp = new Dispatcher();
disp.register(new EchoHandler());
disp.register(new GetRateHandler());
disp.register(new AuthenticateHandler());
disp.register(new NetworkSettingHandler());
disp.register(new RouterInfoHandler());
disp.register(new RouterManagerHandler());
disp.register(new I2PControlHandler());
disp.register(new AdvancedSettingsHandler());
disp.register(new EchoHandler(_helper));
disp.register(new GetRateHandler(_helper));
disp.register(new AuthenticateHandler(_helper, _secMan));
disp.register(new NetworkSettingHandler(_context, _helper));
disp.register(new RouterInfoHandler(_context, _helper));
disp.register(new RouterManagerHandler(_context, _helper));
disp.register(new I2PControlHandler(_context, _helper));
disp.register(new AdvancedSettingsHandler(_context, _helper));
}
@Override
@ -80,12 +98,15 @@ public class JSONRPC2Servlet extends HttpServlet {
if (msg instanceof JSONRPC2Request) {
jsonResp = disp.dispatch((JSONRPC2Request)msg, null);
jsonResp.toJSON().put("API", I2PControlVersion.API_VERSION);
_log.debug("Request: " + msg);
_log.debug("Response: " + jsonResp);
if (_log.shouldDebug()) {
_log.debug("Request: " + msg);
_log.debug("Response: " + jsonResp);
}
}
else if (msg instanceof JSONRPC2Notification) {
disp.dispatch((JSONRPC2Notification)msg, null);
_log.debug("Notification: " + msg);
if (_log.shouldDebug())
_log.debug("Notification: " + msg);
}
out.println(jsonResp);
@ -99,6 +120,7 @@ public class JSONRPC2Servlet extends HttpServlet {
Writer writer = new StringWriter();
BufferedReader reader = new BufferedReader(new InputStreamReader(sis, "UTF-8"));
char[] readBuffer = new char[BUFFER_LENGTH];
int n;
while ((n = reader.read(readBuffer)) != -1) {
writer.write(readBuffer, 0, n);

View File

@ -2,8 +2,15 @@ package net.i2p.i2pcontrol.servlets.configuration;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
import net.i2p.util.SecureFileOutputStream;
import java.io.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@ -16,44 +23,30 @@ import java.util.TreeMap;
*
*/
public class ConfigurationManager {
private static String configLocation = "I2PControl.conf";
private static boolean configLocationModified = false;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ConfigurationManager.class);
private final String CONFIG_FILE = "I2PControl.conf";
private final String configLocation;
private final Log _log;
private static ConfigurationManager instance;
private ConfigurationManager instance;
//Configurations with a String as value
private static Map<String, String> stringConfigurations = new HashMap<String, String>();
private final Map<String, String> stringConfigurations = new HashMap<String, String>();
//Configurations with a Boolean as value
private static Map<String, Boolean> booleanConfigurations = new HashMap<String, Boolean>();
private final Map<String, Boolean> booleanConfigurations = new HashMap<String, Boolean>();
//Configurations with an Integer as value
private static Map<String, Integer> integerConfigurations = new HashMap<String, Integer>();
private final Map<String, Integer> integerConfigurations = new HashMap<String, Integer>();
/**
* Should only be set before getInstance is first called.
* @param dir
*/
public static void setConfDir(String dir) {
if (!configLocationModified) {
if (dir.endsWith("/")) {
configLocation = dir + configLocation;
} else {
configLocation = dir + "/" + configLocation;
}
public ConfigurationManager(String dir) {
_log = I2PAppContext.getGlobalContext().logManager().getLog(ConfigurationManager.class);
if (dir.endsWith("/")) {
configLocation = dir + CONFIG_FILE;
} else {
configLocation = dir + "/" + CONFIG_FILE;
}
}
private ConfigurationManager() {
readConfFile();
}
public synchronized static ConfigurationManager getInstance() {
if (instance == null) {
instance = new ConfigurationManager();
}
return instance;
}
/**
* Collects settingNameuments of the form --word, --word=otherword and -blah
* to determine user parameters.
@ -71,7 +64,7 @@ public class ConfigurationManager {
/**
* Reads configuration from file itoopie.conf, every line is parsed as key=value.
*/
public static void readConfFile() {
public void readConfFile() {
try {
BufferedReader br = new BufferedReader(new FileReader(configLocation));
String input;
@ -89,7 +82,7 @@ public class ConfigurationManager {
/**
* Write configuration into default config file.
*/
public static void writeConfFile() {
public void writeConfFile() {
TreeMap<String, String> tree = new TreeMap<String, String>();
for (Entry<String, String> e : stringConfigurations.entrySet()) {
tree.put(e.getKey(), e.getValue());
@ -101,7 +94,7 @@ public class ConfigurationManager {
tree.put(e.getKey(), e.getValue().toString());
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(configLocation));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(configLocation)));
for (Entry<String, String> e : tree.entrySet()) {
bw.write(e.getKey() + "=" + e.getValue() + "\r\n");
}
@ -116,7 +109,7 @@ public class ConfigurationManager {
* where value will (in order) be parsed as integer/boolean/string.
* @param str
*/
public static void parseConfigStr(String str) {
public void parseConfigStr(String str) {
int eqIndex = str.indexOf('=');
if (eqIndex != -1) {
String key = str.substring(0, eqIndex).trim().toLowerCase();

View File

@ -7,7 +7,6 @@ import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.i2pcontrol.router.RouterManager;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
@ -18,18 +17,20 @@ import java.util.Set;
public class AdvancedSettingsHandler implements RequestHandler {
private static RouterContext _context;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(AdvancedSettingsHandler.class);
private final RouterContext _context;
private final Log _log;
private final JSONRPC2Helper _helper;
private static final String[] requiredArgs = {};
static {
try {
_context = RouterManager.getRouterContext();
} catch (Exception e) {
_log.error("Unable to initialize RouterContext.", e);
}
public AdvancedSettingsHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
if (ctx != null)
_log = ctx.logManager().getLog(AdvancedSettingsHandler.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(AdvancedSettingsHandler.class);
}
private String[] requiredArgs = {};
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"AdvancedSettings"};
@ -39,11 +40,18 @@ public class AdvancedSettingsHandler implements RequestHandler {
@SuppressWarnings("unchecked")
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("AdvancedSettings")) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(requiredArgs, req);
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null) {
return new JSONRPC2Response(err, req.getID());
}
if (_context == null) {
return new JSONRPC2Response(new JSONRPC2Error(
JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
@SuppressWarnings("rawtypes")
HashMap inParams = (HashMap) req.getParams();
Map outParams = new HashMap();

View File

@ -31,7 +31,15 @@ import java.util.Map;
public class AuthenticateHandler implements RequestHandler {
private String[] requiredArgs = {"Password", "API"};
private static final String[] requiredArgs = {"Password", "API"};
private final JSONRPC2Helper _helper;
private final SecurityManager _secMan;
public AuthenticateHandler(JSONRPC2Helper helper, SecurityManager secMan) {
_helper = helper;
_secMan = secMan;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"Authenticate"};
@ -40,7 +48,7 @@ public class AuthenticateHandler implements RequestHandler {
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("Authenticate")) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(requiredArgs, req, JSONRPC2Helper.USE_NO_AUTH);
JSONRPC2Error err = _helper.validateParams(requiredArgs, req, JSONRPC2Helper.USE_NO_AUTH);
if (err != null)
return new JSONRPC2Response(err, req.getID());
@ -50,7 +58,7 @@ public class AuthenticateHandler implements RequestHandler {
// Try get an AuthToken
AuthToken token = SecurityManager.getInstance().validatePasswd(pwd);
AuthToken token = _secMan.validatePasswd(pwd);
if (token == null) {
return new JSONRPC2Response(JSONRPC2ExtendedError.INVALID_PASSWORD, req.getID());
}

View File

@ -11,7 +11,13 @@ import java.util.Map;
public class EchoHandler implements RequestHandler {
private String[] requiredArgs = {"Echo"};
private static final String[] requiredArgs = {"Echo"};
private final JSONRPC2Helper _helper;
public EchoHandler(JSONRPC2Helper helper) {
_helper = helper;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"Echo"};
@ -20,7 +26,7 @@ public class EchoHandler implements RequestHandler {
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("Echo")) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(requiredArgs, req);
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());

View File

@ -31,7 +31,13 @@ import java.util.Map;
public class GetRateHandler implements RequestHandler {
private String[] requiredArgs = {"Stat", "Period"};
private static final String[] requiredArgs = {"Stat", "Period"};
private final JSONRPC2Helper _helper;
public GetRateHandler(JSONRPC2Helper helper) {
_helper = helper;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"GetRate"};
@ -40,7 +46,7 @@ public class GetRateHandler implements RequestHandler {
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("GetRate")) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(requiredArgs, req);
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());

View File

@ -5,14 +5,13 @@ import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.i2pcontrol.I2PControlController;
import net.i2p.i2pcontrol.router.RouterManager;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import java.net.InetAddress;
import java.net.UnknownHostException;
@ -37,20 +36,24 @@ import java.util.Map;
*/
public class I2PControlHandler implements RequestHandler {
private static final int BW_BURST_PCT = 110;
private static final int BW_BURST_TIME = 20;
private static RouterContext _context;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PControlHandler.class);
private static final ConfigurationManager _conf = ConfigurationManager.getInstance();
private final RouterContext _context;
private final Log _log;
//private final ConfigurationManager _conf;
private final JSONRPC2Helper _helper;
static {
try {
_context = RouterManager.getRouterContext();
} catch (Exception e) {
_log.error("Unable to initialize RouterContext.", e);
}
public I2PControlHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
if (ctx != null)
_log = ctx.logManager().getLog(I2PControlHandler.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(I2PControlHandler.class);
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"I2PControl"};
@ -59,7 +62,8 @@ public class I2PControlHandler implements RequestHandler {
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("I2PControl")) {
return process(req);
//return process(req);
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
@ -67,8 +71,9 @@ public class I2PControlHandler implements RequestHandler {
}
/****
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(null, req);
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
@ -191,4 +196,5 @@ public class I2PControlHandler implements RequestHandler {
outParams.put("RestartNeeded", restartNeeded);
return new JSONRPC2Response(outParams, req.getID());
}
****/
}

View File

@ -30,6 +30,12 @@ public class JSONRPC2Helper {
public final static Boolean USE_NO_AUTH = false;
public final static Boolean USE_AUTH = true;
private final SecurityManager _secMan;
public JSONRPC2Helper(SecurityManager secMan) {
_secMan = secMan;
}
/**
* Check incoming request for required arguments, to make sure they are valid.
* @param requiredArgs - Array of names of required arguments. If null don't check for any parameters.
@ -37,7 +43,7 @@ public class JSONRPC2Helper {
* @param useAuth - If true, will validate authentication token.
* @return - null if no errors were found. Corresponding JSONRPC2Error if error is found.
*/
public static JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req, Boolean useAuth) {
public JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req, Boolean useAuth) {
// Error on unnamed parameters
if (req.getParamsType() != JSONRPC2ParamsType.OBJECT) {
@ -75,7 +81,7 @@ public class JSONRPC2Helper {
* @param req - Incoming JSONRPC2 request
* @return - null if no errors were found. Corresponding JSONRPC2Error if error is found.
*/
public static JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req) {
public JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req) {
return validateParams(requiredArgs, req, JSONRPC2Helper.USE_AUTH);
}
@ -86,13 +92,13 @@ public class JSONRPC2Helper {
* @param req - Parameters of incoming request
* @return null if everything is fine, JSONRPC2Error for any corresponding error.
*/
private static JSONRPC2Error validateToken(HashMap params) {
private JSONRPC2Error validateToken(HashMap params) {
String tokenID = (String) params.get("Token");
if (tokenID == null) {
return JSONRPC2ExtendedError.NO_TOKEN;
}
try {
SecurityManager.getInstance().verifyToken(tokenID);
_secMan.verifyToken(tokenID);
} catch (InvalidAuthTokenException e) {
return JSONRPC2ExtendedError.INVALID_TOKEN;
} catch (ExpiredAuthTokenException e) {

View File

@ -7,7 +7,6 @@ import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.i2pcontrol.router.RouterManager;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.transport.FIFOBandwidthRefiller;
@ -41,15 +40,12 @@ import java.util.Map;
public class NetworkSettingHandler implements RequestHandler {
private static final int BW_BURST_PCT = 110;
private static final int BW_BURST_TIME = 20;
private static RouterContext _context;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(NetworkSettingHandler.class);
private final JSONRPC2Helper _helper;
private final RouterContext _context;
static {
try {
_context = RouterManager.getRouterContext();
} catch (Exception e) {
_log.error("Unable to initialize RouterContext.", e);
}
public NetworkSettingHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
@ -69,7 +65,7 @@ public class NetworkSettingHandler implements RequestHandler {
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(null, req);
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());

View File

@ -5,9 +5,9 @@ import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.data.router.RouterAddress;
import net.i2p.i2pcontrol.router.RouterManager;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
@ -15,7 +15,6 @@ import net.i2p.router.RouterVersion;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.transport.TransportUtil;
import net.i2p.router.transport.ntcp.NTCPTransport;
import net.i2p.util.Log;
import java.util.HashMap;
import java.util.Map;
@ -38,17 +37,15 @@ import java.util.Map;
*/
public class RouterInfoHandler implements RequestHandler {
private static RouterContext _context;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(RouterInfoHandler.class);
private final JSONRPC2Helper _helper;
private final RouterContext _context;
static {
try {
_context = RouterManager.getRouterContext();
} catch (Exception e) {
_log.error("Unable to initialize RouterContext.", e);
}
public RouterInfoHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] { "RouterInfo" };
@ -67,7 +64,7 @@ public class RouterInfoHandler implements RequestHandler {
@SuppressWarnings("unchecked")
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(null, req);
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());

View File

@ -5,6 +5,7 @@ import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.i2pcontrol.router.RouterManager;
@ -14,6 +15,7 @@ import net.i2p.router.networkdb.reseed.ReseedChecker;
import net.i2p.update.UpdateManager;
import net.i2p.update.UpdateType;
import net.i2p.util.Log;
import org.tanukisoftware.wrapper.WrapperManager;
import java.util.HashMap;
@ -37,17 +39,15 @@ import java.util.Map;
*/
public class RouterManagerHandler implements RequestHandler {
private static RouterContext _context;
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(RouterManagerHandler.class);
private final JSONRPC2Helper _helper;
private final RouterContext _context;
private final static int SHUTDOWN_WAIT = 1500;
static {
try {
_context = RouterManager.getRouterContext();
} catch (Exception e) {
_log.error("Unable to initialize RouterContext.", e);
}
public RouterManagerHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
@ -67,7 +67,7 @@ public class RouterManagerHandler implements RequestHandler {
}
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = JSONRPC2Helper.validateParams(null, req);
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());