diff options
-rw-r--r-- | nbproject/build-impl.xml | 2 | ||||
-rw-r--r-- | nbproject/genfiles.properties | 4 | ||||
-rw-r--r-- | nbproject/project.properties | 3 | ||||
-rw-r--r-- | nbproject/project.xml | 4 | ||||
-rw-r--r-- | src/java/Login.properties | 4 | ||||
-rw-r--r-- | src/java/Login_ru.properties | 4 | ||||
-rw-r--r-- | src/java/SignUp.properties | 11 | ||||
-rw-r--r-- | src/java/SignUp_ru.properties | 10 | ||||
-rw-r--r-- | src/java/com/juick/http/www/FacebookLogin.java | 162 | ||||
-rw-r--r-- | src/java/com/juick/http/www/Login.java | 7 | ||||
-rw-r--r-- | src/java/com/juick/http/www/Main.java | 32 | ||||
-rw-r--r-- | src/java/com/juick/http/www/PageTemplates.java | 4 | ||||
-rw-r--r-- | src/java/com/juick/http/www/Settings.java | 108 | ||||
-rw-r--r-- | src/java/com/juick/http/www/SignUp.java | 270 | ||||
-rw-r--r-- | src/java/com/juick/http/www/Utils.java | 20 | ||||
-rw-r--r-- | web/scripts3.js | 37 | ||||
-rw-r--r-- | web/style3.css | 8 |
17 files changed, 659 insertions, 31 deletions
diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index 4d5df024..ada51c23 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -696,6 +696,7 @@ exists or setup the property manually. For example like this: <copyfiles files="${reference.com_juick.jar}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/> <copyfiles files="${reference.com_juick_server.jar}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/> <copyfiles files="${reference.com_juick_xmpp.jar}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/> + <copyfiles files="${libs.JSON.classpath}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/> <mkdir dir="${build.web.dir}/META-INF"/> <manifest file="${build.web.dir}/META-INF/MANIFEST.MF" mode="update"/> </target> @@ -703,6 +704,7 @@ exists or setup the property manually. For example like this: <copyfiles files="${reference.com_juick.jar}" todir="${build.web.dir}/WEB-INF/lib"/> <copyfiles files="${reference.com_juick_server.jar}" todir="${build.web.dir}/WEB-INF/lib"/> <copyfiles files="${reference.com_juick_xmpp.jar}" todir="${build.web.dir}/WEB-INF/lib"/> + <copyfiles files="${libs.JSON.classpath}" todir="${build.web.dir}/WEB-INF/lib"/> </target> <target depends="init" if="dist.ear.dir" name="-clean-webinf-lib"> <delete dir="${build.web.dir}/WEB-INF/lib"/> diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index ba8ca356..b1616eec 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -3,6 +3,6 @@ build.xml.script.CRC32=c93fa366 build.xml.stylesheet.CRC32=651128d4@1.33.1.1 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=8d999c58 -nbproject/build-impl.xml.script.CRC32=9d8ae4f2 +nbproject/build-impl.xml.data.CRC32=3001a2bd +nbproject/build-impl.xml.script.CRC32=e812c1f8 nbproject/build-impl.xml.stylesheet.CRC32=0cbf5bb7@1.33.1.1 diff --git a/nbproject/project.properties b/nbproject/project.properties index 1b4e5382..b1817c6c 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -37,7 +37,8 @@ javac.classpath=\ ${reference.com_juick.jar}:\ ${reference.com_juick_server.jar}:\ ${libs.MySQLDriver.classpath}:\ - ${reference.com_juick_xmpp.jar} + ${reference.com_juick_xmpp.jar}:\ + ${libs.JSON.classpath} # Space-separated list of extra javac options javac.compilerargs= javac.debug=true diff --git a/nbproject/project.xml b/nbproject/project.xml index 45861aa2..d7d34d00 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -21,6 +21,10 @@ <file>${reference.com_juick_xmpp.jar}</file> <path-in-war>WEB-INF/lib</path-in-war> </library> + <library dirs="200"> + <file>${libs.JSON.classpath}</file> + <path-in-war>WEB-INF/lib</path-in-war> + </library> </web-module-libraries> <web-module-additional-libraries/> <source-roots> diff --git a/src/java/Login.properties b/src/java/Login.properties index 820b58f3..f75010af 100644 --- a/src/java/Login.properties +++ b/src/java/Login.properties @@ -4,3 +4,7 @@ Login=Login Username=Username Password=Password +Login\ Facebook=Login with Facebook +Login\ XMPP=Login with Jabber/XMPP +XMPP\ instructions=Send <strong>LOGIN</strong> from your Jabber/XMPP account to <strong>juick@juick.com</strong>. +Have\ Juick=Have a Juick account? diff --git a/src/java/Login_ru.properties b/src/java/Login_ru.properties index 402e58eb..84eef016 100644 --- a/src/java/Login_ru.properties +++ b/src/java/Login_ru.properties @@ -4,3 +4,7 @@ Login=\u0412\u0445\u043e\u0434 Username=\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f Password=\u041f\u0430\u0440\u043e\u043b\u044c +Login\ Facebook=\u0412\u043e\u0439\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 Facebook +Login\ XMPP=\u0412\u043e\u0439\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 Jabber/XMPP +XMPP\ instructions=\u041e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 <strong>LOGIN</strong> \u0441 \u0432\u0430\u0448\u0435\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 Jabber/XMPP \u043d\u0430 <strong>juick@juick.com</strong>. +Have\ Juick=\u0423\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043d\u0430 Juick? diff --git a/src/java/SignUp.properties b/src/java/SignUp.properties new file mode 100644 index 00000000..4bb0a162 --- /dev/null +++ b/src/java/SignUp.properties @@ -0,0 +1,11 @@ +Unknown\ account=Unknown account +Link\ with\ existing=Link with existing Juick account +Link\ with\ this=Link with this account +Create\ new=Create new Juick account +Username=Username +Username\ restrictions=(2 to 16 latin letters and/or numbers, dash sign) +Password=Password +Password\ restrictions=(6 to 32 symbols) +Language=Your primary language +Languages=English,Russian,French,Persian,Other +Language\ codes=en,ru,fr,fa,__ diff --git a/src/java/SignUp_ru.properties b/src/java/SignUp_ru.properties new file mode 100644 index 00000000..27776f1f --- /dev/null +++ b/src/java/SignUp_ru.properties @@ -0,0 +1,10 @@ +Unknown\ account=\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 +Link\ with\ existing=\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u0441 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u043c Juick +Link\ with\ this=\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u043c +Create\ new=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 Juick +Username=\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f +Username\ restrictions=(\u041e\u0442 2-\u0445 \u0434\u043e 16-\u0438 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0438/\u0438\u043b\u0438 \u0446\u0438\u0444\u0440, \u0434\u0435\u0444\u0438\u0441) +Password=\u041f\u0430\u0440\u043e\u043b\u044c +Password\ restrictions=(\u043e\u0442 6-\u0438 \u0434\u043e 32-\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432) +Language=\u0412\u0430\u0448 \u0440\u043e\u0434\u043d\u043e\u0439 \u044f\u0437\u044b\u043a +Languages=\u0410\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439,\u0420\u0443\u0441\u0441\u043a\u0438\u0439,\u0424\u0440\u0430\u043d\u0446\u0443\u0437\u0441\u043a\u0438\u0439,\u041f\u0435\u0440\u0441\u0438\u0434\u0441\u043a\u0438\u0439,\u0414\u0440\u0443\u0433\u043e\u0439 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 <http://www.gnu.org/licenses/>. + */ +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("<div id=\"topwrapper\">"); out.println("<div id=\"wrapper\">"); out.println("<div id=\"content\">"); + out.println("<h1 class=\"signup-h1\"><img src=\"//static.juick.com/settings/facebook.png\" alt=\"Facebook\"/>" + rb.getString("Login Facebook") + "</h1>"); + out.println("<p><a href=\"/_fblogin\" rel=\"nofollow\"><img src=\"//static.juick.com/facebook-connect.png\" alt=\"Connect with Facebook\"/></a></p>"); + out.println("<hr class=\"signup-hr\"/>"); + out.println("<h1 class=\"signup-h1\"><img src=\"//static.juick.com/settings/xmpp.png\" alt=\"XMPP\"/>" + rb.getString("Login XMPP") + "</h1>"); + out.println("<p>" + rb.getString("XMPP instructions") + "</p>"); + out.println("<hr class=\"signup-hr\"/>"); + out.println("<h1 class=\"signup-h1\">" + rb.getString("Have Juick") + "</h1>"); out.println("<form action=\"/login\" method=\"post\">"); out.println("<p>" + rb.getString("Username") + ": <input type=\"text\" name=\"username\"/></p>"); out.println("<p>" + rb.getString("Password") + ": <input type=\"password\" name=\"password\"/></p>"); 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("<html>"); out.println("<head>"); out.println(" <title>" + title + "</title>"); - out.println(" <link rel=\"stylesheet\" href=\"//static.juick.com/style3.2013022002.css\"/>"); + out.println(" <link rel=\"stylesheet\" href=\"//static.juick.com/style3.2013032901.css\"/>"); out.println(" <link rel=\"icon\" type=\"image/png\" href=\"//static.juick.com/favicon.png\"/>"); out.println(" <script type=\"text/javascript\" src=\"//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js\" defer=\"defer\"></script>"); out.println(" <script type=\"text/javascript\" src=\"//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js\" defer=\"defer\" async=\"async\"></script>"); - out.println(" <script type=\"text/javascript\" src=\"//static.juick.com/scripts3.2013010300.js\" defer=\"defer\"></script>"); + out.println(" <script type=\"text/javascript\" src=\"//static.juick.com/scripts3.2013032900.js\" defer=\"defer\"></script>"); 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 <http://www.gnu.org/licenses/>. + */ +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("<div id=\"topwrapper\">"); + out.println("<div id=\"wrapper\">"); + out.println("<div id=\"content\">"); + out.println("<form action=\"/login\" method=\"post\">"); + out.println("<p>" + rb.getString("Username") + ": <input type=\"text\" name=\"username\"/></p>"); + out.println("<p>" + rb.getString("Password") + ": <input type=\"password\" name=\"password\"/></p>"); + out.println("<p><input type=\"submit\" value=\" OK \"/></p>"); + out.println("</form>"); + out.println("</div>"); + out.println("</div>"); + out.println("</div>"); // 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 <http://www.gnu.org/licenses/>. + */ +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("<div id=\"topwrapper\">"); + out.println("<div id=\"wrapper\">"); + out.println("<div id=\"content\">"); + + out.print("<h1 class=\"signup-h1\">"); + if (type.charAt(0) == 'f') { + out.print("<img src=\"//static.juick.com/settings/facebook.png\" alt=\"Facebook\"/>"); + } else if (type.charAt(0) == 'x') { + out.print("<img src=\"//static.juick.com/settings/xmpp.png\" alt=\"XMPP\"/>"); + } + out.println(account + "</h1>"); + + out.println("<h2 class=\"signup-h2\">" + rb.getString("Link with existing") + "</h2>"); + out.println("<form action=\"/signup\" method=\"post\">"); + out.println("<input type=\"hidden\" name=\"action\" value=\"link\"/>"); + out.println("<input type=\"hidden\" name=\"type\" value=\"" + type + "\"/>"); + out.println("<input type=\"hidden\" name=\"hash\" value=\"" + hash + "\"/>"); + if (visitor != null) { + out.println("<input type=\"submit\" value=\"" + rb.getString("Link with this") + "\"/>"); + } else { + out.println("<p>" + rb.getString("Username") + ": <input type=\"text\" name=\"username\"/></p>"); + out.println("<p>" + rb.getString("Password") + ": <input type=\"password\" name=\"password\"/></p>"); + out.println("<p><input type=\"submit\" value=\" OK \"/></p>"); + } + out.println("</form>"); + + out.println("<hr class=\"signup-hr\"/>"); + + out.println("<h2 class=\"signup-h2\">" + rb.getString("Create new") + "</h2>"); + out.println("<form action=\"/signup\" method=\"post\">"); + out.println("<input type=\"hidden\" name=\"action\" value=\"new\"/>"); + out.println("<input type=\"hidden\" name=\"type\" value=\"" + type + "\"/>"); + out.println("<input type=\"hidden\" name=\"hash\" value=\"" + hash + "\"/>"); + out.println("<p>" + rb.getString("Username") + ": <input type=\"text\" name=\"username\" id=\"username\" onblur=\"checkUsername()\"/><br/><i>" + rb.getString("Username restrictions") + "</i></p>"); + out.println("<p>" + rb.getString("Password") + ": <input type=\"password\" name=\"password\"/><br/><i>" + rb.getString("Password restrictions") + "</i></p>"); + out.println("<p>" + rb.getString("Language") + ": <select name=\"lang\">"); + String langs[] = rb.getString("Languages").split(","); + String langcodes[] = rb.getString("Language codes").split(","); + for (int i = 0; i < langs.length; i++) { + out.println(" <option value=\"" + langcodes[i] + "\">" + langs[i] + "</option>"); + } + out.println("</select></p>"); + out.println("<p><input type=\"submit\" value=\" OK \"/></p>"); + out.println("</form>"); + + out.println("</div>"); + out.println("</div>"); + out.println("</div>"); // 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 = "<a href=\"" + rs.getString(2) + "\" rel=\"nofollow\">" + rs.getString(1) + "</a>"; + } + } 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; + } + } } diff --git a/web/scripts3.js b/web/scripts3.js index 8be4d551..f4a21da3 100644 --- a/web/scripts3.js +++ b/web/scripts3.js @@ -96,23 +96,32 @@ function openSocialWindow(url) { if(window.focus) w.focus(); } +function checkUsername() { + var uname=$('#username').val(); + $.ajax('http://api.juick.com/users?uname='+uname).done(function() { + $('#username').css('background','#FFCCCC'); + }).fail(function() { + $('#username').css('background','#CCFFCC'); + }); +} + /******************************************************************************/ jQuery.fn.selectText = function(){ - var doc = document; - var element = this[0]; - console.log(this, element); - if (doc.body.createTextRange) { - var range = document.body.createTextRange(); - range.moveToElementText(element); - range.select(); - } else if (window.getSelection) { - var selection = window.getSelection(); - var range = document.createRange(); - range.selectNodeContents(element); - selection.removeAllRanges(); - selection.addRange(range); - } + var doc = document; + var element = this[0]; + console.log(this, element); + if (doc.body.createTextRange) { + var range = document.body.createTextRange(); + range.moveToElementText(element); + range.select(); + } else if (window.getSelection) { + var selection = window.getSelection(); + var range = document.createRange(); + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); + } }; /* diff --git a/web/style3.css b/web/style3.css index f1bc761b..4a79e4ed 100644 --- a/web/style3.css +++ b/web/style3.css @@ -5,7 +5,7 @@ h1,h2 { font-weight: normal; } ul { list-style-type: none; } a { text-decoration: none; color: #069; } img,hr { border: none; } -hr { height: 1px; background: #CCC; } +hr { height: 1px; background: #CCC; margin: 10px 0; } pre { white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; } .u { text-decoration: underline; } @@ -78,6 +78,12 @@ blockquote { border-left: 1px dashed #CCC; margin: 10px 0 10px 10px; padding-lef .page { text-align: center; padding: 5px; background: #E5E5DD; } +/* signup form */ +.signup-h1>img { vertical-align: middle; margin-right: 10px; } +.signup-h1 { margin: 20px 0 10px 0; font-size: x-large; } +.signup-h2 { font-size: large; margin: 10px 0 5px 0; } +.signup-hr { margin: 20px 0; } + /********/ #column { width: 185px; top: 0; padding-top: 10px; overflow: hidden; } |