From cdd48f30c7fca97327de48ff6b1cd9edf1629a5d Mon Sep 17 00:00:00 2001 From: Ugnich Anton Date: Fri, 29 Mar 2013 16:29:02 +0700 Subject: Facebook signup --- src/java/com/juick/http/www/FacebookLogin.java | 162 +++++++++++++++ src/java/com/juick/http/www/Login.java | 7 + src/java/com/juick/http/www/Main.java | 32 ++- src/java/com/juick/http/www/PageTemplates.java | 4 +- src/java/com/juick/http/www/Settings.java | 108 ++++++++++ src/java/com/juick/http/www/SignUp.java | 270 +++++++++++++++++++++++++ src/java/com/juick/http/www/Utils.java | 20 ++ 7 files changed, 590 insertions(+), 13 deletions(-) create mode 100644 src/java/com/juick/http/www/FacebookLogin.java create mode 100644 src/java/com/juick/http/www/Settings.java create mode 100644 src/java/com/juick/http/www/SignUp.java (limited to 'src/java/com/juick') diff --git a/src/java/com/juick/http/www/FacebookLogin.java b/src/java/com/juick/http/www/FacebookLogin.java new file mode 100644 index 00000000..8933075b --- /dev/null +++ b/src/java/com/juick/http/www/FacebookLogin.java @@ -0,0 +1,162 @@ +/* + * Juick + * Copyright (C) 2008-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.http.www; + +import com.juick.server.UserQueries; +import java.io.IOException; +import java.net.URLEncoder; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.json.JSONObject; + +/** + * + * @author Ugnich Anton + */ +public class FacebookLogin { + + private static final String FACEBOOK_APPID = "130568668304"; + private static final String FACEBOOK_SECRET = "95813bfb6ab8f473410c50d4f971649e"; + private static final String FACEBOOK_REDIRECT = "http://juick.com/_fblogin"; + + protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String fbstate; + + String code = request.getParameter("code"); + if (code == null || code.equals("")) { + fbstate = UUID.randomUUID().toString(); + + Cookie c = new Cookie("fbstate", fbstate); + response.addCookie(c); + + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader("Location", "https://www.facebook.com/dialog/oauth?client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, "utf-8") + "&state=" + fbstate); + return; + } + + fbstate = Utils.getCookie(request, "fbstate"); + if (fbstate == null || fbstate.isEmpty() || !fbstate.equals(request.getParameter("state"))) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } else { + Cookie c = new Cookie("fbstate", "-"); + c.setMaxAge(0); + response.addCookie(c); + } + + String token = Utils.fetchURL("https://graph.facebook.com/oauth/access_token?client_id=" + FACEBOOK_APPID + "&redirect_uri=" + URLEncoder.encode(FACEBOOK_REDIRECT, "utf-8") + "&client_secret=" + FACEBOOK_SECRET + "&code=" + URLEncoder.encode(code, "utf-8")); + if (token == null || token.isEmpty() || !token.startsWith("access_token=")) { + System.err.println("FACEBOOK TOKEN ERROR: " + token); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + token = token.substring(13); // access_token=... + int tokenamp = token.indexOf('&'); // &expires= + if (tokenamp > 0) { + token = token.substring(0, tokenamp); + } + + String graph = Utils.fetchURL("https://graph.facebook.com/me?access_token=" + token); + if (graph == null || graph.isEmpty()) { + System.err.println("FACEBOOK GRAPH ERROR"); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + try { + JSONObject json = new JSONObject(graph); + String fbIDStr = json.getString("id"); + String fbName = json.getString("name"); + String fbLink = json.getString("link"); + + long fbID = 0; + if (fbIDStr != null && !fbIDStr.isEmpty()) { + fbID = Long.parseLong(fbIDStr); + } + + if (fbID == 0 || fbName == null || fbLink == null || fbName.isEmpty() || fbLink.isEmpty()) { + throw new Exception(); + } + + int uid = getUIDbyFBID(sql, fbID); + if (uid > 0) { + Cookie c = new Cookie("hash", UserQueries.getHashByUID(sql, uid)); + c.setMaxAge(50 * 24 * 60 * 60); + response.addCookie(c); + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader("Location", "/"); + } else { + String loginhash = UUID.randomUUID().toString(); + if (!insertDB(sql, fbID, loginhash, token, fbName, fbLink)) { + throw new Exception(); + } + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader("Location", "/signup?type=fb&hash=" + loginhash); + } + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + } + + private int getUIDbyFBID(Connection sql, long fbID) { + int uid = 0; + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = sql.prepareStatement("SELECT user_id FROM facebook WHERE fb_id=? AND user_id IS NOT NULL"); + stmt.setLong(1, fbID); + rs = stmt.executeQuery(); + if (rs.first()) { + uid = rs.getInt(1); + } + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(rs, stmt); + } + return uid; + } + + private boolean insertDB(Connection sql, long fbID, String loginhash, String token, String fbName, String fbLink) { + boolean ret = false; + PreparedStatement stmt = null; + try { + stmt = sql.prepareStatement("INSERT INTO facebook(fb_id,loginhash,access_token,fb_name,fb_link) VALUES (?,?,?,?,?)"); + stmt.setLong(1, fbID); + stmt.setString(2, loginhash); + stmt.setString(3, token); + stmt.setString(4, fbName); + stmt.setString(5, fbLink); + stmt.executeUpdate(); + ret = true; + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(null, stmt); + } + return ret; + } +} diff --git a/src/java/com/juick/http/www/Login.java b/src/java/com/juick/http/www/Login.java index ba8fac7e..79f626d0 100644 --- a/src/java/com/juick/http/www/Login.java +++ b/src/java/com/juick/http/www/Login.java @@ -49,6 +49,13 @@ public class Login { out.println("
"); out.println("
"); out.println("
"); + out.println("

\"Facebook\"/" + rb.getString("Login Facebook") + "

"); + out.println("

\"Connect

"); + out.println("
"); + out.println("

\"XMPP\"/" + rb.getString("Login XMPP") + "

"); + out.println("

" + rb.getString("XMPP instructions") + "

"); + out.println("
"); + out.println("

" + rb.getString("Have Juick") + "

"); out.println("
"); out.println("

" + rb.getString("Username") + ":

"); out.println("

" + rb.getString("Password") + ":

"); diff --git a/src/java/com/juick/http/www/Main.java b/src/java/com/juick/http/www/Main.java index a41ccf9b..baaa1cae 100644 --- a/src/java/com/juick/http/www/Main.java +++ b/src/java/com/juick/http/www/Main.java @@ -37,7 +37,7 @@ import ru.sape.Sape; */ @WebServlet(name = "Main", urlPatterns = {"/"}) public class Main extends HttpServlet implements XmppListener { - + Connection sql; Connection sqlSearch; XmppConnection xmpp; @@ -47,14 +47,17 @@ public class Main extends HttpServlet implements XmppListener { User pagesUser = new User(); UserThread pagesUserThread = new UserThread(); NewMessage pagesNewMessage = new NewMessage(); - + FacebookLogin loginFacebook = new FacebookLogin(); + SignUp signup = new SignUp(); + Settings settings = new Settings(); + @Override public void init() throws ServletException { super.init(); try { Properties conf = new Properties(); conf.load(new FileInputStream("/etc/juick/www.conf")); - + Class.forName("com.mysql.jdbc.Driver"); sql = DriverManager.getConnection("jdbc:mysql://localhost/juick?autoReconnect=true&user=" + conf.getProperty("mysql_username", "") + "&password=" + conf.getProperty("mysql_password", "")); sqlSearch = DriverManager.getConnection("jdbc:mysql://127.0.0.1:9306/juick?autoReconnect=true&characterEncoding=utf8&maxAllowedPacket=512000&relaxAutoCommit=true&user=root&password="); @@ -63,15 +66,15 @@ public class Main extends HttpServlet implements XmppListener { xmpp.addListener((XmppListener) this); xmpp.start(); */ - + blogs = new Blogs(sql); - + PageTemplates.sape = new Sape(conf.getProperty("sape_user"), "juick.com", 2000, 3600); } catch (Exception e) { log(null, e); } } - + @Override public void destroy() { super.destroy(); @@ -92,17 +95,17 @@ public class Main extends HttpServlet implements XmppListener { } } } - + @Override public void onAuth(String resource) { log("XMPP AUTH: " + resource); } - + @Override public void onAuthFailed(String message) { log("XMPP AUTH FAILED: " + message); } - + @Override public void onConnectionFailed(String message) { log("XMPP CONNECTION FAILED: " + message); @@ -121,7 +124,7 @@ public class Main extends HttpServlet implements XmppListener { request.setCharacterEncoding("UTF-8"); } String uri = request.getRequestURI(); - + if (uri.equals("/")) { blogs.doGet(sql, sqlSearch, request, response); } else if (uri.equals("/post")) { @@ -140,7 +143,11 @@ public class Main extends HttpServlet implements XmppListener { } else if (uri.equals("/logout")) { login.doGetLogout(sql, request, response); } else if (uri.equals("/settings")) { - //TODO settings + settings.doGet(sql, request, response); + } else if (uri.equals("/_fblogin")) { + loginFacebook.doGet(sql, request, response); + } else if (uri.equals("/signup")) { + signup.doGet(sql, request, response); } else if (uri.equals("/help") || uri.equals("/help/")) { help.doRedirectToHelpIndex(sql, request, response); } else if (uri.startsWith("/help/")) { @@ -230,7 +237,10 @@ public class Main extends HttpServlet implements XmppListener { pagesNewMessage.doPostNewMessage(sql, request, response); } else if (uri.equals("/login")) { login.doPostLogin(sql, request, response); + } else if (uri.equals("/signup")) { + signup.doPost(sql, request, response); } else if (uri.equals("/settings")) { + settings.doPost(sql, request, response); } else { response.sendError(405); } diff --git a/src/java/com/juick/http/www/PageTemplates.java b/src/java/com/juick/http/www/PageTemplates.java index 70f4d1ef..16e7818c 100644 --- a/src/java/com/juick/http/www/PageTemplates.java +++ b/src/java/com/juick/http/www/PageTemplates.java @@ -52,11 +52,11 @@ public class PageTemplates { out.println(""); out.println(""); out.println(" " + title + ""); - out.println(" "); + out.println(" "); out.println(" "); out.println(" "); out.println(" "); - out.println(" "); + out.println(" "); if (headers != null) { out.println(headers); } diff --git a/src/java/com/juick/http/www/Settings.java b/src/java/com/juick/http/www/Settings.java new file mode 100644 index 00000000..7ae0259d --- /dev/null +++ b/src/java/com/juick/http/www/Settings.java @@ -0,0 +1,108 @@ +/* + * Juick + * Copyright (C) 2008-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.http.www; + +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Locale; +import java.util.ResourceBundle; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author Ugnich Anton + */ +public class Settings { + + protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + com.juick.User visitor = Utils.getVisitorUser(sql, request); + Locale locale = request.getLocale(); + ResourceBundle rb = ResourceBundle.getBundle("Login", locale); + + response.setContentType("text/html; charset=UTF-8"); + PrintWriter out = response.getWriter(); + try { + PageTemplates.pageHead(out, rb.getString("Login"), ""); + PageTemplates.pageNavigation(out, locale, visitor, null); + + out.println("
"); + out.println("
"); + out.println("
"); + out.println(""); + out.println("

" + rb.getString("Username") + ":

"); + out.println("

" + rb.getString("Password") + ":

"); + out.println("

"); + out.println(""); + out.println("
"); + out.println("
"); + out.println("
"); // topwrapper + + PageTemplates.pageFooter(request, out, locale, visitor, false); + PageTemplates.pageEnd(out); + } finally { + out.close(); + } + } + + protected void doPost(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String username = request.getParameter("username"); + String password = request.getParameter("password"); + if (username == null || password == null || username.length() > 32 || password.isEmpty()) { + response.sendError(400); + return; + } + + int uid = com.juick.server.UserQueries.checkPassword(sql, username, password); + if (uid > 0) { + String hash = com.juick.server.UserQueries.getHashByUID(sql, uid); + Cookie c = new Cookie("hash", hash); + c.setDomain(".juick.com"); + c.setMaxAge(365 * 24 * 60 * 60); + response.addCookie(c); + + + if (uid > 0) { + PreparedStatement stmt = null; + try { + stmt = sql.prepareStatement("DELETE FROM logins WHERE user_id=?"); + stmt.setInt(1, uid); + stmt.executeUpdate(); + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(null, stmt); + } + } + + String referer = request.getHeader("Referer"); + if (referer != null && referer.startsWith("http://juick.com/") && !referer.equals("http://juick.com/login")) { + response.sendRedirect(referer); + } else { + response.sendRedirect("/"); + } + } else { + response.sendError(403); + } + } +} diff --git a/src/java/com/juick/http/www/SignUp.java b/src/java/com/juick/http/www/SignUp.java new file mode 100644 index 00000000..1afbebbe --- /dev/null +++ b/src/java/com/juick/http/www/SignUp.java @@ -0,0 +1,270 @@ +/* + * Juick + * Copyright (C) 2008-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.http.www; + +import com.juick.server.UserQueries; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Locale; +import java.util.ResourceBundle; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author Ugnich Anton + */ +public class SignUp { + + protected void doGet(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + com.juick.User visitor = Utils.getVisitorUser(sql, request); + Locale locale = request.getLocale(); + ResourceBundle rb = ResourceBundle.getBundle("SignUp", locale); + + String type = request.getParameter("type"); + String hash = request.getParameter("hash"); + if (type == null || type.isEmpty() || hash == null || hash.isEmpty() || hash.length() > 36 || !type.matches("^[a-zA-Z0-9\\-]+$") || !hash.matches("^[a-zA-Z0-9\\-]+$")) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + String account = null; + if (type.equals("fb")) { + account = getFacebookNameByHash(sql, hash); + } else if (type.equals("xmpp")) { + account = getJIDByHash(sql, hash); + } + if (account == null) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + response.setContentType("text/html; charset=UTF-8"); + PrintWriter out = response.getWriter(); + try { + PageTemplates.pageHead(out, rb.getString("Unknown account"), ""); + PageTemplates.pageNavigation(out, locale, visitor, null); + out.println("
"); + out.println("
"); + out.println("
"); + + out.print("

"); + if (type.charAt(0) == 'f') { + out.print("\"Facebook\"/"); + } else if (type.charAt(0) == 'x') { + out.print("\"XMPP\"/"); + } + out.println(account + "

"); + + out.println("

" + rb.getString("Link with existing") + "

"); + out.println("
"); + out.println(""); + out.println(""); + out.println(""); + if (visitor != null) { + out.println(""); + } else { + out.println("

" + rb.getString("Username") + ":

"); + out.println("

" + rb.getString("Password") + ":

"); + out.println("

"); + } + out.println("
"); + + out.println("
"); + + out.println("

" + rb.getString("Create new") + "

"); + out.println("
"); + out.println(""); + out.println(""); + out.println(""); + out.println("

" + rb.getString("Username") + ":
" + rb.getString("Username restrictions") + "

"); + out.println("

" + rb.getString("Password") + ":
" + rb.getString("Password restrictions") + "

"); + out.println("

" + rb.getString("Language") + ":

"); + out.println("

"); + out.println("
"); + + out.println("
"); + out.println("
"); + out.println("
"); // topwrapper + + PageTemplates.pageFooter(request, out, locale, visitor, false); + PageTemplates.pageEnd(out); + } finally { + out.close(); + } + } + + protected void doPost(Connection sql, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + com.juick.User visitor = Utils.getVisitorUser(sql, request); + int uid = 0; + + String type = request.getParameter("type"); + String hash = request.getParameter("hash"); + if (type == null || type.isEmpty() || hash == null || hash.isEmpty() || hash.length() > 36 || !type.matches("^[a-zA-Z0-9\\-]+$") || !hash.matches("^[a-zA-Z0-9\\-]+$")) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + String action = request.getParameter("action"); + if (action.charAt(0) == 'l') { + + if (visitor == null) { + String username = request.getParameter("username"); + String password = request.getParameter("password"); + if (username == null || password == null || username.length() > 32 || password.isEmpty()) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + uid = com.juick.server.UserQueries.checkPassword(sql, username, password); + } else { + uid = visitor.UID; + } + + if (uid == 0) { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + if (!(type.charAt(0) == 'f' && setFacebookUser(sql, hash, uid)) + && !(type.charAt(0) == 'x' && setJIDUser(sql, hash, uid))) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + } else { // Create new account + String username = request.getParameter("username"); + String password = request.getParameter("password"); + String lang = request.getParameter("lang"); + if (username == null || password == null || lang == null || username.length() < 2 || username.length() > 16 || !username.matches("^[a-zA-Z0-9\\-]+$") || password.length() < 6 || password.length() > 32 || lang.length() != 2) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + uid = UserQueries.createUser(sql, username, password, lang); + if (uid == 0) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + if (!(type.charAt(0) == 'f' && setFacebookUser(sql, hash, uid)) + && !(type.charAt(0) == 'x' && setJIDUser(sql, hash, uid))) { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return; + } + + visitor = null; + } + + if (visitor == null) { + hash = com.juick.server.UserQueries.getHashByUID(sql, uid); + Cookie c = new Cookie("hash", hash); + c.setMaxAge(365 * 24 * 60 * 60); + response.addCookie(c); + } + + response.sendRedirect("/"); + } + + private String getFacebookNameByHash(Connection sql, String hash) { + String ret = null; + + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = sql.prepareStatement("SELECT fb_name,fb_link FROM facebook WHERE loginhash=?"); + stmt.setString(1, hash); + rs = stmt.executeQuery(); + if (rs.first()) { + ret = "" + rs.getString(1) + ""; + } + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(rs, stmt); + } + + return ret; + } + + private boolean setFacebookUser(Connection sql, String hash, int uid) { + boolean ret = false; + PreparedStatement stmt = null; + try { + stmt = sql.prepareStatement("UPDATE facebook SET user_id=?,loginhash=NULL WHERE loginhash=?"); + stmt.setInt(1, uid); + stmt.setString(2, hash); + stmt.executeUpdate(); + ret = true; + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(null, stmt); + } + return ret; + } + + private String getJIDByHash(Connection sql, String hash) { + String ret = null; + + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = sql.prepareStatement("SELECT jid FROM jids WHERE loginhash=?"); + stmt.setString(1, hash); + rs = stmt.executeQuery(); + if (rs.first()) { + ret = rs.getString(1); + } + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(rs, stmt); + } + + return ret; + } + + private boolean setJIDUser(Connection sql, String hash, int uid) { + boolean ret = false; + PreparedStatement stmt = null; + try { + stmt = sql.prepareStatement("UPDATE jids SET user_id=?,loginhash=NULL WHERE loginhash=?"); + stmt.setInt(1, uid); + stmt.setString(2, hash); + stmt.executeUpdate(); + ret = true; + } catch (SQLException e) { + System.err.println(e); + } finally { + Utils.finishSQL(null, stmt); + } + return ret; + } +} diff --git a/src/java/com/juick/http/www/Utils.java b/src/java/com/juick/http/www/Utils.java index 38550691..4c41555e 100644 --- a/src/java/com/juick/http/www/Utils.java +++ b/src/java/com/juick/http/www/Utils.java @@ -17,6 +17,10 @@ */ package com.juick.http.www; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -118,4 +122,20 @@ public class Utils { ret = ret.replaceAll("@", "\\\\@"); return ret; } + + public static String fetchURL(String url) { + try { + URLConnection c = new URL(url).openConnection(); + BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream())); + String inputLine; + StringBuilder b = new StringBuilder(); + while ((inputLine = in.readLine()) != null) { + b.append(inputLine).append("\n"); + } + in.close(); + return b.toString(); + } catch (Exception e) { + return null; + } + } } -- cgit v1.2.3