package us.camin.api; /* This file is part of Caminus Caminus is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Caminus is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Caminus. If not, see . */ import java.io.BufferedReader; import java.io.BufferedInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.InetSocketAddress; import java.net.ProtocolException; import java.net.URL; import java.net.URLEncoder; import java.util.logging.Logger; import java.util.logging.Level; import java.util.Scanner; import java.util.Set; import java.util.HashMap; import java.util.Map; import java.util.Iterator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONException; import org.json.JSONStringer; import java.util.Random; import org.apache.commons.codec.binary.Hex; import us.camin.api.events.VaultSlot; import us.camin.api.events.Event; public class Server { Logger log = Logger.getLogger("Caminus.API"); private String m_url; private String m_name; private String m_secret; private String genToken() { Random r = new Random(); int salt = r.nextInt(); MessageDigest crypt; try { crypt = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { log.warning("Could not find SHA-1 algorithm"); return ""; } crypt.reset(); String token = m_name+salt+m_secret; crypt.update(token.getBytes()); token = m_name+"$"+salt+"$"+Hex.encodeHexString(crypt.digest()); log.info("Generated token "+token+" from "+m_name+salt+m_secret); return token; } public JSONObject exec(String path, String method, HashMap params) throws MalformedURLException, ProtocolException, IOException { HttpURLConnection conn = open(path); conn.setRequestMethod(method); if (params.size() > 0) { conn.setDoOutput(true); Set> values = params.entrySet(); Iterator> it = values.iterator(); StringBuilder sb = new StringBuilder(); while(it.hasNext()) { Map.Entry param = it.next(); sb.append(URLEncoder.encode(param.getKey(), "UTF-8")); sb.append("="); sb.append(URLEncoder.encode(param.getValue(), "UTF-8")); sb.append("&"); } String postData = sb.substring(0, sb.length()-1); conn.setFixedLengthStreamingMode(postData.length()); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); DataOutputStream out = new DataOutputStream(conn.getOutputStream()); out.writeBytes(postData); } JSONObject ret = readJSON(conn); conn.disconnect(); return ret; } public HttpURLConnection open(String path) throws MalformedURLException, IOException { URL authServer = new URL(m_url+path); HttpURLConnection conn = (HttpURLConnection)authServer.openConnection(); conn.setRequestProperty("Authorization", "X-Caminus "+genToken()); return conn; } public JSONObject readJSON(HttpURLConnection conn) throws IOException { BufferedInputStream in; try{ in = new BufferedInputStream(conn.getInputStream()); } catch (IOException e) { String errorStr; try { errorStr = new java.util.Scanner(new BufferedInputStream(conn.getErrorStream())).useDelimiter("\\A").next(); throw new IOException("Got bad data from server: "+errorStr, e); } catch (java.util.NoSuchElementException errExc) { throw e; } } String jsonStr; try { jsonStr = new java.util.Scanner(in).useDelimiter("\\A").next(); } catch (java.util.NoSuchElementException e) { jsonStr = ""; } in.close(); try { JSONObject jsonObj = new JSONObject(jsonStr); return jsonObj; } catch (JSONException e) { throw new IOException("JSON parse error: "+jsonStr, e); } } // Convienence methods public JSONObject exec(String path, String method) throws MalformedURLException, ProtocolException, IOException { return exec(path, method, new HashMap()); } public JSONObject get(String path) throws IOException { return exec(path, "GET"); } public JSONObject post(String path, HashMap params) throws MalformedURLException, IOException { try { return exec(path, "POST", params); } catch (ProtocolException e) { return null; } } public JSONObject put(String path, HashMap params) throws MalformedURLException, IOException { try { return exec(path, "PUT", params); } catch (ProtocolException e) { return null; } } public ValidationResponse validatePlayer(String name) throws IOException { log.info("Validating "+name+" against "+m_url); ValidationResponse resp = new ValidationResponse(); JSONObject jsonObj = get("validate/"+name); resp.valid = jsonObj.optBoolean("valid"); if (!resp.valid) return resp; try { JSONArray perms = jsonObj.getJSONArray("permissions"); resp.permissions = new String[perms.length()]; for (int i = 0;i params = new HashMap(); params.put("delta", ""+delta); JSONObject jsonObj = put("server/economy/"+player, params); BalanceAdjustResponse resp = new BalanceAdjustResponse(); resp.success = jsonObj.optBoolean("success", false); resp.newBalance = jsonObj.optDouble("balance", 0); resp.message = jsonObj.optString("message", ""); return resp; } public boolean pingAPI() { log.info("Pinging API server to verify credentials"); JSONObject response; try { response = get("server/whoami"); } catch (IOException e) { log.log(Level.SEVERE, "Could not ping API server.", e); return false; } log.info("Connected to server running "+response.optString("server-version")+", api "+response.optInt("api-version")); return response.optInt("api-version") == 2; } public void closeSession(String player) throws IOException { log.info("Closing session for "+player); get("server/session/"+player+"/close"); } public void notifyEventHandled(Event event) throws IOException { log.info("Closing event "+event._id); HashMap params = new HashMap(); params.put("job", Integer.toString(event._id)); post("server/events", params); } public void sendEvents(Event[] event) throws JSONException, IOException { log.info("Submitting events"); JSONStringer out = new JSONStringer(); out.object(); out.key("events"); out.array(); for (Event evt : event) { out.value(evt.toJSON()); } out.endArray(); out.endObject(); HashMap params = new HashMap(); params.put("events", out.toString()); put("server/events", params); } public Event[] pollEventQueue() throws IOException { log.info("Polling server for events"); JSONObject jsonObj = get("server/events"); JSONArray eventList; try { eventList = jsonObj.getJSONArray("events"); } catch (JSONException e) { return new Event[0]; } Event[] events = new Event[eventList.length()]; for (int i = 0;i params = new HashMap(); //params.put("ip", sourceAddr.toString()); params.put("ip", ""); JSONObject jsonObj = post("server/session/"+player+"/new", params); resp.valid = jsonObj.optBoolean("success"); resp.errorMessage = jsonObj.optString("error"); resp.sessionId = jsonObj.optInt("sessionId"); try { JSONArray perms = jsonObj.getJSONArray("permissions"); resp.permissions = new String[perms.length()]; for (int i = 0;i params = new HashMap(); params.put("contents", out.toString()); put("server/vault/"+player, params); } }