X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=src%2Forg%2Fcacert%2Fgigi%2FdbObjects%2FDomain.java;h=d4ffd8e28d377b038953a1cc2e2d808aeb16fd05;hp=b76add29db4aaf98d887fa877dab2d6d369ca278;hb=36658ae4a12bea7095e02e45b1fe8400d85add8b;hpb=33a87a70ba2320451c3b3b1faa9b487dbcbd3540 diff --git a/src/org/cacert/gigi/dbObjects/Domain.java b/src/org/cacert/gigi/dbObjects/Domain.java index b76add29..d4ffd8e2 100644 --- a/src/org/cacert/gigi/dbObjects/Domain.java +++ b/src/org/cacert/gigi/dbObjects/Domain.java @@ -1,21 +1,13 @@ package org.cacert.gigi.dbObjects; -import java.io.IOException; -import java.io.InputStream; -import java.net.IDN; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Properties; -import java.util.Set; import org.cacert.gigi.GigiApiException; -import org.cacert.gigi.database.DatabaseConnection; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; -import org.cacert.gigi.util.PublicSuffixes; +import org.cacert.gigi.util.DomainAssessment; public class Domain implements IdCachable, Verifyable { @@ -25,106 +17,34 @@ public class Domain implements IdCachable, Verifyable { private int id; - private static final Set IDNEnabledTLDs; - - static { - Properties CPS = new Properties(); - try (InputStream resourceAsStream = Domain.class.getResourceAsStream("CPS.properties")) { - CPS.load(resourceAsStream); - IDNEnabledTLDs = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(CPS.getProperty("IDN-enabled").split(",")))); - } catch (IOException e) { - throw new Error(e); - } - } - - private Domain(int id) { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT `memid`, `domain` FROM `domains` WHERE `id`=? AND `deleted` IS NULL"); - ps.setInt(1, id); - - GigiResultSet rs = ps.executeQuery(); - if ( !rs.next()) { - throw new IllegalArgumentException("Invalid domain id " + id); - } + private Domain(GigiResultSet rs, int id) { this.id = id; - owner = User.getById(rs.getInt(1)); + owner = CertificateOwner.getById(rs.getInt(1)); suffix = rs.getString(2); - rs.close(); } public Domain(User actor, CertificateOwner owner, String suffix) throws GigiApiException { + suffix = suffix.toLowerCase(); synchronized (Domain.class) { - checkCertifyableDomain(suffix, actor.isInGroup(Group.CODESIGNING)); + DomainAssessment.checkCertifiableDomain(suffix, actor.isInGroup(Group.CODESIGNING), true); this.owner = owner; this.suffix = suffix; insert(); } } - public static void checkCertifyableDomain(String s, boolean hasPunycodeRight) throws GigiApiException { - String[] parts = s.split("\\.", -1); - if (parts.length < 2) { - throw new GigiApiException("Domain does not contain '.'."); - } - for (int i = parts.length - 1; i >= 0; i--) { - if ( !isVaildDomainPart(parts[i], hasPunycodeRight)) { - throw new GigiApiException("Syntax error in Domain"); - } - } - String publicSuffix = PublicSuffixes.getInstance().getRegistrablePart(s); - if ( !s.equals(publicSuffix)) { - throw new GigiApiException("You may only register a domain with exactly one lable before the public suffix."); - } - checkPunycode(parts[0], s.substring(parts[0].length() + 1)); - } - - private static void checkPunycode(String label, String domainContext) throws GigiApiException { - if (label.charAt(2) != '-' || label.charAt(3) != '-') { - return; // is no punycode - } - if ( !IDNEnabledTLDs.contains(domainContext)) { - throw new GigiApiException("Punycode label could not be positively verified."); - } - if ( !label.startsWith("xn--")) { - throw new GigiApiException("Unknown ACE prefix."); - } - try { - String unicode = IDN.toUnicode(label); - if (unicode.startsWith("xn--")) { - throw new GigiApiException("Punycode label could not be positively verified."); - } - } catch (IllegalArgumentException e) { - throw new GigiApiException("Punycode label could not be positively verified."); - } - } - - public static boolean isVaildDomainPart(String s, boolean allowPunycode) { - if ( !s.matches("[a-z0-9-]+")) { - return false; - } - if (s.charAt(0) == '-' || s.charAt(s.length() - 1) == '-') { - return false; - } - if (s.length() > 63) { - return false; - } - boolean canBePunycode = s.length() >= 4 && s.charAt(2) == '-' && s.charAt(3) == '-'; - if (canBePunycode && !allowPunycode) { - return false; - } - return true; - } - private static void checkInsert(String suffix) throws GigiApiException { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT 1 FROM `domains` WHERE (`domain`=? OR (CONCAT('.', `domain`)=RIGHT(?,LENGTH(`domain`)+1) OR RIGHT(`domain`,LENGTH(?)+1)=CONCAT('.',?))) AND `deleted` IS NULL"); - ps.setString(1, suffix); - ps.setString(2, suffix); - ps.setString(3, suffix); - ps.setString(4, suffix); - GigiResultSet rs = ps.executeQuery(); - boolean existed = rs.next(); - rs.close(); - if (existed) { - throw new GigiApiException("Domain could not be inserted. Domain is already valid."); + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT 1 FROM `domains` WHERE (`domain`=? OR (CONCAT('.', `domain`)=RIGHT(?,LENGTH(`domain`)+1) OR RIGHT(`domain`,LENGTH(?)+1)=CONCAT('.',?))) AND `deleted` IS NULL")) { + ps.setString(1, suffix); + ps.setString(2, suffix); + ps.setString(3, suffix); + ps.setString(4, suffix); + GigiResultSet rs = ps.executeQuery(); + boolean existed = rs.next(); + rs.close(); + if (existed) { + throw new GigiApiException("Domain could not be inserted. Domain is already known to the system."); + } } } @@ -133,11 +53,12 @@ public class Domain implements IdCachable, Verifyable { throw new GigiApiException("already inserted."); } checkInsert(suffix); - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO `domains` SET memid=?, domain=?"); - ps.setInt(1, owner.getId()); - ps.setString(2, suffix); - ps.execute(); - id = ps.lastInsertId(); + try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `domains` SET memid=?, domain=?")) { + ps.setInt(1, owner.getId()); + ps.setString(2, suffix); + ps.execute(); + id = ps.lastInsertId(); + } myCache.put(this); } @@ -145,9 +66,13 @@ public class Domain implements IdCachable, Verifyable { if (id == 0) { throw new GigiApiException("not inserted."); } - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("UPDATE `domains` SET `deleted`=CURRENT_TIMESTAMP WHERE `id`=?"); - ps.setInt(1, id); - ps.execute(); + synchronized (Domain.class) { + myCache.remove(this); + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `domains` SET `deleted`=CURRENT_TIMESTAMP WHERE `id`=?")) { + ps.setInt(1, id); + ps.execute(); + } + } } public CertificateOwner getOwner() { @@ -169,13 +94,13 @@ public class Domain implements IdCachable, Verifyable { LinkedList configs = this.configs; if (configs == null) { configs = new LinkedList<>(); - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM pingconfig WHERE domainid=?"); - ps.setInt(1, id); - GigiResultSet rs = ps.executeQuery(); - while (rs.next()) { - configs.add(DomainPingConfiguration.getById(rs.getInt(1))); + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT id FROM pingconfig WHERE domainid=? AND `deleted` IS NULL")) { + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + while (rs.next()) { + configs.add(DomainPingConfiguration.getById(rs.getInt(1))); + } } - rs.close(); this.configs = configs; } @@ -183,60 +108,80 @@ public class Domain implements IdCachable, Verifyable { } public void addPing(DomainPingType type, String config) throws GigiApiException { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO `pingconfig` SET `domainid`=?, `type`=?::`pingType`, `info`=?"); - ps.setInt(1, id); - ps.setString(2, type.toString().toLowerCase()); - ps.setString(3, config); - ps.execute(); + try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `pingconfig` SET `domainid`=?, `type`=?::`pingType`, `info`=?")) { + ps.setInt(1, id); + ps.setString(2, type.toString().toLowerCase()); + ps.setString(3, config); + ps.execute(); + } + configs = null; + } + + public void clearPings() throws GigiApiException { + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `pingconfig` SET `deleted`=CURRENT_TIMESTAMP WHERE `deleted` is NULL AND `domainid`=?")) { + ps.setInt(1, id); + ps.execute(); + } configs = null; } public synchronized void verify(String hash) throws GigiApiException { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("UPDATE `domainPinglog` SET `state`='success' WHERE `challenge`=? AND `state`='open' AND `configId` IN (SELECT `id` FROM `pingconfig` WHERE `domainid`=? AND `type`='email')"); - ps.setString(1, hash); - ps.setInt(2, id); - ps.executeUpdate(); + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `domainPinglog` SET `state`='success' WHERE `challenge`=? AND `state`='open' AND `configId` IN (SELECT `id` FROM `pingconfig` WHERE `domainid`=? AND `type`='email')")) { + ps.setString(1, hash); + ps.setInt(2, id); + ps.executeUpdate(); + } } public boolean isVerified() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT 1 FROM `domainPinglog` INNER JOIN `pingconfig` ON `pingconfig`.`id`=`domainPinglog`.`configId` WHERE `domainid`=? AND `state`='success'"); - ps.setInt(1, id); - GigiResultSet rs = ps.executeQuery(); - return rs.next(); + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT 1 FROM `domainPinglog` INNER JOIN `pingconfig` ON `pingconfig`.`id`=`domainPinglog`.`configId` WHERE `domainid`=? AND `state`='success'")) { + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + return rs.next(); + } } public DomainPingExecution[] getPings() throws GigiApiException { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepareScrollable("SELECT `state`, `type`, `info`, `result`, `configId` FROM `domainPinglog` INNER JOIN `pingconfig` ON `pingconfig`.`id`=`domainPinglog`.`configId` WHERE `pingconfig`.`domainid`=? ORDER BY `when` DESC;"); - ps.setInt(1, id); - GigiResultSet rs = ps.executeQuery(); - rs.last(); - DomainPingExecution[] contents = new DomainPingExecution[rs.getRow()]; - rs.beforeFirst(); - for (int i = 0; i < contents.length && rs.next(); i++) { - contents[i] = new DomainPingExecution(rs); + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `state`, `type`, `info`, `result`, `configId`, `when` FROM `domainPinglog` INNER JOIN `pingconfig` ON `pingconfig`.`id`=`domainPinglog`.`configId` WHERE `pingconfig`.`domainid`=? ORDER BY `when` DESC;", true)) { + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + rs.last(); + DomainPingExecution[] contents = new DomainPingExecution[rs.getRow()]; + rs.beforeFirst(); + for (int i = 0; i < contents.length && rs.next(); i++) { + contents[i] = new DomainPingExecution(rs); + } + return contents; } - return contents; } private static final ObjectCache myCache = new ObjectCache<>(); - public static synchronized Domain getById(int id) throws IllegalArgumentException { + public static synchronized Domain getById(int id) { Domain em = myCache.get(id); if (em == null) { - myCache.put(em = new Domain(id)); + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `memid`, `domain` FROM `domains` WHERE `id`=? AND `deleted` IS NULL")) { + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + if ( !rs.next()) { + return null; + } + myCache.put(em = new Domain(rs, id)); + } } return em; } - public static int searchUserIdByDomain(String domain) { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT `memid` FROM `domains` WHERE `domain` = ?"); - ps.setString(1, domain); - GigiResultSet res = ps.executeQuery(); - if (res.next()) { - return res.getInt(1); - } else { - return -1; + public static Domain searchUserIdByDomain(String domain) { + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `id` FROM `domains` WHERE `domain` = ?")) { + ps.setString(1, domain); + GigiResultSet res = ps.executeQuery(); + if (res.next()) { + return getById(res.getInt(1)); + } else { + return null; + } } }