From 27bb19646fe4046628e9a21e63a425c1f7a8f15f Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sun, 31 Jul 2016 01:35:18 +0300 Subject: move components to api module --- .../java/com/juick/www/CrosspostComponent.java | 323 --------------------- .../src/main/java/com/juick/www/PushComponent.java | 311 -------------------- 2 files changed, 634 deletions(-) delete mode 100644 juick-www/src/main/java/com/juick/www/CrosspostComponent.java delete mode 100644 juick-www/src/main/java/com/juick/www/PushComponent.java (limited to 'juick-www/src/main/java/com/juick/www') diff --git a/juick-www/src/main/java/com/juick/www/CrosspostComponent.java b/juick-www/src/main/java/com/juick/www/CrosspostComponent.java deleted file mode 100644 index e2ddbfa5..00000000 --- a/juick-www/src/main/java/com/juick/www/CrosspostComponent.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Juick - * Copyright (C) 2013, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.juick.www; - -import com.juick.server.CrosspostQueries; -import com.juick.xmpp.JID; -import com.juick.xmpp.Message; -import com.juick.xmpp.Stream; -import com.juick.xmpp.StreamComponent; -import com.juick.xmpp.extensions.JuickMessage; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DriverManagerDataSource; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.HttpsURLConnection; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import java.io.*; -import java.net.Socket; -import java.net.URL; -import java.net.URLEncoder; -import java.security.Key; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.Logger; - -/** - * - * @author Ugnich Anton - */ -public class CrosspostComponent implements ServletContextListener, Stream.StreamListener, Message.MessageListener { - - private static Logger logger = Logger.getLogger(CrosspostComponent.class.getName()); - - private ExecutorService executorService; - - public final static String TWITTERURL = "https://api.twitter.com/1.1/statuses/update.json"; - public final static String FBURL = "https://graph.facebook.com/me/feed"; - public final static String VKURL = "https://api.vk.com/method/wall.post"; - JdbcTemplate sql; - Stream xmpp; - String twitter_consumer_key; - String twitter_consumer_secret; - - @Override - public void contextInitialized(final ServletContextEvent sce) { - logger.info("component initialized"); - executorService = Executors.newSingleThreadExecutor(); - executorService.submit((Runnable) () -> { - try { - Properties conf = new Properties(); - conf.load(sce.getServletContext().getResourceAsStream("/WEB-INF/juick.conf")); - - LogManager.getLogManager().readConfiguration( - sce.getServletContext().getResourceAsStream("/WEB-INF/logging.properties")); - twitter_consumer_key = conf.getProperty("twitter_consumer_key", ""); - twitter_consumer_secret = conf.getProperty("twitter_consumer_secret", ""); - - setupSql(conf.getProperty("datasource_driver", "com.mysql.jdbc.Driver"), conf.getProperty("datasource_url", "")); - setupXmppComponent(conf.getProperty("xmpp_password", "")); - } catch (Exception e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } - }); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - executorService.shutdown(); - logger.info("component destroyed"); - } - - public void setupSql(String driver, String url) { - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName(driver); - dataSource.setUrl(url); - sql = new JdbcTemplate(dataSource); - } - - public void setupXmppComponent(String password) { - try { - Socket socket = new Socket("localhost", 5347); - xmpp = new StreamComponent(new JID("", "crosspost.juick.com", ""), socket.getInputStream(), socket.getOutputStream(), password); - xmpp.addChildParser(new JuickMessage()); - xmpp.addListener((Stream.StreamListener) this); - xmpp.addListener((Message.MessageListener) this); - xmpp.startParsing(); - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } - } - - @Override - public void onStreamReady() { - logger.info("XMPP STREAM READY"); - } - - @Override - public void onStreamFail(Exception e) {logger.log(Level.SEVERE, "XMPP STREAM FAIL", e);} - @Override - public void onMessage(com.juick.xmpp.Message msg) { - JuickMessage jmsg = (JuickMessage) msg.getChild(JuickMessage.XMLNS); - if (msg.to != null && msg.to.Username != null && jmsg != null && jmsg.getRID() == 0) { - if (msg.to.Username.equals("twitter")) { - twitterPost(jmsg); - } else if (msg.to.Username.equals("fb")) { - facebookPost(jmsg); - } else if (msg.to.Username.equals("vk")) { - vkontaktePost(jmsg); - } - } - } - - public boolean facebookPost(com.juick.Message jmsg) { - String token = CrosspostQueries.getFacebookToken(sql, jmsg.getUser().getUID()).orElse(""); - if (token.isEmpty()) { - return false; - } - - logger.info("FB: #" + jmsg.getMID()); - - String status = getMessageHashTags(jmsg) + "\n" + jmsg.getText(); - - boolean ret = false; - try { - String body = "access_token=" + URLEncoder.encode(token, "UTF-8") + "&message=" + URLEncoder.encode(status, "UTF-8") + "&link=http%3A%2F%2Fjuick.com%2F" + jmsg.getMID(); - - HttpsURLConnection conn = (HttpsURLConnection) new URL(FBURL).openConnection(); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("User-Agent", "Juick"); - conn.setRequestProperty("Content-Length", Integer.toString(body.length())); - conn.setUseCaches(false); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - conn.connect(); - - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); - wr.write(body); - wr.close(); - - ret = streamToString(conn.getInputStream()) != null; - - conn.disconnect(); - } catch (Exception e) { - logger.log(Level.SEVERE, "fbPost: " + e.getMessage(), e); - } - return ret; - } - - public boolean vkontaktePost(com.juick.Message jmsg) { - Pair tokens = CrosspostQueries.getVKTokens(sql, jmsg.getUser().getUID()).orElse(Pair.of("", "")); - if (tokens.getLeft().isEmpty() || tokens.getRight().isEmpty()) { - return false; - } - - logger.info("VK: #" + jmsg.getMID()); - - String status = getMessageHashTags(jmsg) + "\n" + jmsg.getText() + "\nhttp://juick.com/" + jmsg.getMID(); - - boolean ret = false; - try { - String body = "owner_id=" + tokens.getLeft() + "&access_token=" + URLEncoder.encode(tokens.getRight(), "UTF-8") + "&from_group=1&message=" + URLEncoder.encode(status, "UTF-8"); - - HttpsURLConnection conn = (HttpsURLConnection) new URL(VKURL).openConnection(); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("User-Agent", "Juick"); - conn.setRequestProperty("Content-Length", Integer.toString(body.length())); - conn.setUseCaches(false); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - conn.connect(); - - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); - wr.write(body); - wr.close(); - - ret = streamToString(conn.getInputStream()) != null; - - conn.disconnect(); - } catch (Exception e) { - logger.log(Level.SEVERE, "vkPost: " + e.getMessage(), e); - } - return ret; - } - - public boolean twitterPost(com.juick.Message jmsg) { - Pair tokens = CrosspostQueries.getTwitterTokens(sql, jmsg.getUser().getUID()).orElse(Pair.of("", "")); - if (tokens.getLeft().isEmpty() || tokens.getRight().isEmpty()) { - return false; - } - String token = percentEncode(tokens.getLeft()); - String token_secret = percentEncode(tokens.getRight()); - - logger.info("TWITTER: #" + jmsg.getMID()); - - String status = getMessageHashTags(jmsg) + jmsg.getText(); - if (status.length() > 115) { - status = status.substring(0, 114) + "…"; - } - status += " http://juick.com/" + jmsg.getMID(); - status = percentEncode(status); - - boolean ret = false; - try { - String nonce = UUID.randomUUID().toString(); - String timestamp = Long.toString(System.currentTimeMillis() / 1000L); - String signature = percentEncode(twitterSignature(status, nonce, timestamp, token, token_secret)); - String auth = "OAuth " - + "oauth_consumer_key=\"" + twitter_consumer_key + "\", " - + "oauth_nonce=\"" + nonce + "\", " - + "oauth_signature=\"" + signature + "\", " - + "oauth_signature_method=\"HMAC-SHA1\", " - + "oauth_timestamp=\"" + timestamp + "\", " - + "oauth_token=\"" + token + "\", " - + "oauth_version=\"1.0\""; - - HttpsURLConnection conn = (HttpsURLConnection) new URL(TWITTERURL).openConnection(); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("User-Agent", "Juick"); - conn.setRequestProperty("Content-Length", Integer.toString(status.length() + 7)); - conn.setRequestProperty("Authorization", auth); - conn.setUseCaches(false); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - conn.connect(); - - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); - wr.write("status=" + status); - wr.close(); - - ret = streamToString(conn.getInputStream()) != null; - - conn.disconnect(); - } catch (Exception e) { - logger.log(Level.SEVERE, "twitterPost: " + e.getMessage(), e); - } - return ret; - } - - public String twitterSignature(String status, String nonce, String timestamp, String token, String token_secret) { - try { - // ALPHABET-SORTED - String params = "oauth_consumer_key=" + twitter_consumer_key - + "&oauth_nonce=" + nonce - + "&oauth_signature_method=HMAC-SHA1" - + "&oauth_timestamp=" + timestamp - + "&oauth_token=" + token - + "&oauth_version=1.0" - + "&status=" + status; - - String base = "POST&" + percentEncode(TWITTERURL) + "&" + percentEncode(params); - String key = twitter_consumer_secret + "&" + token_secret; - - Key signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1"); - Mac mac = Mac.getInstance("HmacSHA1"); - mac.init(signingKey); - byte[] rawHmac = mac.doFinal(base.getBytes()); - return Base64.encodeBase64String(rawHmac); - - } catch (Exception e) { - logger.log(Level.SEVERE, "twitterSignature: " + e.getMessage(), e); - } - return null; - } - - public String streamToString(InputStream is) { - try { - BufferedReader buf = new BufferedReader(new InputStreamReader(is)); - StringBuilder str = new StringBuilder(); - String line; - do { - line = buf.readLine(); - str.append(line).append("\n"); - } while (line != null); - return str.toString(); - } catch (Exception e) { - logger.log(Level.SEVERE, "streamToString: " + e.getMessage(), e); - } - return null; - } - - public String getMessageHashTags(com.juick.Message jmsg) { - String hashtags = ""; - for (int i = 0; i < jmsg.Tags.size(); i++) { - hashtags += "#" + jmsg.Tags.get(i) + " "; - } - return hashtags; - } - - public static String percentEncode(String s) { - String ret = ""; - try { - ret = URLEncoder.encode(s, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); - } catch (UnsupportedEncodingException e) { - } - return ret; - } -} diff --git a/juick-www/src/main/java/com/juick/www/PushComponent.java b/juick-www/src/main/java/com/juick/www/PushComponent.java deleted file mode 100644 index 65fbcef0..00000000 --- a/juick-www/src/main/java/com/juick/www/PushComponent.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Juick - * Copyright (C) 2013, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.juick.www; - -import com.google.android.gcm.server.Message; -import com.google.android.gcm.server.MulticastResult; -import com.google.android.gcm.server.Result; -import com.google.android.gcm.server.Sender; -import com.juick.json.MessageSerializer; -import com.juick.server.PushQueries; -import com.juick.server.SubscriptionsQueries; -import com.juick.xmpp.JID; -import com.juick.xmpp.Message.MessageListener; -import com.juick.xmpp.Stream; -import com.juick.xmpp.StreamComponent; -import com.juick.xmpp.extensions.JuickMessage; -import com.juick.xmpp.utils.XmlUtils; -import com.notnoop.apns.APNS; -import com.notnoop.apns.ApnsService; -import org.apache.http.Consts; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.apache.http.util.TextUtils; -import org.json.JSONObject; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DriverManagerDataSource; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import java.io.IOException; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * - * @author Ugnich Anton - */ -public class PushComponent implements ServletContextListener, Stream.StreamListener, MessageListener { - - private static Logger logger = Logger.getLogger(PushComponent.class.getName()); - - private ExecutorService executorService; - String wns_application_sip; - String wns_client_secret; - JdbcTemplate sql; - Socket socket; - Stream xmpp; - Sender GCMSender; - - @Override - public void contextInitialized(final ServletContextEvent sce) { - logger.info("component initialized"); - executorService = Executors.newSingleThreadExecutor(); - executorService.submit((Runnable) () -> { - Properties conf = new Properties(); - try { - conf.load(sce.getServletContext().getResourceAsStream("/WEB-INF/juick.conf")); - LogManager.getLogManager().readConfiguration( - sce.getServletContext().getResourceAsStream("/WEB-INF/logging.properties")); - wns_application_sip = conf.getProperty("wns_application_sip", ""); - wns_client_secret = conf.getProperty("wns_client_secret", ""); - GCMSender = new Sender(conf.getProperty("gcm_key")); - - setupSql(conf.getProperty("datasource_driver", "com.mysql.jdbc.Driver"), conf.getProperty("datasource_url", "")); - setupXmppComponent(new JID("", conf.getProperty("push_jid"), ""), conf.getProperty("xmpp_host", "localhost"), - Integer.parseInt(conf.getProperty("xmpp_port", "5347")), conf.getProperty("push_xmpp_password", "")); - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } - }); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - executorService.shutdown(); - logger.info("component destroyed"); - } - - public void setupSql(String driver, String url) { - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName(driver); - dataSource.setUrl(url); - sql = new JdbcTemplate(dataSource); - } - - public void setupXmppComponent(JID jid, String host, int port, String password) { - try { - socket = new Socket(host, port); - xmpp = new StreamComponent(jid, socket.getInputStream(), socket.getOutputStream(), password); - xmpp.addChildParser(new JuickMessage()); - xmpp.addListener((Stream.StreamListener) this); - xmpp.addListener((MessageListener) this); - xmpp.startParsing(); - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } - } - - @Override - public void onStreamReady() { - logger.info("XMPP STREAM READY"); - } - - @Override - public void onStreamFail(Exception e) {logger.log(Level.SEVERE, "XMPP STREAM FAIL", e);} - - @Override - public void onMessage(com.juick.xmpp.Message msg) { - JuickMessage jmsg = (JuickMessage)msg.getChild(JuickMessage.XMLNS); - List subscribedUsers = new ArrayList<>(); - boolean isPM = jmsg.getMID() == 0; - boolean isReply = jmsg.getRID() > 0; - int pmTo = 0; - if (isPM) { - pmTo = Integer.parseInt(msg.to.Username); - } else { - if (isReply) { - subscribedUsers = - SubscriptionsQueries.getUsersSubscribedToComments(sql, jmsg.getMID(), jmsg.getUser().getUID()); - } else { - // new message - subscribedUsers = SubscriptionsQueries.getSubscribedUsers(sql, jmsg.getUser().getUID(), jmsg.getMID()); - } - } - - /*** ANDROID ***/ - final List regids = new ArrayList<>(); - if (isPM) { - regids.addAll(PushQueries.getAndroidRegID(sql, pmTo)); - } else { - List uids = subscribedUsers.stream().map(com.juick.User::getUID).collect(Collectors.toList()); - if (uids.size() > 0) { - regids.addAll(PushQueries.getAndroidTokens(sql, uids)); - } - } - - if (!regids.isEmpty()) { - MessageSerializer messageSerializer = new MessageSerializer(); - String json = messageSerializer.serialize(jmsg).toString(); - logger.info(json); - Message message = new Message.Builder().addData("message", json).build(); - try { - MulticastResult result = GCMSender.send(message, regids, 3); - List results = result.getResults(); - for (int i = 0; i < results.size(); i++) { - logger.info("RES " + i + ": " + results.get(i).toString()); - } - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage(), e); - } catch (IllegalArgumentException err) { - logger.warning("Android: Invalid API Key"); - } - } else { - logger.info("GMS: no recipients"); - } - - /*** WinPhone ***/ - final List urls = new ArrayList<>(); - if (isPM) { - urls.addAll(PushQueries.getWinPhoneURL(sql, pmTo)); - } else { - List uids = subscribedUsers.stream().map(com.juick.User::getUID).collect(Collectors.toList()); - if (uids.size() > 0) { - urls.addAll(PushQueries.getWindowsTokens(sql, uids)); - } - } - - - if (urls.isEmpty()) { - logger.info("WNS: no recipients"); - } else { - try { - String wnsToken = getWnsAccessToken(); - String text1 = "@" + jmsg.getUser().getUName(); - if (!jmsg.Tags.isEmpty()) { - text1 += ":" + XmlUtils.escape(jmsg.getTagsString()); - } - String text2 = XmlUtils.escape(jmsg.getText()); - String xml = "" - + "" - + "" - + "" - + "" - + "" + text1 + "" - + "" + text2 + "" - + "" - + "" - + "" - + "" - + "" - + ""; - logger.fine(xml); - for (String url : urls) { - logger.info("WNS: " + url); - sendWNS(wnsToken, url, xml); - } - } catch (IOException | IllegalStateException e) { - logger.log(Level.SEVERE, "WNS: ", e); - } - } - - /*** iOS ***/ - final List tokens = new ArrayList<>(); - if (isPM) { - tokens.addAll(PushQueries.getAPNSToken(sql, pmTo)); - } else { - List uids = subscribedUsers.stream().map(com.juick.User::getUID).collect(Collectors.toList()); - if (uids.size() > 0) { - tokens.addAll(PushQueries.getAPNSTokens(sql, uids)); - } - } - if (!tokens.isEmpty()) { - ApnsService service = APNS.newService().withCert("/etc/juick/ios.p12", "juick") - .withSandboxDestination().build(); - for (String token : tokens) { - String payload = APNS.newPayload().alertTitle("@" + jmsg.getUser().getUName()).alertBody(jmsg.getText()).build(); - logger.info("APNS: " + token); - service.push(token, payload); - } - } else { - logger.info("APNS: no recipients"); - } - } - - String getWnsAccessToken() throws IOException, IllegalStateException { - if(TextUtils.isEmpty(wns_application_sip)) { - throw new IllegalStateException("'wns_application_sip' is not initialized"); - } - if(TextUtils.isEmpty(wns_client_secret)) { - throw new IllegalStateException("'wns_client_secret' is not initialized"); - } - HttpClient client = HttpClientBuilder.create().build(); - String url = "https://login.live.com/accesstoken.srf"; - List formParams = new ArrayList<>(); - formParams.add(new BasicNameValuePair("grant_type", "client_credentials")); - formParams.add(new BasicNameValuePair("client_id", wns_application_sip)); - formParams.add(new BasicNameValuePair("client_secret", wns_client_secret)); - formParams.add(new BasicNameValuePair("scope", "notify.windows.com")); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8); - HttpPost httppost = new HttpPost(url); - httppost.setEntity(entity); - HttpResponse response = client.execute(httppost); - int statusCode = response.getStatusLine().getStatusCode(); - String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8); - JSONObject json = new JSONObject(responseContent); - if(statusCode != 200) { - throw new IOException(json.opt("error") + ": " + json.opt("error_description")); - } - String tokenType = (String)json.get("token_type"); - if(tokenType.length() >= 1) { - tokenType = Character.toUpperCase(tokenType.charAt(0)) + tokenType.substring(1); - } - return tokenType + " " + json.get("access_token"); - } - - void sendWNS(String wnsToken, String url, String xml) throws IOException { - HttpClient client = HttpClientBuilder.create().build(); - StringEntity entity = new StringEntity(xml, Consts.UTF_8); - HttpPost httpPost = new HttpPost(url); - httpPost.setHeader("Content-Type", "text/xml"); - httpPost.setHeader("Authorization", wnsToken); - httpPost.setHeader("X-WNS-Type", "wns/toast"); - httpPost.setEntity(entity); - HttpResponse response = client.execute(httpPost); - int statusCode = response.getStatusLine().getStatusCode(); - if(statusCode != 200) { - String headersContent = stringifyWnsHttpHeaders(response.getAllHeaders()); - throw new IOException(headersContent); - } - } - - static String stringifyWnsHttpHeaders(Header[] allHeaders) { - String[] wnsHeaders = Arrays.stream(allHeaders) - .filter(x -> x.getName().startsWith("X-WNS-") || x.getName().startsWith("WWW-")) - .map(x -> x.getName() + ": " + x.getValue()) - .toArray(String[]::new); - return String.join("\n", wnsHeaders); - } -} -- cgit v1.2.3