]> WPIA git - gigi.git/blobdiff - src/org/cacert/gigi/pages/main/Signup.java
upd: enforce a more strict Form call pattern.
[gigi.git] / src / org / cacert / gigi / pages / main / Signup.java
index 3d074441edbd3d587894d1ca865a0d3b62daaa02..011b63843d43aaee07d8c405f268236a5ad516ba 100644 (file)
 package org.cacert.gigi.pages.main;
 
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.cacert.gigi.Language;
-import org.cacert.gigi.User;
-import org.cacert.gigi.database.DatabaseConnection;
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.database.GigiPreparedStatement;
+import org.cacert.gigi.database.GigiResultSet;
+import org.cacert.gigi.dbObjects.User;
 import org.cacert.gigi.email.EmailProvider;
+import org.cacert.gigi.localisation.Language;
+import org.cacert.gigi.output.CountrySelector;
 import org.cacert.gigi.output.DateSelector;
-import org.cacert.gigi.output.Form;
-import org.cacert.gigi.output.Template;
+import org.cacert.gigi.output.NameInput;
+import org.cacert.gigi.output.template.Form;
+import org.cacert.gigi.output.template.PlainOutputable;
+import org.cacert.gigi.output.template.SprintfCommand;
+import org.cacert.gigi.output.template.Template;
+import org.cacert.gigi.output.template.TranslateCommand;
 import org.cacert.gigi.pages.Page;
+import org.cacert.gigi.util.CalendarUtil;
 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.ServerConstants;
+import org.cacert.gigi.util.RateLimit.RateLimitException;
 
 public class Signup extends Form {
-       User buildup = new User();
-       Template t;
-       boolean general = true, country = true, regional = true, radius = true;
-       public Signup() {
-               try {
-                       t = new Template(new InputStreamReader(
-                                       Signup.class.getResourceAsStream("Signup.templ"), "UTF-8"));
-               } catch (UnsupportedEncodingException e) {
-                       e.printStackTrace();
-               }
-               buildup.setFname("");
-               buildup.setMname("");
-               buildup.setLname("");
-               buildup.setSuffix("");
-               buildup.setEmail("");
-               buildup.setDob(new Date(0));
-       }
-       DateSelector myDoB = new DateSelector("day", "month", "year");
 
-       public void output(PrintWriter out, Language l,
-                       Map<String, Object> outerVars) {
-               HashMap<String, Object> vars = new HashMap<String, Object>();
-               vars.put("fname", HTMLEncoder.encodeHTML(buildup.getFname()));
-               vars.put("mname", HTMLEncoder.encodeHTML(buildup.getMname()));
-               vars.put("lname", HTMLEncoder.encodeHTML(buildup.getLname()));
-               vars.put("suffix", HTMLEncoder.encodeHTML(buildup.getSuffix()));
-               vars.put("dob", myDoB);
-               vars.put("email", HTMLEncoder.encodeHTML(buildup.getEmail()));
-               vars.put("general", general ? " checked=\"checked\"" : "");
-               vars.put("country", country ? " checked=\"checked\"" : "");
-               vars.put("regional", regional ? " checked=\"checked\"" : "");
-               vars.put("radius", radius ? " checked=\"checked\"" : "");
-               vars.put(
-                               "helpOnNames",
-                               String.format(
-                                               l.getTranslation("Help on Names %sin the wiki%s"),
-                                               "<a href=\"//wiki.cacert.org/FAQ/HowToEnterNamesInJoinForm\" target=\"_blank\">",
-                                               "</a>"));
-               t.output(out, l, vars);
-       }
-       private void update(HttpServletRequest r) {
-               if (r.getParameter("fname") != null) {
-                       buildup.setFname(r.getParameter("fname"));
-               }
-               if (r.getParameter("lname") != null) {
-                       buildup.setLname(r.getParameter("lname"));
-               }
-               if (r.getParameter("mname") != null) {
-                       buildup.setMname(r.getParameter("mname"));
-               }
-               if (r.getParameter("suffix") != null) {
-                       buildup.setSuffix(r.getParameter("suffix"));
-               }
-               if (r.getParameter("email") != null) {
-                       buildup.setEmail(r.getParameter("email"));
-               }
-               general = "1".equals(r.getParameter("general"));
-               country = "1".equals(r.getParameter("country"));
-               regional = "1".equals(r.getParameter("regional"));
-               radius = "1".equals(r.getParameter("radius"));
-               myDoB.update(r);
-       }
+    private NameInput ni;
 
-       @Override
-       public synchronized boolean submit(PrintWriter out, HttpServletRequest req) {
-               update(req);
-               boolean failed = false;
-               out.println("<div class='formError'>");
-               if (buildup.getFname().equals("") || buildup.getLname().equals("")) {
-                       outputError(out, req, "First and/or last names were blank.");
-                       failed = true;
-               }
-               if (!myDoB.isValid()) {
-                       outputError(out, req, "Invalid date of birth");
-                       failed = true;
-               }
-               if (!"1".equals(req.getParameter("cca_agree"))) {
-                       outputError(out, req,
-                                       "You have to agree to the CAcert Community agreement.");
-                       failed = true;
-               }
-               if (buildup.getEmail().equals("")) {
-                       outputError(out, req, "Email Address was blank");
-                       failed = true;
-               }
-               String pw1 = req.getParameter("pword1");
-               String pw2 = req.getParameter("pword2");
-               if (pw1 == null || pw1.equals("")) {
-                       outputError(out, req, "Pass Phrases were blank");
-                       failed = true;
-               } else if (!pw1.equals(pw2)) {
-                       outputError(out, req, "Pass Phrases don't match");
-                       failed = true;
-               }
-               int pwpoints = PasswordStrengthChecker.checkpw(pw1, buildup);
-               if (pwpoints < 3) {
-                       outputError(
-                                       out,
-                                       req,
-                                       "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("</div>");
-                       return false;
-               }
-               try {
-                       PreparedStatement q1 = DatabaseConnection.getInstance().prepare(
-                                       "select * from `email` where `email`=? and `deleted`=0");
-                       PreparedStatement q2 = DatabaseConnection.getInstance().prepare(
-                                       "select * from `users` where `email`=? and `deleted`=0");
-                       q1.setString(1, buildup.getEmail());
-                       q2.setString(1, buildup.getEmail());
-                       ResultSet r1 = q1.executeQuery();
-                       ResultSet r2 = q2.executeQuery();
-                       if (r1.next() || r2.next()) {
-                               outputError(out, req,
-                                               "This email address is currently valid in the system.");
-                               failed = true;
-                       }
-                       r1.close();
-                       r2.close();
-                       PreparedStatement q3 = DatabaseConnection
-                                       .getInstance()
-                                       .prepare(
-                                                       "select `domain` from `baddomains` where `domain`=RIGHT(?, LENGTH(`domain`))");
-                       q3.setString(1, buildup.getEmail());
+    private String email = "";
 
-                       ResultSet r3 = q3.executeQuery();
-                       if (r3.next()) {
-                               String domain = r3.getString(1);
-                               out.print("<div>");
-                               out.print(String.format(
-                                               Page.translate(req,
-                                                               "We don't allow signups from people using email addresses from %s"),
-                                               domain));
-                               out.println("</div>");
-                               failed = true;
-                       }
-                       r3.close();
-               } catch (SQLException e) {
-                       e.printStackTrace();
-                       failed = true;
-               }
-               String mailResult = EmailProvider.FAIL;
-               try {
-                       mailResult = EmailProvider.getInstance().checkEmailServer(0,
-                                       buildup.getEmail());
-               } catch (IOException e) {
-               }
-               if (!mailResult.equals(EmailProvider.OK)) {
-                       if (mailResult.startsWith("4")) {
-                               outputError(
-                                               out,
-                                               req,
-                                               "The mail server responsible for your domain indicated"
-                                                               + " a temporary failure. This may be due to anti-SPAM measures, such"
-                                                               + " as greylisting. Please try again in a few minutes.");
-                       } else {
-                               outputError(
-                                               out,
-                                               req,
-                                               "Email Address given was invalid, or a test connection"
-                                                               + " couldn't be made to your server, or the server"
-                                                               + " rejected the email address as invalid");
-                       }
-                       if (mailResult.equals(EmailProvider.FAIL)) {
-                               outputError(out, req,
-                                               "Failed to make a connection to the mail server");
-                       } else {
-                               out.print("<div>");
-                               out.print(mailResult);
-                               out.println("</div>");
-                       }
-                       failed = true;
-               }
+    private static final Template t = new Template(Signup.class.getResource("Signup.templ"));
 
-               out.println("</div>");
-               if (failed) {
-                       return false;
-               }
-               try {
-                       run(req, pw1);
-               } catch (SQLException e) {
-                       e.printStackTrace();
-               }
-               return true;
-       }
+    private boolean general = true, country = true, regional = true, radius = true;
 
-       private void run(HttpServletRequest req, String password)
-                       throws SQLException {
-               try {
-                       DatabaseConnection.getInstance().beginTransaction();
-                       String hash = RandomToken.generateToken(16);
+    private CountrySelector cs;
 
-                       buildup.setDob(myDoB.getDate());
-                       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);
+    public Signup(HttpServletRequest hsr) {
+        super(hsr);
+        ni = new NameInput();
+        cs = new CountrySelector("residenceCountry", true);
+    }
 
-                       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(ServerConstants.NORMAL_HOST_NAME);
-                       body.append("/verify?type=email&id=");
-                       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 {
-                               EmailProvider.getInstance().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();
-                       }
-                       DatabaseConnection.getInstance().commitTransaction();
-               } finally {
-                       DatabaseConnection.getInstance().quitTransaction();
-               }
+    private DateSelector myDoB = new DateSelector("day", "month", "year");
+
+    @Override
+    public void outputContent(PrintWriter out, Language l, Map<String, Object> outerVars) {
+        HashMap<String, Object> vars = new HashMap<String, Object>();
+        vars.put("name", ni);
+        vars.put("dob", myDoB);
+        vars.put("email", HTMLEncoder.encodeHTML(email));
+        vars.put("general", general ? " checked=\"checked\"" : "");
+        vars.put("country", country ? " checked=\"checked\"" : "");
+        vars.put("regional", regional ? " checked=\"checked\"" : "");
+        vars.put("radius", radius ? " checked=\"checked\"" : "");
+        vars.put("helpOnNames", String.format(l.getTranslation("Help on Names %sin the wiki%s"), "<a href=\"//wiki.cacert.org/FAQ/HowToEnterNamesInJoinForm\" target=\"_blank\">", "</a>"));
+        vars.put("csrf", getCSRFToken());
+        vars.put("dobmin", User.MINIMUM_AGE + "");
+        vars.put("countryCode", cs);
+        t.output(out, l, vars);
+    }
+
+    private void update(HttpServletRequest r) throws GigiApiException {
+        if (r.getParameter("email") != null) {
+            email = r.getParameter("email");
+        }
+        general = "1".equals(r.getParameter("general"));
+        country = "1".equals(r.getParameter("country"));
+        regional = "1".equals(r.getParameter("regional"));
+        radius = "1".equals(r.getParameter("radius"));
+        GigiApiException problems = new GigiApiException();
+        try {
+            ni.update(r);
+        } catch (GigiApiException e) {
+            problems.mergeInto(e);
+        }
+        try {
+            myDoB.update(r);
+        } catch (GigiApiException e) {
+            problems.mergeInto(e);
+        }
+
+        cs.update(r);
+
+        if ( !problems.isEmpty()) {
+            throw problems;
+        }
+
+    }
+
+    @Override
+    public synchronized SubmissionResult submit(HttpServletRequest req) throws GigiApiException {
+        if (RegisterPage.RATE_LIMIT.isLimitExceeded(req.getRemoteAddr())) {
+            throw new RateLimitException();
+        }
+
+        GigiApiException ga = new GigiApiException();
+        try {
+            update(req);
+        } catch (GigiApiException e) {
+            ga.mergeInto(e);
+        }
+        try {
+            ni.getNameParts();
+        } catch (GigiApiException e) {
+            ga.mergeInto(e);
+        }
+
+        if ( !myDoB.isValid()) {
+            ga.mergeInto(new GigiApiException("Invalid date of birth"));
+        }
+
+        if ( !CalendarUtil.isOfAge(myDoB.getDate(), User.MINIMUM_AGE)) {
+            ga.mergeInto(new GigiApiException("Entered date of birth is below the restricted age requirements."));
+        }
+
+        if (CalendarUtil.isOfAge(myDoB.getDate(), User.MAXIMUM_PLAUSIBLE_AGE)) {
+            ga.mergeInto(new GigiApiException("Entered date of birth exceeds the maximum age set in our policies. Please check your DoB is correct and contact support if the issue persists."));
+        }
+
+        if ( !"1".equals(req.getParameter("tos_agree"))) {
+            ga.mergeInto(new GigiApiException("Acceptance of the ToS is required to continue."));
+        }
+        if (email.equals("")) {
+            ga.mergeInto(new GigiApiException("Email Address was blank"));
+        }
+        String pw1 = req.getParameter("pword1");
+        String pw2 = req.getParameter("pword2");
+        if (pw1 == null || pw1.equals("")) {
+            ga.mergeInto(new GigiApiException("Pass Phrases were blank"));
+        } else if ( !pw1.equals(pw2)) {
+            ga.mergeInto(new GigiApiException("Pass Phrases don't match"));
+        }
+        int pwpoints = PasswordStrengthChecker.checkpw(pw1, ni.getNamePartsPlain(), email);
+        if (pwpoints < 3) {
+            ga.mergeInto(new GigiApiException("The Pass Phrase you submitted failed to contain enough" + " differing characters and/or contained words from" + " your name and/or email address."));
+        }
+        if ( !ga.isEmpty()) {
+            throw ga;
+        }
+        GigiApiException ga2 = new GigiApiException();
+        try (GigiPreparedStatement q1 = new GigiPreparedStatement("SELECT * FROM `emails` WHERE `email`=? AND `deleted` IS NULL"); GigiPreparedStatement q2 = new GigiPreparedStatement("SELECT * FROM `certOwners` INNER JOIN `users` ON `users`.`id`=`certOwners`.`id` WHERE `email`=? AND `deleted` IS NULL")) {
+            q1.setString(1, email);
+            q2.setString(1, email);
+            GigiResultSet r1 = q1.executeQuery();
+            GigiResultSet r2 = q2.executeQuery();
+            if (r1.next() || r2.next()) {
+                ga2.mergeInto(new GigiApiException("This email address is currently valid in the system."));
+            }
+        }
+        try (GigiPreparedStatement q3 = new GigiPreparedStatement("SELECT `domain` FROM `baddomains` WHERE `domain`=RIGHT(?, LENGTH(`domain`))")) {
+            q3.setString(1, email);
+
+            GigiResultSet r3 = q3.executeQuery();
+            if (r3.next()) {
+                String domain = r3.getString(1);
+                ga2.mergeInto(new GigiApiException(SprintfCommand.createSimple("We don't allow signups from people using email addresses from {0}.", domain)));
+            }
+        }
+        String mailResult = EmailProvider.FAIL;
+        try {
+            mailResult = HTMLEncoder.encodeHTML(EmailProvider.getInstance().checkEmailServer(0, email));
+        } catch (IOException e) {
+        }
+        if ( !mailResult.equals(EmailProvider.OK)) {
+            if (mailResult.startsWith("4")) {
+                ga2.mergeInto(new GigiApiException("The mail server responsible for your domain indicated" + " a temporary failure. This may be due to anti-SPAM measures, such" + " as greylisting. Please try again in a few minutes."));
+            } else {
+                ga2.mergeInto(new GigiApiException("Email Address given was invalid, or a test connection" + " couldn't be made to your server, or the server" + " rejected the email address as invalid"));
+            }
+            if (mailResult.equals(EmailProvider.FAIL)) {
+                ga2.mergeInto(new GigiApiException("Failed to make a connection to the mail server"));
+            } else {
+                ga2.mergeInto(new GigiApiException(new PlainOutputable(mailResult)));
+            }
+        }
+
+        if ( !ga2.isEmpty()) {
+            throw ga2;
+        }
+        run(req, pw1);
+        return new SuccessMessageResult(new TranslateCommand("Your information has been submitted" + " into our system. You will now be sent an email with a web link," + " you need to open that link in your web browser within 24 hours" + " or your information will be removed from our system!"));
+    }
+
+    private void run(HttpServletRequest req, String password) throws GigiApiException {
+        User u = new User(email, password, myDoB.getDate(), Page.getLanguage(req).getLocale(), cs.getCountry(), ni.getNameParts());
+
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `alerts` SET `memid`=?," + " `general`=?, `country`=?, `regional`=?, `radius`=?")) {
+            ps.setInt(1, u.getId());
+            ps.setBoolean(2, general);
+            ps.setBoolean(3, country);
+            ps.setBoolean(4, regional);
+            ps.setBoolean(5, radius);
+            ps.execute();
+        }
+        Notary.writeUserAgreement(u, "ToS", "account creation", "", true, 0);
+    }
 
-       }
 }