Java tutorial
/******************************************************************************* * Copyright (C) 2014 Travis Ralston (turt2live) * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package com.turt2live.xmail.engine.connection; import com.turt2live.xmail.XMail; import com.turt2live.xmail.XMailConfig; import com.turt2live.xmail.engine.MinecraftAuthentication; import com.turt2live.xmail.engine.PasswordPolicy; import com.turt2live.xmail.engine.PasswordPolicy.Method; import com.turt2live.xmail.engine.ServerResponse; import com.turt2live.xmail.engine.request.Request.RequestType; import com.turt2live.xmail.mail.Mail; import com.turt2live.xmail.mail.attachment.*; import com.turt2live.xmail.mail.attachment.Attachment.AttachmentType; import com.turt2live.xmail.utils.Variable; import org.json.simple.JSONValue; import org.json.simple.parser.ContainerFactory; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.*; import java.util.Map.Entry; /** * Represents a PHP (Protocol 2A) connection * * @author turt2live */ public class PHPConnection2A extends ServerConnection { /** * The HTTP status code to represent a successful login */ public static final int LOGGED_IN_CODE = 418; /** * The protocol version for this connection class */ public static final String PROTOCOL_VERSION = "2A"; /** * The HTTP status code to indicate a username is taken */ public static final int USERNAME_TAKEN_CODE = 402; private String username = "NotSet", password = "NotSet", secret = "NotSet", server = "NotSet"; /** * Creates a new PHP Server connection (protocol 2A) * * @param server the server to connect to * @param mcAuth the minecraft authentication container */ public PHPConnection2A(String server, MinecraftAuthentication mcAuth) { super(mcAuth); this.server = server; } @Override public Attachment attemptGetAttachment(Map<String, Object> json) { if (json == null) { return null; } if (json.containsKey("type") && json.containsKey("content")) { String type = null, content = null; Object o = json.get("type"); if (o instanceof String) { type = (String) o; } o = json.get("content"); if (o instanceof String) { content = (String) o; } if (type != null && content != null) { AttachmentType atype = AttachmentType.fromName(type); switch (atype) { case MESSAGE: return new MessageAttachment(content); case MONEY: try { double value = Double.parseDouble(content); return new MoneyAttachment(value); } catch (NumberFormatException e) { return new UnknownAttachment(content); } case COD: try { double value = Double.parseDouble(content); return new CODAttachment(value); } catch (NumberFormatException e) { return new UnknownAttachment(content); } case ITEM: ItemAttachment ia = ItemAttachment.deserializeFromJson(content); return ia == null ? new UnknownAttachment(content) : ia; case MAIL: MailMessageAttachment ma = MailMessageAttachment.deserializeFromJson(content); return ma == null ? new UnknownAttachment(content) : ma; default: return new UnknownAttachment(content); } } } return null; } @SuppressWarnings("unchecked") @Override public ServerResponse attemptRequest(RequestType mode, Variable... data) { List<String> lines = new ArrayList<String>(); int errorCode = 200; if (XMailConfig.isDebugMode()) { XMail.getInstance().getLogger().info("[DEBUG] Mode: " + mode.name()); } boolean cannotLogOut = false; try { URL url = new URL(server + ServerConnection.toQuery(data)); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); String userpass = username + ":" + password; String basicAuth = "Basic " + new String(Base64Coder.encode(userpass.getBytes())); connection.setRequestProperty("Authorization", basicAuth); // TODO: Resolve when pushing live //connection.setRequestProperty("XMAIL-DEBUG", XMailConfig.isDebugMode() ? "true" : "false"); connection.setRequestProperty("XMAIL-DEBUG", "false"); connection.setRequestProperty("XMAIL-PROTOCOL-VERSION", PROTOCOL_VERSION); connection.setRequestProperty("XMAIL-SERVER-KEY", secret); connection.setRequestProperty("XMAIL-MODE", mode.name()); if (false || super.mcAuth != null) { connection.setRequestProperty("XMAIL-AUTH-PORT", String.valueOf(super.mcAuth.port)); connection.setRequestProperty("XMAIL-AUTH-VERSION", super.mcAuth.version); } if (mode == RequestType.REQUEST_AUTH) { connection.setRequestProperty("XMAIL-REQUEST-AUTH", "request"); } BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = reader.readLine()) != null) { lines.add(line); JSONParser parser = new JSONParser(); ContainerFactory containerFactory = new ContainerFactory() { @Override public List<Object> creatArrayContainer() { return new LinkedList<Object>(); } @Override public Map<String, Object> createObjectContainer() { return new LinkedHashMap<String, Object>(); } }; Map<String, Object> map = new HashMap<String, Object>(); try { Map<?, ?> json = (Map<?, ?>) parser.parse(line, containerFactory); Iterator<?> iter = json.entrySet().iterator(); // Type check while (iter.hasNext()) { Entry<?, ?> entry = (Entry<?, ?>) iter.next(); if (!(entry.getKey() instanceof String)) { throw new IllegalArgumentException("Not in <String, Object> format"); } } map = (Map<String, Object>) json; } catch (ParseException e) { e.printStackTrace(); return null; } catch (IllegalArgumentException e) { e.printStackTrace(); return null; } checkResponseForAuth(map); if (XMailConfig.isDebugMode()) { XMail.getInstance().getLogger().info("[DEBUG] " + line); } } errorCode = connection.getResponseCode(); if (mode == RequestType.LOGOUT && errorCode == 405) { cannotLogOut = true; } reader.close(); } catch (IOException e) { if (e.getMessage().contains("402")) { errorCode = 402; // Username taken } else if (e.getMessage().contains("418")) { errorCode = 418; // Logged in already } else { e.printStackTrace(); errorCode = -1; } } return new ServerResponse(lines, errorCode, errorCode == LOGGED_IN_CODE || cannotLogOut, errorCode == USERNAME_TAKEN_CODE); } @Override public List<Variable> convertMail(Mail mail) { if (mail == null) { return null; } List<Variable> vars = new ArrayList<Variable>(); Map<String, Object> map = new HashMap<String, Object>(); map.put("to", mail.getTo()); map.put("from", mail.getFrom()); map.put("date", mail.getTimestamp()); map.put("sent-from", mail.getServerSender()); map.put("unread", !mail.isRead()); List<String> tags = mail.getTags(); // Convert attachments List<String> attachments = new ArrayList<String>(); List<Attachment> lAtt = mail.getAttachments(); for (Attachment a : lAtt) { attachments.add(a.toJson()); } map.put("tags", tags); map.put("attachments", attachments); try { vars.add(new Variable("mail", URLEncoder.encode(JSONValue.toJSONString(map), "UTF-8"))); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return vars; } @Override public String getConnectionIP() { return this.server; } @Override public String getVersion() { return PROTOCOL_VERSION; } @SuppressWarnings("unchecked") @Override public void init() { ServerResponse response = attemptRequest(RequestType.REQUEST_AUTH); // Start a request for auth if (response.getErrorCode() == 403) { throw new IllegalAccessError("xMail server denied authentication request"); } else if (response.getErrorCode() < 0) { throw new IllegalAccessError("xMail server cannot be reached"); } List<String> lines = attemptRequest(RequestType.INFORMATION).getLines(); for (String line : lines) { JSONParser parser = new JSONParser(); ContainerFactory containerFactory = new ContainerFactory() { @Override public List<Object> creatArrayContainer() { return new LinkedList<Object>(); } @Override public Map<String, Object> createObjectContainer() { return new LinkedHashMap<String, Object>(); } }; Map<String, Object> map = new HashMap<String, Object>(); try { Map<?, ?> json = (Map<?, ?>) parser.parse(line, containerFactory); Iterator<?> iter = json.entrySet().iterator(); // Type check while (iter.hasNext()) { Entry<?, ?> entry = (Entry<?, ?>) iter.next(); if (!(entry.getKey() instanceof String)) { throw new IllegalArgumentException("Not in <String, Object> format"); } } map = (Map<String, Object>) json; } catch (ParseException e) { e.printStackTrace(); return; } catch (IllegalArgumentException e) { e.printStackTrace(); return; } if (map.containsKey("password-policy")) { // It will be a <String, Object> Map<String, Object> pw = (Map<String, Object>) map.get("password-policy"); String method = (String) pw.get("method"); // It will be a <String, Object> Map<String, Object> saltOpts = (Map<String, Object>) pw.get("salt"); String salt = (String) saltOpts.get("salt"); String format = (String) saltOpts.get("format"); super.generatePasswordPolicy(PasswordPolicy.Method.getMethod(method), salt, format); } if (map.containsKey("time")) { Object time = map.get("time"); if (time instanceof Double) { long t = ((Double) time).longValue(); super.connectionTime.reportedTime = t; super.connectionTime.requestedTime = System.currentTimeMillis() / 1000; } } } if (super.getPasswordPolicy() != null) { String testHash = super.getPasswordPolicy().hashPassword("test-xmail-password"); if (testHash == null) { super.generatePasswordPolicy(Method.SHA1, "", "P"); // Default } } else { super.generatePasswordPolicy(Method.SHA1, "", "P"); // Default } } private void checkResponseForAuth(Map<String, Object> response) { if (response.containsKey("SERVER_ACCESS_UPDATE")) { @SuppressWarnings("unchecked") // It will be a <String, Object> Map<String, Object> map = (Map<String, Object>) response.get("SERVER_ACCESS_UPDATE"); this.username = (String) map.get("username"); this.password = (String) map.get("password"); this.secret = (String) map.get("secret"); } } }