import org.cacert.gigi.output.template.SprintfCommand;
import org.cacert.gigi.util.AuthorizationContext;
import org.cacert.gigi.util.PEM;
+import org.cacert.gigi.util.RateLimit;
import sun.security.pkcs.PKCS9Attribute;
import sun.security.pkcs10.PKCS10;
throw error;
}
try {
+ if (limit.isLimitExceeded(Integer.toString(ctx.getActor().getId()))) {
+ throw new GigiApiException("Rate Limit Exceeded");
+ }
return new Certificate(ctx.getTarget(), ctx.getActor(), subject, selectedDigest, //
this.csr, this.csrType, profile, SANs.toArray(new SubjectAlternateName[SANs.size()]));
} catch (IOException e) {
return null;
}
+ // 100 per 10 minutes
+ private static final RateLimit limit = new RateLimit(100, 10 * 60 * 1000);
+
private String verifyName(GigiApiException error, PropertyTemplate nameTemp, PropertyTemplate wotUserTemp, String verifiedCN) {
// real names,
// possible configurations: name {y,null,?}, name=WoTUser {y,null}
import org.cacert.gigi.output.template.Form;
import org.cacert.gigi.pages.Page;
import org.cacert.gigi.util.AuthorizationContext;
+import org.cacert.gigi.util.RateLimit;
public class RegisterPage extends Page {
public static final String PATH = "/register";
+ // 5 per 5 min
+ public static final RateLimit RATE_LIMIT = new RateLimit(50, 5 * 60 * 1000);
+
public RegisterPage() {
super("Register");
}
if (isFailed(out)) {
return false;
}
+ if (RegisterPage.RATE_LIMIT.isLimitExceeded(req.getRemoteAddr())) {
+ outputError(out, req, "Rate Limit Exceeded");
+ return false;
+ }
try {
run(req, pw1);
} catch (SQLException e) {
--- /dev/null
+package org.cacert.gigi.util;
+
+import java.util.HashMap;
+import java.util.TreeSet;
+
+public class RateLimit {
+
+ private class Entry implements Comparable<Entry> {
+
+ long firstAccess;
+
+ int count = 1;
+
+ String feature;
+
+ public Entry(long firstAccess, String feature) {
+ this.firstAccess = firstAccess;
+ this.feature = feature;
+ }
+
+ public void access() {
+ count++;
+ }
+
+ @Override
+ public int compareTo(Entry o) {
+ return feature.compareTo(o.feature);
+ }
+
+ public boolean isExpired() {
+ return firstAccess + time < System.currentTimeMillis();
+ }
+
+ }
+
+ private final int maxcount;
+
+ private final long time;
+
+ TreeSet<Entry> set = new TreeSet<Entry>();
+
+ HashMap<String, Entry> feat = new HashMap<>();
+
+ public RateLimit(int maxcount, long time) {
+ this.maxcount = maxcount;
+ this.time = time;
+ }
+
+ public synchronized boolean isLimitExceeded(String feature) {
+ clean();
+ Entry e = feat.get(feature);
+ if (e == null) {
+ e = new Entry(System.currentTimeMillis(), feature);
+ set.add(e);
+ feat.put(feature, e);
+ } else {
+ e.access();
+ }
+ return e.count > maxcount;
+ }
+
+ private void clean() {
+ while (set.size() > 0) {
+ Entry e = set.last();
+ if (e.isExpired()) {
+ set.remove(e);
+ feat.remove(e.feature);
+ } else {
+ return;
+ }
+ }
+ }
+}