1 package club.wpia.gigi.pages.wot;
3 import static org.hamcrest.CoreMatchers.*;
4 import static org.junit.Assert.*;
6 import java.io.IOException;
7 import java.io.UnsupportedEncodingException;
8 import java.net.HttpURLConnection;
9 import java.net.MalformedURLException;
10 import java.net.URLConnection;
11 import java.net.URLEncoder;
12 import java.security.GeneralSecurityException;
13 import java.sql.SQLException;
14 import java.sql.Timestamp;
15 import java.text.SimpleDateFormat;
16 import java.util.Calendar;
17 import java.util.Date;
18 import java.util.regex.Pattern;
20 import org.hamcrest.Matcher;
21 import org.junit.Before;
22 import org.junit.Test;
24 import club.wpia.gigi.GigiApiException;
25 import club.wpia.gigi.database.GigiPreparedStatement;
26 import club.wpia.gigi.dbObjects.CATS.CATSType;
27 import club.wpia.gigi.dbObjects.Country;
28 import club.wpia.gigi.dbObjects.Group;
29 import club.wpia.gigi.dbObjects.User;
30 import club.wpia.gigi.pages.account.MyDetails;
31 import club.wpia.gigi.testUtils.IOUtils;
32 import club.wpia.gigi.testUtils.ManagedTest;
33 import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
34 import club.wpia.gigi.util.DayDate;
35 import club.wpia.gigi.util.Notary;
37 public class TestVerification extends ManagedTest {
39 private String agentM;
41 private String applicantM;
43 private int applicantName;
45 private int applicantId;
47 private String cookie;
50 public void setup() throws IOException, GeneralSecurityException, GigiApiException, InterruptedException {
52 agentM = createUniqueName() + "@example.org";
53 applicantM = createUniqueName() + "@example.org";
55 createVerificationUser("a", "b", agentM, TEST_PASSWORD);
56 applicantId = createVerifiedUser("a", "c", applicantM, TEST_PASSWORD);
57 applicantName = User.getById(applicantId).getPreferredName().getId();
59 User users[] = User.findByEmail(agentM);
60 cookie = cookieWithCertificateLogin(users[0]);
63 private Matcher<String> isVerificationForm() {
64 return containsString("<select name=\"verificationType\">");
68 public void testVerifySearch() throws IOException {
69 String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
70 assertThat(loc, isVerificationForm());
74 public void testVerifySearchEmail() throws IOException {
75 String loc = search("email=1" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
76 assertThat(loc, not(isVerificationForm()));
80 public void testVerifySearchDobInvalid() throws IOException {
81 String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=mal");
82 assertThat(loc, not(isVerificationForm()));
86 public void testVerifySearchDob() throws IOException {
87 String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=2&month=1&year=1910");
88 assertThat(loc, not(isVerificationForm()));
89 loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=2&year=1910");
90 assertThat(loc, not(isVerificationForm()));
91 loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1911");
92 assertThat(loc, not(isVerificationForm()));
95 private String search(String query) throws MalformedURLException, IOException, UnsupportedEncodingException {
96 URLConnection uc = get(cookie, VerifyPage.PATH);
98 uc.getOutputStream().write(("search&" + query).getBytes("UTF-8"));
99 uc.getOutputStream().flush();
101 return IOUtils.readURL(uc);
105 public void testVerifyForm() throws IOException {
106 String body = executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
107 assertThat(body, containsString("10"));
108 assertThat(body, containsString(applicantM));
109 getMailReceiver().receive(applicantM);
113 public void testVerifyFormEmpty() throws IOException {
114 URLConnection uc = buildupVerifyFormConnection(true);
115 uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&rules=1&assertion=1&points=10").getBytes("UTF-8"));
116 uc.getOutputStream().flush();
117 String data = IOUtils.readURL(uc);
118 assertThat(data, hasError());
122 public void testVerifyFormContainsData() throws IOException {
123 URLConnection uc = buildupVerifyFormConnection(true);
124 uc.getOutputStream().write(("verifiedName=" + applicantName + "&date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&rules=1&assertion=1&points=10").getBytes("UTF-8"));
125 uc.getOutputStream().flush();
126 String data = IOUtils.readURL(uc);
127 assertThat(data, containsString(validVerificationDateString()));
128 assertThat(data, containsString("testcase"));
132 public void testVerifyFormNoCSRF() throws IOException {
134 HttpURLConnection uc = (HttpURLConnection) buildupVerifyFormConnection(false);
135 uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8"));
136 uc.getOutputStream().flush();
137 assertEquals(500, uc.getResponseCode());
138 uc.getErrorStream().close();
142 public void testVerifyFormWrongCSRF() throws IOException {
144 HttpURLConnection uc = (HttpURLConnection) buildupVerifyFormConnection(false);
145 uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10&csrf=aragc").getBytes("UTF-8"));
146 uc.getOutputStream().flush();
147 assertEquals(500, uc.getResponseCode());
148 uc.getErrorStream().close();
152 public void testVerifyFormRaceDoB() throws IOException, SQLException {
153 testVerifyFormRace(false);
157 public void testVerifyFormRaceDoBBlind() throws IOException, SQLException {
158 testVerifyFormRace(true);
161 public void testVerifyFormRace(boolean succeed) throws IOException, SQLException {
162 URLConnection uc = buildupVerifyFormConnection(true);
164 String applicantCookie = login(applicantM, TEST_PASSWORD);
165 String newDob = "day=1&month=1&year=" + ( !succeed ? 1911 : 1910);
166 loginCertificate = null;
167 assertNull(executeBasicWebInteraction(applicantCookie, MyDetails.PATH, newDob + "&action=updateDoB", 0));
169 uc.getOutputStream().write(("verifiedName=" + applicantName + "&date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8"));
170 uc.getOutputStream().flush();
171 String error = fetchStartErrorMessage(IOUtils.readURL(uc));
174 getMailReceiver().receive(applicantM);
176 assertTrue(error, !error.startsWith("</div>"));
177 assertThat(error, containsString("changed his personal details"));
182 public void testVerifyFormFuture() throws IOException {
183 SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
184 int year = Integer.parseInt(sdf.format(new Date(System.currentTimeMillis()))) + 2;
185 executeFails("date=" + year + "-01-01&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
189 public void testVerifyFormFutureOK() throws IOException {
190 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
191 Calendar c = Calendar.getInstance();
192 c.setTimeInMillis(System.currentTimeMillis());
193 c.add(Calendar.HOUR_OF_DAY, 12);
195 executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
196 getMailReceiver().receive(applicantM);
200 public void testVerifyFormPastInRange() throws IOException {
201 executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
202 getMailReceiver().receive(applicantM);
206 public void testVerifyFormPastOnLimit() throws IOException {
207 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
208 Calendar c = Calendar.getInstance();
209 c.setTimeInMillis(System.currentTimeMillis());
210 c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION);
211 c.add(Calendar.DAY_OF_MONTH, 1);
213 executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
214 getMailReceiver().receive(applicantM);
218 public void testVerifyFormPastOutOfRange() throws IOException {
219 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
220 Calendar c = Calendar.getInstance();
221 c.setTimeInMillis(System.currentTimeMillis());
222 c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION);
224 executeFails("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
228 public void testVerifyFormNoLoc() throws IOException {
229 executeFails("date=" + validVerificationDateString() + "&location=a&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
230 executeFails("date=" + validVerificationDateString() + "&location=&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
234 public void testVerifyFormInvalDate() throws IOException {
235 executeFails("date=20000101&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
236 executeFails("date=&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
240 public void testVerifyFormBoxes() throws IOException {
241 executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=0&rules=1&assertion=1&points=10");
242 executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=&assertion=1&points=10");
243 executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=z&points=10");
247 public void testVerifyListingValid() throws IOException, GigiApiException {
248 String uniqueLoc = createUniqueName();
249 executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
250 getMailReceiver().receive(applicantM);
252 String cookie = login(applicantM, TEST_PASSWORD);
253 loginCertificate = null;
254 URLConnection url = get(cookie, Points.PATH);
255 String resp = IOUtils.readURL(url);
256 resp = resp.split(Pattern.quote("</table>"))[1];
257 assertThat(resp, containsString(uniqueLoc));
258 assertThat(resp, containsString(Country.getCountryByCode("DE", Country.CountryCodeType.CODE_2_CHARS).getName()));
262 public void testAgentListingValid() throws IOException, GigiApiException {
263 String uniqueLoc = createUniqueName();
264 executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
265 getMailReceiver().receive(applicantM);
267 String cookie = login(agentM, TEST_PASSWORD);
268 loginCertificate = null;
269 URLConnection url = get(cookie, Points.PATH);
270 String resp = IOUtils.readURL(url);
271 resp = resp.split(Pattern.quote("</table>"))[2];
272 assertThat(resp, containsString(uniqueLoc));
273 assertThat(resp, containsString(Country.getCountryByCode("DE", Country.CountryCodeType.CODE_2_CHARS).getName()));
276 private void executeFails(String query) throws MalformedURLException, IOException {
277 assertThat(execute(query), hasError());
281 private String executeSuccess(String query) throws MalformedURLException, IOException {
282 String response = execute(query);
283 assertThat(response, hasNoError());
287 private String execute(String query) throws MalformedURLException, IOException {
288 URLConnection uc = buildupVerifyFormConnection(true);
289 uc.getOutputStream().write(("verifiedName=" + applicantName + "&" + query).getBytes("UTF-8"));
290 uc.getOutputStream().flush();
291 return IOUtils.readURL(uc);
294 private URLConnection buildupVerifyFormConnection(boolean doCSRF) throws MalformedURLException, IOException {
295 return buildupVerifyFormConnection(cookie, applicantM, doCSRF);
298 public static URLConnection buildupVerifyFormConnection(String cookie, String email, boolean doCSRF) throws MalformedURLException, IOException {
299 URLConnection uc = get(cookie, VerifyPage.PATH);
300 uc.setDoOutput(true);
301 uc.getOutputStream().write(("email=" + URLEncoder.encode(email, "UTF-8") + "&day=1&month=1&year=1910&search").getBytes("UTF-8"));
303 String csrf = getCSRF(uc);
304 uc = get(cookie, VerifyPage.PATH);
305 uc.setDoOutput(true);
307 uc.getOutputStream().write(("csrf=" + csrf + "&").getBytes("UTF-8"));
313 public void testMultipleVerification() throws IOException, GeneralSecurityException, GigiApiException, InterruptedException {
314 User users[] = User.findByEmail(agentM);
315 int agentID = users[0].getId();
317 users = User.findByEmail(applicantM);
318 int applicantID = users[0].getId();
320 // enter first entry 200 days in the past
321 try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?, `when`=? ")) {
322 ps.setInt(1, agentID);
323 ps.setInt(2, applicantID);
325 ps.setString(4, "test-location");
326 ps.setString(5, "2010-01-01");
327 ps.setTimestamp(6, new Timestamp(System.currentTimeMillis() - DayDate.MILLI_DAY * 200));
331 // enter second entry
332 String uniqueLoc = createUniqueName();
333 executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
334 getMailReceiver().receive(applicantM);
336 // enter third entry on the same day
337 URLConnection uc = get(cookie, VerifyPage.PATH);
338 uc.setDoOutput(true);
339 uc.getOutputStream().write(("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910&search").getBytes("UTF-8"));
340 assertThat(IOUtils.readURL(uc), hasError());
345 public void testVerifyFormNoCountry() throws IOException {
346 executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=&certify=1&rules=1&assertion=1&points=10");
350 public void testRANotificationSet() throws IOException, GigiApiException, GeneralSecurityException, InterruptedException {
351 getMailReceiver().assertEmpty();
353 User users[] = User.findByEmail(agentM);
354 assertTrue("user RA Agent not found", users != null && users.length > 0);
357 u.grantGroup(u, Group.VERIFY_NOTIFICATION);
359 cookie = cookieWithCertificateLogin(users[0]);
361 // enter verification
362 String uniqueLoc = createUniqueName();
363 executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
364 getMailReceiver().receive(applicantM);
366 TestMail tm = getMailReceiver().receive(agentM);
367 assertThat(tm.getMessage(), containsString("You entered a verification for the account with email address " + applicantM));
372 public void testRANotificationNotSet() throws IOException, GigiApiException {
373 getMailReceiver().assertEmpty();
375 User users[] = User.findByEmail(agentM);
376 assertTrue("user RA Agent not found", users != null && users.length > 0);
379 u.revokeGroup(u, Group.VERIFY_NOTIFICATION);
382 // enter verification
383 String uniqueLoc = createUniqueName();
384 executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
386 TestMail tm = getMailReceiver().receive(applicantM);
387 assertThat(tm.getMessage(), not(containsString("You entered a verification for the account with email address " + applicantM)));
392 public void testVerifyWithoutCertLogin() throws IOException {
393 cookie = login(agentM, TEST_PASSWORD);
394 loginCertificate = null;
395 assertEquals(403, get(cookie, VerifyPage.PATH).getResponseCode());
399 public void testVerifyWithoutValidChallenge() throws IOException, GigiApiException {
400 cookie = cookieWithCertificateLogin(User.getById(applicantId));
401 add100Points(applicantId);
402 addChallengeInPast(applicantId, CATSType.AGENT_CHALLENGE);
403 assertEquals(403, get(cookie, VerifyPage.PATH).getResponseCode());
404 addChallenge(applicantId, CATSType.AGENT_CHALLENGE);
405 assertEquals(200, get(cookie, VerifyPage.PATH).getResponseCode());
409 public void testVerifyValidTTPChallenge() throws IOException, GigiApiException {
410 grant(User.getByEmail(agentM), Group.TTP_AGENT);
411 grant(User.getById(applicantId), Group.TTP_APPLICANT);
412 cookie = cookieWithCertificateLogin(User.getById(applicantId));
413 cookie = cookieWithCertificateLogin(User.getByEmail(agentM));
415 // test without valid challenge
416 String content = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
417 assertThat(content, containsString("you need to pass the TTP RA Agent Challenge"));
419 // test with valid challenge
420 addChallenge(User.getByEmail(agentM).getId(), CATSType.TTP_AGENT_CHALLENGE);
421 content = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
422 assertThat(content, not(containsString("you need to pass the TTP RA Agent Challenge")));