]> WPIA git - gigi.git/commitdiff
Merge "upd: redesign of find cert result page"
authorMarcus Mängel <m.maengel@inopiae.de>
Thu, 19 Mar 2020 05:59:59 +0000 (05:59 +0000)
committerGerrit Code Review <gigi-system@dogcraft.de>
Thu, 19 Mar 2020 05:59:59 +0000 (05:59 +0000)
24 files changed:
src/club/wpia/gigi/api/CreateCertificate.java
src/club/wpia/gigi/api/RevokeCertificate.java
src/club/wpia/gigi/dbObjects/Domain.java
src/club/wpia/gigi/dbObjects/Job.java
src/club/wpia/gigi/dbObjects/Name.java
src/club/wpia/gigi/dbObjects/SupportedUser.java
src/club/wpia/gigi/dbObjects/User.java
src/club/wpia/gigi/pages/account/certs/CertificateIssueForm.java
src/club/wpia/gigi/pages/account/certs/CertificateModificationForm.java
src/club/wpia/gigi/pages/account/certs/CertificateRequest.java
src/club/wpia/gigi/pages/account/certs/RevokeSingleCertForm.java
src/club/wpia/gigi/pages/account/domain/DomainManagementForm.templ
src/club/wpia/gigi/pages/account/mail/MailManagementForm.templ
src/club/wpia/gigi/pages/main/KeyCompromiseForm.java
tests/club/wpia/gigi/dbObjects/TestDomain.java [new file with mode: 0644]
tests/club/wpia/gigi/dbObjects/TestUser.java
tests/club/wpia/gigi/dbObjects/TestUserManaged.java [new file with mode: 0644]
tests/club/wpia/gigi/dbObjects/TestVerifyName.java
tests/club/wpia/gigi/pages/account/TestCertificateRequest.java
tests/club/wpia/gigi/testUtils/BusinessTest.java
tests/club/wpia/gigi/testUtils/ClientBusinessTest.java
tests/club/wpia/gigi/testUtils/ConfiguredTest.java
util-testing/club/wpia/gigi/pages/Manager.java
util-testing/club/wpia/gigi/pages/Manager.templ

index 1890e4a9372d4eeb1e54faaa24f6758acea61d5b..41556d131a88052a2652e6adfa6b9682a2bb512e 100644 (file)
@@ -65,7 +65,7 @@ public class CreateCertificate extends APIPoint {
             CertificateRequest cr = new CertificateRequest(ctx, csr, cp);
             Certificate result = cr.draft();
             Job job = result.issue(null, "2y", u);
-            job.waitFor(60000);
+            job.waitFor(Job.WAIT_MIN);
             if (result.getStatus() != CertificateStatus.ISSUED) {
                 resp.sendError(510, "Error, issuing timed out");
                 return;
index 81e57cfbbf3ec23a184bf4f7710ffad0d960b4c1..e8e8b9643eb1e19b2ef781ba987dda97ee7edda4 100644 (file)
@@ -42,7 +42,7 @@ public class RevokeCertificate extends APIPoint {
         }
 
         Job job = c.revoke(RevocationType.USER);
-        job.waitFor(60000);
+        job.waitFor(Job.WAIT_MIN);
         if (c.getStatus() != CertificateStatus.REVOKED) {
             resp.sendError(510, "Error, issuing timed out");
             return;
index 9b356e6067f9d0364c32a23be5ee2f58f9628bde..1d3ba17de35c62b1d65322946e7b3e1407879553 100644 (file)
@@ -7,6 +7,7 @@ import java.util.List;
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.database.GigiResultSet;
+import club.wpia.gigi.dbObjects.Certificate.RevocationType;
 import club.wpia.gigi.util.DomainAssessment;
 
 public class Domain implements IdCachable, Verifyable {
@@ -72,6 +73,19 @@ public class Domain implements IdCachable, Verifyable {
                 ps.setInt(1, id);
                 ps.execute();
             }
+            LinkedList<Job> revokes = new LinkedList<Job>();
+            for (Certificate cert : fetchActiveCertificates()) {
+                revokes.add(cert.revoke(RevocationType.USER));
+            }
+            long start = System.currentTimeMillis();
+            for (Job job : revokes) {
+                int toWait = (int) (60000 + start - System.currentTimeMillis());
+                if (toWait > 0) {
+                    job.waitFor(toWait);
+                } else {
+                    break; // canceled... waited too log
+                }
+            }
         }
     }
 
index a505eb41a05a7a70bbf5e3627361803be1185b14..071b1b2ef0ced65f3eb6bfb0d217bdde6f1f4aa6 100644 (file)
@@ -11,6 +11,8 @@ import club.wpia.gigi.output.CertificateValiditySelector;
 
 public class Job implements IdCachable {
 
+    public static int WAIT_MIN = 60000;
+
     private int id;
 
     private Job(int id) {
index fbcf10eed4c94fc76c8c975102e339e31c83f7a8..ce8e7e2a1ca465eceecc4a6e84117f43fa4a18eb 100644 (file)
@@ -1,6 +1,9 @@
 package club.wpia.gigi.dbObjects;
 
 import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.Map;
 
 import club.wpia.gigi.GigiApiException;
@@ -11,6 +14,7 @@ import club.wpia.gigi.dbObjects.NamePart.NamePartType;
 import club.wpia.gigi.localisation.Language;
 import club.wpia.gigi.output.template.Outputable;
 import club.wpia.gigi.util.HTMLEncoder;
+import club.wpia.gigi.util.TimeConditions;
 
 public class Name implements Outputable, IdCachable {
 
@@ -512,4 +516,26 @@ public class Name implements Outputable, IdCachable {
         }
         return initals.toString();
     }
+
+    public boolean isValidVerification() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Calendar c = Calendar.getInstance();
+        c.setTimeInMillis(System.currentTimeMillis());
+        c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths());
+        String date = sdf.format(new Date(c.getTimeInMillis()));
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT COUNT(id) FROM `notary` WHERE `to` = ? AND `deleted` IS NULL AND (`expire` IS NULL OR `expire` > CURRENT_TIMESTAMP) AND `date` > ?")) {
+            query.setInt(1, getId());
+            query.setString(2, date);
+            GigiResultSet rs = query.executeQuery();
+
+            if (rs.next()) {
+                if (rs.getInt(1) > 0) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+
 }
index 84c43ab8e0db5261d745d200d34d69663be20ef8..1eae478f6a0eb872a03f8a14682f84958ab1e529 100644 (file)
@@ -70,7 +70,7 @@ public class SupportedUser {
         // TODO Check for open jobs!
         if (cert.getStatus() == CertificateStatus.ISSUED) {
             writeSELog("SE Revoke certificate");
-            cert.revoke(RevocationType.SUPPORT).waitFor(60000);
+            cert.revoke(RevocationType.SUPPORT).waitFor(Job.WAIT_MIN);
             // send notification to support
             String subject = "Revoke certificate";
             Outputable message = SprintfCommand.createSimple("Certificate with serial number {0} for {1} <{2}> has been revoked.", cert.getSerial(), target.getPreferredName().toString(), target.getEmail());
index 714bfc3a9122b95bcb1fad5bbd51a2f0ebb0678b..834b6f68bc7a65148c0fd45c74afed35d30e6f20 100644 (file)
@@ -17,6 +17,7 @@ import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.database.GigiResultSet;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
+import club.wpia.gigi.dbObjects.Certificate.RevocationType;
 import club.wpia.gigi.dbObjects.Country.CountryCodeType;
 import club.wpia.gigi.dbObjects.Verification.VerificationType;
 import club.wpia.gigi.email.EmailProvider;
@@ -338,6 +339,15 @@ public class User extends CertificateOwner {
         return false;
     }
 
+    public boolean isValidNameVerification(String name) {
+        for (Name n : getNames()) {
+            if (n.matches(name) && n.isValidVerification()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void updateDefaultEmail(EmailAddress newMail) throws GigiApiException {
         for (EmailAddress email : getEmails()) {
             if (email.getAddress().equals(newMail.getAddress())) {
@@ -364,16 +374,51 @@ public class User extends CertificateOwner {
             throw new GigiApiException("Can't delete user's default e-mail.");
         }
 
+        deleteEmailCerts(delMail, RevocationType.USER);
+    }
+
+    private void deleteEmailCerts(EmailAddress delMail, RevocationType rt) throws GigiApiException {
         for (EmailAddress email : getEmails()) {
             if (email.getId() == delMail.getId()) {
                 try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `emails` SET `deleted`=CURRENT_TIMESTAMP WHERE `id`=?")) {
                     ps.setInt(1, delMail.getId());
                     ps.execute();
                 }
+                LinkedList<Job> revokes = new LinkedList<Job>();
+                for (Certificate cert : fetchActiveEmailCertificates(delMail.getAddress())) {
+                    cert.revoke(RevocationType.USER).waitFor(Job.WAIT_MIN);
+                }
+                long start = System.currentTimeMillis();
+                for (Job job : revokes) {
+                    int toWait = (int) (60000 + start - System.currentTimeMillis());
+                    if (toWait > 0) {
+                        job.waitFor(toWait);
+                    } else {
+                        break; // canceled... waited too log
+                    }
+                }
                 return;
             }
+
         }
         throw new GigiApiException("Email not one of user's email addresses.");
+
+    }
+
+    public Certificate[] fetchActiveEmailCertificates(String email) {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT DISTINCT `certs`.`id` FROM `certs` INNER JOIN `subjectAlternativeNames` ON `subjectAlternativeNames`.`certId` = `certs`.`id` WHERE `contents`=?  AND `type`='email' AND `revoked` IS NULL AND `expire` > CURRENT_TIMESTAMP AND `memid`=?", true)) {
+            ps.setString(1, email);
+            ps.setInt(2, getId());
+            GigiResultSet rs = ps.executeQuery();
+            rs.last();
+            Certificate[] res = new Certificate[rs.getRow()];
+            rs.beforeFirst();
+            int i = 0;
+            while (rs.next()) {
+                res[i++] = Certificate.getById(rs.getInt(1));
+            }
+            return res;
+        }
     }
 
     public synchronized Verification[] getReceivedVerifications() {
index 31be06f4471e7f06990d0bef219b9d30fedb23a8..68002958909e42fa3689adbc982d7a59a9d0f9b6 100644 (file)
@@ -14,6 +14,7 @@ import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
 import club.wpia.gigi.dbObjects.Certificate.SubjectAlternateName;
 import club.wpia.gigi.dbObjects.CertificateProfile;
 import club.wpia.gigi.dbObjects.Domain;
+import club.wpia.gigi.dbObjects.Job;
 import club.wpia.gigi.dbObjects.Organisation;
 import club.wpia.gigi.dbObjects.User;
 import club.wpia.gigi.localisation.Language;
@@ -97,7 +98,7 @@ public class CertificateIssueForm extends Form {
                     }
                     result.setDescription(description);
                 }
-                result.issue(issueDate.getFrom(), issueDate.getTo(), c.getActor()).waitFor(60000);
+                result.issue(issueDate.getFrom(), issueDate.getTo(), c.getActor()).waitFor(Job.WAIT_MIN);
                 this.result = result;
                 Certificate c = result;
                 if (c.getStatus() != CertificateStatus.ISSUED) {
index 7ca73eb05908c3bc3c4c999f70fa0e9194855312..dd6161132a368a4ec5f2d1d01cbb22fdc4dcf85c 100644 (file)
@@ -54,7 +54,7 @@ public class CertificateModificationForm extends Form {
         }
         long start = System.currentTimeMillis();
         for (Job job : revokes) {
-            int toWait = (int) (60000 + start - System.currentTimeMillis());
+            int toWait = (int) (Job.WAIT_MIN + start - System.currentTimeMillis());
             if (toWait > 0) {
                 job.waitFor(toWait);
             } else {
index d9d090caa3e36aee24eb1296b50c41edc14b002e..28a5b098b75f73254884217743a7f3e4f4e2fddd 100644 (file)
@@ -443,7 +443,7 @@ public class CertificateRequest {
                 subject.put("OU", ou);
             }
         }
-        System.out.println(subject);
+
         if ( !error.isEmpty()) {
             throw error;
         }
@@ -493,7 +493,11 @@ public class CertificateRequest {
             User u = (User) ctx.getTarget();
             if (name != null && u.isValidName(name)) {
                 if (realIsOK) {
-                    verifiedCN = name;
+                    if (u.isValidNameVerification(name)) {
+                        verifiedCN = name;
+                    } else {
+                        error.mergeInto(new GigiApiException(SprintfCommand.createSimple("The entered name needs a valid verification within the last {0} months.", TimeConditions.getInstance().getVerificationMonths())));
+                    }
                 } else {
                     error.mergeInto(new GigiApiException("Your real name is not allowed in this certificate."));
                     if (defaultIsOK) {
index 30e404c0cc7b928b95de44eae5f394a6a6ca1c7a..12a7daa92cecac4b510b149e025a389451f9d0af 100644 (file)
@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.dbObjects.Certificate;
 import club.wpia.gigi.dbObjects.Certificate.RevocationType;
+import club.wpia.gigi.dbObjects.Job;
 import club.wpia.gigi.dbObjects.SupportedUser;
 import club.wpia.gigi.localisation.Language;
 import club.wpia.gigi.output.template.Form;
@@ -32,7 +33,7 @@ public class RevokeSingleCertForm extends Form {
         if (target != null) {
             target.revokeCertificate(c);
         } else {
-            c.revoke(RevocationType.USER).waitFor(60000);
+            c.revoke(RevocationType.USER).waitFor(Job.WAIT_MIN);
         }
         return new RedirectResult(req.getPathInfo());
     }
index d022c27146501a08fa43c08358d163f5f56733b7..c4507f2e14844f9c463c624757b9260d20ce875f 100644 (file)
@@ -10,7 +10,7 @@
   </tr>
   <? foreach($domains) { ?>
   <tr>
-       <td><? if($buttonvisible) { ?><button class="btn btn-danger btn-confirm" data-confirm="<?=_Do you really want to delete this domain??>" data-reply="<?=_Cancel?>,<?=_Confirm?>" type="submit" name="delete" value="<?=$id?>">Delete</button><? } ?></td>
+       <td><? if($buttonvisible) { ?><button class="btn btn-danger btn-confirm" data-confirm="<?=_All certificates that reference the affected domain (including those where several different domains appear) will be revoked.?>" data-reply="<?=_Cancel?>,<?=_Confirm?>" type="submit" name="delete" value="<?=$id?>">Delete</button><? } ?></td>
        <td><?=$status?></td>
        <td><? if($domainhref) { ?><a href='<?=$domainhref?>'><?=$domain?><? } else { ?><?=$domain?><? } ?></a></td>
   </tr>
index 2449bca10f0f2ee6b6a0acf60cda9a7b62986a33..c71306f0a27b89c476b095c6b8af6b3ef6651e4e 100644 (file)
@@ -19,7 +19,7 @@
                <td><?=$verification?></td>
                <td><? if($last_verification) { ?><?=$last_verification?><? } else { ?><?=_N/A?><? } ?></td>
                <td><?=$address?></td>
-               <td><button class="btn btn-danger btn-confirm" data-confirm="<?=_Do you really want to delete this email address??>" data-reply="<?=_Cancel?>,<?=_Confirm?>" type="submit" name="delete" value="<?=$id?>"<?=$deletable?>><?=_Delete?></button></td>
+               <td><button class="btn btn-danger btn-confirm" data-confirm="<?=_Do you really want to delete this email address? ALL active certificates that reference the affected email address (including multiple emails, code signing, TLS and S/MIME) will be revoked.?>" data-reply="<?=_Cancel?>,<?=_Confirm?>" type="submit" name="delete" value="<?=$id?>"<?=$deletable?>><?=_Delete?></button></td>
                <td><button class="btn btn-primary" type="submit" name="reping" value="<?=$id?>"><?=_Request reping?></button></td>
        </tr>
  <? } ?>
index e0690844d69189034628fb5a4cc2ce571918b103..ae3e30e02e79db35a90d8c76a9e695a0016f5fe8 100644 (file)
@@ -166,7 +166,7 @@ public class KeyCompromiseForm extends Form {
             throw new GigiApiException("Sending the notification mail failed.");
         }
         Job j = c.revoke(challenge, Base64.getEncoder().encodeToString(signature), message);
-        if ( !j.waitFor(60000)) {
+        if ( !j.waitFor(Job.WAIT_MIN)) {
             throw new PermamentFormException(new GigiApiException("Revocation timed out."));
         }
         if (c.getStatus() != CertificateStatus.REVOKED) {
diff --git a/tests/club/wpia/gigi/dbObjects/TestDomain.java b/tests/club/wpia/gigi/dbObjects/TestDomain.java
new file mode 100644 (file)
index 0000000..93afd63
--- /dev/null
@@ -0,0 +1,43 @@
+package club.wpia.gigi.dbObjects;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.dbObjects.Certificate.SANType;
+import club.wpia.gigi.testUtils.ManagedTest;
+
+public class TestDomain extends ManagedTest {
+
+    @Test
+    public void testDeleteDomainWithCertificate() throws GigiApiException, GeneralSecurityException, IOException, InterruptedException {
+        User u = User.getById(createVerificationUser("Kurti", "Hansel", createUniqueName() + "@email.com", TEST_PASSWORD));
+        String domain = createUniqueName() + ".org";
+        Domain d = new Domain(u, u, domain);
+        KeyPair kp = generateKeypair();
+        String key = generatePEMCSR(kp, "CN=" + domain);
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", domain), Digest.SHA256, key, CSRType.CSR, getClientProfile(), new Certificate.SubjectAlternateName(SANType.DNS, domain));
+        c.issue(null, "2y", u).waitFor(60000);
+
+        c = new Certificate(u, u, Certificate.buildDN("CN", domain), Digest.SHA256, key, CSRType.CSR, getClientProfile(), new Certificate.SubjectAlternateName(SANType.DNS, "www." + domain));
+        c.issue(null, "2y", u).waitFor(60000);
+
+        Certificate[] certs = d.fetchActiveCertificates();
+        assertEquals(2, certs.length);
+
+        d.delete();
+
+        certs = u.getCertificates(false);
+        assertEquals(0, certs.length);
+        certs = d.fetchActiveCertificates();
+        assertEquals(0, certs.length);
+
+    }
+
+}
index e7aa70cff60c09cf2660f03222424b0c527c8542..7d7b6dba93692942e61596b6651aa7fb9cefbbd5 100644 (file)
@@ -134,4 +134,19 @@ public class TestUser extends ClientBusinessTest {
         assertThat(result, ArrayContains.contains(CoreMatchers.equalTo(type)));
     }
 
+    @Test
+    public void testValidVerification() throws GigiApiException {
+        User u0 = User.getById(createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD));
+        assertFalse(u0.isValidNameVerification(u0.getPreferredName().toString()));
+
+        add100Points(u0.getId());
+        assertTrue(u0.isValidNameVerification(u0.getPreferredName().toString()));
+
+        setVerificationDateToPast(u0.getPreferredName());
+        assertFalse(u0.isValidNameVerification(u0.getPreferredName().toString()));
+
+        add100Points(u0.getId());
+        assertTrue(u0.isValidNameVerification(u0.getPreferredName().toString()));
+    }
+
 }
diff --git a/tests/club/wpia/gigi/dbObjects/TestUserManaged.java b/tests/club/wpia/gigi/dbObjects/TestUserManaged.java
new file mode 100644 (file)
index 0000000..d0906ae
--- /dev/null
@@ -0,0 +1,39 @@
+package club.wpia.gigi.dbObjects;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.dbObjects.Certificate.SANType;
+import club.wpia.gigi.testUtils.ManagedTest;
+
+public class TestUserManaged extends ManagedTest {
+
+    @Test
+    public void testDeleteEmailWithCertificate() throws GigiApiException, GeneralSecurityException, IOException, InterruptedException {
+
+        int id = createVerifiedUser("Test", "User", createUniqueName() + "test@test.tld", TEST_PASSWORD);
+        String email = createUniqueName() + "test@test.tld";
+        User u = User.getById(id);
+        Certificate[] certs = u.getCertificates(false);
+        int certCount = certs.length;
+        EmailAddress testAddress = createVerifiedEmail(u, email);
+        KeyPair kp = generateKeypair();
+        String key = generatePEMCSR(kp, "CN=" + email);
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", email), Digest.SHA256, key, CSRType.CSR, getClientProfile(), new Certificate.SubjectAlternateName(SANType.EMAIL, email));
+        c.issue(null, "2y", u).waitFor(Job.WAIT_MIN);
+
+        u.deleteEmail(testAddress);
+
+        assertFalse(c.getRevocationDate().toString().isEmpty());
+        certs = u.getCertificates(false);
+        assertEquals(certCount, certs.length);
+
+    }
+}
index 7f3af269d484acbc4d1baaa252b8b2eebd664b2e..7ad2c7f4532919a35d8e241726519d6908478815 100644 (file)
@@ -5,13 +5,9 @@ import static org.junit.Assert.*;
 import org.junit.Test;
 
 import club.wpia.gigi.GigiApiException;
-import club.wpia.gigi.dbObjects.Country;
-import club.wpia.gigi.dbObjects.Name;
-import club.wpia.gigi.dbObjects.NamePart;
-import club.wpia.gigi.dbObjects.User;
-import club.wpia.gigi.dbObjects.Verification.VerificationType;
 import club.wpia.gigi.dbObjects.Country.CountryCodeType;
 import club.wpia.gigi.dbObjects.NamePart.NamePartType;
+import club.wpia.gigi.dbObjects.Verification.VerificationType;
 import club.wpia.gigi.testUtils.ClientBusinessTest;
 import club.wpia.gigi.util.Notary;
 
@@ -35,4 +31,20 @@ public class TestVerifyName extends ClientBusinessTest {
         assertEquals(10, n4.getVerificationPoints());
         assertEquals(10, u.getMaxVerifyPoints());
     }
+
+    @Test
+    public void testValidVerification() throws GigiApiException {
+        User u0 = User.getById(createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD));
+        assertFalse(u0.getPreferredName().isValidVerification());
+
+        add100Points(u0.getId());
+        assertTrue(u0.getPreferredName().isValidVerification());
+
+        setVerificationDateToPast(u0.getPreferredName());
+        assertFalse(u0.getPreferredName().isValidVerification());
+
+        add100Points(u0.getId());
+        assertTrue(u0.getPreferredName().isValidVerification());
+    }
+
 }
index bb6c575d7ed81d4457c0ac21951a8c3010ae2c3c..372f2bfaba86144d4023d921a38e5d115ac71d3a 100644 (file)
@@ -15,6 +15,7 @@ import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.pages.account.certs.CertificateRequest;
+import club.wpia.gigi.testUtils.ClientBusinessTest;
 import club.wpia.gigi.testUtils.ClientTest;
 import club.wpia.gigi.util.AuthorizationContext;
 import club.wpia.gigi.util.TimeConditions;
@@ -135,4 +136,19 @@ public class TestCertificateRequest extends ClientTest {
         }
 
     }
+
+    @Test
+    public void testVerificationInPast() throws IOException, GeneralSecurityException, GigiApiException {
+
+        ClientBusinessTest.setVerificationDateToPast(u.getPreferredName());
+        try {
+            CertificateRequest cr = new CertificateRequest(ac, generatePEMCSR(kp, "CN=a ab"));
+            cr.update(u.getPreferredName().toString(), "SHA512", "client-a", null, null, "email:" + email);
+            cr.draft();
+            fail();
+        } catch (GigiApiException e) {
+            assertThat(e.getMessage(), containsString("The entered name needs a valid verification within the last"));
+        }
+
+    }
 }
index 28da80f828679c78113bcedec7408a928da49647..4566d0e1f34391f5e6b46533e041bd49381e46ca 100644 (file)
@@ -183,4 +183,13 @@ public abstract class BusinessTest extends ConfiguredTest {
         supporter.refreshGroups();
         return supporter;
     }
+
+    public EmailAddress createVerifiedEmail(User u, String email) throws InterruptedException, GigiApiException {
+        EmailAddress addr = new EmailAddress(u, email, Locale.ENGLISH);
+        TestMail testMail = getMailReceiver().receive(addr.getAddress());
+        String hash = testMail.extractLink().substring(testMail.extractLink().lastIndexOf('=') + 1);
+        addr.verify(hash);
+        getMailReceiver().assertEmpty();
+        return addr;
+    }
 }
index 023d55ed4b3ab43da9567346d26d03db72502409..3a6156946a2b72e77baa9a4fc5f5dab801566a50 100644 (file)
@@ -1,8 +1,14 @@
 package club.wpia.gigi.testUtils;
 
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.dbObjects.Name;
 import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.util.TimeConditions;
 
 public class ClientBusinessTest extends BusinessTest {
 
@@ -21,4 +27,18 @@ public class ClientBusinessTest extends BusinessTest {
             throw new Error(e);
         }
     }
+
+    public static void setVerificationDateToPast(Name name) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Calendar c = Calendar.getInstance();
+        c.setTimeInMillis(System.currentTimeMillis());
+        c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths());
+        String date = sdf.format(new Date(c.getTimeInMillis()));
+        GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `notary` SET `date`=? WHERE `to`=? AND `date`>?");
+        ps.setString(1, date);
+        ps.setInt(2, name.getId());
+        ps.setString(3, date);
+        ps.execute();
+        ps.close();
+    }
 }
index 322af0bc55e6d15e2b744316b8431b0c2c4d17c4..43be01db7d2b64443c484d6ce751274fde334aa3 100644 (file)
@@ -360,9 +360,11 @@ public abstract class ConfiguredTest {
     }
 
     public static void add100Points(int uid) {
-        try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100', `date`=?")) {
             ps2.setInt(1, uid);
             ps2.setInt(2, User.getById(uid).getPreferredName().getId());
+            ps2.setString(3, sdf.format(new Date(System.currentTimeMillis())));
             ps2.execute();
         }
     }
index f68d307bcb8a14789722c11d07d10a9ef7e07541..0ca611994798cedbadfd8868aad45791ff0e2b24 100644 (file)
@@ -48,6 +48,7 @@ import club.wpia.gigi.dbObjects.DomainPingExecution;
 import club.wpia.gigi.dbObjects.DomainPingType;
 import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.Group;
+import club.wpia.gigi.dbObjects.Name;
 import club.wpia.gigi.dbObjects.NamePart;
 import club.wpia.gigi.dbObjects.NamePart.NamePartType;
 import club.wpia.gigi.dbObjects.User;
@@ -447,6 +448,17 @@ public class Manager extends Page {
 
             resp.getWriter().println("User has been verified " + verifications + " times." + info);
 
+        } else if (req.getParameter("verifyexpire") != null) {
+            String mail = req.getParameter("verifyEmail");
+            User byEmail = User.getByEmail(mail);
+            if (byEmail == null) {
+                resp.getWriter().println("User not found.");
+                return;
+            } else {
+                setVerificationDateToPast(byEmail.getPreferredName());
+            }
+
+            resp.getWriter().println("Verification set to time past the limit.");
         } else if (req.getParameter("letverify") != null) {
             String mail = req.getParameter("letverifyEmail");
             User byEmail = User.getByEmail(mail);
@@ -628,4 +640,18 @@ public class Manager extends Page {
 
         form.output(resp.getWriter(), getLanguage(req), vars);
     }
+
+    private static void setVerificationDateToPast(Name name) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Calendar c = Calendar.getInstance();
+        c.setTimeInMillis(System.currentTimeMillis());
+        c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths());
+        String date = sdf.format(new Date(c.getTimeInMillis()));
+        GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `notary` SET `date`=? WHERE `to`=? AND `date`>?");
+        ps.setString(1, date);
+        ps.setInt(2, name.getId());
+        ps.setString(3, date);
+        ps.execute();
+        ps.close();
+    }
 }
index 89627aeea5fb50dfdfdda21378252e2d9e1ef5a1..f6e1519ab89c27d9084a85b07402a0efd21ff7b0 100644 (file)
@@ -70,6 +70,7 @@ Email: <input type="text" name="verifyEmail"/>
 </td><td>
 Verification Points to issue to preferred name: </br>
 <input type="text" name="verificationPoints" value="100"/> <input type="submit" value="Add Points" name="verify"/>
+<input type="submit" value="Set Verification date past limit" name="verifyexpire"/>
 </td></tr>
 
 <tr><td>