package org.evergreen_ils.hatch;
-
-import org.eclipse.jetty.util.FutureCallback;
-
import java.io.IOException;
+import java.io.File;
+import java.io.BufferedReader;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
+import javax.servlet.ServletConfig;
+
+import org.eclipse.jetty.util.ajax.JSON;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import java.util.Arrays;
+import java.util.List;
@WebSocket
public class HatchSocket {
private Session session;
+ static String[] trustedDomains;
+ static String trustedDomainsString;
+ static boolean trustAllDomains = false;
+ static String profileDirectory;
+ private static final Logger logger = Log.getLogger("HatchSocket");
+
+ /**
+ * config is passed in from our WebSocketServlet container,
+ * hence the public+static. Possible to access directly?
+ */
+ public static void configure(ServletConfig config) {
+ logger.info("HatchSocket.configure()");
+
+ trustedDomainsString =
+ config.getServletContext().getInitParameter("trusted-domains");
+
+ profileDirectory =
+ config.getServletContext().getInitParameter("profile-directory");
+
+ // default to ~/.evergreen
+ if (profileDirectory == null) {
+ String home = System.getProperty("user.home");
+ profileDirectory = new File(home, ".evergreen").getPath();
+ if (profileDirectory == null) {
+ logger.info("Unable to set profile directory");
+ }
+ }
+
+ if (trustedDomainsString == null) {
+ logger.info("No trusted domains configured");
+
+ } else {
+
+ if (trustedDomainsString.equals("*")) {
+ trustAllDomains = true;
+ logger.info("All domains trusted");
+
+ } else {
+
+ trustedDomains = trustedDomainsString.split(",");
+ for(String domain : trustedDomains) {
+ logger.info("Trusted domain: " + domain);
+ }
+ }
+ }
+ }
+
+ protected boolean verifyOriginDomain() {
+ logger.info("received connection from IP " +
+ session.getRemoteAddress().getAddress());
+
+ String origin = session.getUpgradeRequest().getHeader("Origin");
+
+ if (origin == null) {
+ logger.warn("No Origin header in request; Dropping connection");
+ return false;
+ }
+
+ logger.info("connection origin is " + origin);
+
+ if (trustAllDomains) return true;
+
+ if (java.util.Arrays.asList(trustedDomains).indexOf(origin) < 0) {
+ logger.warn("Request from un-trusted domain: " + origin);
+ return false;
+ }
+
+ return true;
+ }
+
@OnWebSocketConnect
public void onConnect(Session session) {
- System.out.println("Connect: " + session.getRemoteAddress().getAddress());
this.session = session;
+ if (!verifyOriginDomain()) session.close();
}
@OnWebSocketClose
public void onClose(int statusCode, String reason) {
- System.out.println("Close: statusCode=" + statusCode + ", reason=" + reason);
+ logger.info("onClose() statusCode=" + statusCode + ", reason=" + reason);
this.session = null;
}
- @OnWebSocketMessage
- public void onMessage(String message) {
- System.out.println("Message: " + message);
+ private void sendJSONMessage(Object json) {
try {
- session.getRemote().sendString("hello : " + message);
+ session.getRemote().sendString(JSON.toString(json));
} catch (IOException e) {
- e.printStackTrace();
+ logger.warn(e);
+ }
+ }
+
+ @OnWebSocketMessage
+ public void onMessage(String message) {
+ if (session == null || !session.isOpen()) return;
+ logger.info("onMessage() " + message);
+
+ FileIO io;
+ /*
+ * TODO: inbound message should be a JSON blob
+ String action = request.getParameter("action");
+ String key = request.getParameter("key");
+ String value = request.getParameter("value");
+ */
+ String action = "keys";
+ String key = "";
+ String value = "";
+
+ // all requests require an action
+ /*
+ if (action == null || action.equals("")) {
+ String err = JSON.toString("No action specified in request");
+ sendJSONMessage(err);
+ logger.info(err);
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ */
+
+ if (action.equals("keys")) {
+ io = new FileIO(profileDirectory);
+ String[] keys = io.keys(key); // OK for key to be null
+
+ if (keys != null) {
+ sendJSONMessage(keys);
+ } else {
+ /*
+ response.setStatus(
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ */
+ }
+ return;
+ }
+
+ if (action.equals("printers")) {
+ List printers = new PrintDriver().getPrinters();
+ //response.setStatus(HttpServletResponse.SC_OK);
+ sendJSONMessage(printers);
+ return;
+ }
+
+ // all remaining requests require a key
+ if (key == null || key.equals("")) {
+ String err = "No key specified in request";
+ sendJSONMessage(err);
+ logger.info(err);
+ //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
}
+
+ if (action.equals("get")) {
+ io = new FileIO(profileDirectory);
+ BufferedReader reader = io.get(key);
+ if (reader != null) {
+ String line;
+ //response.setStatus(HttpServletResponse.SC_OK);
+ try {
+ while ( (line = reader.readLine()) != null) {
+ // relay lines of text to the caller as we read them
+ // assume the text content is JSON and return it
+ // un-JSON-ified.
+ sendJSONMessage(line);
+ }
+ } catch (IOException e) {
+ logger.warn(e);
+ }
+ } else {
+ /*
+ response.setStatus(
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ */
+ }
+ return;
+ }
+
+ if (action.equals("delete")) {
+ io = new FileIO(profileDirectory);
+ if (io.delete(key)) {
+ //response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ //response.setStatus(
+ //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ return;
+ }
+
+ // all remaining actions require value
+ if (value == null) {
+ String err = "No value specified in request";
+ sendJSONMessage(err);
+ logger.info(err);
+ //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ switch(action) {
+
+ case "print" :
+ boolean ok = new PrintDriver().printWithDialog(key, value);
+ if (ok) {
+ //response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ //response.setStatus(
+ //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ break;
+
+ case "set" :
+ io = new FileIO(profileDirectory);
+ if (io.set(key, value)) {
+ //response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ //response.setStatus(
+ //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ break;
+
+ case "append" :
+ io = new FileIO(profileDirectory);
+ if (io.append(key, value)) {
+ //response.setStatus(HttpServletResponse.SC_OK);
+ } else {
+ //response.setStatus(
+ //HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ break;
+
+ default:
+ //response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ sendJSONMessage(
+ "\"No Such Action: " + action + "\"");
+ logger.info("No such action: " + action);
+ }
+
}
}