From: Felix Dörre Date: Sat, 28 May 2016 18:26:55 +0000 (+0200) Subject: Enforce Date-of-births to be day-only. X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=c0d62ad52b65d78806431b34ed2ae24bf58c1ada Enforce Date-of-births to be day-only. Change-Id: I23fc14dc6fa83c338297b686b2c8d4ed4fa9baba --- diff --git a/src/org/cacert/gigi/dbObjects/SupportedUser.java b/src/org/cacert/gigi/dbObjects/SupportedUser.java index 044f712b..df5b54e8 100644 --- a/src/org/cacert/gigi/dbObjects/SupportedUser.java +++ b/src/org/cacert/gigi/dbObjects/SupportedUser.java @@ -1,10 +1,9 @@ package org.cacert.gigi.dbObjects; -import java.sql.Date; - import org.cacert.gigi.GigiApiException; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.dbObjects.Certificate.CertificateStatus; +import org.cacert.gigi.util.DayDate; public class SupportedUser { @@ -29,8 +28,8 @@ public class SupportedUser { return true; } - public boolean setDob(Date dob) throws GigiApiException { - if (dob.toString().equals(target.getDoB().toString())) { + public boolean setDob(DayDate dob) throws GigiApiException { + if (dob.equals(target.getDoB())) { return false; } writeSELog("SE dob change"); diff --git a/src/org/cacert/gigi/dbObjects/User.java b/src/org/cacert/gigi/dbObjects/User.java index 70fd8214..d68b183f 100644 --- a/src/org/cacert/gigi/dbObjects/User.java +++ b/src/org/cacert/gigi/dbObjects/User.java @@ -1,6 +1,5 @@ package org.cacert.gigi.dbObjects; -import java.sql.Date; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; @@ -15,6 +14,7 @@ import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.DateSelector; +import org.cacert.gigi.util.DayDate; import org.cacert.gigi.util.Notary; import org.cacert.gigi.util.PasswordHash; import org.cacert.gigi.util.PasswordStrengthChecker; @@ -27,7 +27,7 @@ public class User extends CertificateOwner { private Name name = new Name(null, null, null, null); - private Date dob; + private DayDate dob; private String email; @@ -46,7 +46,7 @@ public class User extends CertificateOwner { private void updateName(GigiResultSet rs) { name = new Name(rs.getString("fname"), rs.getString("lname"), rs.getString("mname"), rs.getString("suffix")); - dob = rs.getDate("dob"); + dob = new DayDate(rs.getDate("dob")); email = rs.getString("email"); String localeStr = rs.getString("language"); @@ -67,7 +67,7 @@ public class User extends CertificateOwner { } } - public User(String email, String password, Name name, Date dob, Locale locale) throws GigiApiException { + public User(String email, String password, Name name, DayDate dob, Locale locale) throws GigiApiException { this.email = email; this.dob = dob; this.name = name; @@ -79,7 +79,7 @@ public class User extends CertificateOwner { query.setString(4, name.getMname()); query.setString(5, name.getLname()); query.setString(6, name.getSuffix()); - query.setDate(7, dob); + query.setDate(7, dob.toSQLDate()); query.setString(8, locale.toString()); query.setInt(9, getId()); query.execute(); @@ -91,11 +91,11 @@ public class User extends CertificateOwner { return name; } - public Date getDoB() { + public DayDate getDoB() { return dob; } - public void setDoB(Date dob) { + public void setDoB(DayDate dob) { this.dob = dob; } @@ -222,7 +222,7 @@ public class User extends CertificateOwner { public boolean isOfAge(int desiredAge) { Calendar c = Calendar.getInstance(); - c.setTime(dob); + c.setTimeInMillis(dob.getTime()); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH); int day = c.get(Calendar.DAY_OF_MONTH); @@ -335,7 +335,7 @@ public class User extends CertificateOwner { update.setString(2, name.getLname()); update.setString(3, name.getMname()); update.setString(4, name.getSuffix()); - update.setDate(5, getDoB()); + update.setDate(5, getDoB().toSQLDate()); update.setInt(6, getId()); update.executeUpdate(); } diff --git a/src/org/cacert/gigi/output/DateSelector.java b/src/org/cacert/gigi/output/DateSelector.java index ad1bdf33..22a0f620 100644 --- a/src/org/cacert/gigi/output/DateSelector.java +++ b/src/org/cacert/gigi/output/DateSelector.java @@ -4,7 +4,6 @@ import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; -import java.util.Date; import java.util.GregorianCalendar; import java.util.Map; import java.util.TimeZone; @@ -14,16 +13,17 @@ import javax.servlet.http.HttpServletRequest; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.template.Outputable; +import org.cacert.gigi.util.DayDate; import org.cacert.gigi.util.HTMLEncoder; public class DateSelector implements Outputable { private String[] names; - public DateSelector(String day, String month, String year, Date date) { + public DateSelector(String day, String month, String year, DayDate date) { this(day, month, year); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTF")); - cal.setTime(date); + cal.setTimeInMillis(date.getTime()); this.day = cal.get(Calendar.DAY_OF_MONTH); this.month = cal.get(Calendar.MONTH) + 1; this.year = cal.get(Calendar.YEAR); @@ -126,10 +126,11 @@ public class DateSelector implements Outputable { return "DateSelector [names=" + Arrays.toString(names) + ", day=" + day + ", month=" + month + ", year=" + year + "]"; } - public java.sql.Date getDate() { + public DayDate getDate() { Calendar gc = GregorianCalendar.getInstance(); - gc.set(year, month - 1, day); - return new java.sql.Date(gc.getTime().getTime()); + gc.set(year, month - 1, day, 0, 0, 0); + gc.set(Calendar.MILLISECOND, 0); + return new DayDate(gc.getTime().getTime()); } public static SimpleDateFormat getDateFormat() { diff --git a/src/org/cacert/gigi/output/template/Template.java b/src/org/cacert/gigi/output/template/Template.java index 858b0480..84727f25 100644 --- a/src/org/cacert/gigi/output/template/Template.java +++ b/src/org/cacert/gigi/output/template/Template.java @@ -18,6 +18,7 @@ import java.util.regex.Pattern; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.DateSelector; +import org.cacert.gigi.util.DayDate; import org.cacert.gigi.util.HTMLEncoder; public class Template implements Outputable { @@ -190,8 +191,8 @@ public class Template implements Outputable { } if (s instanceof Outputable) { ((Outputable) s).output(out, l, vars); - } else if (s instanceof java.sql.Date) { - out.print(DateSelector.getDateFormat().format(s)); + } else if (s instanceof DayDate) { + out.print(DateSelector.getDateFormat().format(((DayDate) s).toDate())); } else if (s instanceof Date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); out.print(sdf.format(s)); diff --git a/src/org/cacert/gigi/pages/wot/AssuranceForm.java b/src/org/cacert/gigi/pages/wot/AssuranceForm.java index a840aa75..05aed3d2 100644 --- a/src/org/cacert/gigi/pages/wot/AssuranceForm.java +++ b/src/org/cacert/gigi/pages/wot/AssuranceForm.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.text.SimpleDateFormat; -import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -23,6 +22,7 @@ import org.cacert.gigi.output.template.IterableDataset; import org.cacert.gigi.output.template.Template; import org.cacert.gigi.pages.Page; import org.cacert.gigi.pages.PasswordResetPage; +import org.cacert.gigi.util.DayDate; import org.cacert.gigi.util.Notary; import org.cacert.gigi.util.RandomToken; import org.cacert.gigi.util.ServerConstants; @@ -33,7 +33,7 @@ public class AssuranceForm extends Form { private Name assureeName; - private Date dob; + private DayDate dob; private String location = ""; @@ -69,8 +69,8 @@ public class AssuranceForm extends Form { res.put("nameExplicit", assuree.getName()); res.put("name", assuree.getName().toString()); res.put("maxpoints", assurer.getMaxAssurePoints()); - res.put("dob", sdf.format(assuree.getDoB())); - res.put("dobFmt2", sdf2.format(assuree.getDoB())); + res.put("dob", sdf.format(assuree.getDoB().toDate())); + res.put("dobFmt2", sdf2.format(assuree.getDoB().toDate())); res.put("location", location); res.put("date", date); res.put("aword", aword); diff --git a/src/org/cacert/gigi/util/DayDate.java b/src/org/cacert/gigi/util/DayDate.java new file mode 100644 index 00000000..0b7ba383 --- /dev/null +++ b/src/org/cacert/gigi/util/DayDate.java @@ -0,0 +1,70 @@ +package org.cacert.gigi.util; + +import java.sql.Date; + +/** + * This Class consists of a millisecond timestamp that is only interesting up to + * day-precision. + */ +public class DayDate { + + public static final long MILLI_DAY = 24 * 60 * 60 * 1000; + + private long time; + + /** + * Creates a new {@link DayDate} from the SQL Day-exact variant {@link Date} + * . + * + * @see #toSQLDate() + */ + public DayDate(Date date) { + this(date.getTime()); + } + + /** + * Creates a new {@link DayDate} based on the given millisecond timestamp. + * + * @param millis + * the timestamp to create the Date from. + * @throws IllegalArgumentException + * if the parameter contains more precision than needed. + */ + public DayDate(long millis) { + this.time = millis; + if (millis % MILLI_DAY != 0) { + throw new IllegalArgumentException(); + } + } + + /** + * Gets the enclosed timestamp. + * + * @return the enclosed timestamp. + */ + public long getTime() { + return time; + } + + /** + * Converts this DayDate to an {@link Date}. + * + * @return the corresponding {@link Date} + * @see #DayDate(Date) + */ + public Date toSQLDate() { + return new Date(time); + } + + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof DayDate)) { + throw new Error("You may not compare this date somthing other than a DayDate"); + } + return ((DayDate) obj).time == time; + } + + public java.util.Date toDate() { + return new java.util.Date(time); + } +} diff --git a/src/org/cacert/gigi/util/Notary.java b/src/org/cacert/gigi/util/Notary.java index 7cb15aad..24118fc3 100644 --- a/src/org/cacert/gigi/util/Notary.java +++ b/src/org/cacert/gigi/util/Notary.java @@ -72,7 +72,7 @@ public class Notary { * @throws GigiApiException * if the assurance fails (for various reasons) */ - public synchronized static void assure(User assurer, User assuree, Name assureeName, Date dob, int awarded, String location, String date, AssuranceType type) throws GigiApiException { + public synchronized static void assure(User assurer, User assuree, Name assureeName, DayDate dob, int awarded, String location, String date, AssuranceType type) throws GigiApiException { may(assurer, assuree, AssuranceType.FACE_TO_FACE); GigiApiException gae = new GigiApiException(); if ( !gae.isEmpty()) { diff --git a/tests/org/cacert/gigi/TestObjectCache.java b/tests/org/cacert/gigi/TestObjectCache.java index e4dec8a3..d2a04595 100644 --- a/tests/org/cacert/gigi/TestObjectCache.java +++ b/tests/org/cacert/gigi/TestObjectCache.java @@ -3,7 +3,6 @@ package org.cacert.gigi; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; -import java.sql.Date; import java.sql.SQLException; import java.util.Calendar; import java.util.Locale; @@ -13,6 +12,7 @@ import org.cacert.gigi.dbObjects.EmailAddress; import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.ManagedTest; +import org.cacert.gigi.util.DayDate; import org.junit.Test; public class TestObjectCache extends ManagedTest { @@ -24,8 +24,9 @@ public class TestObjectCache extends ManagedTest { assertThat(User.getById(uid), is(sameInstance(User.getById(uid)))); Calendar c = Calendar.getInstance(); - c.set(1950, 1, 1); - User u = new User(createUniqueName() + "@example.org", TEST_PASSWORD, new Name("fname", "lname", "mname", "suffix"), new Date(c.getTime().getTime()), Locale.ENGLISH); + c.set(1950, 1, 1, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + User u = new User(createUniqueName() + "@example.org", TEST_PASSWORD, new Name("fname", "lname", "mname", "suffix"), new DayDate(c.getTime().getTime()), Locale.ENGLISH); assertThat(u, is(sameInstance(User.getById(u.getId())))); assertThat(User.getById(u.getId()), is(sameInstance(User.getById(u.getId())))); diff --git a/tests/org/cacert/gigi/TestUser.java b/tests/org/cacert/gigi/TestUser.java index 1124179a..a3dfb777 100644 --- a/tests/org/cacert/gigi/TestUser.java +++ b/tests/org/cacert/gigi/TestUser.java @@ -3,7 +3,6 @@ package org.cacert.gigi; import static org.junit.Assert.*; import java.io.IOException; -import java.sql.Date; import java.sql.SQLException; import java.util.Locale; @@ -13,6 +12,7 @@ import org.cacert.gigi.dbObjects.EmailAddress; import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.ManagedTest; +import org.cacert.gigi.util.DayDate; import org.junit.Test; public class TestUser extends ManagedTest { @@ -21,7 +21,7 @@ public class TestUser extends ManagedTest { public void testStoreAndLoad() throws SQLException, GigiApiException { long dob = System.currentTimeMillis(); dob -= dob % (1000 * 60 * 60 * 24); - User u = new User(createUniqueName() + "a@email.org", "password", new Name("user", "last", "", ""), new java.sql.Date(dob), Locale.ENGLISH); + User u = new User(createUniqueName() + "a@email.org", "password", new Name("user", "last", "", ""), new DayDate(dob), Locale.ENGLISH); int id = u.getId(); User u2 = User.getById(id); assertEquals(u.getName(), u2.getName()); @@ -95,7 +95,9 @@ public class TestUser extends ManagedTest { @Test public void testDoubleInsert() throws GigiApiException { - User u = new User(createUniqueName() + "@example.org", TEST_PASSWORD, new Name("f", "k", "m", "s"), new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365), Locale.ENGLISH); + long d = System.currentTimeMillis(); + d -= d % DayDate.MILLI_DAY; + User u = new User(createUniqueName() + "@example.org", TEST_PASSWORD, new Name("f", "k", "m", "s"), new DayDate(d + 1000L * 60 * 60 * 24 * 365), Locale.ENGLISH); Assurance[] ma = u.getMadeAssurances(); Assurance[] ma2 = u.getMadeAssurances(); Assurance[] ra = u.getReceivedAssurances(); diff --git a/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java b/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java index 536634be..d40bb98b 100644 --- a/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java +++ b/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java @@ -102,7 +102,7 @@ public class TestMyDetailsEdit extends ManagedTest { cal.set(Calendar.DAY_OF_MONTH, Calendar.FEBRUARY); cal.set(Calendar.MONTH, 1); Date d = new Date(cal.getTimeInMillis()); - assertEquals(d.toString(), u.getDoB().toString()); + assertEquals(d.toString(), u.getDoB().toSQLDate().toString()); } @Test diff --git a/tests/org/cacert/gigi/pages/wot/TestAssurance.java b/tests/org/cacert/gigi/pages/wot/TestAssurance.java index ffc9ea57..3468f1f4 100644 --- a/tests/org/cacert/gigi/pages/wot/TestAssurance.java +++ b/tests/org/cacert/gigi/pages/wot/TestAssurance.java @@ -107,27 +107,42 @@ public class TestAssurance extends ManagedTest { @Test public void testAssureFormRaceName() throws IOException, SQLException { - testAssureFormRace(true); + testAssureFormRace(true, false); } @Test public void testAssureFormRaceDoB() throws IOException, SQLException { - testAssureFormRace(false); + testAssureFormRace(false, false); } - public void testAssureFormRace(boolean name) throws IOException, SQLException { + @Test + public void testAssureFormRaceNameBlind() throws IOException, SQLException { + testAssureFormRace(true, true); + } + + @Test + public void testAssureFormRaceDoBBlind() throws IOException, SQLException { + testAssureFormRace(false, true); + } + + public void testAssureFormRace(boolean name, boolean succeed) throws IOException, SQLException { URLConnection uc = buildupAssureFormConnection(true); String assureeCookie = login(assureeM, TEST_PASSWORD); - String newName = "lname=" + (name ? "c" : "a") + "&fname=a&mname=&suffix="; - String newDob = "day=1&month=1&year=" + (name ? 1910 : 1911); + String newName = "lname=" + (name && !succeed ? "a" : "c") + "&fname=a&mname=&suffix="; + String newDob = "day=1&month=1&year=" + ( !name && !succeed ? 1911 : 1910); assertNull(executeBasicWebInteraction(assureeCookie, MyDetails.PATH, newName + "&" + newDob + "&processDetails", 0)); uc.getOutputStream().write(("date=2000-01-01&location=testcase&certify=1&rules=1&CCAAgreed=1&assertion=1&points=10").getBytes("UTF-8")); uc.getOutputStream().flush(); String error = fetchStartErrorMessage(IOUtils.readURL(uc)); - assertTrue(error, !error.startsWith("")); + if (succeed) { + assertNull(error); + } else { + assertTrue(error, !error.startsWith("")); + assertThat(error, containsString("changed his personal details")); + } } @Test diff --git a/util-testing/org/cacert/gigi/pages/Manager.java b/util-testing/org/cacert/gigi/pages/Manager.java index 3ac191ac..460fc4d2 100644 --- a/util-testing/org/cacert/gigi/pages/Manager.java +++ b/util-testing/org/cacert/gigi/pages/Manager.java @@ -7,7 +7,6 @@ import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Signature; -import java.sql.Date; import java.util.Base64; import java.util.Calendar; import java.util.GregorianCalendar; @@ -45,6 +44,7 @@ import org.cacert.gigi.pages.account.certs.CertificateRequest; import org.cacert.gigi.ping.DomainPinger; import org.cacert.gigi.ping.PingerDaemon; import org.cacert.gigi.util.AuthorizationContext; +import org.cacert.gigi.util.DayDate; import org.cacert.gigi.util.Notary; import sun.security.x509.X509Key; @@ -210,7 +210,7 @@ public class Manager extends Page { private void createUser(String email) throws GigiApiException, IllegalAccessException { Calendar gc = GregorianCalendar.getInstance(); gc.set(1990, 0, 1); - User u = new User(email, "xvXV12°§", new Name("Först", "Läst", "Müddle", "Süffix"), new Date(gc.getTime().getTime()), Locale.ENGLISH); + User u = new User(email, "xvXV12°§", new Name("Först", "Läst", "Müddle", "Süffix"), new DayDate(gc.getTime().getTime()), Locale.ENGLISH); EmailAddress ea = u.getEmails()[0]; if (f == null) { System.out.println("verification failed");