From b0ab4664edfc6ee90b658bfa662a54dec42879b3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Tue, 24 Jun 2014 01:14:57 +0200 Subject: [PATCH] Finish up signup process (so that it's usable except "verify") --- src/org/cacert/gigi/User.java | 22 ++++ .../gigi/database/DatabaseConnection.java | 9 ++ src/org/cacert/gigi/pages/main/Signup.java | 69 +++++++++++- src/org/cacert/gigi/util/Notary.java | 28 +++++ src/org/cacert/gigi/util/PasswordHash.java | 4 + .../gigi/util/PasswordStrengthChecker.java | 2 +- src/org/cacert/gigi/util/RandomToken.java | 23 ++++ src/org/cacert/gigi/util/Sendmail.java | 106 ++++++++++++++++++ src/org/cacert/gigi/util/ServerConstants.java | 5 + 9 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 src/org/cacert/gigi/util/Notary.java create mode 100644 src/org/cacert/gigi/util/RandomToken.java create mode 100644 src/org/cacert/gigi/util/Sendmail.java create mode 100644 src/org/cacert/gigi/util/ServerConstants.java diff --git a/src/org/cacert/gigi/User.java b/src/org/cacert/gigi/User.java index 50e13ac0..b049bc3f 100644 --- a/src/org/cacert/gigi/User.java +++ b/src/org/cacert/gigi/User.java @@ -6,6 +6,7 @@ import java.sql.SQLException; import java.util.Date; import org.cacert.gigi.database.DatabaseConnection; +import org.cacert.gigi.util.PasswordHash; public class User { @@ -77,5 +78,26 @@ public class User { public void setLname(String lname) { this.lname = lname; } + public void insert(String password) throws SQLException { + if (id != 0) { + throw new Error("refusing to insert"); + } + PreparedStatement query = DatabaseConnection.getInstance().prepare( + "insert into `users` set `email`=?, `password`=?, " + + "`fname`=?, `mname`=?, `lname`=?, " + + "`suffix`=?, `dob`=?, `created`=NOW()," + + " `orgadmin`=0, `adadmin`=0, `locked`=0," + + " `uniqueID`=0, `otphash`='', `otppin`=0"); + query.setString(1, email); + query.setString(2, PasswordHash.hash(password)); + query.setString(3, fname); + query.setString(4, mname); + query.setString(5, lname); + query.setString(6, suffix); + query.setDate(7, new java.sql.Date(dob.getTime())); + query.execute(); + id = DatabaseConnection.lastInsertId(query); + System.out.println("Inserted: " + id); + } } diff --git a/src/org/cacert/gigi/database/DatabaseConnection.java b/src/org/cacert/gigi/database/DatabaseConnection.java index 6d505d86..68ddd8c8 100644 --- a/src/org/cacert/gigi/database/DatabaseConnection.java +++ b/src/org/cacert/gigi/database/DatabaseConnection.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Properties; @@ -43,6 +44,14 @@ public class DatabaseConnection { } return statement; } + + public static int lastInsertId(PreparedStatement query) throws SQLException { + ResultSet rs = query.getGeneratedKeys(); + rs.next(); + int id = rs.getInt(1); + rs.close(); + return id; + } static ThreadLocal instances = new ThreadLocal() { @Override protected DatabaseConnection initialValue() { diff --git a/src/org/cacert/gigi/pages/main/Signup.java b/src/org/cacert/gigi/pages/main/Signup.java index cad5d141..f4ba0c1b 100644 --- a/src/org/cacert/gigi/pages/main/Signup.java +++ b/src/org/cacert/gigi/pages/main/Signup.java @@ -21,12 +21,14 @@ import org.cacert.gigi.output.Template; import org.cacert.gigi.pages.Page; import org.cacert.gigi.util.EmailChecker; import org.cacert.gigi.util.HTMLEncoder; +import org.cacert.gigi.util.Notary; import org.cacert.gigi.util.PasswordStrengthChecker; +import org.cacert.gigi.util.RandomToken; +import org.cacert.gigi.util.Sendmail; +import org.cacert.gigi.util.ServerConstants; public class Signup { User buildup = new User(); - String password; - String password2; Template t; boolean general = true, country = true, regional = true, radius = true; public Signup() { @@ -88,7 +90,7 @@ public class Signup { myDoB.update(r); } - public boolean submit(PrintWriter out, HttpServletRequest req) { + public synchronized boolean submit(PrintWriter out, HttpServletRequest req) { update(req); boolean failed = false; out.println("
"); @@ -126,6 +128,7 @@ public class Signup { "The Pass Phrase you submitted failed to contain enough" + " differing characters and/or contained words from" + " your name and/or email address."); + failed = true; } if (failed) { out.println("
"); @@ -205,7 +208,11 @@ public class Signup { if (failed) { return false; } - // TODO start getting to work + try { + run(req, pw1); + } catch (SQLException e) { + e.printStackTrace(); + } return true; } private void outputError(PrintWriter out, ServletRequest req, String text) { @@ -213,4 +220,58 @@ public class Signup { out.print(Page.translate(req, text)); out.println(""); } + + private void run(HttpServletRequest req, String password) + throws SQLException { + String hash = RandomToken.generateToken(16); + + buildup.insert(password); + int memid = buildup.getId(); + PreparedStatement ps = DatabaseConnection.getInstance().prepare( + "insert into `email` set `email`=?," + + " `hash`=?, `created`=NOW(),`memid`=?"); + ps.setString(1, buildup.getEmail()); + ps.setString(2, hash); + ps.setInt(3, memid); + ps.execute(); + int emailid = DatabaseConnection.lastInsertId(ps); + ps = DatabaseConnection + .getInstance() + .prepare( + "insert into `alerts` set `memid`=?," + + " `general`=?, `country`=?, `regional`=?, `radius`=?"); + ps.setInt(1, memid); + ps.setString(2, general ? "1" : "0"); + ps.setString(3, country ? "1" : "0"); + ps.setString(4, regional ? "1" : "0"); + ps.setString(5, radius ? "1" : "0"); + ps.execute(); + Notary.writeUserAgreement(memid, "CCA", "account creation", "", true, 0); + + StringBuffer body = new StringBuffer(); + body.append(Page + .translate( + req, + "Thanks for signing up with CAcert.org, below is the link you need to open to verify your account. Once your account is verified you will be able to start issuing certificates till your hearts' content!")); + body.append("\n\n"); + body.append("http://"); + body.append(ServerConstants.NORMAL_HOST_NAME); + body.append("/verify.php?type=email&emailid="); + body.append(emailid); + body.append("&hash="); + body.append(hash); + body.append("\n\n"); + body.append(Page.translate(req, "Best regards")); + body.append("\n"); + body.append(Page.translate(req, "CAcert.org Support!")); + try { + Sendmail.sendmail(buildup.getEmail(), + "[CAcert.org] " + Page.translate(req, "Mail Probe"), + body.toString(), "support@cacert.org", null, null, null, + null, false); + } catch (IOException e) { + e.printStackTrace(); + } + + } } diff --git a/src/org/cacert/gigi/util/Notary.java b/src/org/cacert/gigi/util/Notary.java new file mode 100644 index 00000000..92609ff5 --- /dev/null +++ b/src/org/cacert/gigi/util/Notary.java @@ -0,0 +1,28 @@ +package org.cacert.gigi.util; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.cacert.gigi.database.DatabaseConnection; + +public class Notary { + public static void writeUserAgreement(int memid, String document, + String method, String comment, boolean active, int secmemid) { + try { + PreparedStatement q = DatabaseConnection + .getInstance() + .prepare( + "insert into `user_agreements` set `memid`=?, `secmemid`=?," + + " `document`=?,`date`=NOW(), `active`=?,`method`=?,`comment`=?"); + q.setInt(1, memid); + q.setInt(2, secmemid); + q.setString(3, document); + q.setInt(4, active ? 1 : 0); + q.setString(5, method); + q.setString(6, comment); + q.execute(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/src/org/cacert/gigi/util/PasswordHash.java b/src/org/cacert/gigi/util/PasswordHash.java index 1baf1370..edc1ad53 100644 --- a/src/org/cacert/gigi/util/PasswordHash.java +++ b/src/org/cacert/gigi/util/PasswordHash.java @@ -23,4 +23,8 @@ public class PasswordHash { throw new Error(e); } } + + public static String hash(String password) { + return sha1(password); + } } diff --git a/src/org/cacert/gigi/util/PasswordStrengthChecker.java b/src/org/cacert/gigi/util/PasswordStrengthChecker.java index 37307992..0f72664e 100644 --- a/src/org/cacert/gigi/util/PasswordStrengthChecker.java +++ b/src/org/cacert/gigi/util/PasswordStrengthChecker.java @@ -64,7 +64,7 @@ public class PasswordStrengthChecker { return light; } private static boolean contained(String pw, String check) { - if (check == null) { + if (check == null || check.equals("")) { return false; } if (pw.contains(check)) { diff --git a/src/org/cacert/gigi/util/RandomToken.java b/src/org/cacert/gigi/util/RandomToken.java new file mode 100644 index 00000000..8e83bb90 --- /dev/null +++ b/src/org/cacert/gigi/util/RandomToken.java @@ -0,0 +1,23 @@ +package org.cacert.gigi.util; + +import java.security.SecureRandom; + +public class RandomToken { + static SecureRandom sr = new SecureRandom(); + public static String generateToken(int length) { + StringBuffer token = new StringBuffer(); + for (int i = 0; i < length; i++) { + int rand = sr.nextInt(26 * 2 + 10); + if (rand < 10) { + token.append('0' + rand); + } + rand -= 10; + if (rand < 26) { + token.append('a' + rand); + } + rand -= 26; + token.append('A' + rand); + } + return token.toString(); + } +} diff --git a/src/org/cacert/gigi/util/Sendmail.java b/src/org/cacert/gigi/util/Sendmail.java new file mode 100644 index 00000000..3333a11a --- /dev/null +++ b/src/org/cacert/gigi/util/Sendmail.java @@ -0,0 +1,106 @@ +package org.cacert.gigi.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; +import java.util.Locale; +import java.util.regex.Pattern; + +public class Sendmail { + private Sendmail() { + } + private static final Pattern NON_ASCII = Pattern + .compile("[^a-zA-Z0-9 .-\\[\\]!_@]"); + + public static void sendmail(String to, String subject, String message, + String from, String replyto, String toname, String fromname, + String errorsto, boolean extra) throws IOException { + + String[] bits = from.split(","); + + Socket smtp = new Socket("dogcraft.de", 25); + PrintWriter out = new PrintWriter(smtp.getOutputStream()); + BufferedReader in = new BufferedReader(new InputStreamReader( + smtp.getInputStream())); + readResponse(in); + out.print("HELO www.cacert.org\r\n"); + out.flush(); + readResponse(in); + out.print("MAIL FROM:\r\n"); + out.flush(); + readResponse(in); + bits = to.split(","); + for (String user : bits) { + out.print("RCPT TO:<" + user.trim() + ">\r\n"); + out.flush(); + readResponse(in); + } + out.print("DATA\r\n"); + out.flush(); + readResponse(in); + out.print("X-Mailer: CAcert.org Website\r\n"); + // if (array_key_exists("REMOTE_ADDR", $_SERVER)) { + // out.print("X-OriginatingIP: ".$_SERVER["REMOTE_ADDR"]."\r\n"); + // } + // TODO + SimpleDateFormat emailDate = new SimpleDateFormat( + "E, d MMM yyyy HH:mm:ss ZZZZ (z)", Locale.ENGLISH); + out.print("Date: " + + emailDate.format(new Date(System.currentTimeMillis())) + + "\r\n"); + out.print("Sender: " + errorsto + "\r\n"); + out.print("Errors-To: " + errorsto + "\r\n"); + if (replyto != null) { + out.print("Reply-To: " + replyto + "\r\n"); + } else { + out.print("Reply-To: " + from + "\r\n"); + } + out.print("From: " + from + "\r\n"); + out.print("To: " + to + "\r\n"); + if (NON_ASCII.matcher(subject).matches()) { + + out.print("Subject: =?utf-8?B?" + + Base64.getEncoder().encodeToString(subject.getBytes()) + + "?=\r\n"); + } else { + out.print("Subject: " + subject + "\r\n"); + } + out.print("Mime-Version: 1.0\r\n"); + if (!extra) { + out.print("Content-Type: text/plain; charset=\"utf-8\"\r\n"); + out.print("Content-Transfer-Encoding: 8bit\r\n"); + } else { + out.print("Content-Type: text/plain; charset=\"iso-8859-1\"\r\n"); + out.print("Content-Transfer-Encoding: quoted-printable\r\n"); + out.print("Content-Disposition: inline\r\n"); + } + // out.print("Content-Transfer-Encoding: BASE64\r\n"); + out.print("\r\n"); + // out.print(chunk_split(base64_encode(recode("html..utf-8", + // $message)))."\r\n.\r\n"); + message = message + "\r\n"; + + String sendM = message.replace("\r", "").replace("\n.\n", "\n") + .replace("\n.\n", "\n").replace("\n", "\r\n") + + ".\r\n"; + out.print(sendM); + out.flush(); + readResponse(in); + out.print("QUIT\n"); + out.flush(); + readResponse(in); + smtp.close(); + } + private static void readResponse(BufferedReader in) throws IOException { + String line; + while ((line = in.readLine()) != null && line.matches("\\d+-")) { + } + + } + +} diff --git a/src/org/cacert/gigi/util/ServerConstants.java b/src/org/cacert/gigi/util/ServerConstants.java new file mode 100644 index 00000000..c2d7fd85 --- /dev/null +++ b/src/org/cacert/gigi/util/ServerConstants.java @@ -0,0 +1,5 @@ +package org.cacert.gigi.util; + +public class ServerConstants { + public static final String NORMAL_HOST_NAME = "www.cacert.org"; +} -- 2.39.2