}
public void format(PrintWriter out, Language language) {
- out.println("<div class='formError'>");
+ out.println("<div class='bg-danger error-msgs'>");
if (isInternalError()) {
e.printStackTrace();
- out.print("<div>");
+ out.print("<p>");
out.println(language.getTranslation("An internal error occurred."));
- out.println("</div>");
+ out.println("</p>");
}
HashMap<String, Object> map = new HashMap<>();
for (Outputable message : messages) {
map.clear();
- out.print("<div>");
+ out.print("<p>");
message.output(out, language, map);
- out.println("</div>");
+ out.println("</p>");
}
out.println("</div>");
import java.io.PrintWriter;
import java.util.Map;
-import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.cacert.gigi.GigiApiException;
import org.cacert.gigi.localisation.Language;
-import org.cacert.gigi.pages.Page;
import org.cacert.gigi.util.RandomToken;
/**
} else {
out.println("<form method='POST' action='" + action + "'>");
}
- failed = false;
outputContent(out, l, vars);
out.print("<input type='hidden' name='" + CSRF_FIELD + "' value='");
out.print(getCSRFToken());
*/
protected abstract void outputContent(PrintWriter out, Language l, Map<String, Object> vars);
- private boolean failed;
-
- protected void outputError(PrintWriter out, ServletRequest req, String text, Object... contents) {
- if ( !failed) {
- failed = true;
- out.println("<div class='formError'>");
- }
- out.print("<div>");
- if (contents.length == 0) {
- out.print(Page.translate(req, text));
- } else {
- out.print(String.format(Page.translate(req, text), contents));
- }
- out.println("</div>");
- }
-
- protected void outputErrorPlain(PrintWriter out, String text) {
- if ( !failed) {
- failed = true;
- out.println("<div class='formError'>");
- }
- out.print("<div>");
- out.print(text);
- out.println("</div>");
- }
-
- public boolean isFailed(PrintWriter out) {
- if (failed) {
- out.println("</div>");
- }
- return failed;
- }
-
protected String getCSRFToken() {
return csrf;
}
--- /dev/null
+package org.cacert.gigi.output.template;
+
+import java.io.PrintWriter;
+import java.util.Map;
+
+import org.cacert.gigi.localisation.Language;
+import org.cacert.gigi.util.HTMLEncoder;
+
+public class PlainOutputable implements Outputable {
+
+ String text;
+
+ public PlainOutputable(String text) {
+ this.text = HTMLEncoder.encodeHTML(text);
+ }
+
+ @Override
+ public void output(PrintWriter out, Language l, Map<String, Object> vars) {
+ out.print(text);
+ }
+
+}
import org.cacert.gigi.util.AuthorizationContext;
import org.cacert.gigi.util.PasswordHash;
import org.cacert.gigi.util.RateLimit;
+import org.cacert.gigi.util.RateLimit.RateLimitException;
import org.cacert.gigi.util.ServerConstants;
public class LoginPage extends Page {
@Override
public boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException {
if (RegisterPage.RATE_LIMIT.isLimitExceeded(req.getRemoteAddr())) {
- outputError(out, req, "Rate Limit Exceeded");
- return false;
+ throw new RateLimitException();
}
tryAuthWithUnpw(req);
return false;
public static final String LOGIN_RETURNPATH = "login-returnpath";
+ private static final String SUBMIT_EXCEPTION = "login-submit-exception";
+
public LoginPage() {
super("Password Login");
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ Object o = req.getAttribute(SUBMIT_EXCEPTION);
+ if (o != null) {
+ ((GigiApiException) o).format(resp.getWriter(), getLanguage(req));
+ }
if (req.getHeader("Host").equals(ServerConstants.getSecureHostNamePort())) {
resp.getWriter().println(getLanguage(req).getTranslation("Authentication with certificate failed. Try another certificate or use a password."));
} else {
try {
Form.getForm(req, LoginForm.class).submit(resp.getWriter(), req);
} catch (GigiApiException e) {
+ req.setAttribute(SUBMIT_EXCEPTION, e);
+ return false;
}
}
}
return false;
}
- private void tryAuthWithUnpw(HttpServletRequest req) {
+ private void tryAuthWithUnpw(HttpServletRequest req) throws GigiApiException {
String un = req.getParameter("username");
String pw = req.getParameter("password");
try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `password`, `id` FROM `users` WHERE `email`=? AND verified='1'")) {
}
loginSession(req, User.getById(rs.getInt(2)));
req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Password"));
+ return;
}
}
}
+ throw new GigiApiException("Username and password didn't match.");
}
public static User getUser(HttpServletRequest req) {
import org.cacert.gigi.dbObjects.User;
import org.cacert.gigi.localisation.Language;
import org.cacert.gigi.output.template.Form;
+import org.cacert.gigi.output.template.PlainOutputable;
import org.cacert.gigi.output.template.Template;
import org.cacert.gigi.pages.Page;
}
@Override
- public boolean submit(PrintWriter out, HttpServletRequest req) {
+ public boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException {
String formMail = req.getParameter("newemail");
mail = formMail;
try {
new EmailAddress(target, mail, Page.getLanguage(req).getLocale());
} catch (IllegalArgumentException e) {
- out.println("<div class='formError'>Error: Invalid address!</div>");
- return false;
- } catch (GigiApiException e) {
- e.format(out, Page.getLanguage(req));
- return false;
+ throw new GigiApiException(new PlainOutputable("Invalid address."));
}
return true;
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.cacert.gigi.GigiApiException;
import org.cacert.gigi.dbObjects.User;
import org.cacert.gigi.localisation.Language;
import org.cacert.gigi.output.template.Form;
PrintWriter out = resp.getWriter();
if (req.getParameter("addmail") != null) {
MailAddForm f = Form.getForm(req, MailAddForm.class);
- if (f.submit(out, req)) {
- resp.sendRedirect(MailOverview.DEFAULT_PATH);
+ try {
+ if (f.submit(out, req)) {
+ resp.sendRedirect(MailOverview.DEFAULT_PATH);
+ }
+ } catch (GigiApiException e) {
+ e.format(resp.getWriter(), getLanguage(req));
}
} else {
MailManagementForm f = Form.getForm(req, MailManagementForm.class);
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import org.cacert.gigi.GigiApiException;
import org.cacert.gigi.output.template.Form;
import org.cacert.gigi.pages.Page;
import org.cacert.gigi.util.AuthorizationContext;
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Signup s = Form.getForm(req, Signup.class);
- if (s == null) {
- resp.getWriter().println(translate(req, "CSRF token check failed."));
- } else if (s.submit(resp.getWriter(), req)) {
- HttpSession hs = req.getSession();
- hs.setAttribute(SIGNUP_PROCESS, null);
- resp.getWriter().println(translate(req, "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!"));
- return;
+ try {
+ if (s.submit(resp.getWriter(), req)) {
+ HttpSession hs = req.getSession();
+ hs.setAttribute(SIGNUP_PROCESS, null);
+ resp.getWriter().println(translate(req, "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!"));
+ return;
+ }
+ } catch (GigiApiException e) {
+ e.format(resp.getWriter(), getLanguage(req));
}
outputGet(req, resp, s);
import java.io.IOException;
import java.io.PrintWriter;
-import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.cacert.gigi.localisation.Language;
import org.cacert.gigi.output.DateSelector;
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.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.RateLimit.RateLimitException;
public class Signup extends Form {
}
@Override
- public synchronized boolean submit(PrintWriter out, HttpServletRequest req) {
+ public synchronized boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException {
if (RegisterPage.RATE_LIMIT.isLimitExceeded(req.getRemoteAddr())) {
- outputError(out, req, "Rate Limit Exceeded");
- return false;
+ throw new RateLimitException();
}
update(req);
+ GigiApiException ga = new GigiApiException();
if (buildupName.getLname().trim().equals("")) {
- outputError(out, req, "Last name were blank.");
+ ga.mergeInto(new GigiApiException("Last name were blank."));
}
if ( !myDoB.isValid()) {
- outputError(out, req, "Invalid date of birth");
+ ga.mergeInto(new GigiApiException("Invalid date of birth"));
}
if ( !CalendarUtil.isOfAge(myDoB.getDate(), User.MINIMUM_AGE)) {
- outputError(out, req, "Entered dated of birth is below the restricted age requirements.");
+ ga.mergeInto(new GigiApiException("Entered dated of birth is below the restricted age requirements."));
}
if ( !"1".equals(req.getParameter("tos_agree"))) {
- outputError(out, req, "Acceptance of the ToS is required to continue.");
+ ga.mergeInto(new GigiApiException("Acceptance of the ToS is required to continue."));
}
if (email.equals("")) {
- outputError(out, req, "Email Address was blank");
+ ga.mergeInto(new GigiApiException("Email Address was blank"));
}
String pw1 = req.getParameter("pword1");
String pw2 = req.getParameter("pword2");
if (pw1 == null || pw1.equals("")) {
- outputError(out, req, "Pass Phrases were blank");
+ ga.mergeInto(new GigiApiException("Pass Phrases were blank"));
} else if ( !pw1.equals(pw2)) {
- outputError(out, req, "Pass Phrases don't match");
+ ga.mergeInto(new GigiApiException("Pass Phrases don't match"));
}
int pwpoints = PasswordStrengthChecker.checkpw(pw1, buildupName, email);
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.");
+ 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 (isFailed(out)) {
- return false;
+ 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()) {
- outputError(out, req, "This email address is currently valid in the system.");
+ 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`))")) {
GigiResultSet r3 = q3.executeQuery();
if (r3.next()) {
String domain = r3.getString(1);
- outputError(out, req, "We don't allow signups from people using email addresses from %s", domain);
+ ga2.mergeInto(new GigiApiException(SprintfCommand.createSimple("We don't allow signups from people using email addresses from {0}.", domain)));
}
}
String mailResult = EmailProvider.FAIL;
}
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.");
+ 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 {
- 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");
+ 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)) {
- outputError(out, req, "Failed to make a connection to the mail server");
+ ga2.mergeInto(new GigiApiException("Failed to make a connection to the mail server"));
} else {
- outputErrorPlain(out, mailResult);
+ ga2.mergeInto(new GigiApiException(new PlainOutputable(mailResult)));
}
}
- if (isFailed(out)) {
- return false;
- }
- try {
- run(req, pw1);
- } catch (SQLException e) {
- e.printStackTrace();
- } catch (GigiApiException e) {
- e.format(out, Page.getLanguage(req));
- return false;
+ if ( !ga2.isEmpty()) {
+ throw ga2;
}
+ run(req, pw1);
return true;
}
- private void run(HttpServletRequest req, String password) throws SQLException, GigiApiException {
+ private void run(HttpServletRequest req, String password) throws GigiApiException {
User u = new User(email, password, buildupName, myDoB.getDate(), Page.getLanguage(req).getLocale());
try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `alerts` SET `memid`=?," + " `general`=?, `country`=?, `regional`=?, `radius`=?")) {
}
@Override
- public boolean submit(PrintWriter out, HttpServletRequest req) {
+ public boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException {
location = req.getParameter("location");
date = req.getParameter("date");
+ GigiApiException gae = new GigiApiException();
if (date == null || location == null) {
- outputError(out, req, "You need to enter location and date!");
+ gae.mergeInto(new GigiApiException("You need to enter location and date!"));
}
if ( !"1".equals(req.getParameter("certify")) || !"1".equals(req.getParameter("rules")) || !"1".equals(req.getParameter("tos_agree")) || !"1".equals(req.getParameter("assertion"))) {
- outputError(out, req, "You failed to check all boxes to validate" + " your adherence to the rules and policies of SomeCA");
+ gae.mergeInto(new GigiApiException("You failed to check all boxes to validate" + " your adherence to the rules and policies of SomeCA"));
}
if ("1".equals(req.getParameter("passwordReset"))) {
aword = req.getParameter("passwordResetValue");
try {
type = AssuranceType.valueOf(val);
} catch (IllegalArgumentException e) {
- outputError(out, req, "Assurance Type wrong.");
+ gae.mergeInto(new GigiApiException("Assurance Type wrong."));
}
}
int pointsI = 0;
String points = req.getParameter("points");
if (points == null || "".equals(points)) {
- outputError(out, req, "For an assurance, you need to enter points.");
+ gae.mergeInto(new GigiApiException("For an assurance, you need to enter points."));
} else {
try {
pointsI = Integer.parseInt(points);
} catch (NumberFormatException e) {
- outputError(out, req, "The points entered were not a number.");
+ gae.mergeInto(new GigiApiException("The points entered were not a number."));
}
}
- if (isFailed(out)) {
- return false;
+ if ( !gae.isEmpty()) {
+ throw gae;
}
- try {
- Notary.assure(assurer, assuree, assureeName, dob, pointsI, location, req.getParameter("date"), type);
- if (aword != null && !aword.equals("")) {
- Language l = Language.getInstance(assuree.getPreferredLocale());
- String method = l.getTranslation("A password reset was triggered. If you did a password reset by assurance, please enter your secret password using this form:");
- String subject = l.getTranslation("Password reset by assurance");
- PasswordResetPage.initPasswordResetProcess(out, assuree, req, aword, l, method, subject);
- }
- return true;
- } catch (GigiApiException e) {
- e.format(out, Page.getLanguage(req));
+ Notary.assure(assurer, assuree, assureeName, dob, pointsI, location, req.getParameter("date"), type);
+ if (aword != null && !aword.equals("")) {
+ Language l = Language.getInstance(assuree.getPreferredLocale());
+ String method = l.getTranslation("A password reset was triggered. If you did a password reset by assurance, please enter your secret password using this form:");
+ String subject = l.getTranslation("Password reset by assurance");
+ PasswordResetPage.initPasswordResetProcess(out, assuree, req, aword, l, method, subject);
}
-
- return false;
+ return true;
}
public User getAssuree() {
PrintWriter out = resp.getWriter();
if (req.getParameter("search") == null) {
AssuranceForm form = Form.getForm(req, AssuranceForm.class);
- if (form.submit(out, req)) {
- out.println(translate(req, "Assurance complete."));
- } else {
+ try {
+ if (form.submit(out, req)) {
+ out.println(translate(req, "Assurance complete."));
+ return;
+ }
+ } catch (GigiApiException e) {
+ e.format(out, Page.getLanguage(req));
try {
Notary.checkAssuranceIsPossible(LoginPage.getUser(req), form.getAssuree());
form.output(out, getLanguage(req), new HashMap<String, Object>());
- } catch (GigiApiException e) {
- e.format(out, Page.getLanguage(req));
+ } catch (GigiApiException e1) {
+ e1.format(out, Page.getLanguage(req));
}
}
}
}
} else {
- out.print("<div class='formError'>");
-
- out.println(translate(req, "I'm sorry, there was no email and date of birth matching" + " what you entered in the system. Please double check" + " your information."));
- out.print("</div>");
+ GigiApiException e = new GigiApiException("I'm sorry, there was no email and date of birth matching" //
+ + " what you entered in the system. Please double check your information.");
+ e.format(out, getLanguage(req));
}
}
import java.util.HashMap;
import java.util.TreeSet;
+import org.cacert.gigi.GigiApiException;
+
public class RateLimit {
+ public static final class RateLimitException extends GigiApiException {
+
+ public RateLimitException() {
+ super("Rate limit exceeded.");
+ }
+ }
+
private class Entry implements Comparable<Entry> {
long firstAccess;
.experthidden{
display: none;
}
+div.error-msgs p{
+ padding: 6px;
+}
public class TestCertificateAdd extends ClientTest {
+ private static class OnPageError extends Error {
+
+ public OnPageError(String page) {
+ super(page);
+ }
+ }
+
KeyPair kp = generateKeypair();
String csrf;
assertArrayEquals(new String[] {
"client", CertificateRequest.DEFAULT_CN, "", Digest.SHA512.toString()
}, res);
- } catch (Error e) {
- assertTrue(e.getMessage().startsWith("<div>Challenge mismatch"));
+ } catch (OnPageError e) {
+ String error = fetchStartErrorMessage(e.getMessage());
+ assertTrue(error, error.startsWith("<p>Challenge mismatch"));
}
return csrf;
}
private String[] extractFormData(HttpURLConnection uc) throws IOException, Error {
String result = IOUtils.readURL(uc);
- if (result.contains("<div class='formError'>")) {
- String s = fetchStartErrorMessage(result);
- throw new Error(s);
+ if (result.contains("<div class='bg-danger error-msgs'>")) {
+ throw new OnPageError(result);
}
String profileKey = extractPattern(result, Pattern.compile("<option value=\"([^\"]*)\" selected>"));
}
public static String fetchStartErrorMessage(String d) throws IOException {
- String formFail = "<div class='formError'>";
+ String formFail = "<div class='bg-danger error-msgs'>";
int idx = d.indexOf(formFail);
if (idx == -1) {
return null;