Files
i2p.plugins.i2pcontrol/src/java/net/i2p/i2pcontrol/servlets/JSONRPC2Servlet.java
2018-02-06 14:36:31 +00:00

246 lines
9.6 KiB
Java

package net.i2p.i2pcontrol.servlets;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
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.util.PortMapper;
import net.i2p.i2pcontrol.I2PControlVersion;
import net.i2p.i2pcontrol.security.KeyStoreProvider;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.jsonrpc2handlers.*;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
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.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
/**
* Provide an JSON-RPC 2.0 API for remote controlling of I2P
*/
public class JSONRPC2Servlet extends HttpServlet {
private static final long serialVersionUID = -45075606818515212L;
private static final int BUFFER_LENGTH = 2048;
private static final String SVC_HTTP_I2PCONTROL = "http_i2pcontrol";
private static final String SVC_HTTPS_I2PCONTROL = "https_i2pcontrol";
private Dispatcher disp;
private Log _log;
private final SecurityManager _secMan;
private final ConfigurationManager _conf;
private final JSONRPC2Helper _helper;
private final RouterContext _context;
private final boolean _isWebapp;
private boolean _isHTTP, _isHTTPS;
/**
* Webapp
*/
public JSONRPC2Servlet() {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (!ctx.isRouterContext())
throw new IllegalStateException();
_context = (RouterContext) ctx;
File appDir = ctx.getAppDir();
_conf = new ConfigurationManager(ctx, appDir, false);
// we don't really need a keystore
//File ksDir = new File(ctx.getConfigDir(), "keystore");
//ksDir.mkDir();
//KeyStoreProvider ksp = new KeyStoreProvider(ksDir.getAbsolutePath());
//_secMan = new SecurityManager(ctx, ksp, _conf);
_secMan = new SecurityManager(ctx, null, _conf);
_helper = new JSONRPC2Helper(_secMan);
_log = ctx.logManager().getLog(JSONRPC2Servlet.class);
_conf.writeConfFile();
_isWebapp = true;
}
/**
* Plugin
*/
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);
_conf = null;
_isWebapp = false;
}
@Override
public void init() throws ServletException {
super.init();
disp = new Dispatcher();
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, _secMan));
disp.register(new AdvancedSettingsHandler(_context, _helper));
if (_isWebapp) {
PortMapper pm = _context.portMapper();
int port = pm.getPort(PortMapper.SVC_CONSOLE);
if (port > 0) {
String host = pm.getHost(PortMapper.SVC_CONSOLE, "127.0.0.1");
pm.register(SVC_HTTP_I2PCONTROL, host, port);
_isHTTP = true;
}
port = pm.getPort(PortMapper.SVC_HTTPS_CONSOLE);
if (port > 0) {
String host = pm.getHost(PortMapper.SVC_HTTPS_CONSOLE, "127.0.0.1");
pm.register(SVC_HTTPS_I2PCONTROL, host, port);
_isHTTPS = true;
}
}
}
@Override
public void destroy() {
if (_isWebapp) {
PortMapper pm = _context.portMapper();
if (_isHTTP)
pm.unregister(SVC_HTTP_I2PCONTROL);
if (_isHTTPS)
pm.unregister(SVC_HTTPS_I2PCONTROL);
_secMan.stopTimedEvents();
_conf.writeConfFile();
}
super.destroy();
}
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
httpServletResponse.setContentType("text/html");
PrintWriter out = httpServletResponse.getWriter();
out.println("<p>I2PControl RPC Service version " + I2PControlVersion.VERSION + " : Running");
if ("/password".equals(httpServletRequest.getServletPath())) {
out.println("<form method=\"POST\" action=\"password\">");
if (_secMan.isDefaultPasswordValid()) {
out.println("<p>The current API password is the default, \"" + _secMan.DEFAULT_AUTH_PASSWORD + "\". You should change it.");
} else {
out.println("<p>Current API password:<input name=\"password\" type=\"password\">");
}
out.println("<p>New API password (twice):<input name=\"password2\" type=\"password\">" +
"<input name=\"password3\" type=\"password\">" +
"<input name=\"save\" type=\"submit\" value=\"Change API Password\">" +
"<p>If you forget the API password, stop i2pcontrol, delete the file <tt>" + _conf.getConfFile() +
"</tt>, and restart i2pcontrol.");
} else {
out.println("<p><a href=\"password\">Change API Password</a>");
}
out.close();
}
/** @since 0.12 */
private void doPasswordChange(HttpServletRequest req, HttpServletResponse httpServletResponse) throws ServletException, IOException {
httpServletResponse.setContentType("text/html");
PrintWriter out = httpServletResponse.getWriter();
String pw = req.getParameter("password");
if (pw == null)
pw = _secMan.DEFAULT_AUTH_PASSWORD;
else
pw = pw.trim();
String pw2 = req.getParameter("password2");
String pw3 = req.getParameter("password3");
if (pw2 == null || pw3 == null) {
out.println("<p>Enter new password twice!");
} else {
pw2 = pw2.trim();
pw3 = pw3.trim();
if (!pw2.equals(pw3)) {
out.println("<p>New passwords don't match!");
} else if (pw2.length() <= 0) {
out.println("<p>Enter new password twice!");
} else if (_secMan.isValid(pw)) {
_secMan.setPasswd(pw2);
out.println("<p>API Password changed");
} else {
out.println("<p>Incorrect old password, not changed");
}
}
out.println("<p><a href=\"password\">Change API Password</a>");
}
@Override
protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
if ("/password".equals(httpServletRequest.getServletPath())) {
doPasswordChange(httpServletRequest, httpServletResponse);
return;
}
String req = getRequest(httpServletRequest.getInputStream());
httpServletResponse.setContentType("application/json");
PrintWriter out = httpServletResponse.getWriter();
JSONRPC2Message msg = null;
JSONRPC2Response jsonResp = null;
try {
msg = JSONRPC2Message.parse(req);
if (msg instanceof JSONRPC2Request) {
jsonResp = disp.process((JSONRPC2Request)msg, null);
jsonResp.toJSONObject().put("API", I2PControlVersion.API_VERSION);
if (_log.shouldDebug()) {
_log.debug("Request: " + msg);
_log.debug("Response: " + jsonResp);
}
}
else if (msg instanceof JSONRPC2Notification) {
disp.process((JSONRPC2Notification)msg, null);
if (_log.shouldDebug())
_log.debug("Notification: " + msg);
}
out.println(jsonResp);
out.close();
} catch (JSONRPC2ParseException e) {
_log.error("Unable to parse JSONRPC2Message: " + e.getMessage());
}
}
private String getRequest(ServletInputStream sis) throws IOException {
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);
}
return writer.toString();
}
}