Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,33 @@ public void run() throws IOException {
phonePrefixMap = combineMultipleTimes(phonePrefixMap);
PrintWriter printWriter = new PrintWriter(new BufferedOutputStream(outputStream));
for (Map.Entry<String, String> mapping : phonePrefixMap.entrySet()) {
printWriter.printf("%s|%s%s", mapping.getKey(), mapping.getValue(), outputLineSeparator);
printWriter.printf("%s|%s%s",
escapeHtml(mapping.getKey()),
escapeHtml(mapping.getValue()),
outputLineSeparator);
}
printWriter.flush();
}

private static String escapeHtml(String input) {
if (input == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
switch (c) {
case '<': sb.append("&lt;"); break;
case '>': sb.append("&gt;"); break;
case '&': sb.append("&amp;"); break;
case '"': sb.append("&quot;"); break;
case '\'': sb.append("&#39;"); break;
default: sb.append(c);
}
}
return sb.toString();
}

public static void main(String[] args) {
if (args.length != 2) {
LOGGER.severe("usage: java -jar combine-geodata.jar /path/to/input /path/to/output");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,47 @@
* A servlet that invokes the geocoding data combination tool.
*/
public class CombineGeoDataServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, javax.servlet.ServletException {
req.setAttribute("csrf_token", getOrGenerateCsrfToken(req));
req.getRequestDispatcher("index.jsp").forward(req, resp);
}

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (!isTokenValid(req)) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid or missing CSRF token.");
return;
}

resp.setContentType("text/html;charset=UTF-8");
String input = req.getParameter("geodata");
if (input == null) {
input = "";
}
resp.getOutputStream().print("<html><head>");
resp.getOutputStream().print(
"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"></head>");
resp.getOutputStream().print("<body>");
CombineGeoData combineGeoData = new CombineGeoData(
new ByteArrayInputStream(input.getBytes()), resp.getOutputStream(), "<br>");
new ByteArrayInputStream(input.getBytes("UTF-8")), resp.getOutputStream(), "<br>");
combineGeoData.run();
resp.getOutputStream().print("</body></html>");
resp.getOutputStream().flush();
}

protected String getOrGenerateCsrfToken(HttpServletRequest req) {
String csrfToken = (String) req.getSession().getAttribute("csrf_token");
if (csrfToken == null) {
csrfToken = java.util.UUID.randomUUID().toString();
req.getSession().setAttribute("csrf_token", csrfToken);
}
return csrfToken;
}

protected boolean isTokenValid(HttpServletRequest req) {
String sessionToken = (String) req.getSession().getAttribute("csrf_token");
String requestToken = req.getParameter("csrf_token");
return sessionToken != null && sessionToken.equals(requestToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.google.i18n.phonenumbers;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class CombineGeoDataServletTest {

private CombineGeoDataServlet servlet;
private Map<String, Object> sessionAttributes;
private Map<String, Object> requestAttributes;

@Before
public void setUp() {
servlet = new CombineGeoDataServlet();
sessionAttributes = new HashMap<>();
requestAttributes = new HashMap<>();
}

@Test
public void testGetOrGenerateCsrfToken_NewSession() {
HttpServletRequest mockRequest = createMockRequest();

String token = servlet.getOrGenerateCsrfToken(mockRequest);

assertNotNull(token);
assertEquals(token, sessionAttributes.get("csrf_token"));
}

@Test
public void testGetOrGenerateCsrfToken_ExistingSession() {
String existingToken = UUID.randomUUID().toString();
sessionAttributes.put("csrf_token", existingToken);
HttpServletRequest mockRequest = createMockRequest();

String token = servlet.getOrGenerateCsrfToken(mockRequest);

assertEquals(existingToken, token);
}

@Test
public void testIsTokenValid_NoSessionToken() {
HttpServletRequest mockRequest = createMockRequest();
// No token in session

assertFalse(servlet.isTokenValid(mockRequest));
}

@Test
public void testIsTokenValid_ValidToken() {
String token = UUID.randomUUID().toString();
sessionAttributes.put("csrf_token", token);
HttpServletRequest mockRequest = createMockRequest(token);

assertTrue(servlet.isTokenValid(mockRequest));
}

private HttpServletRequest createMockRequest() {
return createMockRequest(null);
}

private HttpServletRequest createMockRequest(String requestToken) {
return (HttpServletRequest) Proxy.newProxyInstance(
HttpServletRequest.class.getClassLoader(),
new Class[] { HttpServletRequest.class },
(proxy, method, args) -> {
if (method.getName().equals("getSession")) {
return createMockSession();
} else if (method.getName().equals("setAttribute")) {
requestAttributes.put((String) args[0], args[1]);
return null;
} else if (method.getName().equals("getAttribute")) {
return requestAttributes.get(args[0]);
} else if (method.getName().equals("getParameter")) {
if ("csrf_token".equals(args[0])) {
return requestToken;
}
return null;
}
return null;
});
}

private HttpSession createMockSession() {
return (HttpSession) Proxy.newProxyInstance(
HttpSession.class.getClassLoader(),
new Class[] { HttpSession.class },
(proxy, method, args) -> {
if (method.getName().equals("getAttribute")) {
return sessionAttributes.get(args[0]);
} else if (method.getName().equals("setAttribute")) {
sessionAttributes.put((String) args[0], args[1]);
return null;
}
return null;
});
}
}
6 changes: 5 additions & 1 deletion tools/java/data/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
<servlet-name>CombineGeoDataServlet</servlet-name>
<url-pattern>/combine</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CombineGeoDataServlet</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><meta http-equiv="content-type" content="text/html; charset=UTF-8"></head>

<body>
<form action="/combine" method="post" accept-charset="UTF-8">
<input type="hidden" name="csrf_token" value="<%= request.getAttribute("csrf_token") %>">
<h2>Geocoding Prefix Reducer</h2>

<p>Please paste your geocoding data below. Each line should be in the format
Expand Down