From 9def69bd08ea69eb27786d5b34f00e154e09e9f3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Thu, 14 Jul 2016 12:44:42 +0200 Subject: [PATCH] add: Allow multiple names, name-schemes, multi-name-assurance, etc. This allows for multiple names based on name schemes. Changes assurances to verify names instead of user accounts. Change-Id: I80d694c35e017e030a0ff381b6c611ab039091b6 --- src/org/cacert/gigi/api/FindAgent.java | 2 +- .../gigi/database/DatabaseConnection.java | 2 +- .../cacert/gigi/database/tableStructure.sql | 34 +- .../cacert/gigi/database/upgrade/from_19.sql | 41 ++ src/org/cacert/gigi/dbObjects/Assurance.java | 6 +- src/org/cacert/gigi/dbObjects/Name.java | 476 +++++++++++++++--- src/org/cacert/gigi/dbObjects/NamePart.java | 81 +++ .../cacert/gigi/dbObjects/SupportedUser.java | 17 +- src/org/cacert/gigi/dbObjects/User.java | 128 +++-- src/org/cacert/gigi/output/ArrayIterable.java | 30 ++ .../cacert/gigi/output/AssurancesDisplay.java | 7 +- .../gigi/output/AssurancesDisplay.templ | 4 + src/org/cacert/gigi/output/NameInput.java | 109 ++++ src/org/cacert/gigi/output/NameInput.templ | 24 + .../cacert/gigi/pages/account/MyDetails.java | 6 +- .../gigi/pages/account/MyDetailsForm.java | 95 +++- .../gigi/pages/account/MyDetailsForm.templ | 33 +- .../pages/account/MyDetailsFormAssured.templ | 28 -- .../cacert/gigi/pages/account/NamesForm.templ | 19 + .../account/certs/CertificateRequest.java | 4 +- .../cacert/gigi/pages/admin/TTPAdminForm.java | 2 +- .../cacert/gigi/pages/admin/TTPAdminPage.java | 2 +- .../admin/support/SupportUserDetailsForm.java | 30 +- .../support/SupportUserDetailsForm.templ | 22 +- src/org/cacert/gigi/pages/main/Signup.java | 48 +- src/org/cacert/gigi/pages/main/Signup.templ | 23 +- .../gigi/pages/orga/AffiliationForm.java | 2 +- .../cacert/gigi/pages/wot/AssuranceForm.java | 54 +- .../cacert/gigi/pages/wot/AssuranceForm.templ | 5 +- src/org/cacert/gigi/pages/wot/AssurePage.java | 11 +- src/org/cacert/gigi/pages/wot/MyPoints.templ | 2 +- .../gigi/util/AuthorizationContext.java | 4 +- src/org/cacert/gigi/util/Notary.java | 51 +- .../gigi/util/PasswordStrengthChecker.java | 30 +- tests/org/cacert/gigi/TestName.java | 167 +++++- tests/org/cacert/gigi/TestObjectCache.java | 4 +- tests/org/cacert/gigi/TestUser.java | 59 ++- tests/org/cacert/gigi/api/IssueCert.java | 8 +- tests/org/cacert/gigi/api/TestFindAgent.java | 2 +- .../cacert/gigi/dbObjects/TestAssurance.java | 52 +- .../cacert/gigi/dbObjects/TestAssureName.java | 32 ++ .../gigi/pages/account/TestMyDetailsEdit.java | 89 ++-- .../account/TestPasswordResetExternal.java | 2 +- .../admin/TestSEAdminNotificationMail.java | 4 +- .../pages/admin/TestSEAdminPageDetails.java | 66 +-- .../cacert/gigi/pages/wot/TestAssurance.java | 32 +- .../cacert/gigi/testUtils/BusinessTest.java | 22 +- .../gigi/testUtils/ClientBusinessTest.java | 4 + .../cacert/gigi/testUtils/ConfiguredTest.java | 3 +- tests/org/cacert/gigi/util/TestNotary.java | 10 +- .../util/TestPasswordStrengthChecker.java | 10 +- .../org/cacert/gigi/pages/Manager.java | 11 +- 52 files changed, 1390 insertions(+), 619 deletions(-) create mode 100644 src/org/cacert/gigi/database/upgrade/from_19.sql create mode 100644 src/org/cacert/gigi/dbObjects/NamePart.java create mode 100644 src/org/cacert/gigi/output/ArrayIterable.java create mode 100644 src/org/cacert/gigi/output/NameInput.java create mode 100644 src/org/cacert/gigi/output/NameInput.templ create mode 100644 src/org/cacert/gigi/pages/account/NamesForm.templ create mode 100644 tests/org/cacert/gigi/dbObjects/TestAssureName.java diff --git a/src/org/cacert/gigi/api/FindAgent.java b/src/org/cacert/gigi/api/FindAgent.java index 29e536e1..bca3a127 100644 --- a/src/org/cacert/gigi/api/FindAgent.java +++ b/src/org/cacert/gigi/api/FindAgent.java @@ -77,7 +77,7 @@ public class FindAgent extends APIPoint { continue; } // date, recheck(?), name - resp.getWriter().println(i + "," + u1.canAssure() + "," + u1.getName().toString()); + resp.getWriter().println(i + "," + u1.canAssure() + "," + u1.getPreferredName().toAbbreviatedString()); } } else if (pi.equals(PATH_MAIL)) { String id = req.getParameter("from"); diff --git a/src/org/cacert/gigi/database/DatabaseConnection.java b/src/org/cacert/gigi/database/DatabaseConnection.java index 39071a3d..e7c98488 100644 --- a/src/org/cacert/gigi/database/DatabaseConnection.java +++ b/src/org/cacert/gigi/database/DatabaseConnection.java @@ -122,7 +122,7 @@ public class DatabaseConnection { } - public static final int CURRENT_SCHEMA_VERSION = 19; + public static final int CURRENT_SCHEMA_VERSION = 20; public static final int CONNECTION_TIMEOUT = 24 * 60 * 60; diff --git a/src/org/cacert/gigi/database/tableStructure.sql b/src/org/cacert/gigi/database/tableStructure.sql index 467160cd..883adf76 100644 --- a/src/org/cacert/gigi/database/tableStructure.sql +++ b/src/org/cacert/gigi/database/tableStructure.sql @@ -12,10 +12,7 @@ CREATE TABLE "users" ( "id" int NOT NULL, "email" varchar(255) NOT NULL DEFAULT '', "password" varchar(255) NOT NULL DEFAULT '', - "fname" varchar(255) NOT NULL DEFAULT '', - "mname" varchar(255) NOT NULL DEFAULT '', - "lname" varchar(255) NOT NULL DEFAULT '', - "suffix" varchar(50) NOT NULL DEFAULT '', + "preferredName" int NULL, "dob" date NOT NULL, "verified" boolean NOT NULL DEFAULT 'false', "language" varchar(5) NOT NULL DEFAULT '', @@ -377,7 +374,7 @@ CREATE TABLE "schemeVersion" ( "version" smallint NOT NULL, PRIMARY KEY ("version") ); -INSERT INTO "schemeVersion" (version) VALUES(19); +INSERT INTO "schemeVersion" (version) VALUES(20); DROP TABLE IF EXISTS `passwordResetTickets`; CREATE TABLE `passwordResetTickets` ( @@ -655,3 +652,30 @@ INSERT INTO `countryIsoCode`(english, code2, code3, obp_id) VALUES ('South Afric INSERT INTO `countryIsoCode`(english, code2, code3, obp_id) VALUES ('Zambia', 'ZM', 'ZMB', 894); INSERT INTO `countryIsoCode`(english, code2, code3, obp_id) VALUES ('Zimbabwe', 'ZW', 'ZWE', 716); + + +DROP TABLE IF EXISTS "names"; +DROP TYPE IF EXISTS "nameSchemaType"; +CREATE TYPE "nameSchemaType" AS ENUM ('single', 'western'); + +CREATE TABLE "names" ( + "id" serial NOT NULL, + "uid" int NOT NULL, + "type" "nameSchemaType" NOT NULL, + "created" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" timestamp NULL DEFAULT NULL, + "deprecated" timestamp NULL DEFAULT NULL, + PRIMARY KEY ("id") +); + + +DROP TABLE IF EXISTS "nameParts"; +DROP TYPE IF EXISTS "namePartType"; +CREATE TYPE "namePartType" AS ENUM ('first-name', 'last-name', 'single-name', 'suffix'); + +CREATE TABLE "nameParts" ( + "id" int NOT NULL, + "position" int NOT NULL, + "type" "namePartType" NOT NULL, + "value" varchar(255) NOT NULL +); diff --git a/src/org/cacert/gigi/database/upgrade/from_19.sql b/src/org/cacert/gigi/database/upgrade/from_19.sql new file mode 100644 index 00000000..ad027d60 --- /dev/null +++ b/src/org/cacert/gigi/database/upgrade/from_19.sql @@ -0,0 +1,41 @@ +DROP TYPE IF EXISTS "nameSchemaType"; +CREATE TYPE "nameSchemaType" AS ENUM ('single', 'western'); + +DROP TABLE IF EXISTS "names"; +CREATE TABLE "names" ( + "id" serial NOT NULL, + "uid" int NOT NULL, + "type" "nameSchemaType" NOT NULL, + "created" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" timestamp NULL DEFAULT NULL, + "deprecated" timestamp NULL DEFAULT NULL, + PRIMARY KEY ("id") +); + + +DROP TABLE IF EXISTS "nameParts"; +DROP TYPE IF EXISTS "namePartType"; +CREATE TYPE "namePartType" AS ENUM ('first-name', 'last-name', 'single-name', 'suffix'); + +CREATE TABLE "nameParts" ( + "id" int NOT NULL, + "position" int NOT NULL, + "type" "namePartType" NOT NULL, + "value" varchar(255) NOT NULL +); + +INSERT INTO "names" ("uid", "type") (SELECT "id" as "uid", 'western'::"nameSchemaType" AS "type" from users ORDER BY id); +INSERT INTO "nameParts" SELECT names.id, 1, 'first-name'::"namePartType", "fname" FROM "users" INNER JOIN "names" ON "names"."uid" = "users"."id"; + +INSERT INTO "nameParts" SELECT names.id, 2, 'first-name'::"namePartType", "mname" FROM "users" INNER JOIN "names" ON "names"."uid" = "users"."id" WHERE "mname" != ''; +INSERT INTO "nameParts" SELECT names.id, 3, 'last-name'::"namePartType", "lname" FROM "users" INNER JOIN "names" ON "names"."uid" = "users"."id"; +INSERT INTO "nameParts" SELECT names.id, 4, 'suffix'::"namePartType", "suffix" FROM "users" INNER JOIN "names" ON "names"."uid" = "users"."id" WHERE "suffix" != ''; + +UPDATE "notary" SET "to"=(SELECT "id" FROM "names" WHERE "uid"="notary"."to"); + +ALTER TABLE "users" ADD "preferredName" int; +UPDATE "users" SET "preferredName"=(SELECT "id" FROM "names" WHERE "uid"="users"."id"); +ALTER TABLE "users" DROP "fname"; +ALTER TABLE "users" DROP "mname"; +ALTER TABLE "users" DROP "lname"; +ALTER TABLE "users" DROP "suffix"; diff --git a/src/org/cacert/gigi/dbObjects/Assurance.java b/src/org/cacert/gigi/dbObjects/Assurance.java index 65a5a599..dbcc20b6 100644 --- a/src/org/cacert/gigi/dbObjects/Assurance.java +++ b/src/org/cacert/gigi/dbObjects/Assurance.java @@ -23,7 +23,7 @@ public class Assurance { private User from; - private User to; + private Name to; private String location; @@ -33,7 +33,7 @@ public class Assurance { private String date; - public Assurance(int id, User from, User to, String location, String method, int points, String date) { + public Assurance(int id, User from, Name to, String location, String method, int points, String date) { this.id = id; this.from = from; this.to = to; @@ -60,7 +60,7 @@ public class Assurance { return points; } - public User getTo() { + public Name getTo() { return to; } diff --git a/src/org/cacert/gigi/dbObjects/Name.java b/src/org/cacert/gigi/dbObjects/Name.java index d0cf00f7..f9099cec 100644 --- a/src/org/cacert/gigi/dbObjects/Name.java +++ b/src/org/cacert/gigi/dbObjects/Name.java @@ -3,121 +3,447 @@ package org.cacert.gigi.dbObjects; import java.io.PrintWriter; import java.util.Map; -import org.cacert.gigi.dbObjects.wrappers.DataContainer; +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.database.GigiPreparedStatement; +import org.cacert.gigi.database.GigiResultSet; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.template.Outputable; import org.cacert.gigi.util.HTMLEncoder; -@DataContainer -public class Name implements Outputable { +public class Name implements Outputable, IdCachable { - private final String fname; + private abstract static class SchemedName { - private final String mname; + /** + * @see Name#matches(String) + */ + public abstract boolean matches(String text); - private final String lname; + public abstract String toPreferredString(); - private final String suffix; + /** + * @see Name#toAbbreviatedString() + */ + public abstract String toAbbreviatedString(); - public Name(String fname, String lname, String mname, String suffix) { - this.fname = fname; - this.lname = lname; - this.mname = mname; - this.suffix = suffix; - } + public abstract String getSchemeName(); - @Override - public void output(PrintWriter out, Language l, Map vars) { - out.println(""); - out.print(""); - out.print(HTMLEncoder.encodeHTML(fname)); - out.print(" "); - out.print(""); - out.print(HTMLEncoder.encodeHTML(lname)); - out.print(""); - out.println(""); - } + /** + * @see Name#output(PrintWriter, Language, Map) + */ + public abstract void output(PrintWriter out); - @Override - public String toString() { - return fname + " " + lname; } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((fname == null) ? 0 : fname.hashCode()); - result = prime * result + ((lname == null) ? 0 : lname.hashCode()); - result = prime * result + ((mname == null) ? 0 : mname.hashCode()); - result = prime * result + ((suffix == null) ? 0 : suffix.hashCode()); - return result; + private static class SingleName extends SchemedName { + + private NamePart singlePart; + + public SingleName(NamePart singlePart) { + this.singlePart = singlePart; + } + + @Override + public boolean matches(String text) { + return text.equals(singlePart.getValue()); + } + + @Override + public String toPreferredString() { + return singlePart.getValue(); + } + + @Override + public String toAbbreviatedString() { + return singlePart.getValue(); + } + + @Override + public String getSchemeName() { + return "single"; + } + + @Override + public void output(PrintWriter out) { + out.println(""); + out.print(HTMLEncoder.encodeHTML(singlePart.getValue())); + out.println(""); + } } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + /** + * Naming scheme where any first name and the first last name is required. + * Requires first names in arbitrary order. Last names and suffixes in + * correct order. + */ + private static class WesternName extends SchemedName { + + private NamePart[] firstNames; + + private NamePart[] lastNames; + + private NamePart[] suffixes; + + public WesternName(NamePart[] firstName, NamePart lastName[], NamePart[] suffixes) { + if (lastName.length < 1 || firstName.length < 1) { + throw new Error("Requires at least one first and one last name"); + } + this.lastNames = lastName; + this.firstNames = firstName; + this.suffixes = suffixes; } - if (obj == null) { + + @Override + public boolean matches(String text) { + String[] tokens = text.split(" "); + + NamePart mandatoryLN = lastNames[0]; + for (int i = 0; i < tokens.length; i++) { + if (tokens[i].equals(mandatoryLN.getValue())) { + if (tryMatchFirst(tokens, i) && tryMatchLastSuff(tokens, i)) { + return true; + } + + } + } return false; } - if (getClass() != obj.getClass()) { + + private boolean tryMatchLastSuff(String[] tokens, int lastName) { + int userInputPos = lastName + 1; + boolean currentlyMatchingLastNames = true; + int referencePos = 1; + while ((currentlyMatchingLastNames || referencePos < suffixes.length) && (userInputPos < tokens.length)) { + // we break when we match suffixes and there is no + // reference-suffix left + if (currentlyMatchingLastNames) { + if (referencePos >= lastNames.length) { + referencePos = 0; + currentlyMatchingLastNames = false; + } else if (tokens[userInputPos].equals(lastNames[referencePos].getValue())) { + userInputPos++; + referencePos++; + } else { + referencePos++; + } + } else { + if (tokens[userInputPos].equals(suffixes[referencePos].getValue())) { + userInputPos++; + referencePos++; + } else { + referencePos++; + } + } + } + if (userInputPos >= tokens.length) { + // all name parts are covered we're done here + return true; + } return false; } - Name other = (Name) obj; - if (fname == null) { - if (other.fname != null) { + + private boolean tryMatchFirst(String[] tokens, int lastName) { + if (lastName == 0) { return false; } - } else if ( !fname.equals(other.fname)) { - return false; + boolean[] fnUsed = new boolean[firstNames.length]; + for (int i = 0; i < lastName; i++) { + boolean found = false; + for (int j = 0; j < fnUsed.length; j++) { + if ( !fnUsed[j] && firstNames[j].getValue().equals(tokens[i])) { + fnUsed[j] = true; + found = true; + break; + } + } + if ( !found) { + return false; + } + } + return true; } - if (lname == null) { - if (other.lname != null) { - return false; + + @Override + public String toPreferredString() { + StringBuilder res = new StringBuilder(); + appendArray(res, firstNames); + appendArray(res, lastNames); + appendArray(res, suffixes); + res.deleteCharAt(res.length() - 1); + return res.toString(); + } + + @Override + public void output(PrintWriter out) { + outputNameParts(out, "fname", firstNames); + outputNameParts(out, "lname", lastNames); + outputNameParts(out, "suffix", suffixes); + } + + private void outputNameParts(PrintWriter out, String type, NamePart[] input) { + StringBuilder res; + res = new StringBuilder(); + appendArray(res, input); + if (res.length() > 0) { + res.deleteCharAt(res.length() - 1); + out.print(""); + out.print(HTMLEncoder.encodeHTML(res.toString())); + out.println(""); } - } else if ( !lname.equals(other.lname)) { - return false; } - if (mname == null) { - if (other.mname != null) { - return false; + + private void appendArray(StringBuilder res, NamePart[] ps) { + for (int i = 0; i < ps.length; i++) { + res.append(ps[i].getValue()); + res.append(" "); } - } else if ( !mname.equals(other.mname)) { - return false; } - if (suffix == null) { - if (other.suffix != null) { - return false; + + @Override + public String getSchemeName() { + return "western"; + } + + @Override + public String toAbbreviatedString() { + return firstNames[0].getValue() + " " + lastNames[0].getValue().charAt(0) + "."; + } + } + + private int id; + + private int ownerId; + + /** + * Only resolved lazily to resolve circular referencing with {@link User} on + * {@link User#getPreferredName()}. Resolved based on {@link #ownerId}. + */ + private User owner; + + private NamePart[] parts; + + private SchemedName scheme; + + /** + * This name should not get assured anymore and therefore not be displayed + * to the RA-Agent. This state is irrevocable. + */ + private boolean deprecated; + + private Name(GigiResultSet rs) { + ownerId = rs.getInt(1); + id = rs.getInt(2); + deprecated = rs.getString("deprecated") != null; + try (GigiPreparedStatement partFetcher = new GigiPreparedStatement("SELECT `type`, `value` FROM `nameParts` WHERE `id`=? ORDER BY `position` ASC", true)) { + partFetcher.setInt(1, id); + GigiResultSet rs1 = partFetcher.executeQuery(); + rs1.last(); + NamePart[] dt = new NamePart[rs1.getRow()]; + rs1.beforeFirst(); + for (int i = 0; rs1.next(); i++) { + dt[i] = new NamePart(rs1); } - } else if ( !suffix.equals(other.suffix)) { - return false; + parts = dt; + scheme = detectScheme(); } - return true; + } + public Name(User u, NamePart... np) throws GigiApiException { + synchronized (Name.class) { + parts = np; + owner = u; + scheme = detectScheme(); + if (scheme == null) { + throw new GigiApiException("Name particles don't match up for any known name scheme."); + } + try (GigiPreparedStatement inserter = new GigiPreparedStatement("INSERT INTO `names` SET `uid`=?, `type`=?::`nameSchemaType`")) { + inserter.setInt(1, u.getId()); + inserter.setString(2, scheme.getSchemeName()); + inserter.execute(); + id = inserter.lastInsertId(); + } + try (GigiPreparedStatement inserter = new GigiPreparedStatement("INSERT INTO `nameParts` SET `id`=?, `position`=?, `type`=?::`namePartType`, `value`=?")) { + inserter.setInt(1, id); + for (int i = 0; i < np.length; i++) { + inserter.setInt(2, i); + inserter.setString(3, np[i].getType().getDbValue()); + inserter.setString(4, np[i].getValue()); + inserter.execute(); + } + } + cache.put(this); + } + } + + private SchemedName detectScheme() { + if (parts.length == 1 && parts[0].getType() == NamePartType.SINGLE_NAME) { + return new SingleName(parts[0]); + } + int suffixCount = 0; + int lastCount = 0; + int firstCount = 0; + int stage = 0; + for (NamePart p : parts) { + if (p.getType() == NamePartType.LAST_NAME) { + lastCount++; + if (stage < 1) { + stage = 1; + } else if (stage != 1) { + return null; + } + } else if (p.getType() == NamePartType.FIRST_NAME) { + firstCount++; + if (stage != 0) { + return null; + } + } else if (p.getType() == NamePartType.SUFFIX) { + suffixCount++; + if (stage < 2) { + stage = 2; + } else if (stage != 2) { + return null; + } + + } else { + return null; + } + } + if (firstCount == 0 || lastCount == 0) { + return null; + } + NamePart[] firstNames = new NamePart[firstCount]; + NamePart[] lastNames = new NamePart[lastCount]; + NamePart[] suffixes = new NamePart[suffixCount]; + int fn = 0; + int ln = 0; + int sn = 0; + for (NamePart p : parts) { + if (p.getType() == NamePartType.FIRST_NAME) { + firstNames[fn++] = p; + } else if (p.getType() == NamePartType.SUFFIX) { + suffixes[sn++] = p; + } else if (p.getType() == NamePartType.LAST_NAME) { + lastNames[ln++] = p; + } + } + + return new WesternName(firstNames, lastNames, suffixes); + } + + /** + * Outputs an HTML variant suitable for locations where special UI features + * should indicate the different Name Parts. + */ + @Override + public void output(PrintWriter out, Language l, Map vars) { + out.print(""); + scheme.output(out); + out.print(" "); + } + + /** + * Tests, if this name fits into the given string. + * + * @param text + * the name to test against + * @return true, iff this name matches. + */ public boolean matches(String text) { - return text.equals(fname + " " + lname) || // - (mname != null && text.equals(fname + " " + mname + " " + lname)) || // - (suffix != null && text.equals(fname + " " + lname + " " + suffix)) || // - (mname != null && suffix != null && text.equals(fname + " " + mname + " " + lname + " " + suffix)); + if ( !text.equals(text.trim())) { + return false; + } + return scheme.matches(text); } - public String getFname() { - return fname; + @Override + public String toString() { + return scheme.toPreferredString(); } - public String getLname() { - return lname; + /** + * Transforms this String into a short form. This short form should not be + * unique. (For "western" names this would be + * "firstName firstCharOfLastName.".) + * + * @return the short form of the name + */ + public String toAbbreviatedString() { + return scheme.toAbbreviatedString(); } - public String getMname() { - return mname; + public int getAssurancePoints() { + try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT SUM(`points`) FROM (SELECT DISTINCT ON (`from`) `points` FROM `notary` WHERE `to`=? AND `deleted` IS NULL AND (`expire` IS NULL OR `expire` > CURRENT_TIMESTAMP) ORDER BY `from`, `when` DESC) AS p")) { + query.setInt(1, getId()); + + GigiResultSet rs = query.executeQuery(); + int points = 0; + + if (rs.next()) { + points = rs.getInt(1); + } + + return points; + } } - public String getSuffix() { - return suffix; + @Override + public int getId() { + return id; } + private static ObjectCache cache = new ObjectCache<>(); + + public synchronized static Name getById(int id) { + Name cacheRes = cache.get(id); + if (cacheRes != null) { + return cacheRes; + } + + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT `uid`, `id`, `deprecated` FROM `names` WHERE `deleted` IS NULL AND `id` = ?")) { + ps.setInt(1, id); + GigiResultSet rs = ps.executeQuery(); + if ( !rs.next()) { + return null; + } + + Name c = new Name(rs); + cache.put(c); + return c; + } + } + + public NamePart[] getParts() { + return parts; + } + + public void remove() { + synchronized (Name.class) { + cache.remove(this); + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `names` SET `deleted` = now() WHERE `id`=?")) { + ps.setInt(1, id); + ps.executeUpdate(); + } + } + } + + public synchronized void deprecate() { + deprecated = true; + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `names` SET `deprecated`=now() WHERE `id`=?")) { + ps.setInt(1, id); + ps.executeUpdate(); + } + } + + public boolean isDeprecated() { + return deprecated; + } + + public synchronized User getOwner() { + if (owner == null) { + owner = User.getById(ownerId); + } + return owner; + } } diff --git a/src/org/cacert/gigi/dbObjects/NamePart.java b/src/org/cacert/gigi/dbObjects/NamePart.java new file mode 100644 index 00000000..42464b74 --- /dev/null +++ b/src/org/cacert/gigi/dbObjects/NamePart.java @@ -0,0 +1,81 @@ +package org.cacert.gigi.dbObjects; + +import org.cacert.gigi.database.GigiResultSet; +import org.cacert.gigi.dbObjects.wrappers.DataContainer; + +@DataContainer +public class NamePart { + + public enum NamePartType { + FIRST_NAME, LAST_NAME, SINGLE_NAME, SUFFIX; + + public String getDbValue() { + return name().toLowerCase().replace("_", "-"); + } + } + + private NamePartType type; + + private String value; + + public NamePart(NamePartType type, String value) { + if (type == null || value == null || value.trim().isEmpty() || !value.trim().equals(value)) { + throw new IllegalArgumentException(); + } + this.type = type; + this.value = value; + } + + public NamePart(GigiResultSet rs1) { + value = rs1.getString("value"); + type = NamePartType.valueOf(rs1.getString("type").replace("-", "_").toUpperCase()); + } + + public NamePartType getType() { + return type; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + NamePart other = (NamePart) obj; + if (type != other.type) { + return false; + } + if (value == null) { + if (other.value != null) { + return false; + } + } else if ( !value.equals(other.value)) { + return false; + } + return true; + } + +} diff --git a/src/org/cacert/gigi/dbObjects/SupportedUser.java b/src/org/cacert/gigi/dbObjects/SupportedUser.java index 7affe34c..193a32b0 100644 --- a/src/org/cacert/gigi/dbObjects/SupportedUser.java +++ b/src/org/cacert/gigi/dbObjects/SupportedUser.java @@ -30,21 +30,12 @@ public class SupportedUser { this.ticket = ticket; } - public boolean setName(Name newName) throws GigiApiException { - if (newName.equals(target.getName())) { - return false; - } - writeSELog("SE Name change"); - target.setName(newName); - return true; - } - public boolean setDob(DayDate dob) throws GigiApiException { if (dob.equals(target.getDoB())) { return false; } writeSELog("SE dob change"); - target.setDoB(dob); + target.setDoBAsSupport(dob); return true; } @@ -88,10 +79,6 @@ public class SupportedUser { return target; } - public void submitSupportAction() throws GigiApiException { - target.rawUpdateUserData(); - } - public void grant(Group toMod) { target.grantGroup(supporter, toMod); } @@ -105,7 +92,7 @@ public class SupportedUser { StringWriter sw = new StringWriter(); PrintWriter outMail = new PrintWriter(sw); outMail.print("Hi," + "\n\n"); - SprintfCommand.createSimple("supporter {0} triggered:", supporter.getName().toString()).output(outMail, Language.getInstance(Locale.ENGLISH), new HashMap()); + SprintfCommand.createSimple("supporter {0} triggered:", supporter.getPreferredName().toString()).output(outMail, Language.getInstance(Locale.ENGLISH), new HashMap()); outMail.print("\n\n"); message.output(outMail, Language.getInstance(Locale.ENGLISH), new HashMap()); outMail.print("\n\n"); diff --git a/src/org/cacert/gigi/dbObjects/User.java b/src/org/cacert/gigi/dbObjects/User.java index d3d5da02..91ab46cb 100644 --- a/src/org/cacert/gigi/dbObjects/User.java +++ b/src/org/cacert/gigi/dbObjects/User.java @@ -28,8 +28,6 @@ import org.cacert.gigi.util.PasswordStrengthChecker; */ public class User extends CertificateOwner { - private Name name = new Name(null, null, null, null); - private DayDate dob; private String email; @@ -55,15 +53,17 @@ public class User extends CertificateOwner { */ public static final int VERIFICATION_MONTHS = 39; + private Name preferredName; + protected User(GigiResultSet rs) { super(rs.getInt("id")); updateName(rs); } private void updateName(GigiResultSet rs) { - name = new Name(rs.getString("fname"), rs.getString("lname"), rs.getString("mname"), rs.getString("suffix")); dob = new DayDate(rs.getDate("dob")); email = rs.getString("email"); + preferredName = Name.getById(rs.getInt("preferredName")); String localeStr = rs.getString("language"); if (localeStr == null || localeStr.equals("")) { @@ -83,36 +83,68 @@ public class User extends CertificateOwner { } } - public User(String email, String password, Name name, DayDate dob, Locale locale) throws GigiApiException { + public User(String email, String password, DayDate dob, Locale locale, NamePart... preferred) throws GigiApiException { this.email = email; this.dob = dob; - this.name = name; this.locale = locale; - try (GigiPreparedStatement query = new GigiPreparedStatement("INSERT INTO `users` SET `email`=?, `password`=?, " + "`fname`=?, `mname`=?, `lname`=?, " + "`suffix`=?, `dob`=?, `language`=?, id=?")) { + this.preferredName = new Name(this, preferred); + try (GigiPreparedStatement query = new GigiPreparedStatement("INSERT INTO `users` SET `email`=?, `password`=?, `dob`=?, `language`=?, id=?, `preferredName`=?")) { query.setString(1, email); query.setString(2, PasswordHash.hash(password)); - query.setString(3, name.getFname()); - query.setString(4, name.getMname()); - query.setString(5, name.getLname()); - query.setString(6, name.getSuffix()); - query.setDate(7, dob.toSQLDate()); - query.setString(8, locale.toString()); - query.setInt(9, getId()); + query.setDate(3, dob.toSQLDate()); + query.setString(4, locale.toString()); + query.setInt(5, getId()); + query.setInt(6, preferredName.getId()); query.execute(); } new EmailAddress(this, email, locale); } - public Name getName() { - return name; + public Name[] getNames() { + try (GigiPreparedStatement gps = new GigiPreparedStatement("SELECT `id` FROM `names` WHERE `uid`=? AND `deleted` IS NULL", true)) { + return fetchNamesToArray(gps); + } + } + + public Name[] getNonDeprecatedNames() { + try (GigiPreparedStatement gps = new GigiPreparedStatement("SELECT `id` FROM `names` WHERE `uid`=? AND `deleted` IS NULL AND `deprecated` IS NULL", true)) { + return fetchNamesToArray(gps); + } + } + + private Name[] fetchNamesToArray(GigiPreparedStatement gps) { + gps.setInt(1, getId()); + GigiResultSet rs = gps.executeQuery(); + rs.last(); + Name[] dt = new Name[rs.getRow()]; + rs.beforeFirst(); + for (int i = 0; rs.next(); i++) { + dt[i] = Name.getById(rs.getInt(1)); + } + return dt; } public DayDate getDoB() { return dob; } - public void setDoB(DayDate dob) { - this.dob = dob; + public void setDoB(DayDate dob) throws GigiApiException { + synchronized (Notary.class) { + if (getReceivedAssurances().length != 0) { + throw new GigiApiException("No change after assurance allowed."); + } + this.dob = dob; + rawUpdateUserData(); + } + + } + + protected void setDoBAsSupport(DayDate dob) throws GigiApiException { + synchronized (Notary.class) { + this.dob = dob; + rawUpdateUserData(); + } + } public String getEmail() { @@ -135,7 +167,7 @@ public class User extends CertificateOwner { } private void setPassword(String newPass) throws GigiApiException { - PasswordStrengthChecker.assertStrongPassword(newPass, getName(), getEmail()); + PasswordStrengthChecker.assertStrongPassword(newPass, getNames(), getEmail()); try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE users SET `password`=? WHERE id=?")) { ps.setString(1, PasswordHash.hash(newPass)); ps.setInt(2, getId()); @@ -143,10 +175,6 @@ public class User extends CertificateOwner { } } - public void setName(Name name) { - this.name = name; - } - public boolean canAssure() { if (POJAM_ENABLED) { if ( !CalendarUtil.isOfAge(dob, POJAM_AGE)) { // PoJAM @@ -180,7 +208,7 @@ public class User extends CertificateOwner { } public int getAssurancePoints() { - try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT SUM(lastpoints) FROM ( SELECT DISTINCT ON (`from`) `from`, `to`, `points` as lastpoints, `method` FROM `notary` WHERE `deleted` is NULL AND (`expire` IS NULL OR `expire` > CURRENT_TIMESTAMP) AND `to` = ? ORDER BY `from`, `when` DESC) as p")) { + try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT SUM(lastpoints) FROM ( SELECT DISTINCT ON (`from`) `from`, `points` as lastpoints FROM `notary` INNER JOIN `names` ON `names`.`id`=`to` WHERE `notary`.`deleted` is NULL AND (`expire` IS NULL OR `expire` > CURRENT_TIMESTAMP) AND `names`.`uid` = ? ORDER BY `from`, `when` DESC) as p")) { query.setInt(1, getId()); GigiResultSet rs = query.executeQuery(); @@ -195,7 +223,7 @@ public class User extends CertificateOwner { } public int getExperiencePoints() { - try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT count(*) FROM ( SELECT `to` FROM `notary` WHERE `from`=? AND `deleted` IS NULL AND `method` = ? ::`notaryType` GROUP BY `to`) as p")) { + try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT count(*) FROM ( SELECT `names`.`uid` FROM `notary` INNER JOIN `names` ON `names`.`id` = `to` WHERE `from`=? AND `notary`.`deleted` IS NULL AND `method` = ? ::`notaryType` GROUP BY `names`.`uid`) as p")) { query.setInt(1, getId()); query.setString(2, AssuranceType.FACE_TO_FACE.getDescription()); @@ -244,7 +272,12 @@ public class User extends CertificateOwner { } public boolean isValidName(String name) { - return getName().matches(name); + for (Name n : getNames()) { + if (n.matches(name) && n.getAssurancePoints() >= 50) { + return true; + } + } + return false; } public void updateDefaultEmail(EmailAddress newMail) throws GigiApiException { @@ -287,7 +320,7 @@ public class User extends CertificateOwner { public synchronized Assurance[] getReceivedAssurances() { if (receivedAssurances == null) { - try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `notary` WHERE `to`=? AND `deleted` IS NULL")) { + try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `notary` INNER JOIN `names` ON `names`.`id` = `notary`.`to` WHERE `names`.`uid`=? AND `notary`.`deleted` IS NULL")) { query.setInt(1, getId()); GigiResultSet res = query.executeQuery(); @@ -332,23 +365,10 @@ public class User extends CertificateOwner { receivedAssurances = null; } - public void updateUserData() throws GigiApiException { - synchronized (Notary.class) { - if (getReceivedAssurances().length != 0) { - throw new GigiApiException("No change after assurance allowed."); - } - rawUpdateUserData(); - } - } - - protected void rawUpdateUserData() { - try (GigiPreparedStatement update = new GigiPreparedStatement("UPDATE users SET fname=?, lname=?, mname=?, suffix=?, dob=? WHERE id=?")) { - update.setString(1, name.getFname()); - update.setString(2, name.getLname()); - update.setString(3, name.getMname()); - update.setString(4, name.getSuffix()); - update.setDate(5, getDoB().toSQLDate()); - update.setInt(6, getId()); + private void rawUpdateUserData() { + try (GigiPreparedStatement update = new GigiPreparedStatement("UPDATE users SET dob=? WHERE id=?")) { + update.setDate(1, getDoB().toSQLDate()); + update.setInt(2, getId()); update.executeUpdate(); } } @@ -362,6 +382,23 @@ public class User extends CertificateOwner { } + public Name getPreferredName() { + return preferredName; + } + + public synchronized void setPreferredName(Name preferred) throws GigiApiException { + if (preferred.getOwner() != this) { + throw new GigiApiException("Cannot set a name as preferred one that does not belong to this account."); + } + this.preferredName = preferred; + try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `users` SET `preferredName`=? WHERE `id`=?")) { + ps.setInt(1, preferred.getId()); + ps.setInt(2, getId()); + ps.executeUpdate(); + } + + } + public boolean isInGroup(Group g) { return groups.contains(g); } @@ -539,11 +576,11 @@ public class User extends CertificateOwner { } private Assurance assuranceByRes(GigiResultSet res) { - return new Assurance(res.getInt("id"), User.getById(res.getInt("from")), User.getById(res.getInt("to")), res.getString("location"), res.getString("method"), res.getInt("points"), res.getString("date")); + return new Assurance(res.getInt("id"), User.getById(res.getInt("from")), Name.getById(res.getInt("to")), res.getString("location"), res.getString("method"), res.getInt("points"), res.getString("date")); } public boolean isInVerificationLimit() { - try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT 1 FROM `notary` WHERE `to` = ? AND `when` > (now() - (interval '1 month' * ?)) AND (`expire` IS NULL OR `expire` > now()) AND `deleted` IS NULL;")) { + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT 1 FROM `notary` INNER JOIN `names` ON `names`.`id`=`to` WHERE `names`.`uid` = ? AND `when` > (now() - (interval '1 month' * ?)) AND (`expire` IS NULL OR `expire` > now()) AND `notary`.`deleted` IS NULL;")) { ps.setInt(1, getId()); ps.setInt(2, VERIFICATION_MONTHS); @@ -551,4 +588,5 @@ public class User extends CertificateOwner { return rs.next(); } } + } diff --git a/src/org/cacert/gigi/output/ArrayIterable.java b/src/org/cacert/gigi/output/ArrayIterable.java new file mode 100644 index 00000000..90bad436 --- /dev/null +++ b/src/org/cacert/gigi/output/ArrayIterable.java @@ -0,0 +1,30 @@ +package org.cacert.gigi.output; + +import java.util.Map; + +import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.template.IterableDataset; + +public abstract class ArrayIterable implements IterableDataset { + + private T[] dt; + + protected int i = 0; + + public ArrayIterable(T[] dt) { + this.dt = dt; + } + + @Override + public boolean next(Language l, Map vars) { + if (i >= dt.length) { + return false; + } + apply(dt[i], l, vars); + i++; + return true; + } + + public abstract void apply(T t, Language l, Map vars); + +} diff --git a/src/org/cacert/gigi/output/AssurancesDisplay.java b/src/org/cacert/gigi/output/AssurancesDisplay.java index 9cd7558c..2266c6e8 100644 --- a/src/org/cacert/gigi/output/AssurancesDisplay.java +++ b/src/org/cacert/gigi/output/AssurancesDisplay.java @@ -29,6 +29,7 @@ public class AssurancesDisplay implements Outputable { vars.put("verb", l.getTranslation("To")); } else { vars.put("verb", l.getTranslation("From")); + vars.put("myName", "yes"); } IterableDataset assuranceGroup = new IterableDataset() { @@ -44,9 +45,11 @@ public class AssurancesDisplay implements Outputable { vars.put("id", assurance.getId()); vars.put("method", assurance.getMethod()); if (assurer) { - vars.put("verbVal", assurance.getTo().getName()); + vars.put("verbVal", assurance.getTo().getOwner().getPreferredName()); + vars.put("myName", assurance.getTo()); } else { - vars.put("verbVal", assurance.getFrom().getName()); + vars.put("verbVal", assurance.getFrom().getPreferredName()); + vars.put("myName", assurance.getTo()); } vars.put("date", assurance.getDate()); vars.put("location", assurance.getLocation()); diff --git a/src/org/cacert/gigi/output/AssurancesDisplay.templ b/src/org/cacert/gigi/output/AssurancesDisplay.templ index 4a91eefa..ab851632 100644 --- a/src/org/cacert/gigi/output/AssurancesDisplay.templ +++ b/src/org/cacert/gigi/output/AssurancesDisplay.templ @@ -6,6 +6,7 @@ + @@ -15,6 +16,9 @@ + + + diff --git a/src/org/cacert/gigi/output/NameInput.java b/src/org/cacert/gigi/output/NameInput.java new file mode 100644 index 00000000..5eeba5e9 --- /dev/null +++ b/src/org/cacert/gigi/output/NameInput.java @@ -0,0 +1,109 @@ +package org.cacert.gigi.output; + +import java.io.PrintWriter; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; +import org.cacert.gigi.dbObjects.User; +import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.template.Outputable; +import org.cacert.gigi.output.template.Template; + +public class NameInput implements Outputable { + + private static final Template t = new Template(NameInput.class.getResource("NameInput.templ")); + + private String fname = ""; + + private String lname = ""; + + private String suffix = ""; + + private String name = ""; + + public NameInput() {} + + public void update(HttpServletRequest req) throws GigiApiException { + fname = req.getParameter("fname"); + lname = req.getParameter("lname"); + suffix = req.getParameter("suffix"); + name = req.getParameter("name"); + if (fname == null) { + fname = ""; + } + if (lname == null) { + lname = ""; + } + if (suffix == null) { + suffix = ""; + } + if (name == null) { + name = ""; + } + if (name != null && name.contains(" ")) { + throw new GigiApiException("Single names may only have one part."); + } + + } + + @Override + public void output(PrintWriter out, Language l, Map vars) { + vars.put("fname", fname); + vars.put("lname", lname); + vars.put("suffix", suffix); + vars.put("name", name); + t.output(out, l, vars); + } + + public void createName(User u) throws GigiApiException { + new Name(u, getNameParts()); + } + + public NamePart[] getNameParts() throws GigiApiException { + if (name != null && !name.isEmpty()) { + return new NamePart[] { + new NamePart(NamePartType.SINGLE_NAME, name) + }; + } + String[] fparts = split(fname); + String[] lparts = split(lname); + String[] suff = split(suffix); + if (fparts.length == 0 || fparts[0].equals("") || lparts.length == 0 || lparts[0].equals("")) { + throw new GigiApiException("requires at least one first and one last name"); + } + NamePart[] np = new NamePart[fparts.length + lparts.length + suff.length]; + int p = 0; + for (int i = 0; i < fparts.length; i++) { + np[p++] = new NamePart(NamePartType.FIRST_NAME, fparts[i]); + } + for (int i = 0; i < lparts.length; i++) { + np[p++] = new NamePart(NamePartType.LAST_NAME, lparts[i]); + } + for (int i = 0; i < suff.length; i++) { + np[p++] = new NamePart(NamePartType.SUFFIX, suff[i]); + } + + return np; + } + + private String[] split(String toSplit) { + if (toSplit == null || toSplit.trim().isEmpty()) { + return new String[0]; + } + return toSplit.split(" "); + } + + public String[] getNamePartsPlain() throws GigiApiException { + NamePart[] p = getNameParts(); + String[] s = new String[p.length]; + for (int i = 0; i < s.length; i++) { + s[i] = p[i].getValue(); + } + return s; + } +} diff --git a/src/org/cacert/gigi/output/NameInput.templ b/src/org/cacert/gigi/output/NameInput.templ new file mode 100644 index 00000000..2cb11fc7 --- /dev/null +++ b/src/org/cacert/gigi/output/NameInput.templ @@ -0,0 +1,24 @@ +

+

+ +

+
    +
  • +
  • +
  • +
+
+ + + +
+

+

+ +

+
    +
  • +
+
+ +
\ No newline at end of file diff --git a/src/org/cacert/gigi/pages/account/MyDetails.java b/src/org/cacert/gigi/pages/account/MyDetails.java index 4b0aa992..bf80d47b 100644 --- a/src/org/cacert/gigi/pages/account/MyDetails.java +++ b/src/org/cacert/gigi/pages/account/MyDetails.java @@ -44,8 +44,10 @@ public class MyDetails extends Page { @Override public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (req.getParameter("processDetails") != null) { - Form.getForm(req, MyDetailsForm.class).submit(resp.getWriter(), req); + if (req.getParameter("action") != null || req.getParameter("removeName") != null || req.getParameter("deprecateName") != null || req.getParameter("preferred") != null) { + if (Form.getForm(req, MyDetailsForm.class).submit(resp.getWriter(), req)) { + resp.sendRedirect(PATH); + } } super.doPost(req, resp); } diff --git a/src/org/cacert/gigi/pages/account/MyDetailsForm.java b/src/org/cacert/gigi/pages/account/MyDetailsForm.java index d35ba45e..2d1f7ff3 100644 --- a/src/org/cacert/gigi/pages/account/MyDetailsForm.java +++ b/src/org/cacert/gigi/pages/account/MyDetailsForm.java @@ -9,11 +9,12 @@ import org.cacert.gigi.GigiApiException; import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.ArrayIterable; import org.cacert.gigi.output.DateSelector; +import org.cacert.gigi.output.NameInput; import org.cacert.gigi.output.template.Form; import org.cacert.gigi.output.template.Template; import org.cacert.gigi.pages.Page; -import org.cacert.gigi.util.HTMLEncoder; public class MyDetailsForm extends Form { @@ -21,36 +22,65 @@ public class MyDetailsForm extends Form { private static final Template templ = new Template(MyDetailsForm.class.getResource("MyDetailsForm.templ")); + private static final Template names = new Template(MyDetailsForm.class.getResource("NamesForm.templ")); + private User target; private DateSelector ds; + private NameInput ni; + public MyDetailsForm(HttpServletRequest hsr, User target) { super(hsr); this.target = target; + ni = new NameInput(); + this.ds = new DateSelector("day", "month", "year", target.getDoB()); } @Override public boolean submit(PrintWriter out, HttpServletRequest req) { try { - synchronized (target) { - if (target.getAssurancePoints() == 0) { - String newFname = req.getParameter("fname").trim(); - String newLname = req.getParameter("lname").trim(); - String newMname = req.getParameter("mname").trim(); - String newSuffix = req.getParameter("suffix").trim(); - if (newLname.isEmpty()) { - throw new GigiApiException("Last name cannot be empty."); - } - - target.setName(new Name(newFname, newLname, newMname, newSuffix)); - ds.update(req); - target.setDoB(ds.getDate()); - target.updateUserData(); - } else { - throw new GigiApiException("No change after assurance allowed."); + String rn = req.getParameter("removeName"); + if (rn != null) { + Name n = Name.getById(Integer.parseInt(rn)); + if (n.getOwner() != target) { + throw new GigiApiException("Cannot remove a name that does not belong to this account."); } + if (n.equals(target.getPreferredName())) { + throw new GigiApiException("Cannot remove the account's preferred name."); + } + n.remove(); + return true; + } + String dn = req.getParameter("deprecateName"); + if (dn != null) { + Name n = Name.getById(Integer.parseInt(dn)); + if (n.getOwner() != target) { + throw new GigiApiException("Cannot deprecate a name that does not belong to this account."); + } + if (n.equals(target.getPreferredName())) { + throw new GigiApiException("Cannot deprecate the account's preferred name."); + } + n.deprecate(); + return true; + } + String pn = req.getParameter("preferred"); + if (pn != null) { + Name n = Name.getById(Integer.parseInt(pn)); + target.setPreferredName(n); + return true; + } + + String action = req.getParameter("action"); + if ("addName".equals(action)) { + ni.update(req); + ni.createName(target); + return true; + } + if ("updateDoB".equals(action)) { + ds.update(req); + target.setDoB(ds.getDate()); } } catch (GigiApiException e) { e.format(out, Page.getLanguage(req)); @@ -64,12 +94,31 @@ public class MyDetailsForm extends Form { @Override protected void outputContent(PrintWriter out, Language l, Map vars) { - Name name = target.getName(); - vars.put("fname", HTMLEncoder.encodeHTML(name.getFname())); - vars.put("mname", name.getMname() == null ? "" : HTMLEncoder.encodeHTML(name.getMname())); - vars.put("lname", HTMLEncoder.encodeHTML(name.getLname())); - vars.put("suffix", name.getSuffix() == null ? "" : HTMLEncoder.encodeHTML(name.getSuffix())); - vars.put("details", ""); + vars.put("exNames", new ArrayIterable(target.getNames()) { + + Name preferred = target.getPreferredName(); + + @Override + public void apply(Name t, Language l, Map vars) { + if (t.equals(preferred)) { + vars.put("preferred", " disabled"); + vars.put("deprecated", " disabled"); + } else { + if (t.isDeprecated()) { + vars.put("deprecated", " disabled"); + } else { + vars.put("deprecated", ""); + } + vars.put("preferred", ""); + } + vars.put("name", t); + vars.put("id", t.getId()); + vars.put("npoints", Integer.toString(t.getAssurancePoints())); + } + + }); + vars.put("name", ni); + names.output(out, l, vars); if (target.getAssurancePoints() == 0) { vars.put("DoB", ds); templ.output(out, l, vars); diff --git a/src/org/cacert/gigi/pages/account/MyDetailsForm.templ b/src/org/cacert/gigi/pages/account/MyDetailsForm.templ index d4d3c7e0..f9ea0c72 100644 --- a/src/org/cacert/gigi/pages/account/MyDetailsForm.templ +++ b/src/org/cacert/gigi/pages/account/MyDetailsForm.templ @@ -1,42 +1,13 @@ - - - - - - - - - - - - - - - - - - - - - + - - - - - - - +
:

- () -
:

- ()

()
diff --git a/src/org/cacert/gigi/pages/account/MyDetailsFormAssured.templ b/src/org/cacert/gigi/pages/account/MyDetailsFormAssured.templ index 8cfb7705..8dde8c3c 100644 --- a/src/org/cacert/gigi/pages/account/MyDetailsFormAssured.templ +++ b/src/org/cacert/gigi/pages/account/MyDetailsFormAssured.templ @@ -1,29 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - @@ -32,9 +8,5 @@ - - - -
:

- () -
:

- ()

()
diff --git a/src/org/cacert/gigi/pages/account/NamesForm.templ b/src/org/cacert/gigi/pages/account/NamesForm.templ new file mode 100644 index 00000000..1ca468de --- /dev/null +++ b/src/org/cacert/gigi/pages/account/NamesForm.templ @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + +
:
: +
diff --git a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java index 2baf95e8..12b6323d 100644 --- a/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java +++ b/src/org/cacert/gigi/pages/account/certs/CertificateRequest.java @@ -497,7 +497,7 @@ public class CertificateRequest { if (nullIsOK) { name = ""; } else if (realIsOK) { - name = u.getName().toString(); + name = u.getPreferredName().toString(); } } } else if (name == null || name.equals("")) { @@ -508,7 +508,7 @@ public class CertificateRequest { if (defaultIsOK) { name = DEFAULT_CN; } else if (realIsOK) { - name = u.getName().toString(); + name = u.getPreferredName().toString(); } } } else { diff --git a/src/org/cacert/gigi/pages/admin/TTPAdminForm.java b/src/org/cacert/gigi/pages/admin/TTPAdminForm.java index 2c8b5719..ce6eecb3 100644 --- a/src/org/cacert/gigi/pages/admin/TTPAdminForm.java +++ b/src/org/cacert/gigi/pages/admin/TTPAdminForm.java @@ -36,7 +36,7 @@ public class TTPAdminForm extends Form { @Override protected void outputContent(PrintWriter out, Language l, Map vars) { - vars.put("name", u.getName()); + vars.put("name", u.getPreferredName()); vars.put("email", u.getEmail()); vars.put("DoB", u.getDoB()); vars.put("uid", Integer.toString(u.getId())); diff --git a/src/org/cacert/gigi/pages/admin/TTPAdminPage.java b/src/org/cacert/gigi/pages/admin/TTPAdminPage.java index a6bd0d47..2ffd12e2 100644 --- a/src/org/cacert/gigi/pages/admin/TTPAdminPage.java +++ b/src/org/cacert/gigi/pages/admin/TTPAdminPage.java @@ -74,7 +74,7 @@ public class TTPAdminPage extends Page { return false; } vars.put("id", Integer.toString(users[i].getId())); - vars.put("name", users[i].getName().toString()); + vars.put("name", users[i].getPreferredName().toString()); vars.put("email", users[i].getEmail()); i++; diff --git a/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.java b/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.java index 75173e06..16ece067 100644 --- a/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.java +++ b/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.java @@ -13,6 +13,7 @@ import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.SupportedUser; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.ArrayIterable; import org.cacert.gigi.output.DateSelector; import org.cacert.gigi.output.GroupSelector; import org.cacert.gigi.output.template.Form; @@ -76,22 +77,11 @@ public class SupportUserDetailsForm extends Form { return true; } dobSelector.update(req); - String fname = req.getParameter("fname"); - String mname = req.getParameter("mname"); - String lname = req.getParameter("lname"); - String suffix = req.getParameter("suffix"); - if (fname == null || mname == null || lname == null | suffix == null) { - throw new GigiApiException("Incomplete request!"); - } if ( !dobSelector.isValid()) { throw new GigiApiException("Invalid date of birth!"); } - Name newName = new Name(fname, lname, mname, suffix); - synchronized (user.getTargetUser()) { - if (user.setDob(dobSelector.getDate()) | user.setName(newName)) { - user.submitSupportAction(); - } - } + user.setDob(dobSelector.getDate()); + String subject = "Change Account Data"; Outputable message = new TranslateCommand("The account data was changed."); user.sendSupportNotification(subject, message); @@ -101,12 +91,16 @@ public class SupportUserDetailsForm extends Form { @Override protected void outputContent(PrintWriter out, Language l, Map vars) { User user = this.user.getTargetUser(); - Name name = user.getName(); vars.put("mail", user.getEmail()); - vars.put("fname", name.getFname()); - vars.put("mname", name.getMname()); - vars.put("lname", name.getLname()); - vars.put("suffix", name.getSuffix()); + vars.put("exNames", new ArrayIterable(user.getNames()) { + + @Override + public void apply(Name t, Language l, Map vars) { + vars.put("name", t); + vars.put("points", Integer.toString(t.getAssurancePoints())); + } + + }); vars.put("assurer", user.canAssure()); vars.put("dob", dobSelector); vars.put("assurancepoints", user.getAssurancePoints()); diff --git a/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.templ b/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.templ index c4f52d0e..06dbd042 100644 --- a/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.templ +++ b/src/org/cacert/gigi/pages/admin/support/SupportUserDetailsForm.templ @@ -6,26 +6,12 @@ : + - : - - - - - - : - - - - : - - - - - - : - + : + () + : diff --git a/src/org/cacert/gigi/pages/main/Signup.java b/src/org/cacert/gigi/pages/main/Signup.java index 0fc04d8e..7cc389e7 100644 --- a/src/org/cacert/gigi/pages/main/Signup.java +++ b/src/org/cacert/gigi/pages/main/Signup.java @@ -10,11 +10,11 @@ import javax.servlet.http.HttpServletRequest; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; -import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.email.EmailProvider; import org.cacert.gigi.localisation.Language; import org.cacert.gigi.output.DateSelector; +import org.cacert.gigi.output.NameInput; import org.cacert.gigi.output.template.Form; import org.cacert.gigi.output.template.PlainOutputable; import org.cacert.gigi.output.template.SprintfCommand; @@ -28,28 +28,25 @@ import org.cacert.gigi.util.RateLimit.RateLimitException; public class Signup extends Form { - Name buildupName = new Name("", "", "", ""); + private NameInput ni; - String email = ""; + private String email = ""; private static final Template t = new Template(Signup.class.getResource("Signup.templ")); - boolean general = true, country = true, regional = true, radius = true; + private boolean general = true, country = true, regional = true, radius = true; public Signup(HttpServletRequest hsr) { super(hsr); - + ni = new NameInput(); } - DateSelector myDoB = new DateSelector("day", "month", "year"); + private DateSelector myDoB = new DateSelector("day", "month", "year"); @Override public void outputContent(PrintWriter out, Language l, Map outerVars) { HashMap vars = new HashMap(); - vars.put("fname", HTMLEncoder.encodeHTML(buildupName.getFname())); - vars.put("mname", HTMLEncoder.encodeHTML(buildupName.getMname())); - vars.put("lname", HTMLEncoder.encodeHTML(buildupName.getLname())); - vars.put("suffix", HTMLEncoder.encodeHTML(buildupName.getSuffix())); + vars.put("name", ni); vars.put("dob", myDoB); vars.put("email", HTMLEncoder.encodeHTML(email)); vars.put("general", general ? " checked=\"checked\"" : ""); @@ -62,27 +59,11 @@ public class Signup extends Form { t.output(out, l, vars); } - private void update(HttpServletRequest r) { - String fname = buildupName.getFname(); - String lname = buildupName.getLname(); - String mname = buildupName.getMname(); - String suffix = buildupName.getSuffix(); - if (r.getParameter("fname") != null) { - fname = r.getParameter("fname"); - } - if (r.getParameter("lname") != null) { - lname = r.getParameter("lname"); - } - if (r.getParameter("mname") != null) { - mname = r.getParameter("mname"); - } - if (r.getParameter("suffix") != null) { - suffix = r.getParameter("suffix"); - } + private void update(HttpServletRequest r) throws GigiApiException { + ni.update(r); if (r.getParameter("email") != null) { email = r.getParameter("email"); } - buildupName = new Name(fname, lname, mname, suffix); general = "1".equals(r.getParameter("general")); country = "1".equals(r.getParameter("country")); regional = "1".equals(r.getParameter("regional")); @@ -101,9 +82,12 @@ public class Signup extends Form { update(req); GigiApiException ga = new GigiApiException(); - if (buildupName.getLname().trim().equals("")) { - ga.mergeInto(new GigiApiException("Last name were blank.")); + try { + ni.getNameParts(); + } catch (GigiApiException e) { + ga.mergeInto(e); } + if ( !myDoB.isValid()) { ga.mergeInto(new GigiApiException("Invalid date of birth")); } @@ -125,7 +109,7 @@ public class Signup extends Form { } else if ( !pw1.equals(pw2)) { ga.mergeInto(new GigiApiException("Pass Phrases don't match")); } - int pwpoints = PasswordStrengthChecker.checkpw(pw1, buildupName, email); + int pwpoints = PasswordStrengthChecker.checkpw(pw1, ni.getNamePartsPlain(), email); if (pwpoints < 3) { ga.mergeInto(new GigiApiException("The Pass Phrase you submitted failed to contain enough" + " differing characters and/or contained words from" + " your name and/or email address.")); } @@ -177,7 +161,7 @@ public class Signup extends Form { } private void run(HttpServletRequest req, String password) throws GigiApiException { - User u = new User(email, password, buildupName, myDoB.getDate(), Page.getLanguage(req).getLocale()); + User u = new User(email, password, myDoB.getDate(), Page.getLanguage(req).getLocale(), ni.getNameParts()); try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `alerts` SET `memid`=?," + " `general`=?, `country`=?, `regional`=?, `radius`=?")) { ps.setInt(1, u.getId()); diff --git a/src/org/cacert/gigi/pages/main/Signup.templ b/src/org/cacert/gigi/pages/main/Signup.templ index 59e22cd4..c47bf8f1 100644 --- a/src/org/cacert/gigi/pages/main/Signup.templ +++ b/src/org/cacert/gigi/pages/main/Signup.templ @@ -6,29 +6,10 @@ - : - + : + - - -
- () - - - - - - : - - - - -
- () -
- -
() diff --git a/src/org/cacert/gigi/pages/orga/AffiliationForm.java b/src/org/cacert/gigi/pages/orga/AffiliationForm.java index f6a2da7d..6ffc8822 100644 --- a/src/org/cacert/gigi/pages/orga/AffiliationForm.java +++ b/src/org/cacert/gigi/pages/orga/AffiliationForm.java @@ -63,7 +63,7 @@ public class AffiliationForm extends Form { return false; } Affiliation aff = iter.next(); - vars.put("name", aff.getTarget().getName()); + vars.put("name", aff.getTarget().getPreferredName()); vars.put("master", aff.isMaster() ? l.getTranslation("master") : ""); vars.put("e-mail", aff.getTarget().getEmail()); return true; diff --git a/src/org/cacert/gigi/pages/wot/AssuranceForm.java b/src/org/cacert/gigi/pages/wot/AssuranceForm.java index 07a0fdc2..7d15e8da 100644 --- a/src/org/cacert/gigi/pages/wot/AssuranceForm.java +++ b/src/org/cacert/gigi/pages/wot/AssuranceForm.java @@ -2,7 +2,9 @@ package org.cacert.gigi.pages.wot; import java.io.PrintWriter; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; @@ -14,8 +16,10 @@ import org.cacert.gigi.dbObjects.Assurance.AssuranceType; import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.ArrayIterable; import org.cacert.gigi.output.template.Form; import org.cacert.gigi.output.template.IterableDataset; +import org.cacert.gigi.output.template.SprintfCommand; import org.cacert.gigi.output.template.Template; import org.cacert.gigi.pages.Page; import org.cacert.gigi.pages.PasswordResetPage; @@ -26,7 +30,9 @@ public class AssuranceForm extends Form { private User assuree; - private Name assureeName; + private Name[] assureeNames; + + private boolean[] selected; private DayDate dob; @@ -42,12 +48,31 @@ public class AssuranceForm extends Form { private static final Template templ = new Template(AssuranceForm.class.getResource("AssuranceForm.templ")); - public AssuranceForm(HttpServletRequest hsr, User assuree) { + public AssuranceForm(HttpServletRequest hsr, User assuree) throws GigiApiException { super(hsr); assurer = Page.getUser(hsr); this.assuree = assuree; - assureeName = this.assuree.getName(); + + if (assurer.getId() == assuree.getId()) { + throw new GigiApiException("You cannot verify yourself."); + } + if ( !assurer.canAssure()) { + throw new GigiApiException("You are not a RA-Agent."); + } + + Name[] initialNames = this.assuree.getNonDeprecatedNames(); + LinkedList names = new LinkedList<>(); + for (Name name : initialNames) { + if (Notary.checkAssuranceIsPossible(assurer, name)) { + names.add(name); + } + } + if (names.size() == 0) { + throw new GigiApiException(SprintfCommand.createSimple("You have already verified all names of this applicant within the last {0} days.", Notary.LIMIT_DAYS_VERIFICATION)); + } + assureeNames = names.toArray(new Name[names.size()]); dob = this.assuree.getDoB(); + selected = new boolean[assureeNames.length]; } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); @@ -58,8 +83,17 @@ public class AssuranceForm extends Form { public void outputContent(PrintWriter out, Language l, Map vars) { HashMap res = new HashMap(); res.putAll(vars); - res.put("nameExplicit", assuree.getName()); - res.put("name", assuree.getName().toString()); + res.put("names", new ArrayIterable(assureeNames) { + + @Override + public void apply(Name t, Language l, Map vars) { + vars.put("nameExplicit", t); + vars.put("nameId", t.getId()); + vars.put("checked", selected[i] ? " checked" : ""); + } + + }); + res.put("name", assuree.getPreferredName().toString()); res.put("maxpoints", assurer.getMaxAssurePoints()); res.put("dob", sdf.format(assuree.getDoB().toDate())); res.put("dobFmt2", sdf2.format(assuree.getDoB().toDate())); @@ -133,11 +167,19 @@ public class AssuranceForm extends Form { gae.mergeInto(new GigiApiException("The points entered were not a number.")); } } + HashSet data = new HashSet<>(Arrays.asList(req.getParameterValues("assuredName"))); + for (int i = 0; i < assureeNames.length; i++) { + selected[i] = data.contains(Integer.toString(assureeNames[i].getId())); + } if ( !gae.isEmpty()) { throw gae; } - Notary.assure(assurer, assuree, assureeName, dob, pointsI, location, req.getParameter("date"), type); + for (int i = 0; i < selected.length; i++) { + if (selected[i]) { + Notary.assure(assurer, assuree, assureeNames[i], dob, pointsI, location, req.getParameter("date"), type); + } + } if (aword != null && !aword.equals("")) { Language l = Language.getInstance(assuree.getPreferredLocale()); String method = l.getTranslation("A password reset was triggered. If you did a password reset by assurance, please enter your secret password using this form:"); diff --git a/src/org/cacert/gigi/pages/wot/AssuranceForm.templ b/src/org/cacert/gigi/pages/wot/AssuranceForm.templ index 5bebe9b7..004710aa 100644 --- a/src/org/cacert/gigi/pages/wot/AssuranceForm.templ +++ b/src/org/cacert/gigi/pages/wot/AssuranceForm.templ @@ -5,11 +5,12 @@ - + : - + > + : () diff --git a/src/org/cacert/gigi/pages/wot/AssurePage.java b/src/org/cacert/gigi/pages/wot/AssurePage.java index 5255cf32..8d4a3aac 100644 --- a/src/org/cacert/gigi/pages/wot/AssurePage.java +++ b/src/org/cacert/gigi/pages/wot/AssurePage.java @@ -14,10 +14,8 @@ import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.output.DateSelector; import org.cacert.gigi.output.template.Form; import org.cacert.gigi.output.template.Template; -import org.cacert.gigi.pages.LoginPage; import org.cacert.gigi.pages.Page; import org.cacert.gigi.util.AuthorizationContext; -import org.cacert.gigi.util.Notary; public class AssurePage extends Page { @@ -58,12 +56,7 @@ public class AssurePage extends Page { } } catch (GigiApiException e) { e.format(out, Page.getLanguage(req)); - try { - Notary.checkAssuranceIsPossible(LoginPage.getUser(req), form.getAssuree()); - form.output(out, getLanguage(req), new HashMap()); - } catch (GigiApiException e1) { - e1.format(out, Page.getLanguage(req)); - } + form.output(out, getLanguage(req), new HashMap()); } return; @@ -88,9 +81,7 @@ public class AssurePage extends Page { } else { User assuree = User.getById(id); - User myself = LoginPage.getUser(req); try { - Notary.checkAssuranceIsPossible(myself, assuree); new AssuranceForm(req, assuree).output(out, getLanguage(req), new HashMap()); } catch (GigiApiException e) { e.format(out, Page.getLanguage(req)); diff --git a/src/org/cacert/gigi/pages/wot/MyPoints.templ b/src/org/cacert/gigi/pages/wot/MyPoints.templ index a0c65480..7fdd5c8f 100644 --- a/src/org/cacert/gigi/pages/wot/MyPoints.templ +++ b/src/org/cacert/gigi/pages/wot/MyPoints.templ @@ -1,3 +1,4 @@ +

@@ -6,5 +7,4 @@ :
:
- diff --git a/src/org/cacert/gigi/util/AuthorizationContext.java b/src/org/cacert/gigi/util/AuthorizationContext.java index dfd591e4..8098eeed 100644 --- a/src/org/cacert/gigi/util/AuthorizationContext.java +++ b/src/org/cacert/gigi/util/AuthorizationContext.java @@ -75,10 +75,10 @@ public class AuthorizationContext implements Outputable { public void output(PrintWriter out, Language l, Map vars) { if (target != actor) { vars.put("user", ((Organisation) target).getName().toString()); - vars.put("target", actor.getName().toString()); + vars.put("target", actor.getPreferredName().toString()); inner.output(out, l, vars); } else { - out.println(actor.getName().toString()); + out.println(actor.getPreferredName().toString()); } } }); diff --git a/src/org/cacert/gigi/util/Notary.java b/src/org/cacert/gigi/util/Notary.java index e6288988..0ecc14e4 100644 --- a/src/org/cacert/gigi/util/Notary.java +++ b/src/org/cacert/gigi/util/Notary.java @@ -31,23 +31,14 @@ public class Notary { } } - public static void checkAssuranceIsPossible(User assurer, User target) throws GigiApiException { - if (assurer.getId() == target.getId()) { - throw new GigiApiException("You cannot assure yourself."); - } + public static boolean checkAssuranceIsPossible(User assurer, Name target) { try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT 1 FROM `notary` where `to`=? and `from`=? and `method` = ? ::`notaryType` AND `deleted` IS NULL AND `when` > (now() - interval '1 days' * ?)")) { ps.setInt(1, target.getId()); ps.setInt(2, assurer.getId()); ps.setString(3, AssuranceType.FACE_TO_FACE.getDescription()); ps.setInt(4, LIMIT_DAYS_VERIFICATION); GigiResultSet rs = ps.executeQuery(); - if (rs.next()) { - rs.close(); - throw new GigiApiException(SprintfCommand.createSimple("You have already verified this applicant within the last {0} days.", LIMIT_DAYS_VERIFICATION)); - } - } - if ( !assurer.canAssure()) { - throw new GigiApiException("You are not an assurer."); + return !rs.next(); } } @@ -105,16 +96,24 @@ public class Notary { gae.mergeInto(new GigiApiException("You must enter a location with at least 3 characters eg town and country.")); } synchronized (assuree) { + if (assurer.getId() == assuree.getId()) { + throw new GigiApiException("You cannot verify yourself."); + } + if (assureeName.getOwner() != assuree) { + throw new GigiApiException("Internal error, name does not belong to applicant."); + } + if ( !assurer.canAssure()) { + throw new GigiApiException("You are not an RA-Agent."); + } - try { - checkAssuranceIsPossible(assurer, assuree); - } catch (GigiApiException e) { - gae.mergeInto(e); + if ( !checkAssuranceIsPossible(assurer, assureeName)) { + gae.mergeInto(new GigiApiException(SprintfCommand.createSimple("You have already verified this applicant within the last {0} days.", LIMIT_DAYS_VERIFICATION))); } - if ( !assuree.getName().equals(assureeName) || !assuree.getDoB().equals(dob)) { + if ( !assuree.getDoB().equals(dob)) { gae.mergeInto(new GigiApiException("The person you are assuring changed his personal details.")); } + if (awarded < 0) { gae.mergeInto(new GigiApiException("The points you are trying to award are out of range.")); } else { @@ -134,11 +133,11 @@ public class Notary { } if (type == AssuranceType.FACE_TO_FACE) { - assureF2F(assurer, assuree, awarded, location, date); + assureF2F(assurer, assuree, assureeName, awarded, location, date); } else if (type == AssuranceType.NUCLEUS) { - assureNucleus(assurer, assuree, awarded, location, date); + assureNucleus(assurer, assuree, assureeName, awarded, location, date); } else if (type == AssuranceType.TTP_ASSISTED) { - assureTTP(assurer, assuree, awarded, location, date); + assureTTP(assurer, assuree, assureeName, awarded, location, date); } else { throw new GigiApiException(SprintfCommand.createSimple("Unknown Assurance type: {0}", type.toString())); } @@ -147,11 +146,11 @@ public class Notary { } } - private static void assureF2F(User assurer, User assuree, int awarded, String location, String date) throws GigiApiException { + private static void assureF2F(User assurer, User assuree, Name name, int awarded, String location, String date) throws GigiApiException { may(assurer, assuree, AssuranceType.FACE_TO_FACE); try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?")) { ps.setInt(1, assurer.getId()); - ps.setInt(2, assuree.getId()); + ps.setInt(2, name.getId()); ps.setInt(3, awarded); ps.setString(4, location); ps.setString(5, date); @@ -159,11 +158,11 @@ public class Notary { } } - private static void assureTTP(User assurer, User assuree, int awarded, String location, String date) throws GigiApiException { + private static void assureTTP(User assurer, User assuree, Name name, int awarded, String location, String date) throws GigiApiException { may(assurer, assuree, AssuranceType.TTP_ASSISTED); try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?, `method`='TTP-Assisted'")) { ps.setInt(1, assurer.getId()); - ps.setInt(2, assuree.getId()); + ps.setInt(2, name.getId()); ps.setInt(3, awarded); ps.setString(4, location); ps.setString(5, date); @@ -199,11 +198,11 @@ public class Notary { throw new GigiApiException("Verification type not possible."); } - private static void assureNucleus(User assurer, User assuree, int awarded, String location, String date) throws GigiApiException { + private static void assureNucleus(User assurer, User assuree, Name name, int awarded, String location, String date) throws GigiApiException { may(assurer, assuree, AssuranceType.NUCLEUS); // Do up to 35 points as f2f int f2fPoints = Math.min(assurer.getMaxAssurePoints(), awarded); - assureF2F(assurer, assuree, f2fPoints, location, date); + assureF2F(assurer, assuree, name, f2fPoints, location, date); awarded -= f2fPoints; if (awarded <= 0) { @@ -214,7 +213,7 @@ public class Notary { // Valid for 4 Weeks = 28 days try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?, `method`='Nucleus Bonus', `expire` = CURRENT_TIMESTAMP + interval '28 days'")) { ps.setInt(1, assurer.getId()); - ps.setInt(2, assuree.getId()); + ps.setInt(2, name.getId()); ps.setInt(3, awarded); ps.setString(4, location); ps.setString(5, date); diff --git a/src/org/cacert/gigi/util/PasswordStrengthChecker.java b/src/org/cacert/gigi/util/PasswordStrengthChecker.java index a1d21450..c957665e 100644 --- a/src/org/cacert/gigi/util/PasswordStrengthChecker.java +++ b/src/org/cacert/gigi/util/PasswordStrengthChecker.java @@ -1,9 +1,11 @@ package org.cacert.gigi.util; +import java.util.TreeSet; import java.util.regex.Pattern; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; public class PasswordStrengthChecker { @@ -51,7 +53,7 @@ public class PasswordStrengthChecker { return points; } - public static int checkpw(String pw, Name name, String email) { + public static int checkpw(String pw, String[] nameParts, String email) { if (pw == null) { return 0; } @@ -59,24 +61,23 @@ public class PasswordStrengthChecker { if (contained(pw, email)) { light -= 2; } - if (contained(pw, name.getFname())) { - light -= 2; - } - if (contained(pw, name.getLname())) { - light -= 2; - } - if (contained(pw, name.getMname())) { - light -= 2; - } - if (contained(pw, name.getSuffix())) { - light -= 2; + for (int i = 0; i < nameParts.length; i++) { + if (contained(pw, nameParts[i])) { + light -= 2; + } } // TODO dictionary check return light; } - public static void assertStrongPassword(String pw, Name name, String email) throws GigiApiException { - if (checkpw(pw, name, email) < 3) { + public static void assertStrongPassword(String pw, Name[] names, String email) throws GigiApiException { + TreeSet parts = new TreeSet<>(); + for (int i = 0; i < names.length; i++) { + for (NamePart string : names[i].getParts()) { + parts.add(string.getValue()); + } + } + if (checkpw(pw, parts.toArray(new String[parts.size()]), email) < 3) { throw new GigiApiException("The Pass Phrase you submitted failed to contain enough" + " differing characters and/or contained words from" + " your name and/or email address."); } } @@ -93,4 +94,5 @@ public class PasswordStrengthChecker { } return false; } + } diff --git a/tests/org/cacert/gigi/TestName.java b/tests/org/cacert/gigi/TestName.java index b4311660..ba901a8a 100644 --- a/tests/org/cacert/gigi/TestName.java +++ b/tests/org/cacert/gigi/TestName.java @@ -3,42 +3,165 @@ package org.cacert.gigi; import static org.junit.Assert.*; import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; +import org.cacert.gigi.testUtils.ClientBusinessTest; import org.junit.Before; import org.junit.Test; -public class TestName { - - Name n = new Name("fn", "ln", "mn", "sf"); +public class TestName extends ClientBusinessTest { @Before public void setUp() throws Exception {} @Test - public void testHashCode() { - assertEquals(new Name("fname", "lname", null, null).hashCode(), new Name("fname", "lname", null, null).hashCode()); - assertNotEquals(new Name("fname", "lname", null, null).hashCode(), new Name("fname", "lname", null, "b").hashCode()); - assertNotEquals(new Name("fname", "lname", null, null).hashCode(), new Name("fname", "lname", "b", null).hashCode()); - assertNotEquals(new Name("fname", "lname", null, null).hashCode(), new Name("fname", "name", null, null).hashCode()); - assertNotEquals(new Name("fname", "lname", null, null).hashCode(), new Name("name", "lname", null, null).hashCode()); + public void testNamePartHash() { + assertEquals(new NamePart(NamePartType.FIRST_NAME, "f"), new NamePart(NamePartType.FIRST_NAME, "f")); + assertNotEquals(new NamePart(NamePartType.FIRST_NAME, "f"), new NamePart(NamePartType.FIRST_NAME, "f2")); + assertNotEquals(new NamePart(NamePartType.FIRST_NAME, "f"), new NamePart(NamePartType.LAST_NAME, "f")); } + /** + * Tests fitness for {@link NamePart#equals(Object)}. + */ @Test - public void testEqualsObject() { - assertFalse(n.equals(null)); - assertFalse(n.equals("blargh")); - Name nullname = new Name(null, null, null, null); - assertFalse(n.equals(nullname)); - assertFalse(nullname.equals(n)); - assertTrue(nullname.equals(nullname)); - assertTrue(n.equals(n)); + public void testNamePartEquals() { + NamePart name = new NamePart(NamePartType.FIRST_NAME, "fn"); + assertFalse(name.equals(null)); + assertFalse(name.equals("blargh")); + + // namePart that differs in content + NamePart diffContent = new NamePart(NamePartType.FIRST_NAME, "f"); + assertFalse(name.equals(diffContent)); + assertFalse(diffContent.equals(name)); + assertTrue(diffContent.equals(diffContent)); + assertTrue(name.equals(name)); + + // name part that is equal + NamePart same = new NamePart(NamePartType.FIRST_NAME, "fn"); + assertTrue(same.equals(name)); + assertTrue(name.equals(same)); + assertTrue(same.equals(same)); + + // name part that differs in type + NamePart diffType = new NamePart(NamePartType.LAST_NAME, "fn"); + assertFalse(diffType.equals(name)); + assertFalse(name.equals(diffType)); + assertTrue(diffType.equals(diffType)); + + assertFalse(name.equals("BLA")); } @Test - public void testMatches() { - assertTrue(n.matches("fn ln")); - assertTrue(n.matches("fn ln sf")); - assertTrue(n.matches("fn mn ln sf")); - assertFalse(n.matches("blargh")); + public void testNamePartConstructorCheck() { + try { + new NamePart(null, "a"); + fail("Exception expected"); + } catch (IllegalArgumentException e) { + + } + try { + new NamePart(NamePartType.FIRST_NAME, null); + fail("Exception expected"); + } catch (IllegalArgumentException e) { + + } + try { + new NamePart(NamePartType.FIRST_NAME, ""); + fail("Exception expected"); + } catch (IllegalArgumentException e) { + + } } + /** + * Testing {@link Name#matches(String)}. For multiple first names. + */ + @Test + public void testMatches() throws GigiApiException { + Name n0 = new Name(u, new NamePart(NamePartType.FIRST_NAME, "Fir"), new NamePart(NamePartType.FIRST_NAME, "Fir2"), new NamePart(NamePartType.LAST_NAME, "Last")); + + // Having the name "Fir Fir2 Last". + // This name requires the Last name to be present and at least one of + // the first names. + + // Simple tests... + assertTrue(n0.matches("Fir Last")); + assertFalse(n0.matches("Fir Last")); + assertFalse(n0.matches("Fir Last ")); + assertFalse(n0.matches(" Fir Last")); + + // full name + assertTrue(n0.matches("Fir Fir2 Last")); + // removing and changing parts + assertTrue(n0.matches("Fir2 Last")); + assertFalse(n0.matches("Fir Bast")); + assertFalse(n0.matches("Fir2 Bast")); + assertFalse(n0.matches("Fir Fir2 Bast")); + // only last-name fails + assertFalse(n0.matches("Last")); + // one-character first-name is not enough + assertFalse(n0.matches("F. Last")); + assertFalse(n0.matches("E. Last")); + assertFalse(n0.matches("E Last")); + assertFalse(n0.matches("F Last")); + + assertFalse(n0.matches("Bast")); + + // test the abbreviated name (for e.g in find-RA-Agent-system) + assertEquals("Fir L.", n0.toAbbreviatedString()); + } + + /** + * Testing {@link Name#matches(String)} for multiple last-names and a + * suffix. + */ + @Test + public void testMatchesLNSuf() throws GigiApiException { + Name n0 = new Name(u, new NamePart(NamePartType.FIRST_NAME, "Fir"), new NamePart(NamePartType.LAST_NAME, "Last"), new NamePart(NamePartType.LAST_NAME, "Last2"), new NamePart(NamePartType.SUFFIX, "Suff")); + + // leaving stuff out in order + assertTrue(n0.matches("Fir Last")); + assertTrue(n0.matches("Fir Last Last2")); + assertTrue(n0.matches("Fir Last Last2 Suff")); + assertTrue(n0.matches("Fir Last Suff")); + + // omitting primary last name + assertFalse(n0.matches("Fir")); + assertFalse(n0.matches("Fir Last2")); + assertFalse(n0.matches("Fir Last2 Suff")); + assertFalse(n0.matches("Fir Suff")); + + // bringing things out of order + assertFalse(n0.matches("Fir Last Suff Last2")); + assertFalse(n0.matches("Fir Suff Last Last2")); + assertFalse(n0.matches("Fir Suff Last")); + assertFalse(n0.matches("Fir Last2 Last")); + assertFalse(n0.matches("Fir Last2 Last Suff")); + } + + /** + * Testing {@link Name#matches(String)} for multiple last-names and a + * suffix. + */ + @Test + public void testMatchesDoubleNameParts() throws GigiApiException { + Name name = new Name(u, // + new NamePart(NamePartType.FIRST_NAME, "A"), new NamePart(NamePartType.FIRST_NAME, "Fir"), new NamePart(NamePartType.FIRST_NAME, "A"),// + new NamePart(NamePartType.LAST_NAME, "A"), new NamePart(NamePartType.LAST_NAME, "Last"), new NamePart(NamePartType.LAST_NAME, "A")); + + assertTrue(name.matches("A A")); + assertTrue(name.matches("Fir A")); + assertTrue(name.matches("A A Last")); + assertTrue(name.matches("A A A")); + assertTrue(name.matches("Fir A A A")); + assertTrue(name.matches("Fir A A A A")); + + assertFalse(name.matches("A Last")); + assertFalse(name.matches("Last A")); + assertFalse(name.matches("Last A Last")); + assertFalse(name.matches("Fir Last")); + assertFalse(name.matches("Fir A A A A A")); + + } } diff --git a/tests/org/cacert/gigi/TestObjectCache.java b/tests/org/cacert/gigi/TestObjectCache.java index 69bd4390..1d35669b 100644 --- a/tests/org/cacert/gigi/TestObjectCache.java +++ b/tests/org/cacert/gigi/TestObjectCache.java @@ -9,10 +9,8 @@ import java.util.Locale; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.EmailAddress; -import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.ClientBusinessTest; -import org.cacert.gigi.util.DayDate; import org.junit.Test; public class TestObjectCache extends ClientBusinessTest { @@ -24,7 +22,7 @@ public class TestObjectCache extends ClientBusinessTest { Calendar c = Calendar.getInstance(); 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); + User u = createUser("fname", "lname", createUniqueName() + "@example.org", TEST_PASSWORD); 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 1a26f539..65271f6d 100644 --- a/tests/org/cacert/gigi/TestUser.java +++ b/tests/org/cacert/gigi/TestUser.java @@ -4,15 +4,21 @@ import static org.junit.Assert.*; import java.io.IOException; import java.sql.SQLException; +import java.util.Arrays; import java.util.Locale; import org.cacert.gigi.dbObjects.Assurance; +import org.cacert.gigi.dbObjects.Assurance.AssuranceType; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.EmailAddress; import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.BusinessTest; import org.cacert.gigi.util.DayDate; +import org.cacert.gigi.util.Notary; +import org.hamcrest.CoreMatchers; import org.junit.Test; public class TestUser extends BusinessTest { @@ -21,10 +27,10 @@ public class TestUser extends BusinessTest { 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 DayDate(dob), Locale.ENGLISH); + User u = createUser("f", "l", createUniqueName() + "a@email.org", TEST_PASSWORD); int id = u.getId(); User u2 = User.getById(id); - assertEquals(u.getName(), u2.getName()); + assertEquals(u.getNames()[0], u2.getNames()[0]); assertEquals(u.getDoB().toString(), u2.getDoB().toString()); assertEquals(u.getEmail(), u2.getEmail()); } @@ -33,11 +39,11 @@ public class TestUser extends BusinessTest { public void testWebStoreAndLoad() throws SQLException, GigiApiException { int id = createVerifiedUser("aä", "b", createUniqueName() + "a@email.org", TEST_PASSWORD); - Name u = User.getById(id).getName(); + Name u = User.getById(id).getNames()[0]; - assertEquals("aä", u.getFname()); - assertEquals("b", u.getLname()); - assertEquals("", u.getMname()); + assertThat(Arrays.asList(u.getParts()), CoreMatchers.hasItem(new NamePart(NamePartType.FIRST_NAME, "aä"))); + assertThat(Arrays.asList(u.getParts()), CoreMatchers.hasItem(new NamePart(NamePartType.LAST_NAME, "b"))); + assertEquals(2, u.getParts().length); } @Test @@ -52,26 +58,17 @@ public class TestUser extends BusinessTest { assertEquals(2, expPoints); assertTrue(u.hasPassedCATS()); assertEquals(10, u.getMaxAssurePoints()); - Name name = u.getName(); - assertEquals("aä", name.getFname()); - assertEquals("b", name.getLname()); - assertEquals("", name.getMname()); } @Test - public void testMatcherMethods() throws SQLException, GigiApiException, IOException { + public void testMatcherMethodsDomain() throws SQLException, GigiApiException, IOException { String uq = createUniqueName(); int id = createVerifiedUser("aä", "b", uq + "a@email.org", TEST_PASSWORD); User u = User.getById(id); - new EmailAddress(u, uq + "b@email.org", Locale.ENGLISH); - getMailReceiver().receive().verify(); - new EmailAddress(u, uq + "c@email.org", Locale.ENGLISH); - getMailReceiver().receive();// no-verify verify(new Domain(u, u, uq + "a-testdomain.org")); verify(new Domain(u, u, uq + "b-testdomain.org")); verify(new Domain(u, u, uq + "c-testdomain.org")); - assertEquals(3, u.getEmails().length); assertEquals(3, u.getDomains().length); assertTrue(u.isValidDomain(uq + "a-testdomain.org")); assertTrue(u.isValidDomain(uq + "b-testdomain.org")); @@ -80,12 +77,40 @@ public class TestUser extends BusinessTest { assertTrue(u.isValidDomain("*." + uq + "a-testdomain.org")); assertFalse(u.isValidDomain("a" + uq + "a-testdomain.org")); assertFalse(u.isValidDomain("b" + uq + "a-testdomain.org")); + } + + @Test + public void testMatcherMethodsEmail() throws SQLException, GigiApiException, IOException { + String uq = createUniqueName(); + int id = createVerifiedUser("aä", "b", uq + "a@email.org", TEST_PASSWORD); + + User u = User.getById(id); + + new EmailAddress(u, uq + "b@email.org", Locale.ENGLISH); + getMailReceiver().receive().verify(); + new EmailAddress(u, uq + "c@email.org", Locale.ENGLISH); + getMailReceiver().receive();// no-verify + assertEquals(3, u.getEmails().length); assertTrue(u.isValidEmail(uq + "a@email.org")); assertTrue(u.isValidEmail(uq + "b@email.org")); assertFalse(u.isValidEmail(uq + "b+6@email.org")); assertFalse(u.isValidEmail(uq + "b*@email.org")); assertFalse(u.isValidEmail(uq + "c@email.org")); + } + + @Test + public void testMatcherMethodsName() throws SQLException, GigiApiException, IOException { + String uq = createUniqueName(); + int id = createVerifiedUser("aä", "b", uq + "a@email.org", TEST_PASSWORD); + + User u = User.getById(id); + + User[] us = new User[5]; + for (int i = 0; i < us.length; i++) { + us[i] = User.getById(createAssuranceUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD)); + Notary.assure(us[i], u, u.getPreferredName(), u.getDoB(), 10, "here", "2000-01-01", AssuranceType.FACE_TO_FACE); + } assertTrue(u.isValidName("aä b")); assertFalse(u.isValidName("aä c")); @@ -97,7 +122,7 @@ public class TestUser extends BusinessTest { public void testDoubleInsert() throws GigiApiException { 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); + User u = createUser("f", "l", createUniqueName() + "@example.org", TEST_PASSWORD); Assurance[] ma = u.getMadeAssurances(); Assurance[] ma2 = u.getMadeAssurances(); Assurance[] ra = u.getReceivedAssurances(); diff --git a/tests/org/cacert/gigi/api/IssueCert.java b/tests/org/cacert/gigi/api/IssueCert.java index c2825d07..f6040008 100644 --- a/tests/org/cacert/gigi/api/IssueCert.java +++ b/tests/org/cacert/gigi/api/IssueCert.java @@ -22,7 +22,6 @@ import org.cacert.gigi.dbObjects.CertificateProfile; import org.cacert.gigi.dbObjects.Digest; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.Group; -import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.Organisation; import org.cacert.gigi.testUtils.ClientTest; import org.cacert.gigi.testUtils.IOUtils; @@ -73,13 +72,12 @@ public class IssueCert extends ClientTest { public void testIssueCertAssured() throws Exception { makeAssurer(id); - Name n = u.getName(); - String whishName = n.getFname() + " " + n.getLname(); - String cert = issueCert(generatePEMCSR(kp, "EMAIL=" + email + ",CN=" + whishName), "profile=client-a"); + String intendedName = "a b"; + String cert = issueCert(generatePEMCSR(kp, "EMAIL=" + email + ",CN=" + intendedName), "profile=client-a"); CertificateFactory cf = CertificateFactory.getInstance("X509"); java.security.cert.X509Certificate xcert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(cert.getBytes("UTF-8"))); - assertEquals(whishName, ((X500Name) xcert.getSubjectDN()).getCommonName()); + assertEquals(intendedName, ((X500Name) xcert.getSubjectDN()).getCommonName()); } diff --git a/tests/org/cacert/gigi/api/TestFindAgent.java b/tests/org/cacert/gigi/api/TestFindAgent.java index e889f1e8..3b8b9927 100644 --- a/tests/org/cacert/gigi/api/TestFindAgent.java +++ b/tests/org/cacert/gigi/api/TestFindAgent.java @@ -82,6 +82,6 @@ public class TestFindAgent extends RestrictedApiTest { grant(email, Group.LOCATE_AGENT); grant(User.getById(u2).getEmail(), Group.LOCATE_AGENT); res = IOUtils.readURL(doApi(FindAgent.PATH_INFO, "id=" + id + "&id=" + u2)).replace("\r", ""); - assertEquals(id + ",true," + u.getName().toString() + "\n" + u2 + ",false," + User.getById(u2).getName().toString() + "\n", res); + assertEquals(id + ",true," + u.getPreferredName().toAbbreviatedString() + "\n" + u2 + ",false," + User.getById(u2).getPreferredName().toAbbreviatedString() + "\n", res); } } diff --git a/tests/org/cacert/gigi/dbObjects/TestAssurance.java b/tests/org/cacert/gigi/dbObjects/TestAssurance.java index dda8d81d..14c7b35b 100644 --- a/tests/org/cacert/gigi/dbObjects/TestAssurance.java +++ b/tests/org/cacert/gigi/dbObjects/TestAssurance.java @@ -37,6 +37,8 @@ public class TestAssurance extends BusinessTest { private int applicantID; + private int applicantNameID; + private User applicant; private int applicantMultID; @@ -112,75 +114,67 @@ public class TestAssurance extends BusinessTest { agent2ID = createAssuranceUser("a", "d", createUniqueName() + "@example.com", TEST_PASSWORD); applicantID = createVerifiedUser("a", "c", createUniqueName() + "@example.com", TEST_PASSWORD); applicant = User.getById(applicantID); + applicantNameID = User.getById(applicantID).getPreferredName().getId(); applicantMultID = createVerifiedUser("a", "e", createUniqueName() + "@example.com", TEST_PASSWORD); } @Test public void testVerificationYesterday() throws IOException { - enterAssuranceWhen(agentID, applicantID, yesterday); + enterAssuranceWhen(agentID, applicantNameID, yesterday); assertTrue(applicant.isInVerificationLimit()); } @Test public void testApprox24MonthAgo() throws IOException { - enterAssuranceWhen(agentID, applicantID, min24month); + enterAssuranceWhen(agentID, applicantNameID, min24month); assertTrue(applicant.isInVerificationLimit()); } @Test public void testApprox39MonthAgo() throws IOException { - enterAssuranceWhen(agentID, applicantID, min39month); + enterAssuranceWhen(agentID, applicantNameID, min39month); assertFalse(applicant.isInVerificationLimit()); } @Test public void testTomorrowExpired() throws IOException { - enterAssuranceExpired(agentID, applicantID, tomorrow); + enterAssuranceExpired(agentID, applicantNameID, tomorrow); assertTrue(applicant.isInVerificationLimit()); } @Test public void testYesterdayExpired() throws IOException { - enterAssuranceExpired(agentID, applicantID, yesterday); + enterAssuranceExpired(agentID, applicantNameID, yesterday); assertFalse(applicant.isInVerificationLimit()); } @Test public void testNormal() throws IOException { - enterAssurance(agentID, applicantID); + enterAssurance(agentID, applicantNameID); assertTrue(applicant.isInVerificationLimit()); } @Test public void testDeletedYesterday() throws IOException { - enterAssuranceDeleted(agentID, applicantID, yesterday); + enterAssuranceDeleted(agentID, applicantNameID, yesterday); assertFalse(applicant.isInVerificationLimit()); } @Test public void testMultipleAssurancePossible() throws IOException { - User agent = User.getById(agentID); User applicantMult = User.getById(applicantMultID); - enterAssuranceWhen(agentID, applicantMultID, min39month); + enterAssuranceWhen(agentID, applicantMult.getPreferredName().getId(), min39month); // test that new entry would be possible - try { - Notary.checkAssuranceIsPossible(agent, applicantMult); - } catch (GigiApiException e) { - assertTrue(false); - } + assertTrue(Notary.checkAssuranceIsPossible(agent, applicantMult.getPreferredName())); // enter new entry - enterAssuranceWhen(agentID, applicantMultID, yesterday); + enterAssuranceWhen(agentID, applicantMult.getPreferredName().getId(), yesterday); // test that new entry is not possible - try { - Notary.checkAssuranceIsPossible(agent, applicantMult); - } catch (GigiApiException e) { - assertTrue(true); - } + assertFalse(Notary.checkAssuranceIsPossible(agent, applicantMult.getPreferredName())); } @@ -190,8 +184,7 @@ public class TestAssurance extends BusinessTest { User agent = User.getById(agentID); User applicantMult = User.getById(applicantMultID); - enterAssuranceWhen(agentID, applicantMultID, min39month); - + enterAssuranceWhen(agentID, applicantMult.getPreferredName().getId(), min39month); int xPoints = agent.getExperiencePoints(); // test that VP after first entry @@ -199,40 +192,41 @@ public class TestAssurance extends BusinessTest { assertEquals(applicantMult.getAssurancePoints(), 10); // enter second entry to check correct calculation with larger points - enterAssuranceWhen(agentID, applicantMultID, min24month, 20); + enterAssuranceWhen(agentID, applicantMult.getPreferredName().getId(), min24month, 20); assertEquals(applicantMult.getAssurancePoints(), 20); // test correct XP calculation assertEquals(agent.getExperiencePoints(), xPoints); // enter third entry to check correct calculation with less points - enterAssuranceWhen(agentID, applicantMultID, yesterday, 15); + enterAssuranceWhen(agentID, applicantMult.getPreferredName().getId(), yesterday, 15); assertEquals(applicantMult.getAssurancePoints(), 15); // test correct XP calculation assertEquals(agent.getExperiencePoints(), xPoints); // enter expired entry - enterAssuranceExpired(agentID, applicantMultID, yesterday); + enterAssuranceExpired(agentID, applicantMult.getPreferredName().getId(), yesterday); assertEquals(applicantMult.getAssurancePoints(), 15); // enter deleted entry same agent - enterAssuranceDeleted(agentID, applicantMultID, yesterday); + enterAssuranceDeleted(agentID, applicantMult.getPreferredName().getId(), yesterday); assertEquals(applicantMult.getAssurancePoints(), 15); // enter expired entry future - enterAssuranceExpired(agentID, applicantMultID, tomorrow); + enterAssuranceExpired(agentID, applicantMult.getPreferredName().getId(), tomorrow); assertEquals(applicantMult.getAssurancePoints(), 10); // test correct XP calculation assertEquals(agent.getExperiencePoints(), xPoints); // enter entry from different agent - enterAssuranceWhen(agent2ID, applicantMultID, yesterday); + enterAssuranceWhen(agent2ID, applicantMult.getPreferredName().getId(), yesterday); assertEquals(applicantMult.getAssurancePoints(), 20); // enter entry for second applicant - enterAssuranceWhen(agentID, applicantID, yesterday); + enterAssuranceWhen(agentID, applicant.getPreferredName().getId(), yesterday); + assertEquals(agent.getExperiencePoints(), xPoints + 2); } diff --git a/tests/org/cacert/gigi/dbObjects/TestAssureName.java b/tests/org/cacert/gigi/dbObjects/TestAssureName.java new file mode 100644 index 00000000..9296e35c --- /dev/null +++ b/tests/org/cacert/gigi/dbObjects/TestAssureName.java @@ -0,0 +1,32 @@ +package org.cacert.gigi.dbObjects; + +import static org.junit.Assert.*; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Assurance.AssuranceType; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; +import org.cacert.gigi.testUtils.ClientBusinessTest; +import org.cacert.gigi.util.Notary; +import org.junit.Test; + +public class TestAssureName extends ClientBusinessTest { + + @Test + public void testIt() throws GigiApiException { + User u0 = User.getById(createAssuranceUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD)); + Name n2 = new Name(u, new NamePart(NamePartType.SINGLE_NAME, "Testiaa")); + Name n3 = new Name(u, new NamePart(NamePartType.SINGLE_NAME, "Testiaa")); + Name n4 = new Name(u, new NamePart(NamePartType.SINGLE_NAME, "Testiaac")); + + assertEquals(0, n0.getAssurancePoints()); + Notary.assure(u0, u, n0, u.getDoB(), 10, "test mgr", "2010-01-01", AssuranceType.FACE_TO_FACE); + assertEquals(10, n0.getAssurancePoints()); + Notary.assure(u0, u, n2, u.getDoB(), 10, "test mgr", "2010-01-01", AssuranceType.FACE_TO_FACE); + assertEquals(10, n2.getAssurancePoints()); + Notary.assure(u0, u, n3, u.getDoB(), 10, "test mgr", "2010-01-01", AssuranceType.FACE_TO_FACE); + assertEquals(10, n3.getAssurancePoints()); + Notary.assure(u0, u, n4, u.getDoB(), 10, "test mgr", "2010-01-01", AssuranceType.FACE_TO_FACE); + assertEquals(10, n4.getAssurancePoints()); + assertEquals(10, u.getMaxAssurePoints()); + } +} diff --git a/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java b/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java index e6361eb6..6917a141 100644 --- a/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java +++ b/tests/org/cacert/gigi/pages/account/TestMyDetailsEdit.java @@ -4,11 +4,17 @@ import static org.junit.Assert.*; import java.io.IOException; import java.sql.Date; +import java.util.Arrays; import java.util.Calendar; import java.util.TimeZone; +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.ManagedTest; +import org.hamcrest.CoreMatchers; import org.junit.Test; public class TestMyDetailsEdit extends ManagedTest { @@ -22,81 +28,42 @@ public class TestMyDetailsEdit extends ManagedTest { public TestMyDetailsEdit() throws IOException {} @Test - public void testChangeFnameValid() throws IOException { + public void testAddName() throws IOException { + int startn = User.getById(id).getNames().length; String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "fname=" + newName + "&lname=Hansel&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); + assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "fname=" + newName + "&lname=Hansel&action=addName", 0)); User u = User.getById(id); - assertEquals(newName, u.getName().getFname()); - } - @Test - public void testChangeLnameValid() throws IOException { - String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "lname=" + newName + "&fname=Kurti&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals(newName, u.getName().getLname()); - } - - @Test - public void testChangeMnameValid() throws IOException { - String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "mname=" + newName + "&fname=Kurti&lname=Hansel&suffix=&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals(newName, u.getName().getMname()); - } - - @Test - public void testChangeSuffixValid() throws IOException { - String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "mname=&fname=Kurti&lname=Hansel&suffix=" + newName + "&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals(newName, u.getName().getSuffix()); + NamePart[] parts = u.getNames()[startn].getParts(); + assertThat(Arrays.asList(parts), CoreMatchers.hasItem(new NamePart(NamePartType.FIRST_NAME, newName))); + assertThat(Arrays.asList(parts), CoreMatchers.hasItem(new NamePart(NamePartType.LAST_NAME, "Hansel"))); + assertEquals(2, parts.length); + assertEquals(startn + 1, User.getById(id).getNames().length); } @Test - public void testUnsetSuffix() throws IOException { + public void testDelName() throws IOException, GigiApiException { + User user = User.getById(id); + int startn = user.getNames().length; String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "mname=&fname=Kurti&lname=Hansel&suffix=" + newName + "&day=1&month=1&year=2000&processDetails", 0)); - clearCaches(); - User u = User.getById(id); - assertEquals(newName, u.getName().getSuffix()); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "mname=&fname=Kurti&lname=Hansel&suffix=&day=1&month=1&year=2000&processDetails", 0)); - clearCaches(); - u = User.getById(id); - assertEquals("", u.getName().getSuffix()); - } - - @Test - public void testUnsetFname() throws IOException { - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "fname=&lname=Hansel&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals("", u.getName().getFname()); + Name n1 = new Name(user, new NamePart(NamePartType.SINGLE_NAME, newName)); + assertEquals(startn + 1, user.getNames().length); + assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "removeName=" + n1.getId(), 0)); + assertEquals(startn, user.getNames().length); } @Test - public void testUnsetLname() throws IOException { - assertNotNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "lname=&fname=Kurti&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals("Hansel", u.getName().getLname()); - } - - @Test - public void testUnsetMname() throws IOException { - String newName = createUniqueName(); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "mname=" + newName + "&fname=Kurti&lname=Hansel&suffix=&day=1&month=1&year=2000&processDetails", 0)); - User u = User.getById(id); - assertEquals(newName, u.getName().getMname()); - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "lname=Hansel&fname=Kurti&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - clearCaches(); - u = User.getById(id); - assertEquals("", u.getName().getMname()); - + public void testDelDefaultName() throws IOException { + User user = User.getById(id); + assertEquals(1, user.getNames().length); + assertNotNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "removeName=" + user.getNames()[0].getId(), 0)); + assertEquals(1, user.getNames().length); } @Test public void testChangeDOBValid() throws IOException { - assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "lname=Hansel&fname=Kurti&mname=&suffix=&day=1&month=2&year=2000&processDetails", 0)); + assertNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "day=1&month=2&year=2000&action=updateDoB", 0)); User u = User.getById(id); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal.set(Calendar.YEAR, 2000); @@ -108,6 +75,6 @@ public class TestMyDetailsEdit extends ManagedTest { @Test public void testChangeDOBInvalid() throws IOException { - assertNotNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "lname=Hansel&fname=Kurti&mname=&suffix=&day=1&month=1&year=test&processDetails", 0)); + assertNotNull(executeBasicWebInteraction(cookie, MyDetails.PATH, "day=1&month=1&year=test&action=updateDoB", 0)); } } diff --git a/tests/org/cacert/gigi/pages/account/TestPasswordResetExternal.java b/tests/org/cacert/gigi/pages/account/TestPasswordResetExternal.java index d39bfba2..1ec408a5 100644 --- a/tests/org/cacert/gigi/pages/account/TestPasswordResetExternal.java +++ b/tests/org/cacert/gigi/pages/account/TestPasswordResetExternal.java @@ -28,7 +28,7 @@ public class TestPasswordResetExternal extends ClientTest { String cookie2 = login(u.getEmail(), TEST_PASSWORD); URLConnection uc = TestAssurance.buildupAssureFormConnection(cookie2, email, true); String avalue = RandomToken.generateToken(32); - uc.getOutputStream().write(("date=1910-01-01&location=testcase&certify=1&rules=1&assertion=1&points=10&passwordReset=1&passwordResetValue=" + URLEncoder.encode(avalue, "UTF-8")).getBytes("UTF-8")); + uc.getOutputStream().write(("assuredName=" + u.getPreferredName().getId() + "&date=1910-01-01&location=testcase&certify=1&rules=1&assertion=1&points=10&passwordReset=1&passwordResetValue=" + URLEncoder.encode(avalue, "UTF-8")).getBytes("UTF-8")); uc.getOutputStream().flush(); String error = fetchStartErrorMessage(IOUtils.readURL(uc)); assertNull(error); diff --git a/tests/org/cacert/gigi/pages/admin/TestSEAdminNotificationMail.java b/tests/org/cacert/gigi/pages/admin/TestSEAdminNotificationMail.java index ae89544f..bd64f9bf 100644 --- a/tests/org/cacert/gigi/pages/admin/TestSEAdminNotificationMail.java +++ b/tests/org/cacert/gigi/pages/admin/TestSEAdminNotificationMail.java @@ -31,11 +31,11 @@ public class TestSEAdminNotificationMail extends ClientTest { @Test public void testChangeAccountData() throws MalformedURLException, IOException { - executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + targetID, "fname=Kurti3&lname=Hansel&mname=&suffix=&dobd=1&dobm=2&doby=2000&detailupdate", 0); + executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + targetID, "dobd=1&dobm=2&doby=2000&detailupdate", 0); String message = getMailReceiver().receive().getMessage(); assertThat(message, containsString("The account data was changed.")); - assertThat(message, containsString("supporter " + u.getName() + " triggered:")); + assertThat(message, containsString("supporter " + u.getPreferredName().toString() + " triggered:")); } diff --git a/tests/org/cacert/gigi/pages/admin/TestSEAdminPageDetails.java b/tests/org/cacert/gigi/pages/admin/TestSEAdminPageDetails.java index edcd4344..228528b7 100644 --- a/tests/org/cacert/gigi/pages/admin/TestSEAdminPageDetails.java +++ b/tests/org/cacert/gigi/pages/admin/TestSEAdminPageDetails.java @@ -16,7 +16,6 @@ import org.cacert.gigi.dbObjects.Group; import org.cacert.gigi.dbObjects.ObjectCache; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.pages.account.History; -import org.cacert.gigi.pages.account.MyDetails; import org.cacert.gigi.pages.admin.support.SupportEnterTicketPage; import org.cacert.gigi.pages.admin.support.SupportUserDetailsPage; import org.cacert.gigi.testUtils.ClientTest; @@ -39,8 +38,8 @@ public class TestSEAdminPageDetails extends ClientTest { URLConnection uc = get(SupportUserDetailsPage.PATH + id); uc.setDoOutput(true); String res = IOUtils.readURL(uc); - assertThat(res, containsString("type=\"text\" value=\"" + fname + "\" name=\"fname\">")); - assertThat(res, containsString("type=\"text\" value=\"" + lname + "\" name=\"lname\">")); + assertThat(res, containsString(fname)); + assertThat(res, containsString(lname)); assertThat(res, containsString(email)); } @@ -69,31 +68,6 @@ public class TestSEAdminPageDetails extends ClientTest { assertEquals(2, countRegex(res, Pattern.quote(email2))); } - @Test - public void testUserDetailsEdit() throws MalformedURLException, IOException { - String email = createUniqueName() + "@example.com"; - String fname = "Först"; - String lname = "Secönd"; - int id = createVerifiedUser(fname, lname, email, TEST_PASSWORD); - - String userCookie = login(email, TEST_PASSWORD); - assertEquals("Först", getFname(IOUtils.readURL(get(userCookie, MyDetails.PATH)))); - // User can change his name - assertNull(executeBasicWebInteraction(userCookie, MyDetails.PATH, "fname=Kurti&lname=Hansel&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - assertEquals("Kurti", getFname(IOUtils.readURL(get(userCookie, MyDetails.PATH)))); - // But when assurer - makeAssurer(id); - // User cannot change his name, and the form changed - assertNotNull(executeBasicWebInteraction(userCookie, MyDetails.PATH, "fname=Kurti2&lname=Hansel&mname=&suffix=&day=1&month=1&year=2000&processDetails", 0)); - assertNull(getFname(IOUtils.readURL(get(userCookie, MyDetails.PATH)))); - assertEquals("Kurti", getFnamePlain(IOUtils.readURL(get(userCookie, MyDetails.PATH)))); - - // but support still can - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti3&lname=Hansel&mname=&suffix=&dobd=1&dobm=2&doby=2000&detailupdate", 0)); - assertEquals("Kurti3", getFnamePlain(IOUtils.readURL(get(userCookie, MyDetails.PATH)))); - - } - @Test public void testUserDetailsEditToLog() throws MalformedURLException, IOException { String email = createUniqueName() + "@example.com"; @@ -105,29 +79,29 @@ public class TestSEAdminPageDetails extends ClientTest { assertEquals(0, logCountAdmin(id)); assertEquals(0, logCountUser(clientCookie)); // chaniging both leads to 2 entries - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti&lname=Hansel&mname=&suffix=&dobd=1&dobm=2&doby=2000&detailupdate", 0)); - assertEquals(2, logCountAdmin(id)); - assertEquals(2, logCountUser(clientCookie)); + assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "dobd=1&dobm=2&doby=2000&detailupdate", 0)); + assertEquals(1, logCountAdmin(id)); + assertEquals(1, logCountUser(clientCookie)); // Sending same data keeps same - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti&lname=Hansel&mname=&suffix=&dobd=1&dobm=2&doby=2000&detailupdate", 0)); + assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "dobd=1&dobm=2&doby=2000&detailupdate", 0)); + assertEquals(1, logCountAdmin(id)); + assertEquals(1, logCountUser(clientCookie)); + + // changing one leads to one entry + assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "dobd=1&dobm=3&doby=2000&detailupdate", 0)); assertEquals(2, logCountAdmin(id)); assertEquals(2, logCountUser(clientCookie)); // changing one leads to one entry - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti2&lname=Hansel&mname=&suffix=&dobd=1&dobm=2&doby=2000&detailupdate", 0)); + assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "dobd=2&dobm=3&doby=2000&detailupdate", 0)); assertEquals(3, logCountAdmin(id)); assertEquals(3, logCountUser(clientCookie)); - // changing one leads to one entry - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti2&lname=Hansel&mname=&suffix=&dobd=2&dobm=2&doby=2000&detailupdate", 0)); - assertEquals(4, logCountAdmin(id)); - assertEquals(4, logCountUser(clientCookie)); - // changing none -> no entry - assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "fname=Kurti2&lname=Hansel&mname=&suffix=&dobd=2&dobm=2&doby=2000&detailupdate", 0)); - assertEquals(4, logCountAdmin(id)); - assertEquals(4, logCountUser(clientCookie)); + assertNull(executeBasicWebInteraction(cookie, SupportUserDetailsPage.PATH + id, "dobd=2&dobm=3&doby=2000&detailupdate", 0)); + assertEquals(3, logCountAdmin(id)); + assertEquals(3, logCountUser(clientCookie)); } @@ -154,7 +128,7 @@ public class TestSEAdminPageDetails extends ClientTest { } private String getFname(String res) { - Pattern p = Pattern.compile("type=\"text\" name=\"fname\" value=\"([^\"]*)\">"); + Pattern p = Pattern.compile("([^<]*)"); Matcher m = p.matcher(res); if (m.find()) { return m.group(1); @@ -162,12 +136,4 @@ public class TestSEAdminPageDetails extends ClientTest { return null; } - private String getFnamePlain(String res) { - Pattern p = Pattern.compile("\\s*]*>First Name: \\s*]*>([^<]*)"); - Matcher m = p.matcher(res); - if (m.find()) { - return m.group(1); - } - return null; - } } diff --git a/tests/org/cacert/gigi/pages/wot/TestAssurance.java b/tests/org/cacert/gigi/pages/wot/TestAssurance.java index 4108cf8f..2a68173d 100644 --- a/tests/org/cacert/gigi/pages/wot/TestAssurance.java +++ b/tests/org/cacert/gigi/pages/wot/TestAssurance.java @@ -32,6 +32,8 @@ public class TestAssurance extends ManagedTest { private String assureeM; + private int assureeName; + private String cookie; @Before @@ -41,7 +43,8 @@ public class TestAssurance extends ManagedTest { assureeM = createUniqueName() + "@cacert-test.org"; createAssuranceUser("a", "b", assurerM, TEST_PASSWORD); - createVerifiedUser("a", "c", assureeM, TEST_PASSWORD); + int assureeId = createVerifiedUser("a", "c", assureeM, TEST_PASSWORD); + assureeName = User.getById(assureeId).getPreferredName().getId(); cookie = login(assurerM, TEST_PASSWORD); } @@ -95,7 +98,7 @@ public class TestAssurance extends ManagedTest { @Test public void testAssureFormContanisData() throws IOException { URLConnection uc = buildupAssureFormConnection(true); - uc.getOutputStream().write(("date=2000-01-01&location=testcase&rules=1&assertion=1&points=10").getBytes("UTF-8")); + uc.getOutputStream().write(("assuredName=" + assureeName + "&date=2000-01-01&location=testcase&rules=1&assertion=1&points=10").getBytes("UTF-8")); uc.getOutputStream().flush(); String data = IOUtils.readURL(uc); assertThat(data, containsString("2000-01-01")); @@ -120,36 +123,25 @@ public class TestAssurance extends ManagedTest { assertEquals(500, uc.getResponseCode()); } - @Test - public void testAssureFormRaceName() throws IOException, SQLException { - testAssureFormRace(true, false); - } - @Test public void testAssureFormRaceDoB() throws IOException, SQLException { - testAssureFormRace(false, false); - } - - @Test - public void testAssureFormRaceNameBlind() throws IOException, SQLException { - testAssureFormRace(true, true); + testAssureFormRace(false); } @Test public void testAssureFormRaceDoBBlind() throws IOException, SQLException { - testAssureFormRace(false, true); + testAssureFormRace(true); } - public void testAssureFormRace(boolean name, boolean succeed) throws IOException, SQLException { + public void testAssureFormRace(boolean succeed) throws IOException, SQLException { URLConnection uc = buildupAssureFormConnection(true); String assureeCookie = login(assureeM, TEST_PASSWORD); - String newName = "lname=" + (name && !succeed ? "a" : "c") + "&fname=a&mname=&suffix="; - String newDob = "day=1&month=1&year=" + ( !name && !succeed ? 1911 : 1910); + String newDob = "day=1&month=1&year=" + ( !succeed ? 1911 : 1910); - assertNull(executeBasicWebInteraction(assureeCookie, MyDetails.PATH, newName + "&" + newDob + "&processDetails", 0)); + assertNull(executeBasicWebInteraction(assureeCookie, MyDetails.PATH, newDob + "&action=updateDoB", 0)); - uc.getOutputStream().write(("date=2000-01-01&location=testcase&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8")); + uc.getOutputStream().write(("assuredName=" + assureeName + "&date=2000-01-01&location=testcase&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8")); uc.getOutputStream().flush(); String error = fetchStartErrorMessage(IOUtils.readURL(uc)); if (succeed) { @@ -231,7 +223,7 @@ public class TestAssurance extends ManagedTest { private String execute(String query) throws MalformedURLException, IOException { URLConnection uc = buildupAssureFormConnection(true); - uc.getOutputStream().write((query).getBytes("UTF-8")); + uc.getOutputStream().write(("assuredName=" + assureeName + "&" + query).getBytes("UTF-8")); uc.getOutputStream().flush(); return IOUtils.readURL(uc); } diff --git a/tests/org/cacert/gigi/testUtils/BusinessTest.java b/tests/org/cacert/gigi/testUtils/BusinessTest.java index c014e2b3..8de7a586 100644 --- a/tests/org/cacert/gigi/testUtils/BusinessTest.java +++ b/tests/org/cacert/gigi/testUtils/BusinessTest.java @@ -17,7 +17,8 @@ import java.util.regex.Pattern; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.EmailAddress; -import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.email.EmailProvider; import org.cacert.gigi.ping.PingerDaemon; @@ -118,17 +119,14 @@ public abstract class BusinessTest extends ConfiguredTest { c.set(1950, 1, 1, 0, 0, 0); c.set(Calendar.MILLISECOND, 0); - User u = new User(createUniqueName() + "@email.com", TEST_PASSWORD, new Name("a", "m", "c", ""), new DayDate(c.getTimeInMillis()), Locale.ENGLISH); + User u = new User(createUniqueName() + "@email.com", TEST_PASSWORD, new DayDate(c.getTimeInMillis()), Locale.ENGLISH, // + new NamePart(NamePartType.FIRST_NAME, "a"), new NamePart(NamePartType.FIRST_NAME, "m"), new NamePart(NamePartType.LAST_NAME, "c")); InVMEmail.getInstance().mails.poll().verify(); return u; } public static int createVerifiedUser(String f, String l, String mail, String pw) throws GigiApiException { - Calendar c = Calendar.getInstance(); - c.set(1950, 1, 1, 0, 0, 0); - c.set(Calendar.MILLISECOND, 0); - - User u = new User(mail, pw, new Name(f, l, "", ""), new DayDate(c.getTimeInMillis()), Locale.ENGLISH); + User u = createUser(f, l, mail, pw); try { InVMEmail.getInstance().mails.poll().verify(); } catch (IOException e) { @@ -137,6 +135,16 @@ public abstract class BusinessTest extends ConfiguredTest { return u.getId(); } + public static User createUser(String f, String l, String mail, String pw) throws GigiApiException { + Calendar c = Calendar.getInstance(); + c.set(1950, 1, 1, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + + User u = new User(mail, pw, new DayDate(c.getTimeInMillis()), Locale.ENGLISH,// + new NamePart(NamePartType.FIRST_NAME, f), new NamePart(NamePartType.LAST_NAME, l)); + return u; + } + public static int createAssuranceUser(String f, String l, String mail, String pw) throws GigiApiException { int u = createVerifiedUser(f, l, mail, pw); makeAssurer(u); diff --git a/tests/org/cacert/gigi/testUtils/ClientBusinessTest.java b/tests/org/cacert/gigi/testUtils/ClientBusinessTest.java index e096be4c..31c28686 100644 --- a/tests/org/cacert/gigi/testUtils/ClientBusinessTest.java +++ b/tests/org/cacert/gigi/testUtils/ClientBusinessTest.java @@ -1,18 +1,22 @@ package org.cacert.gigi.testUtils; import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Name; import org.cacert.gigi.dbObjects.User; public class ClientBusinessTest extends BusinessTest { protected final User u; + protected final Name n0; + protected final int id; public ClientBusinessTest() { try { id = createVerifiedUser("a", "b", createUniqueName() + "@example.com", TEST_PASSWORD); u = User.getById(id); + n0 = u.getNames()[0]; } catch (GigiApiException e) { throw new Error(e); } diff --git a/tests/org/cacert/gigi/testUtils/ConfiguredTest.java b/tests/org/cacert/gigi/testUtils/ConfiguredTest.java index e696acd3..5ab20079 100644 --- a/tests/org/cacert/gigi/testUtils/ConfiguredTest.java +++ b/tests/org/cacert/gigi/testUtils/ConfiguredTest.java @@ -26,6 +26,7 @@ import org.cacert.gigi.database.SQLFileManager.ImportType; import org.cacert.gigi.dbObjects.CATS.CATSType; import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.DomainPingType; +import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.testUtils.TestEmailReceiver.TestMail; import org.cacert.gigi.util.DatabaseManager; import org.cacert.gigi.util.DomainAssessment; @@ -178,7 +179,7 @@ public abstract class ConfiguredTest { try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) { ps2.setInt(1, uid); - ps2.setInt(2, uid); + ps2.setInt(2, User.getById(uid).getPreferredName().getId()); ps2.execute(); } } diff --git a/tests/org/cacert/gigi/util/TestNotary.java b/tests/org/cacert/gigi/util/TestNotary.java index 477345f3..21045c9a 100644 --- a/tests/org/cacert/gigi/util/TestNotary.java +++ b/tests/org/cacert/gigi/util/TestNotary.java @@ -31,7 +31,7 @@ public class TestNotary extends BusinessTest { }; try { - Notary.assure(assurer, users[0], users[0].getName(), users[0].getDoB(), -1, "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); + Notary.assure(assurer, users[0], users[0].getPreferredName(), users[0].getDoB(), -1, "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); fail("This shouldn't have passed"); } catch (GigiApiException e) { // expected @@ -40,7 +40,7 @@ public class TestNotary extends BusinessTest { assertEquals(result[i], assurer.getMaxAssurePoints()); assuranceFail(assurer, users[i], result[i] + 1, "test-notary", "2014-01-01"); - Notary.assure(assurer, users[i], users[i].getName(), users[i].getDoB(), result[i], "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); + Notary.assure(assurer, users[i], users[i].getPreferredName(), users[i].getDoB(), result[i], "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); assuranceFail(assurer, users[i], result[i], "test-notary", "2014-01-01"); } @@ -52,7 +52,7 @@ public class TestNotary extends BusinessTest { private void assuranceFail(User assurer, User user, int i, String location, String date) throws SQLException { try { - Notary.assure(assurer, user, user.getName(), user.getDoB(), i, location, date, AssuranceType.FACE_TO_FACE); + Notary.assure(assurer, user, user.getPreferredName(), user.getDoB(), i, location, date, AssuranceType.FACE_TO_FACE); fail("This shouldn't have passed"); } catch (GigiApiException e) { // expected @@ -77,7 +77,7 @@ public class TestNotary extends BusinessTest { assuranceFail(assurer, users[i], -1, "test-notary", "2014-01-01"); assuranceFail(assurer, users[i], 11, "test-notary", "2014-01-01"); if (User.POJAM_ENABLED) { - Notary.assure(assurer, users[i], users[i].getName(), users[i].getDoB(), 10, "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); + Notary.assure(assurer, users[i], users[i].getPreferredName(), users[i].getDoB(), 10, "test-notary", "2014-01-01", AssuranceType.FACE_TO_FACE); } assuranceFail(assurer, users[i], 10, "test-notary", "2014-01-01"); } @@ -113,7 +113,7 @@ public class TestNotary extends BusinessTest { assuranceFail(assuree, assuranceUser, 10, "notary-junit-test", "2014-01-01"); // valid - Notary.assure(assuranceUser, assuree, assuree.getName(), assuree.getDoB(), 10, "notary-junit-test", "2014-01-01", AssuranceType.FACE_TO_FACE); + Notary.assure(assuranceUser, assuree, assuree.getPreferredName(), assuree.getDoB(), 10, "notary-junit-test", "2014-01-01", AssuranceType.FACE_TO_FACE); // assure double assuranceFail(assuranceUser, assuree, 10, "notary-junit-test", "2014-01-01"); diff --git a/tests/org/cacert/gigi/util/TestPasswordStrengthChecker.java b/tests/org/cacert/gigi/util/TestPasswordStrengthChecker.java index 254df05a..94c60591 100644 --- a/tests/org/cacert/gigi/util/TestPasswordStrengthChecker.java +++ b/tests/org/cacert/gigi/util/TestPasswordStrengthChecker.java @@ -2,19 +2,19 @@ package org.cacert.gigi.util; import static org.junit.Assert.*; -import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.testUtils.ClientBusinessTest; import org.junit.Test; -public class TestPasswordStrengthChecker { - - Name n = new Name("fname", "lname", "mname", "suffix"); +public class TestPasswordStrengthChecker extends ClientBusinessTest { String e = "email"; public TestPasswordStrengthChecker() {} private int check(String pw) { - return PasswordStrengthChecker.checkpw(pw, n, e); + return PasswordStrengthChecker.checkpw(pw, new String[] { + "fname", "lname", "mname", "suffix" + }, e); } @Test diff --git a/util-testing/org/cacert/gigi/pages/Manager.java b/util-testing/org/cacert/gigi/pages/Manager.java index 6a4a521a..6889bfbe 100644 --- a/util-testing/org/cacert/gigi/pages/Manager.java +++ b/util-testing/org/cacert/gigi/pages/Manager.java @@ -39,7 +39,8 @@ import org.cacert.gigi.dbObjects.Domain; import org.cacert.gigi.dbObjects.DomainPingType; import org.cacert.gigi.dbObjects.EmailAddress; import org.cacert.gigi.dbObjects.Group; -import org.cacert.gigi.dbObjects.Name; +import org.cacert.gigi.dbObjects.NamePart; +import org.cacert.gigi.dbObjects.NamePart.NamePartType; import org.cacert.gigi.dbObjects.User; import org.cacert.gigi.email.EmailProvider; import org.cacert.gigi.localisation.Language; @@ -203,7 +204,9 @@ public class Manager extends Page { Calendar gc = GregorianCalendar.getInstance(); gc.setTimeInMillis(0); gc.set(1990, 0, 1); - User u = new User(email, "xvXV12°§", new Name("Först", "Läst", "Müddle", "Süffix"), new DayDate(gc.getTime().getTime()), Locale.ENGLISH); + User u = new User(email, "xvXV12°§", new DayDate(gc.getTime().getTime()), Locale.ENGLISH, // + new NamePart(NamePartType.FIRST_NAME, "Först"), new NamePart(NamePartType.FIRST_NAME, "Müddle"),// + new NamePart(NamePartType.LAST_NAME, "Läst"), new NamePart(NamePartType.SUFFIX, "Süffix")); EmailAddress ea = u.getEmails()[0]; verify(email, ea); } @@ -269,7 +272,7 @@ public class Manager extends Page { } try { for (int i = 0; i < 10; i++) { - Notary.assure(getAssurer(i), byEmail, byEmail.getName(), byEmail.getDoB(), 10, "Testmanager Assure up code", "2014-11-06", AssuranceType.FACE_TO_FACE); + Notary.assure(getAssurer(i), byEmail, byEmail.getPreferredName(), byEmail.getDoB(), 10, "Testmanager Assure up code", "2014-11-06", AssuranceType.FACE_TO_FACE); } } catch (GigiApiException e) { throw new Error(e); @@ -281,7 +284,7 @@ public class Manager extends Page { try { for (int i = 0; i < 25; i++) { User a = getAssurer(i); - Notary.assure(byEmail, a, a.getName(), a.getDoB(), 10, "Testmanager exp up code", "2014-11-06", AssuranceType.FACE_TO_FACE); + Notary.assure(byEmail, a, a.getNames()[0], a.getDoB(), 10, "Testmanager exp up code", "2014-11-06", AssuranceType.FACE_TO_FACE); } } catch (GigiApiException e) { throw new Error(e); -- 2.39.2