From: Felix Dörre Date: Sat, 31 Jan 2015 22:14:34 +0000 (+0100) Subject: UPD: Correct reping (with 5min rate limiting) X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=98aa1434dc5e06971dcd35f6b9bd335216edce43 UPD: Correct reping (with 5min rate limiting) Thereby Fix times against SQL.. (only UTC everywhere... ) ... execpt somewhere in mysql or blargh... I don't know... output is UTC. --- diff --git a/doc/tableStructure.sql b/doc/tableStructure.sql index 7ff0769c..867a1c63 100644 --- a/doc/tableStructure.sql +++ b/doc/tableStructure.sql @@ -92,7 +92,6 @@ CREATE TABLE `pingconfig` ( `domainid` int(11) NOT NULL, `type` enum('email', 'ssl', 'http', 'dns') NOT NULL, `info` varchar(255) NOT NULL, - `reping` enum('y','n') NOT NULL DEFAULT 'n', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/org/cacert/gigi/Gigi.java b/src/org/cacert/gigi/Gigi.java index 4e96e9a0..8c4a234c 100644 --- a/src/org/cacert/gigi/Gigi.java +++ b/src/org/cacert/gigi/Gigi.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.cacert.gigi.database.DatabaseConnection; +import org.cacert.gigi.dbObjects.DomainPingConfiguration; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.Menu; @@ -400,7 +401,17 @@ public class Gigi extends HttpServlet { return instance.reveresePages.get(p).replaceFirst("/?\\*$", ""); } - public static void notifyPinger() { + /** + * Requests Pinging of domains. + * + * @param toReping + * if not null, the {@link DomainPingConfiguration} to test, if + * null, just re-check if there is something to do. + */ + public static void notifyPinger(DomainPingConfiguration toReping) { + if (toReping != null) { + instance.pinger.queue(toReping); + } instance.pinger.interrupt(); } diff --git a/src/org/cacert/gigi/database/DatabaseConnection.java b/src/org/cacert/gigi/database/DatabaseConnection.java index abeb78d0..661565d8 100644 --- a/src/org/cacert/gigi/database/DatabaseConnection.java +++ b/src/org/cacert/gigi/database/DatabaseConnection.java @@ -34,7 +34,7 @@ public class DatabaseConnection { private void tryConnect() { try { c = DriverManager.getConnection(credentials.getProperty("sql.url") + "?zeroDateTimeBehavior=convertToNull", credentials.getProperty("sql.user"), credentials.getProperty("sql.password")); - PreparedStatement ps = c.prepareStatement("SET SESSION wait_timeout=?;"); + PreparedStatement ps = c.prepareStatement("SET SESSION wait_timeout=?, time_zone='+0:00';"); ps.setInt(1, CONNECTION_TIMEOUT); ps.execute(); ps.close(); diff --git a/src/org/cacert/gigi/database/GigiResultSet.java b/src/org/cacert/gigi/database/GigiResultSet.java index 9dc83bd7..48157ffa 100644 --- a/src/org/cacert/gigi/database/GigiResultSet.java +++ b/src/org/cacert/gigi/database/GigiResultSet.java @@ -3,7 +3,6 @@ package org.cacert.gigi.database; import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Time; import java.sql.Timestamp; public class GigiResultSet { @@ -59,15 +58,6 @@ public class GigiResultSet { } } - public Time getTime(int columnIndex) { - try { - return target.getTime(columnIndex); - } catch (SQLException e) { - handleSQL(e); - throw new Error(e); - } - } - public String getString(String columnLabel) { try { return target.getString(columnLabel); @@ -113,15 +103,6 @@ public class GigiResultSet { } } - public Time getTime(String columnLabel) { - try { - return target.getTime(columnLabel); - } catch (SQLException e) { - handleSQL(e); - throw new Error(e); - } - } - public boolean next() { try { return target.next(); diff --git a/src/org/cacert/gigi/dbObjects/Certificate.java b/src/org/cacert/gigi/dbObjects/Certificate.java index df940dbc..ced044cd 100644 --- a/src/org/cacert/gigi/dbObjects/Certificate.java +++ b/src/org/cacert/gigi/dbObjects/Certificate.java @@ -219,10 +219,10 @@ public class Certificate { crtName = rs.getString(1); serial = rs.getString(4); - if (rs.getTime(2) == null) { + if (rs.getTimestamp(2) == null) { return CertificateStatus.DRAFT; } - if (rs.getTime(2) != null && rs.getTime(3) == null) { + if (rs.getTimestamp(2) != null && rs.getTimestamp(3) == null) { return CertificateStatus.ISSUED; } return CertificateStatus.REVOKED; diff --git a/src/org/cacert/gigi/dbObjects/DomainPingConfiguration.java b/src/org/cacert/gigi/dbObjects/DomainPingConfiguration.java index 1146cca0..cf1292b8 100644 --- a/src/org/cacert/gigi/dbObjects/DomainPingConfiguration.java +++ b/src/org/cacert/gigi/dbObjects/DomainPingConfiguration.java @@ -1,5 +1,9 @@ package org.cacert.gigi.dbObjects; +import java.util.Date; + +import org.cacert.gigi.Gigi; +import org.cacert.gigi.GigiApiException; import org.cacert.gigi.database.DatabaseConnection; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; @@ -59,10 +63,33 @@ public class DomainPingConfiguration implements IdCachable { return res; } - public void requestReping() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("UPDATE pingconfig set reping='y' WHERE id=?"); + public Date getLastExecution() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT `when` AS stamp from domainPinglog WHERE configId=? ORDER BY `when` DESC LIMIT 1"); + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + if (rs.next()) { + return new Date(rs.getTimestamp("stamp").getTime()); + } + return new Date(0); + } + + public Date getLastSuccess() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT `when` AS stamp from domainPinglog WHERE configId=? AND state='success' ORDER BY `when` DESC LIMIT 1"); ps.setInt(1, id); - ps.execute(); + GigiResultSet rs = ps.executeQuery(); + if (rs.next()) { + return new Date(rs.getTimestamp("stamp").getTime()); + } + return new Date(0); + } + + public synchronized void requestReping() throws GigiApiException { + Date lastExecution = getLastExecution(); + if (lastExecution.getTime() + 5 * 60 * 1000 < System.currentTimeMillis()) { + Gigi.notifyPinger(this); + return; + } + throw new GigiApiException("Reping is only allowed after 5 minutes"); } } diff --git a/src/org/cacert/gigi/pages/account/domain/DomainOverview.java b/src/org/cacert/gigi/pages/account/domain/DomainOverview.java index 16770292..906e2a16 100644 --- a/src/org/cacert/gigi/pages/account/domain/DomainOverview.java +++ b/src/org/cacert/gigi/pages/account/domain/DomainOverview.java @@ -6,7 +6,6 @@ import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.cacert.gigi.Gigi; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.DomainPingConfiguration; @@ -71,8 +70,12 @@ public class DomainOverview extends Page { if (dpc.getTarget() != d) { return; } - dpc.requestReping(); - Gigi.notifyPinger(); + try { + dpc.requestReping(); + } catch (GigiApiException e) { + e.format(resp.getWriter(), getLanguage(req)); + return; + } resp.sendRedirect(PATH + i); } if (req.getParameter("adddomain") != null) { diff --git a/src/org/cacert/gigi/pages/account/domain/PingConfigForm.java b/src/org/cacert/gigi/pages/account/domain/PingConfigForm.java index 91ea7cc0..5b5da852 100644 --- a/src/org/cacert/gigi/pages/account/domain/PingConfigForm.java +++ b/src/org/cacert/gigi/pages/account/domain/PingConfigForm.java @@ -133,7 +133,7 @@ public class PingConfigForm extends Form { } } - Gigi.notifyPinger(); + Gigi.notifyPinger(null); return false; } diff --git a/src/org/cacert/gigi/ping/PingerDaemon.java b/src/org/cacert/gigi/ping/PingerDaemon.java index 2a316743..ceb88e9a 100644 --- a/src/org/cacert/gigi/ping/PingerDaemon.java +++ b/src/org/cacert/gigi/ping/PingerDaemon.java @@ -2,42 +2,56 @@ package org.cacert.gigi.ping; import java.security.KeyStore; import java.util.HashMap; +import java.util.LinkedList; +import java.util.Queue; import org.cacert.gigi.database.DatabaseConnection; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; import org.cacert.gigi.dbObjects.Domain; -import org.cacert.gigi.dbObjects.User; +import org.cacert.gigi.dbObjects.DomainPingConfiguration; +import org.cacert.gigi.dbObjects.DomainPingConfiguration.PingType; import org.cacert.gigi.util.RandomToken; public class PingerDaemon extends Thread { - HashMap pingers = new HashMap<>(); + HashMap pingers = new HashMap<>(); private GigiPreparedStatement searchNeededPings; private GigiPreparedStatement enterPingResult; - private GigiPreparedStatement updatePingStatus; - private KeyStore truststore; + private Queue toExecute = new LinkedList<>(); + public PingerDaemon(KeyStore truststore) { this.truststore = truststore; } @Override public void run() { - searchNeededPings = DatabaseConnection.getInstance().prepare("SELECT pingconfig.*, domains.domain, domains.memid FROM pingconfig LEFT JOIN domainPinglog ON domainPinglog.configId=pingconfig.id INNER JOIN domains ON domains.id=pingconfig.domainid WHERE ( pingconfig.reping='y' OR domainPinglog.configId IS NULL) AND domains.deleted IS NULL GROUP BY pingconfig.id"); + searchNeededPings = DatabaseConnection.getInstance().prepare("SELECT pingconfig.id FROM pingconfig LEFT JOIN domainPinglog ON domainPinglog.configId=pingconfig.id INNER JOIN domains ON domains.id=pingconfig.domainid WHERE ( domainPinglog.configId IS NULL) AND domains.deleted IS NULL GROUP BY pingconfig.id"); enterPingResult = DatabaseConnection.getInstance().prepare("INSERT INTO domainPinglog SET configId=?, state=?, result=?, challenge=?"); - updatePingStatus = DatabaseConnection.getInstance().prepare("UPDATE pingconfig SET reping='n' WHERE id=?"); - pingers.put("email", new EmailPinger()); - pingers.put("ssl", new SSLPinger(truststore)); - pingers.put("http", new HTTPFetch()); - pingers.put("dns", new DNSPinger()); + pingers.put(PingType.EMAIL, new EmailPinger()); + pingers.put(PingType.SSL, new SSLPinger(truststore)); + pingers.put(PingType.HTTP, new HTTPFetch()); + pingers.put(PingType.DNS, new DNSPinger()); while (true) { - execute(); + synchronized (this) { + DomainPingConfiguration conf; + while ((conf = toExecute.peek()) != null) { + handle(conf); + toExecute.remove(); + } + notifyAll(); + } + + GigiResultSet rs = searchNeededPings.executeQuery(); + while (rs.next()) { + handle(DomainPingConfiguration.getById(rs.getInt("id"))); + } try { Thread.sleep(5000); } catch (InterruptedException e) { @@ -45,29 +59,35 @@ public class PingerDaemon extends Thread { } } - private void execute() { - - GigiResultSet rs = searchNeededPings.executeQuery(); - while (rs.next()) { - String type = rs.getString("type"); - String config = rs.getString("info"); - DomainPinger dp = pingers.get(type); - if (dp != null) { - String token = null; - if (dp instanceof EmailPinger) { - token = RandomToken.generateToken(16); - config = config + ":" + token; - } - updatePingStatus.setInt(1, rs.getInt("id")); - updatePingStatus.execute(); - enterPingResult.setInt(1, rs.getInt("id")); - String resp = dp.ping(Domain.getById(rs.getInt("domainid")), config, User.getById(rs.getInt("memid"))); - enterPingResult.setString(2, DomainPinger.PING_STILL_PENDING == resp ? "open" : DomainPinger.PING_SUCCEDED.equals(resp) ? "success" : "failed"); - enterPingResult.setString(3, resp); - enterPingResult.setString(4, token); - enterPingResult.execute(); + private void handle(DomainPingConfiguration conf) { + PingType type = conf.getType(); + String config = conf.getInfo(); + DomainPinger dp = pingers.get(type); + if (dp != null) { + String token = null; + if (dp instanceof EmailPinger) { + token = RandomToken.generateToken(16); + config = config + ":" + token; } + enterPingResult.setInt(1, conf.getId()); + Domain target = conf.getTarget(); + String resp = dp.ping(target, config, target.getOwner()); + enterPingResult.setString(2, DomainPinger.PING_STILL_PENDING == resp ? "open" : DomainPinger.PING_SUCCEDED.equals(resp) ? "success" : "failed"); + enterPingResult.setString(3, resp); + enterPingResult.setString(4, token); + enterPingResult.execute(); } } + public synchronized void queue(DomainPingConfiguration toReping) { + interrupt(); + toExecute.add(toReping); + while (toExecute.size() > 0) { + try { + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } }