Bundle I2PControl 0.12, as a console webapp

Includes mods to use org.json.simple package.
See licenses/LICENSE-Apache2.0.txt
Includes jBCrypt:
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
See licenses/LICENSE-jBCrypt.txt
Includes jsonrpc2 libs:
See licenses/LICENSE-Apache2.0.txt
http://software.dzhuvinov.com/json-rpc-2.0-server.html
Jars from maven central:
jsonrpc2-base-1.38.1-sources.jar  22-Oct-2017
jsonrpc2-server-1.11-sources.jar  16-Mar-2015
This commit is contained in:
zzz
2018-11-25 13:26:43 +00:00
parent d6e350184c
commit d4caafb592
44 changed files with 10640 additions and 1 deletions

View File

@@ -0,0 +1,263 @@
package com.thetransactioncompany.jsonrpc2.server;
import java.util.Hashtable;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Notification;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
/**
* Dispatcher for JSON-RPC 2.0 requests and notifications. This class is
* tread-safe.
*
* <p>Use the {@code register()} methods to add a request or notification
* handler for an RPC method.
*
* <p>Use the {@code process()} methods to have an incoming request or
* notification processed by the matching handler.
*
* <p>The {@code reportProcTime()} method enables reporting of request
* processing time (in microseconds) by appending a non-standard "xProcTime"
* attribute to the resulting JSON-RPC 2.0 response message.
*
* <p>Example:
*
* <pre>
* {
* "result" : "xyz",
* "id" : 1,
* "jsonrpc" : "2.0",
* "xProcTime" : "189 us"
* }
* </pre>
*
* <p>Note: The dispatch(...) methods were deprecated in version 1.7. Use
* process(...) instead.
*
* @author Vladimir Dzhuvinov
*/
public class Dispatcher implements RequestHandler, NotificationHandler {
/**
* Hashtable of request name / handler pairs.
*/
private final Hashtable<String,RequestHandler> requestHandlers;
/**
* Hashtable of notification name / handler pairs.
*/
private final Hashtable<String,NotificationHandler> notificationHandlers;
/**
* Controls reporting of request processing time by appending a
* non-standard "xProcTime" attribute to the JSON-RPC 2.0 response.
*/
private boolean reportProcTime = false;
/**
* Creates a new dispatcher with no registered handlers.
*/
public Dispatcher() {
requestHandlers = new Hashtable<String,RequestHandler>();
notificationHandlers = new Hashtable<String,NotificationHandler>();
}
/**
* Registers a new JSON-RPC 2.0 request handler.
*
* @param handler The request handler to register. Must not be
* {@code null}.
*
* @throws IllegalArgumentException On attempting to register a handler
* that duplicates an existing request
* name.
*/
public void register(final RequestHandler handler) {
for (String name: handler.handledRequests()) {
if (requestHandlers.containsKey(name))
throw new IllegalArgumentException("Cannot register a duplicate JSON-RPC 2.0 handler for request " + name);
requestHandlers.put(name, handler);
}
}
/**
* Registers a new JSON-RPC 2.0 notification handler.
*
* @param handler The notification handler to register. Must not be
* {@code null}.
*
* @throws IllegalArgumentException On attempting to register a handler
* that duplicates an existing
* notification name.
*/
public void register(final NotificationHandler handler) {
for (String name: handler.handledNotifications()) {
if (notificationHandlers.containsKey(name))
throw new IllegalArgumentException("Cannot register a duplicate JSON-RPC 2.0 handler for notification " + name);
notificationHandlers.put(name, handler);
}
}
@Override
public String[] handledRequests() {
java.util.Set<String> var = requestHandlers.keySet();
return var.toArray(new String[var.size()]);
}
@Override
public String[] handledNotifications() {
java.util.Set<String> var = notificationHandlers.keySet();
return var.toArray(new String[var.size()]);
}
/**
* Gets the handler for the specified JSON-RPC 2.0 request name.
*
* @param requestName The request name to lookup.
*
* @return The corresponding request handler or {@code null} if none
* was found.
*/
public RequestHandler getRequestHandler(final String requestName) {
return requestHandlers.get(requestName);
}
/**
* Gets the handler for the specified JSON-RPC 2.0 notification name.
*
* @param notificationName The notification name to lookup.
*
* @return The corresponding notification handler or {@code null} if
* none was found.
*/
public NotificationHandler getNotificationHandler(final String notificationName) {
return notificationHandlers.get(notificationName);
}
/**
* @deprecated
*/
public JSONRPC2Response dispatch(final JSONRPC2Request request, final MessageContext requestCtx) {
return process(request, requestCtx);
}
@Override
public JSONRPC2Response process(final JSONRPC2Request request, final MessageContext requestCtx) {
long startNanosec = 0;
// Measure request processing time?
if (reportProcTime)
startNanosec = System.nanoTime();
final String method = request.getMethod();
RequestHandler handler = getRequestHandler(method);
if (handler == null) {
// We didn't find a handler for the requested RPC
Object id = request.getID();
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, id);
}
// Process the request
JSONRPC2Response response = handler.process(request, requestCtx);
if (reportProcTime) {
final long procTimeNanosec = System.nanoTime() - startNanosec;
response.appendNonStdAttribute("xProcTime", procTimeNanosec / 1000 + " us");
}
return response;
}
/**
* @deprecated
*/
public void dispatch(final JSONRPC2Notification notification, final MessageContext notificationCtx) {
process(notification, notificationCtx);
}
@Override
public void process(final JSONRPC2Notification notification, final MessageContext notificationCtx) {
final String method = notification.getMethod();
NotificationHandler handler = getNotificationHandler(method);
if (handler == null) {
// We didn't find a handler for the requested RPC
return;
}
// Process the notification
handler.process(notification, notificationCtx);
}
/**
* Controls reporting of request processing time by appending a
* non-standard "xProcTime" attribute to the JSON-RPC 2.0 response.
* Reporting is disabled by default.
*
* @param enable {@code true} to enable proccessing time reporting,
* {@code false} to disable it.
*/
public void reportProcTime(final boolean enable) {
reportProcTime = enable;
}
/**
* Returns {@code true} if reporting of request processing time is
* enabled. See the {@link #reportProcTime} description for more
* information.
*
* @return {@code true} if reporting of request processing time is
* enabled, else {@code false}.
*/
public boolean reportsProcTime() {
return reportProcTime;
}
}

View File

@@ -0,0 +1,428 @@
package com.thetransactioncompany.jsonrpc2.server;
import java.net.InetAddress;
import java.net.URLConnection;
import java.security.Principal;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
/**
* Context information about JSON-RPC 2.0 request and notification messages.
* This class is immutable.
*
* <ul>
* <li>The client's host name.
* <li>The client's IP address.
* <li>Whether the request / notification was transmitted securely (e.g.
* via HTTPS).
* <li>The client principal(s) (user), if authenticated.
* </ul>
*
* @author Vladimir Dzhuvinov
*/
public class MessageContext {
/**
* The client hostname, {@code null} if none was specified.
*/
private String clientHostName = null;
/**
* The client IP address, {@code null} if none was specified.
*/
private String clientInetAddress = null;
/**
* Indicates whether the request was received over a secure channel
* (typically HTTPS).
*/
private boolean secure = false;
/**
* The authenticated client principals, {@code null} if none were
* specified.
*/
private Principal[] principals = null;
/**
* Minimal implementation of the {@link java.security.Principal}
* interface.
*/
public class BasicPrincipal implements Principal {
/**
* The principal name.
*/
private String name;
/**
* Creates a new principal.
*
* @param name The principal name, must not be {@code null} or
* empty string.
*
* @throws IllegalArgumentException On a {@code null} or empty
* principal name.
*/
public BasicPrincipal(final String name) {
if (name == null || name.trim().isEmpty())
throw new IllegalArgumentException("The principal name must be defined");
this.name = name;
}
/**
* Checks for equality.
*
* @param another The object to compare to.
*/
public boolean equals(final Object another) {
return another != null &&
another instanceof Principal &&
((Principal)another).getName().equals(this.getName());
}
/**
* Returns a hash code for this principal.
*
* @return The hash code.
*/
public int hashCode() {
return getName().hashCode();
}
/**
* Returns the principal name.
*
* @return The principal name.
*/
public String getName() {
return name;
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
* @param principalName Specifies the authenticated client principle
* name, {@code null} if unknown. The name must
* not be an empty or blank string.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure,
final String principalName) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
if (principalName != null) {
principals = new Principal[1];
principals[0] = new BasicPrincipal(principalName);
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
* @param principalNames Specifies the authenticated client principle
* names, {@code null} if unknown. The names
* must not be an empty or blank string.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure,
final String[] principalNames) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
if (principalNames != null) {
principals = new Principal[principalNames.length];
for (int i=0; i < principals.length; i++)
principals[0] = new BasicPrincipal(principalNames[i]);
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. No
* authenticated client principal is specified.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. Indicates
* an insecure transport (plain HTTP) and no authenticated client
* principal.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = false;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. Indicates
* an insecure transport (plain HTTP) and no authenticated client
* principal. Not client host name / IP is specified.
*/
public MessageContext() {
this.secure = false;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context from the
* specified HTTP request.
*
* @param httpRequest The HTTP request.
*/
public MessageContext(final HttpServletRequest httpRequest) {
clientInetAddress = httpRequest.getRemoteAddr();
clientHostName = httpRequest.getRemoteHost();
if (clientHostName != null && clientHostName.equals(clientInetAddress))
clientHostName = null; // not resolved actually
secure = httpRequest.isSecure();
X509Certificate[] certs = (X509Certificate[])httpRequest.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null && certs.length > 0) {
principals = new Principal[certs.length];
for (int i=0; i < principals.length; i++)
principals[i] = certs[i].getSubjectX500Principal();
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context from the
* specified URL connection. Use this constructor in cases when the
* HTTP server is the origin of the JSON-RPC 2.0 requests /
* notifications. If the IP address of the HTTP server cannot be
* resolved {@link #getClientInetAddress} will return {@code null}.
*
* @param connection The URL connection, must be established and not
* {@code null}.
*/
public MessageContext(final URLConnection connection) {
clientHostName = connection.getURL().getHost();
InetAddress ip = null;
if (clientHostName != null) {
try {
ip = InetAddress.getByName(clientHostName);
} catch (Exception e) {
// UnknownHostException, SecurityException
// ignore
}
}
if (ip != null)
clientInetAddress = ip.getHostAddress();
if (connection instanceof HttpsURLConnection) {
secure = true;
HttpsURLConnection httpsConnection = (HttpsURLConnection)connection;
Principal prn = null;
try {
prn = httpsConnection.getPeerPrincipal();
} catch (Exception e) {
// SSLPeerUnverifiedException, IllegalStateException
// ignore
}
if (prn != null) {
principals = new Principal[1];
principals[0] = prn;
}
}
}
/**
* Gets the host name of the client that sent the request /
* notification.
*
* @return The client host name, {@code null} if unknown.
*/
public String getClientHostName() {
return clientHostName;
}
/**
* Gets the IP address of the client that sent the request /
* notification.
*
* @return The client IP address, {@code null} if unknown.
*/
public String getClientInetAddress() {
return clientInetAddress;
}
/**
* Indicates whether the request / notification was received over a
* secure HTTPS connection.
*
* @return {@code true} If the request was received over HTTPS,
* {@code false} if it was received over plain HTTP.
*/
public boolean isSecure() {
return secure;
}
/**
* Returns the first authenticated client principal, {@code null} if
* none.
*
* @return The first client principal, {@code null} if none.
*/
public Principal getPrincipal() {
if (principals != null)
return principals[0];
else
return null;
}
/**
* Returns the authenticated client principals, {@code null} if
* none.
*
* @return The client principals, {@code null} if none.
*/
public Principal[] getPrincipals() {
return principals;
}
/**
* Returns the first authenticated client principal name, {@code null}
* if none.
*
* @return The first client principal name, {@code null} if none.
*/
public String getPrincipalName() {
if (principals != null)
return principals[0].getName();
else
return null;
}
/**
* Returns the authenticated client principal names, {@code null}
* if none.
*
* @return The client principal names, {@code null} if none.
*/
public String[] getPrincipalNames() {
String[] names = new String[principals.length];
for (int i=0; i < names.length; i++)
names[i] = principals[i].getName();
return names;
}
@Override
public String toString() {
String s = "[host=" + clientHostName + " hostIP=" + clientInetAddress + " secure=" + secure;
if (principals != null) {
int i = 0;
for (Principal p: principals)
s += " principal[" + (i++) + "]=" + p;
}
return s + "]";
}
}

View File

@@ -0,0 +1,35 @@
package com.thetransactioncompany.jsonrpc2.server;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Notification;
/**
* Interface for handling JSON-RPC 2.0 notifications.
*
* @author Vladimir Dzhuvinov
*/
public interface NotificationHandler {
/**
* Gets the names of the handled JSON-RPC 2.0 notification methods.
*
* @return The names of the handled JSON-RPC 2.0 notification methods.
*/
public String[] handledNotifications();
/**
* Processes a JSON-RPC 2.0 notification.
*
* <p>Note that JSON-RPC 2.0 notifications don't produce a response!
*
* @param notification A valid JSON-RPC 2.0 notification instance.
* Must not be {@code null}.
* @param notificationCtx Context information about the notification
* message, may be {@code null} if undefined.
*/
public void process(final JSONRPC2Notification notification, final MessageContext notificationCtx);
}

View File

@@ -0,0 +1,36 @@
package com.thetransactioncompany.jsonrpc2.server;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
/**
* Interface for handling JSON-RPC 2.0 requests.
*
* @author Vladimir Dzhuvinov
*/
public interface RequestHandler {
/**
* Gets the names of the handled JSON-RPC 2.0 request methods.
*
* @return The names of the handled JSON-RPC 2.0 request methods.
*/
public String[] handledRequests();
/**
* Processes a JSON-RPC 2.0 request.
*
* @param request A valid JSON-RPC 2.0 request instance. Must not be
* {@code null}.
* @param requestCtx Context information about the request message, may
* be {@code null} if undefined.
*
* @return The resulting JSON-RPC 2.0 response. It indicates success
* or an error, such as METHOD_NOT_FOUND.
*/
public JSONRPC2Response process(final JSONRPC2Request request, final MessageContext requestCtx);
}

View File

@@ -0,0 +1,34 @@
/**
* Simple server framework for processing JSON-RPC 2.0 requests and
* notifications.
*
* <p>Usage:
*
* <ol>
* <li>Implement {@link com.thetransactioncompany.jsonrpc2.server.RequestHandler request}
* and / or {@link com.thetransactioncompany.jsonrpc2.server.NotificationHandler notification}
* handlers for the various expected JSON-RPC 2.0 messages. A handler
* may process one or more request/notification methods (identified by
* method name).
* <li>Create a new {@link com.thetransactioncompany.jsonrpc2.server.Dispatcher}
* and register the handlers with it.
* <li>Pass the received JSON-RPC 2.0 requests and notifications to the
* appropriate {@code Dispatcher.dispatch(...)} method, then, if the
* message is a request, pass the resulting JSON-RPC 2.0 response back
* to the client.
* </ol>
*
* <p>Direct package dependencies:
*
* <ul>
* <li><b><a href="http://software.dzhuvinov.com/json-rpc-2.0-base.html">JSON-RPC 2.0 Base</a></b>
* [<i>com.thetransactioncompany.jsonrpc2</i>] to construct and represent
* JSON-RPC 2.0 messages.
* <li><b>Java Servlet API</b> [<i>javax.servlet.http</i>] for constructing
* {@link com.thetransactioncompany.jsonrpc2.server.MessageContext}
* objects from HTTP servlet requests.
* </ul>
*
* @author Vladimir Dzhuvinov
*/
package com.thetransactioncompany.jsonrpc2.server;